Skip to content
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

Merged
merged 10 commits into from
Feb 28, 2024

Conversation

samamorgan
Copy link
Collaborator

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

  • Added model_id decorator function
  • Added a test to ensure that Patient subresources always accept patient_id as the first argument
  • Added unit tests for all new utility methods
  • Merged welkin.util and welkin.models.util

@samamorgan samamorgan force-pushed the samm/parent-accessors branch from 09ad12c to 5caec44 Compare October 27, 2023 02:05
@samamorgan samamorgan requested a review from gone October 27, 2023 02:10
except TypeError:
continue
@pytest.mark.parametrize("class_name", __all__)
def test_collection_pageable(client, class_name: str):
Copy link
Collaborator Author

@samamorgan samamorgan Oct 27, 2023

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):
Copy link
Collaborator Author

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):
Copy link
Collaborator Author

@samamorgan samamorgan Oct 27, 2023

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
Copy link
Collaborator Author

@samamorgan samamorgan Oct 27, 2023

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'

@samamorgan samamorgan force-pushed the samm/parent-accessors branch from aa1f945 to 3a32fd4 Compare October 27, 2023 22:37
@samamorgan samamorgan merged commit 80f1c99 into Lightmatter:develop Feb 28, 2024
@samamorgan samamorgan deleted the samm/parent-accessors branch February 29, 2024 16:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant