Morbidostat.py '>=' not supported between instances of 'dict' and 'float'

Hi!

I have problems with the morbidostat.py plugin (automation-examples/dosing/morbidostat.py at main · Pioreactor/automation-examples · GitHub). More specifically, with a slight variation of it, which takes into account the OD instead of the nOD. This is the code:

  GNU nano 7.2                                        morbidostat.py                                                  
# -*- coding: utf-8 -*-
from __future__ import annotations

from pioreactor.automations import events
from pioreactor.automations.dosing.base import DosingAutomationJobContrib
from pioreactor.exc import CalibrationError


class Morbidostat(DosingAutomationJobContrib):
    """
    As defined in Toprak 2013., keep cell density below and threshold using chemical means. The conc.
    of the chemical is diluted slowly over time, allowing the microbes to recover.
    """

    automation_name = "morbidostat"
    published_settings = {
        "volume": {"datatype": "float", "settable": True, "unit": "mL"},
        "target_od": {"datatype": "float", "settable": True, "unit": "AU"},
        "duration": {"datatype": "float", "settable": True, "unit": "min"},
    }

    def __init__(self, target_od: float | str, volume: float | str, **kwargs):
        super(Morbidostat, self).__init__(**kwargs)

        self.target_od = float(target_od)
        self.volume = float(volume)

    def execute(self) -> events.AutomationEvent:
        if self.previous_od is None:
            return events.NoEvent("skip first event to wait for OD readings.")
        elif (
            self.latest_od >= self.target_od
            self.latest_od >= self.previous_od
        ):
            # if we are above the threshold, and growth rate is greater than dilution rate
            # the second condition is an approximation of this.
            self.execute_io_action(alt_media_ml=self.volume, waste_ml=self.volume)
            return events.AddAltMediaEvent(
                f"latest OD, {self.latest_od:.2f} >= Target OD, {self.target_od:.2f} and Latest OD, {self.latest_od:.>
            )
        else:
            self.execute_io_action(media_ml=self.volume, waste_ml=self.volume)
            return events.DilutionEvent(
                f"latest OD, {self.latest_od:.2f} < Target OD, {self.target_od:.2f} or Latest OD, {self.latest_od:.2f>
            )



In previous versions of pioreactor, the plugin variation worked fine. However, after upgrading to 25.5.22, it reports the following problem:

'>=“ not supported between instances of 'dict” and “float”"

I understand the problem, but I don’t know how to fix it. I guess it will affect this part of the code where the OD is compared with the threshold value.

I tried to solve it by cascading the variable such that:

  float(self.latest_od) >= float(self.target_od)
  float(self.latest_od) >=float(self.previous_od)

but I get this other error:

float() argument must be a string or a real number, not “dict”.

More information:

Software version (all pios): 25.5.22

File path morbidostat.py (all pios): /home/pioreactor/.pioreactor/plugins/

File path morbidostat.yaml (just in leader):/home/pioreactor/.pioreactor/plugins/ui/contrib/automations/dosing/

yaml file:

---
display_name: Morbidostat (Classic)
automation_name: morbidostat
description: >

 As defined in Toprak 2013., keep cell density below and threshold using chemical means. The concentration of the che>

fields:
  - key: target_od
    default: 0.2
    unit: AU
    label: Target OD
    type: numeric
  - key: volume
    default: 1.0
    unit: mL
    label: Volume
    type: numeric
  - key: duration
    default: 12
    unit: min
    label: Time between check
    disabled: False
    type: numeric

Any solution? Some colleagues are visiting us for a week to learn how the pyoreactor works and the experiment has gone down the drain :confused:

Hi @Pedre91

The issue is that self.latest_od and self.previous_od are dictionaries now (they’ve been that way for a while). You need to reference the PD channel being used. , probably "2", to get the OD reading.

Updated code that extracts the floats from the dictionary, and uses those throughout:

    def execute(self) -> events.AutomationEvent:
        previous_od = self.previous_od["2"]
        latest_od = self.latest_od["2"]

        if self.previous_od is None:
            return events.NoEvent("skip first event to wait for OD readings.")
        elif (
            latest_od >= self.target_od and
            latest_od >= previous_od
        ):
            # if we are above the threshold, and growth rate is greater than dilution rate
            # the second condition is an approximation of this.
            self.execute_io_action(alt_media_ml=self.volume, waste_ml=self.volume)
            return events.AddAltMediaEvent(
                f"latest OD, {latest_od:.2f} >= Target OD, {self.target_od:.2f} and Latest OD, {latest_od:.2f} >= Previous OD {previous_od:.2f}" 
            )
        else:
            self.execute_io_action(media_ml=self.volume, waste_ml=self.volume)
            return events.DilutionEvent(
                f"latest OD, {latest_od:.2f} < Target OD, {self.target_od:.2f} or Latest OD, {latest_od:.2f} < Previous OD {previous_od:.2f}" 
            )

1 Like

Thank you so much for the fast reply, Cameron!!! I going to try it now

Hi again Cameron, I get the following new error: “‘NoneType’ object is not subscriptable”

Ah, right, change:

        previous_od = self.previous_od["2"]
        latest_od = self.latest_od["2"]

to

        previous_od = self.previous_od["2"] if self.previous_od else None
        latest_od = self.latest_od["2"]  if self.latest_od else None
1 Like