load_budget should not modify class
Currently in the code for load_budget, the yaml file is loaded and the class is modified!
Budget = getattr(mod, bname)
ifopath = os.path.join(modpath, 'ifo.yaml')
if not ifo and os.path.exists(ifopath):
ifo = Struct.from_file(ifopath)
Budget.ifo = ifo
This means a single class cannot reasonably be loaded from multiple yaml files without being confusing. It is already a bit confusing as a user needs to know to create instances before modifying the B.ifo parameter, or all future instances will be modified.
Two options to remedy:
use the type(name, bases, dict)
metaclass/metafunction to dynamically subclass from the desired Budget class, the loaded ifo can be passed as an attribute during the dynamic subclass creation. This looks like
Budget = getattr(mod, bname)
ifopath = os.path.join(modpath, 'ifo.yaml')
if not ifo and os.path.exists(ifopath):
ifo = Struct.from_file(ifopath)
Budget2 = type(name_or_path, (Budget,), {"ifo" : ifo})
return Budget2
Or (my preference)
since load_budget is acting as an object factory, I don't see why it shouldn't also take the *args, **kwargs and return the instance directly. Is there anything useful that comes from returning the Budget class as an intermediary?
Budget = getattr(mod, bname)
ifopath = os.path.join(modpath, 'ifo.yaml')
b = Budget(*args, **kwargs)
b.ifo = Struct.from_file(ifopath)
return b