Major refactor of the taurus <-> citrine-python interaction#223
Major refactor of the taurus <-> citrine-python interaction#223
Conversation
|
|
||
| encoder = None | ||
|
|
||
| def __init__(self, typ: str): |
There was a problem hiding this comment.
audit_info was moved here from Storable
| @classmethod | ||
| def from_dict(cls, d: dict): | ||
| """Build a data concepts option from a dictionary.""" | ||
| audit_info = d.pop("audit_info", None) |
There was a problem hiding this comment.
This is a general pattern for if we want to add fields to taurus objects
There was a problem hiding this comment.
What do you think about having something like
citrine_python_fields = {'audit_info': AuditInfo}at the class level and looping over that in this method?
| setattr(dc_linked_obj, reverse_field, dc_obj) | ||
| # Re-establish the link between linked_obj and obj_with_soft_links | ||
| setattr(linked_obj, reverse_field, obj_with_soft_links) | ||
| return cls.get_encoder().copy(data) |
| DataConcepts._make_class_dict() | ||
| cls.encoder = TaurusJson() | ||
| cls.encoder.register_classes( | ||
| {k: v for k, v in DataConcepts.class_dict.items() if k != "link_by_uid"} |
There was a problem hiding this comment.
This is where we override the taurus objects with their citrine-python equivalents
| return MaterialRun.build(model) | ||
|
|
||
| # Add the root to the context and sort by writable order | ||
| blob = dict() |
There was a problem hiding this comment.
This reconstructs the json serialization format so that json deserialization can be used to build the connected material history
| from taurus.util import flatten | ||
|
|
||
|
|
||
| def test_flatten(): |
There was a problem hiding this comment.
This is the originating test that we wanted to get passing.
|
|
kroenlein
left a comment
There was a problem hiding this comment.
Generally looks good.
| @@ -1,4 +1,4 @@ | |||
| taurus-citrine==0.4.1 | |||
| git+https://github.com/CitrineInformatics/taurus.git@develop | |||
There was a problem hiding this comment.
Why is the official requirements file pulling in develop?
There was a problem hiding this comment.
That's outdated; it was just for testing before the taurus 0.6.0 release.
|
I'm wondering if we shouldn't leave in |
| :py:mod:`JSON encoder <taurus.jsonr>`. The ensuing dictionary must | ||
| have a `type` field that corresponds to the response key of this class or of | ||
| :py:class:`LinkByUID <taurus.entity.link_by_uid.LinkByUID>`. | ||
| session: Session |
kroenlein
left a comment
There was a problem hiding this comment.
Generally agree. There's a residual
from taurus.client.json_encoder import loads, dumps
in tests/serialization/test_attribute_template.py that does not appear to be intentional. Should it be scrubbed?
asantas93
left a comment
There was a problem hiding this comment.
Huge fan of this. Left a few small comments.
| The name of the field | ||
| audit_info = d.pop("audit_info", None) | ||
| obj = super().from_dict(d) | ||
| obj.skip.add("_audit_info") |
There was a problem hiding this comment.
I'm a little put off by mutations to skip -- isn't it a class variable?
There was a problem hiding this comment.
Looks like we just don't need this.
| @classmethod | ||
| def from_dict(cls, d: dict): | ||
| """Build a data concepts option from a dictionary.""" | ||
| audit_info = d.pop("audit_info", None) |
There was a problem hiding this comment.
What do you think about having something like
citrine_python_fields = {'audit_info': AuditInfo}at the class level and looping over that in this method?
| data['context'] + [data['root']], | ||
| key=lambda x: writable_sort_order(x["type"]) | ||
| ) | ||
| root_uid = next(iter(data['root']['uids'].items())) |
There was a problem hiding this comment.
| root_uid = next(iter(data['root']['uids'].items())) | |
| root_scope, root_id = next(iter(data['root']['uids'].items())) |
maybe?
| blob["context"] = sorted( | ||
| data['context'] + [data['root']], | ||
| key=lambda x: writable_sort_order(x["type"]) | ||
| ) |
|
|
||
| # Serialize using normal json (with the TaurusEncoder) and then deserialize with the | ||
| # TaurusJson encoder in order to rebuild the material history | ||
| return MaterialRun.get_encoder().loads(json.dumps(blob, cls=TaurusEncoder, sort_keys=True)) |
There was a problem hiding this comment.
Is there a way to move from python primitive types to citrine-python types directly? In my dream world git grep 'loads.*dumps' exits with failure.
There was a problem hiding this comment.
I think we'd want to dive into get_resource to deserialize using get_json_support the first time rather than going round-robin through the string again. Let's leave that out of scope for this PR, though? It'd be an easy non-breaking change to make in the future.
| if popped[field] is None: | ||
| setattr(obj, "_{}".format(field), None) | ||
| elif isinstance(popped[field], dict): | ||
| setattr(obj, "_{}".format(field), clazz.build(popped[field])) |
There was a problem hiding this comment.
I think we probably want to fall back on clazz(popped[field]) when hasattr(clazz, 'build') is false. That would allow us to use primitive types.
There was a problem hiding this comment.
Actually there's probably a neater way than hasattr. Either way I think we can probably use that and ditch the is instance of dict check above.
There was a problem hiding this comment.
issubclass seems to be the thing I'm thinking of instead of hasattr
There was a problem hiding this comment.
Can we cross that bridge when we get there? We'll have more information when we next decide to add a client_specific_field.
Citrine Python PR
Description
This PR is a major refactor of the way that citrine-python uses taurus. In taurus 0.6.0, the json serializer/deserializer was encapsulated in the
TaurusJson()class. This allowed for theregister_classesmethod to be exposed, which allows the class dictionary of aTaurusJsonobject to be updated. This change usesregister_classesto override the deserialization of taurus objects like MaterialRun and ProcessTemplate to their citrine-python resource counterparts. That way, the taurus loads/dumps methods can be used to reconstruct material histories from the response of the material history route, which significantly simplifies the logic contained here in this repo (-923 lines!).This leads to two other semi-significant changes:
citrine.attributesno longer need to be duplicated from taurus; the taurus versions will do fine on their ownStorablewas therefore rolled back intoDataConceptsand the logic to include audit_info was moved there.There are some consequences to the json format due to the upgrade from taurus 0.4.1 to 0.6.0, which are communicated in v0.5.0 release notes and v0.6.0 release notes.
PR Type:
Adherence to team decisions