Make dynamic attributes of model introspectable

`dir(object)` is a useful Python function that tells you what attributes
and methods an object has. It’s also used by tools like iPython and IDEs
for code completion.

Some of the attributes of a `JSONModel` are dynamic, based on what
fields we expect in the underlying JSON. Therefore they don’t
automatically end up in the result of calling `dir`. To get around this
we can implement our own `__dir__` method, which also returns the names
of the fields we’re expecting the the JSON.

Inspired by this Raymond Hettinger tweet:

> #python tip:  If you add attributes to an API with __getattr__() or
> __getattribute__(), remember to update __dir__() to make the extension
> introspectable.

— https://twitter.com/raymondh/status/1249860863525146624
This commit is contained in:
Chris Hill-Scott
2020-04-14 09:39:39 +01:00
parent cee7277b47
commit 23e1682260
2 changed files with 11 additions and 0 deletions

View File

@@ -18,6 +18,9 @@ class JSONModel():
def __hash__(self):
return hash(self.id)
def __dir__(self):
return super().__dir__() + list(sorted(self.ALLOWED_PROPERTIES))
def __eq__(self, other):
return self.id == other.id

View File

@@ -68,3 +68,11 @@ def test_model_doesnt_swallow_attribute_errors(json_response):
Custom(json_response).foo
assert str(e.value) == 'Something has gone wrong'
def test_dynamic_properties_are_introspectable():
class Custom(JSONModel):
ALLOWED_PROPERTIES = {'foo', 'bar', 'baz'}
assert dir(Custom({}))[-3:] == ['bar', 'baz', 'foo']