-
Notifications
You must be signed in to change notification settings - Fork 3
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
Unify parent accessor methods #90
Unify parent accessor methods #90
Conversation
09ad12c
to
5caec44
Compare
except TypeError: | ||
continue | ||
@pytest.mark.parametrize("class_name", __all__) | ||
def test_collection_pageable(client, class_name: str): |
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.
Note: The change to this test was just to make it parametrized. No functional changes.
@@ -45,6 +45,9 @@ def __getattr__(self, name): | |||
def __setattr__(self, name, value): | |||
super().__setitem__(name, value) | |||
|
|||
def __delattr__(self, name): |
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.
Added this as a convenience. Previously, if one tried to del
an attribute of this class, an AttributeError
would be raised. The only way to actually delete an attribute was with dictionary syntax. Now both are possible.
r = Resource(id="123")
del r["id"]
del r.id # Previously not possible
|
||
|
||
class CDT(Resource): | ||
def create(self): | ||
@model_id("Patient") | ||
def create(self, patient_id: str): |
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.
Adding a positional argument to a method would usually trigger a higher-level version bump. However, this change is technically idempotent and fully backwards-compatible since model_id
will set the argument.
return f(self, *args, **kwargs) | ||
except TypeError as exc: | ||
# Raise from the outer `AttributeError` so we don't lose context. | ||
raise exc from outer_exc |
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.
The exception pattern here probably looks a little strange, so let me explain.
At the end of the chain, we do want to raise the normal TypeError
that Python would raise if the model ID argument isn't filled. However, we don't want to lose the context so implementers have some hints on how to fix the issue, since this mechanism is doing a bit of recursive introspection. The end result is a traceback chain that includes both the TypeError
and the AttributeError
(s) like so:
>>> from welkin.models import Patient
>>> Patient().Encounter().EncounterDisposition().get()
Traceback (most recent call last):
File "/Users/sammorgan/Git/zest-welkin-health/welkin/util.py", line 164, in wrapper
raise e from outer_exc
File "/Users/sammorgan/Git/zest-welkin-health/welkin/util.py", line 161, in wrapper
kwargs[key] = find_model_id(self, model)
File "/Users/sammorgan/Git/zest-welkin-health/welkin/util.py", line 135, in find_model_id
return find_model_id(instance._parent, model_name)
File "/Users/sammorgan/Git/zest-welkin-health/welkin/util.py", line 135, in find_model_id
return find_model_id(instance._parent, model_name)
File "/Users/sammorgan/Git/zest-welkin-health/welkin/util.py", line 131, in find_model_id
return instance.id
File "/Users/sammorgan/Git/zest-welkin-health/welkin/models/base.py", line 34, in __getattr__
value = super().__getattr__(name)
File "/Users/sammorgan/Git/zest-welkin-health/welkin/models/base.py", line 24, in __getattr__
raise AttributeError(e) from None
AttributeError: 'Patient' object has no attribute 'id'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/Users/sammorgan/Git/zest-welkin-health/welkin/util.py", line 164, in wrapper
raise e from outer_exc
File "/Users/sammorgan/Git/zest-welkin-health/welkin/util.py", line 161, in wrapper
kwargs[key] = find_model_id(self, model)
File "/Users/sammorgan/Git/zest-welkin-health/welkin/util.py", line 135, in find_model_id
return find_model_id(instance._parent, model_name)
File "/Users/sammorgan/Git/zest-welkin-health/welkin/util.py", line 131, in find_model_id
return instance.id
File "/Users/sammorgan/Git/zest-welkin-health/welkin/models/base.py", line 34, in __getattr__
value = super().__getattr__(name)
File "/Users/sammorgan/Git/zest-welkin-health/welkin/models/base.py", line 24, in __getattr__
raise AttributeError(e) from None
AttributeError: 'Encounter' object has no attribute 'id'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/sammorgan/Git/zest-welkin-health/welkin/util.py", line 172, in wrapper
raise exc from outer_exc
File "/Users/sammorgan/Git/zest-welkin-health/welkin/util.py", line 169, in wrapper
return f(self, *args, **kwargs)
TypeError: EncounterDisposition.get() missing 2 required positional arguments: 'patient_id' and 'encounter_id'
aa1f945
to
3a32fd4
Compare
We had a number of methods that were introspecting the parent chain for IDs, this cleans all of those up and centralizes all functionality.
This should be backwards-compatible, as no changes were made to existing model tests.
Changelog
model_id
decorator functionPatient
subresources always acceptpatient_id
as the first argumentwelkin.util
andwelkin.models.util