-
Notifications
You must be signed in to change notification settings - Fork 49
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
pydantic anti patterns #273
Comments
We never do 2. directly, but what we have in the sources is something like this: class PlanarSource(Source, ABC):
"""A source defined on a 2D plane."""
@property
def injection_axis(self):
"""Injection axis of the source."""
return self.size.index(0.0)
@injection_axis.setter
def injection_axis(self):
raise ValueError("PlanarSource injection axis is defined by the axis normal to the plane.")
class DirectionalSource(Source, ABC):
"""A Source defined with a direction of propagation."""
direction: Direction
injection_axis: Axis
class ModeSource(PlanarSource, DirectionalSource):
"""Injects current source to excite modal profile on finite extent plane.""" I feel like this is almost kosher, because there's no way (that I can think of) that it can produce unexpected results. That said it's probably not best practice. It's just that the alternatives seem to make code reuse (e.g. in the plotting of the arrows) harder. Note also that currently we don't have any Regarding 1, we only do that in validators, right? I wonder if, again in the interest of simplified API and internal code, doing something like this can't be considered OK if we make sure to validate for the extra data in the subclass: class Model1:
data1: Any = None
class Model2(Model1):
data2: Any = None
pydantic.validator("data2")
def validate_data2(cls, val, values):
values["data1"] = something
pydantic.validator("data1")
def validate_data1(cls, val):
raise ValueError("'data1' is implicitly set by 'data2' in 'Model2' models.") This could be the approach in e.g. PolySlab w.r.t. |
Regarding 1, maybe the best strategy is to use properties instead of through validators or setting somewhere else in code. class Model:
data:Any = None
def some_method(self):
self.data = something becomes class Model:
@property
def data(self):
return something |
Well this is certainly a good approach within the limited scope of this toy example, but the point is what happens when other models subclass from |
Yea I guess this approach I put was with things like For geometry, I'm not so sure. We might need to rewrite the polyslab to use a center + size approach by default instead of by bounds for this to be consistent. |
Regarding 2, seems a bit tricker, maybe we need to refactor a little more to make it work. I'll think about it some more. |
Yeah that should definitely be set up like that.
Maybe, I'm just wondering if it's not OK using the validators as I proposed above in the interest of simpler API.
Yeah give it some thought, another strange thing there is that the |
Revisiting this a bit because why not:
class Model:
_data: DataType = PrivateAttr(None)
def some_method(self):
self._data = something |
Yeah, that works if possible. But the main issue with this has been setting something in a subclass that is a proper field in the parent class (setting length from slab_bounds in PolySlab). |
In this case, potentially the |
Things we do that maybe we shouldn't.
Setting an attribute in the model.
What if the user specifies data2?
Properties and attributes
The text was updated successfully, but these errors were encountered: