-
Notifications
You must be signed in to change notification settings - Fork 0
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
Refactor evolver.base #217
Conversation
Codecov ReportAttention: Patch coverage is
📢 Thoughts on this report? Let us know! |
Signed-off-by: James Noss <jnoss@jhu.edu>
Signed-off-by: James Noss <jnoss@jhu.edu>
Signed-off-by: James Noss <jnoss@jhu.edu>
7d14cb2
to
ecfda50
Compare
@classmethod | ||
def load(cls, file_path: Path, encoding: str | None = None): | ||
"""Loads the specified config file and return a new instance.""" | ||
with open(file_path, encoding=encoding) as f: | ||
return cls.model_validate(yaml.safe_load(f)) | ||
|
||
def save(self, file_path: Path, encoding: str | None = None): | ||
"""Write out config as yaml file to specified file.""" | ||
file_path = Path(file_path) | ||
file_path.parent.mkdir(parents=True, exist_ok=True) | ||
with open(file_path, "w", encoding=encoding) as f: | ||
yaml.dump(self.model_dump(mode="json"), f) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These were unnecessarily duplicated.
e5ca24c
to
ab64d08
Compare
Signed-off-by: James Noss <jnoss@jhu.edu>
ab64d08
to
818accc
Compare
try: | ||
# json str might be that for a ConfigDescriptor, so try that 1st. | ||
descriptor = ConfigDescriptor.model_validate_json(obj, strict=strict, context=context) | ||
except Exception: | ||
# Ok, maybe it wasn't a ConfigDescriptor... (or was but was malformed) | ||
# Explicitly call ``model_validate_json`` rather than ``super().model_validate()`` to declare explicit | ||
# code logic. | ||
return cls.model_validate_json(obj, strict=strict, context=context) | ||
else: | ||
# Cool, it was a ConfigDescriptor so validate from that. Remember ``ConfigDescriptor.config`` is just a | ||
# dict. | ||
return super().model_validate( | ||
descriptor.config, strict=strict, from_attributes=from_attributes, context=context | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@amitschang It would be handy for #234 if this duplication got nuked. Does it make sense for us to lose info by converting from a descriptor to a naked Config
?
It appears that there's currently no test in the suite for this (which I can add), however, I can't think of an existing or needed use case for this, can you? If not, maybe we should nuke it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test added.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean a need for converting from a ConfigDescriptor
to Config
(of the class specified in classinfo
, I guess)? If the loss you are talking about is when serializing that Config
object we lose the classinfo
, then yeah I can't think of a reason we desire this.
But not sure if that is what you are asking.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that's exactly it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jamienoss, is there something you will change here, then? Or is it ready?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not in this PR as it opens questions to removing other sections of that switch also, i.e., all other sections dealing with descriptors, not just those as strings.
Sorry for the confusion, I just wanted to know as an aid to working on #234.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Opened #242 to address this.
Signed-off-by: James Noss <jnoss@jhu.edu>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good overall, just a couple comments
evolver/base.py
Outdated
@@ -8,6 +8,7 @@ | |||
import pydantic | |||
import pydantic_core | |||
import yaml | |||
from pydantic._internal._validators import import_string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we be using this? the _internal
and lack of docs make me think not. It looks like this is used to import from fqcn to a type, perhaps we could either make a util using importlib or a simple wrapper around a pydantic model that has ImportString type?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at https://github.com/pydantic/pydantic/blob/main/pydantic/_internal/_validators.py#L72, it doesn't seem worth it to replicate this. Your second suggestion sound great though and will implement that, thanks!
evolver/base.py
Outdated
validate_classinfo(descriptor.classinfo) | ||
config = descriptor.config | ||
|
||
config_dict = config.shallow_model_dump() if isinstance(config, _BaseConfig) else config |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be worth a note here for posterity as to why this is needed - is it because this could be a dict due to 287 or 301? In the latter case, should it be validated or has it already been?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment added. Also, note that this should be checked against _BaseModel
and not _BaseConfig
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
...and it will have been validated by then.
Signed-off-by: James Noss <jnoss@jhu.edu>
Signed-off-by: James Noss <jnoss@jhu.edu>
# Next handle dict | str, which could be that representing a Config or a ConfigDescriptor. | ||
# First see if config is actually a descriptor by trying to create one, since it's only fields are limited | ||
# to classinfo and config. | ||
# Last is a str representing either a Config or ConfigDescriptor. | ||
try: | ||
descriptor = ConfigDescriptor.model_validate(config, context=dict(extra="forbid")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re #217 (comment), validation takes place here.
elif _is_descriptor_dict(config): | ||
validate_classinfo(config["classinfo"]) | ||
config = cls.Config.model_validate(config["config"]) | ||
elif isinstance(config, dict): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re #217 (comment), validation takes place here.
#213 Was the main driver for this refactor. However, it does not fix that issue but instead refactors some code to make things more manageable to future changes.
The core change is the creation of
_BaseModel
for the separation of conversion back and forth betweenConfig
, instances, andConfigDescriptors
such that it is clearer where in the code this happens - it is no longer circular. For clarity_BaseModel
does not handle the conversion betweenConfig
andconfigDescriptor
and instead only includes other base conversions, i.e., json strings. Soln. to #234 would also go in this new class. This PR introduces some duplication in logic, but at the expense of it being more direct and explicit per specific desired class behavior.This should also help and relate to #234.