Copying (or deep copying) a model instance results in an error within copy.py:
import copy
import flopy
m = flopy.modflow.Modflow()
cp = copy.copy(m)
TypeError: 'NoneType' object is not callable
I think this is because of how BaseModel.__getattr__() is implemented. Unhandled attributes are returned as None, which causes the error in copy.py. Doing some googling and looking at the Learning Python book, I think __getattr__ is supposed to raise an AttributeError for unhandled attributes, as it is the last stop in the attribute lookup sequence. The problem with doing this right now is there are at least a few (maybe many) instances where undefined attributes are called. For example, ModflowDis.__init__ calls model._rotation, which may not be defined. Currently, when loading a model, this call gets passed thru __getattr__, which returns None, but would otherwise result in an AttributeError.
It seems like we shouldn't be relying on __getattr__ to initialize any undefined attributes that are called, and should instead initialize them to None in the model.__init__ methods. But maybe there's a better way.
I think we do want to be able to copy model instances. In addition to any user cases, this could be important in refactoring the test suite using fixtures to be more efficient.
It looks like this issue also applies to mf6 simulation, model and package instances. Modflow-2005 style Package instances copy fine, presumably because they don't overload __getattr__.
Copying (or deep copying) a model instance results in an error within
copy.py:I think this is because of how
BaseModel.__getattr__()is implemented. Unhandled attributes are returned asNone, which causes the error incopy.py. Doing some googling and looking at the Learning Python book, I think__getattr__is supposed to raise anAttributeErrorfor unhandled attributes, as it is the last stop in the attribute lookup sequence. The problem with doing this right now is there are at least a few (maybe many) instances where undefined attributes are called. For example,ModflowDis.__init__callsmodel._rotation, which may not be defined. Currently, when loading a model, this call gets passed thru__getattr__, which returnsNone, but would otherwise result in anAttributeError.It seems like we shouldn't be relying on
__getattr__to initialize any undefined attributes that are called, and should instead initialize them toNonein themodel.__init__methods. But maybe there's a better way.I think we do want to be able to copy model instances. In addition to any user cases, this could be important in refactoring the test suite using fixtures to be more efficient.
It looks like this issue also applies to mf6 simulation, model and package instances. Modflow-2005 style Package instances copy fine, presumably because they don't overload
__getattr__.