mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-02-08 20:33:47 -05:00
Brings in: - re-usable `SerialisedModel` - speed improvements to processing CSVs against email templates I chose not to rename `JSONModel` or `ModelList` to keep the diff nice and small.
69 lines
1.9 KiB
Python
69 lines
1.9 KiB
Python
from abc import abstractmethod
|
||
|
||
from flask import abort
|
||
from notifications_utils.serialised_model import (
|
||
SerialisedModel,
|
||
SerialisedModelCollection,
|
||
)
|
||
|
||
|
||
class JSONModel(SerialisedModel):
|
||
|
||
def __init__(self, _dict):
|
||
# in the case of a bad request _dict may be `None`
|
||
self._dict = _dict or {}
|
||
|
||
def __bool__(self):
|
||
return self._dict != {}
|
||
|
||
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
|
||
|
||
def __getattribute__(self, attr):
|
||
# Eventually we should remove this custom implementation in
|
||
# favour of looping over self.ALLOWED_PROPERTIES in __init__
|
||
|
||
try:
|
||
return super().__getattribute__(attr)
|
||
except AttributeError as e:
|
||
# Re-raise any `AttributeError`s that are not directly on
|
||
# this object because they indicate an underlying exception
|
||
# that we don’t want to swallow
|
||
if str(e) != "'{}' object has no attribute '{}'".format(
|
||
self.__class__.__name__, attr
|
||
):
|
||
raise e
|
||
|
||
if attr in super().__getattribute__('ALLOWED_PROPERTIES'):
|
||
return super().__getattribute__('_dict')[attr]
|
||
|
||
raise AttributeError((
|
||
"'{}' object has no attribute '{}' and '{}' is not a field "
|
||
"in the underlying JSON"
|
||
).format(
|
||
self.__class__.__name__, attr, attr
|
||
))
|
||
|
||
def _get_by_id(self, things, id):
|
||
try:
|
||
return next(thing for thing in things if thing['id'] == str(id))
|
||
except StopIteration:
|
||
abort(404)
|
||
|
||
|
||
class ModelList(SerialisedModelCollection):
|
||
|
||
@property
|
||
@abstractmethod
|
||
def client_method(self):
|
||
pass
|
||
|
||
def __init__(self, *args):
|
||
self.items = self.client_method(*args)
|