diff --git a/archivist/access_policies.py b/archivist/access_policies.py index ad118182..f138839b 100644 --- a/archivist/access_policies.py +++ b/archivist/access_policies.py @@ -21,10 +21,14 @@ """ +from typing import List, Optional import logging - from copy import deepcopy +# pylint:disable=unused-import # To prevent cyclical import errors forward referencing is used +# pylint:disable=cyclic-import # but pylint doesn't understand this feature +from archivist import archivist as type_helper + from .constants import ( SEP, ACCESS_POLICIES_SUBPATH, @@ -42,10 +46,14 @@ LOGGER = logging.getLogger(__name__) +class AccessPolicy(dict): + """AccessPolicy object""" + + class _AccessPoliciesClient: """AccessPoliciesClient - Access to access_policies entitiies using CRUD interface. This class is usually + Access to access_policies entities using CRUD interface. This class is usually accessed as an attribute of the Archivist class. Args: @@ -53,10 +61,12 @@ class _AccessPoliciesClient: """ - def __init__(self, archivist): + def __init__(self, archivist: "type_helper.Archivist"): self._archivist = archivist - def create(self, props, filters, access_permissions): + def create( + self, props: dict, filters: List, access_permissions: List + ) -> AccessPolicy: """Create access policy Creates access policy with defined attributes. @@ -75,7 +85,7 @@ def create(self, props, filters, access_permissions): self.__query(props, filters=filters, access_permissions=access_permissions), ) - def create_from_data(self, data): + def create_from_data(self, data: dict) -> AccessPolicy: """Create access policy Creates access policy with request body from data stream. @@ -95,7 +105,7 @@ def create_from_data(self, data): ) ) - def read(self, identity): + def read(self, identity: str) -> AccessPolicy: """Read Access Policy Reads access policy. @@ -114,7 +124,13 @@ def read(self, identity): ) ) - def update(self, identity, props=None, filters=None, access_permissions=None): + def update( + self, + identity, + props: Optional[dict] = None, + filters: Optional[list] = None, + access_permissions: Optional[list] = None, + ) -> AccessPolicy: """Update Access Policy Update access policy. @@ -139,7 +155,7 @@ def update(self, identity, props=None, filters=None, access_permissions=None): ) ) - def delete(self, identity): + def delete(self, identity: str) -> dict: """Delete Access Policy Deletes access policy. @@ -164,7 +180,7 @@ def __query(props, *, filters=None, access_permissions=None): return query - def count(self, *, display_name=None): + def count(self, *, display_name: Optional[str] = None) -> int: """Count access policies. Counts number of access policies that match criteria. @@ -183,10 +199,7 @@ def count(self, *, display_name=None): ) def list( - self, - *, - page_size=DEFAULT_PAGE_SIZE, - display_name=None, + self, *, page_size: int = DEFAULT_PAGE_SIZE, display_name: Optional[str] = None ): """List access policies. @@ -212,10 +225,10 @@ def list( ) # additional queries on different endpoints - def count_matching_assets(self, access_policy_id): + def count_matching_assets(self, access_policy_id: str) -> int: """Count assets that match access_policy. - Counts number of assets that match an access_polocy. + Counts number of assets that match an access_policy. Args: access_policy_id (str): e.g. access_policies/xxxxxxxxxxxxxxx @@ -229,10 +242,7 @@ def count_matching_assets(self, access_policy_id): ) def list_matching_assets( - self, - access_policy_id, - *, - page_size=DEFAULT_PAGE_SIZE, + self, access_policy_id: str, *, page_size: int = DEFAULT_PAGE_SIZE ): """List matching assets. @@ -255,7 +265,7 @@ def list_matching_assets( ) ) - def count_matching_access_policies(self, asset_id): + def count_matching_access_policies(self, asset_id: str) -> int: """Count access policies that match asset. Counts number of access policies that match asset. @@ -271,7 +281,9 @@ def count_matching_access_policies(self, asset_id): SEP.join((ACCESS_POLICIES_SUBPATH, asset_id, ACCESS_POLICIES_LABEL)), ) - def list_matching_access_policies(self, asset_id, *, page_size=DEFAULT_PAGE_SIZE): + def list_matching_access_policies( + self, asset_id: str, *, page_size: int = DEFAULT_PAGE_SIZE + ): """List matching access policies. List access policies that match asset. @@ -292,7 +304,3 @@ def list_matching_access_policies(self, asset_id, *, page_size=DEFAULT_PAGE_SIZE page_size=page_size, ) ) - - -class AccessPolicy(dict): - """AccessPolicy object""" diff --git a/archivist/archivist.py b/archivist/archivist.py index dee8468c..55ba3627 100644 --- a/archivist/archivist.py +++ b/archivist/archivist.py @@ -6,7 +6,7 @@ the basic REST verbs to GET, POST, PATCH and DELETE entities.. The REST methods in this class should only be used directly when - a CRUD endpoint for the specific type of entity is unavaliable. + a CRUD endpoint for the specific type of entity is unavailable. Current CRUD endpoints are assets, events, locations, attachments. IAM subjects and IAM access policies. @@ -24,7 +24,7 @@ auth=authtoken, ) - The arch variable now has additonal endpoints assets,events,locations, + The arch variable now has additional endpoints assets,events,locations, attachments, IAM subjects and IAM access policies documented elsewhere. """ @@ -33,7 +33,8 @@ import json from os.path import isfile as os_path_isfile -from typing import Optional +from typing import IO, Optional +from requests.models import Response from flatten_dict import flatten import requests @@ -92,7 +93,15 @@ class Archivist: # pylint: disable=too-many-instance-attributes """ - def __init__(self, url, *, auth=None, cert=None, verify=True): + def __init__( + self, + url: str, + *, + auth: Optional[str] = None, + cert: Optional[str] = None, + verify: bool = True, + ): + self._headers = {"content-type": "application/json"} if auth is not None: self._headers["authorization"] = "Bearer " + auth.strip() @@ -114,14 +123,14 @@ def __init__(self, url, *, auth=None, cert=None, verify=True): self._cert = cert # keep these in sync with CLIENTS map above - self.assets: Optional[_AssetsClient] - self.events: Optional[_EventsClient] - self.locations: Optional[_LocationsClient] - self.attachments: Optional[_AttachmentsClient] - self.access_policies: Optional[_AccessPoliciesClient] - self.subjects: Optional[_SubjectsClient] - - def __getattr__(self, value): + self.assets: _AssetsClient + self.events: _EventsClient + self.locations: _LocationsClient + self.attachments: _AttachmentsClient + self.access_policies: _AccessPoliciesClient + self.subjects: _SubjectsClient + + def __getattr__(self, value: str): """Create endpoints on demand""" client = CLIENTS.get(value) @@ -133,22 +142,22 @@ def __getattr__(self, value): return c @property - def headers(self): + def headers(self) -> dict: """dict: Headers REST headers from response""" return self._headers @property - def url(self): + def url(self) -> str: """str: URL of Archivist endpoint""" return self._url @property - def verify(self): + def verify(self) -> bool: """bool: Returns True if https connections are to be verified""" return self._verify @property - def cert(self): + def cert(self) -> str: """str: filepath containing authorisation certificate.""" return self._cert @@ -161,7 +170,9 @@ def __add_headers(self, headers): return newheaders - def get(self, subpath, identity, *, headers=None): + def get( + self, subpath: str, identity: str, *, headers: Optional[dict] = None + ) -> dict: """GET method (REST) Args: @@ -173,7 +184,6 @@ def get(self, subpath, identity, *, headers=None): dict representing the response body (entity). """ - LOGGER.debug("get %s/%s", subpath, identity) response = requests.get( SEP.join((self.url, ROOT, subpath, identity)), headers=self.__add_headers(headers), @@ -187,7 +197,9 @@ def get(self, subpath, identity, *, headers=None): return response.json() - def get_file(self, subpath, identity, fd, *, headers=None): + def get_file( + self, subpath: str, identity: str, fd: IO, *, headers: Optional[dict] = None + ) -> Response: """GET method (REST) - chunked Downloads a binary object from upstream storage. @@ -220,7 +232,7 @@ def get_file(self, subpath, identity, fd, *, headers=None): return response - def post(self, path, request, *, headers=None): + def post(self, path: str, request: dict, *, headers: Optional[dict] = None) -> dict: """POST method (REST) Creates an entity @@ -249,7 +261,7 @@ def post(self, path, request, *, headers=None): return response.json() - def post_file(self, path, fd, mtype): + def post_file(self, path: str, fd: IO, mtype: str) -> dict: """POST method (REST) - upload binary Uploads a file to an endpoint @@ -286,7 +298,9 @@ def post_file(self, path, fd, mtype): return response.json() - def delete(self, subpath, identity, *, headers=None): + def delete( + self, subpath: str, identity: str, *, headers: Optional[dict] = None + ) -> dict: """DELETE method (REST) Deletes an entity @@ -313,7 +327,14 @@ def delete(self, subpath, identity, *, headers=None): return response.json() - def patch(self, subpath, identity, request, *, headers=None): + def patch( + self, + subpath: str, + identity: str, + request: dict, + *, + headers: Optional[dict] = None, + ) -> dict: """PATCH method (REST) Updates the specified entity. @@ -365,7 +386,9 @@ def __query(query): sorted(f"{k}={v}" for k, v in flatten(query, reducer="dot").items()) ) - def get_by_signature(self, path, field, query, *, headers=None): + def get_by_signature( + self, path: str, field: str, query: dict, *, headers: Optional[dict] = None + ) -> dict: """GET method (REST) with query string Reads an entity indirectly by searching for its signature @@ -413,7 +436,7 @@ def get_by_signature(self, path, field, query, *, headers=None): return records[0] - def count(self, path, *, query=None): + def count(self, path: str, *, query: Optional[dict] = None) -> int: """GET method (REST) with query string Returns the count of objects that match query @@ -439,7 +462,15 @@ def count(self, path, *, query=None): return int(response.headers[HEADERS_TOTAL_COUNT]) - def list(self, path, field, *, page_size=None, query=None, headers=None): + def list( + self, + path: str, + field: str, + *, + page_size: Optional[int] = None, + query: Optional[dict] = None, + headers: Optional[dict] = None, + ): """GET method (REST) with query string Lists entities that match the query dictionary. diff --git a/archivist/assets.py b/archivist/assets.py index 08c35aef..f6ece2d5 100644 --- a/archivist/assets.py +++ b/archivist/assets.py @@ -22,9 +22,14 @@ """ import logging - +from typing import List, Optional from copy import deepcopy +# pylint:disable=unused-import # To prevent cyclical import errors forward referencing is used +# pylint:disable=cyclic-import # but pylint doesn't understand this feature +from archivist import archivist as type_helper + + from .constants import ( ASSETS_SUBPATH, ASSETS_LABEL, @@ -40,10 +45,57 @@ LOGGER = logging.getLogger(__name__) +class Asset(dict): + """Asset + + Asset object has dictionary attributes and properties. + + """ + + @property + def primary_image(self): + """Primary Image + + Attachment that is the primary image of the asset. + + Returns: + :class:`Attachment` instance + + """ + try: + attachments = self["attributes"]["arc_attachments"] + except (KeyError, TypeError): + pass + else: + return next( # pragma: no cover + ( + a + for a in attachments + if "arc_display_name" in a + if a["arc_display_name"] == "arc_primary_image" + ), + None, + ) + + return None + + @property + def name(self): + """str: name of the asset""" + try: + name = self["attributes"]["arc_display_name"] + except (KeyError, TypeError): + pass + else: + return name + + return None + + class _AssetsClient: """AssetsClient - Access to assets entitiies using CRUD interface. This class is usually + Access to assets entities using CRUD interface. This class is usually accessed as an attribute of the Archivist class. Args: @@ -51,10 +103,10 @@ class _AssetsClient: """ - def __init__(self, archivist): + def __init__(self, archivist: "type_helper.Archivist"): self._archivist = archivist - def create(self, behaviours, attrs, *, confirm=False): + def create(self, behaviours: List, attrs: dict, *, confirm: bool = False) -> Asset: """Create asset Creates asset with defined behaviours and attributes. @@ -77,14 +129,14 @@ def create(self, behaviours, attrs, *, confirm=False): confirm=confirm, ) - def create_from_data(self, data, *, confirm=False): + def create_from_data(self, data: dict, *, confirm: bool = False) -> Asset: """Create asset Creates asset with request body from data stream. Suitable for reading data from a file using json.load or yaml.load Args: - data (dict): request bosy of asset. + data (dict): request body of asset. confirm (bool): if True wait for asset to be confirmed on DLT. Returns: @@ -102,7 +154,7 @@ def create_from_data(self, data, *, confirm=False): return wait_for_confirmation(self, asset["identity"]) - def read(self, identity): + def read(self, identity: str) -> Asset: """Read asset Reads asset. @@ -124,7 +176,9 @@ def __query(props, attrs): return query - def count(self, *, props=None, attrs=None): + def count( + self, *, props: Optional[dict] = None, attrs: Optional[dict] = None + ) -> int: """Count assets. Counts number of assets that match criteria. @@ -141,7 +195,9 @@ def count(self, *, props=None, attrs=None): f"{ASSETS_SUBPATH}/{ASSETS_LABEL}", query=self.__query(props, attrs) ) - def wait_for_confirmed(self, *, props=None, attrs=None): + def wait_for_confirmed( + self, *, props: Optional[dict] = None, attrs: Optional[dict] = None + ) -> bool: """Wait for assets to be confirmed. Waits for all assets that match criteria to be confirmed. @@ -156,7 +212,13 @@ def wait_for_confirmed(self, *, props=None, attrs=None): """ return wait_for_confirmed(self, props=props, attrs=attrs) - def list(self, *, page_size=DEFAULT_PAGE_SIZE, props=None, attrs=None): + def list( + self, + *, + page_size: int = DEFAULT_PAGE_SIZE, + props: Optional[dict] = None, + attrs: Optional[dict] = None, + ): """List assets. Lists assets that match criteria. @@ -180,7 +242,9 @@ def list(self, *, page_size=DEFAULT_PAGE_SIZE, props=None, attrs=None): ) ) - def read_by_signature(self, *, props=None, attrs=None): + def read_by_signature( + self, *, props: Optional[dict] = None, attrs: Optional[dict] = None + ) -> Asset: """Read Asset by signature. Reads asset that meets criteria. Only one asset is expected. @@ -200,50 +264,3 @@ def read_by_signature(self, *, props=None, attrs=None): query=self.__query(props, attrs), ) ) - - -class Asset(dict): - """Asset - - Asset object has dictionary attributes and properties. - - """ - - @property - def primary_image(self): - """Primary Image - - Attachment that is the primary image of the asset. - - Returns: - :class:`Attachment` instance - - """ - try: - attachments = self["attributes"]["arc_attachments"] - except (KeyError, TypeError): - pass - else: - return next( # pragma: no cover - ( - a - for a in attachments - if "arc_display_name" in a - if a["arc_display_name"] == "arc_primary_image" - ), - None, - ) - - return None - - @property - def name(self): - """str: name of the asset""" - try: - name = self["attributes"]["arc_display_name"] - except (KeyError, TypeError): - pass - else: - return name - - return None diff --git a/archivist/attachments.py b/archivist/attachments.py index 9fa6b5a8..92ba3b7f 100644 --- a/archivist/attachments.py +++ b/archivist/attachments.py @@ -24,17 +24,32 @@ # pylint:disable=too-few-public-methods +from typing import IO import logging +from requests.models import Response + +# pylint:disable=unused-import # To prevent cyclical import errors forward referencing is used +# pylint:disable=cyclic-import # but pylint doesn't understand this feature +from archivist import archivist as type_helper + from .constants import ATTACHMENTS_SUBPATH, ATTACHMENTS_LABEL LOGGER = logging.getLogger(__name__) +class Attachment(dict): + """Attachment + + Attachment object has dictionary attributes. + + """ + + class _AttachmentsClient: """AttachmentsClient - Access to attachments entitiies using CRUD interface. This class is usually + Access to attachments entities using CRUD interface. This class is usually accessed as an attribute of the Archivist class. Args: @@ -42,10 +57,10 @@ class _AttachmentsClient: """ - def __init__(self, archivist): + def __init__(self, archivist: "type_helper.Archivist"): self._archivist = archivist - def upload(self, fd, *, mtype="image/jpg"): + def upload(self, fd: IO, *, mtype: str = "image/jpg") -> Attachment: """Create attachment Creates attachment from opened file or other data source. @@ -68,7 +83,7 @@ def upload(self, fd, *, mtype="image/jpg"): ) ) - def download(self, identity, fd): + def download(self, identity: str, fd: IO) -> Response: """Read attachment Reads attachment into data sink (usually a file opened for write).. @@ -88,11 +103,3 @@ def download(self, identity, fd): identity, fd, ) - - -class Attachment(dict): - """Attachment - - Attachment object has dictionary attributes. - - """ diff --git a/archivist/confirm.py b/archivist/confirm.py index 60a0b989..753d2e23 100644 --- a/archivist/confirm.py +++ b/archivist/confirm.py @@ -86,7 +86,7 @@ def __on_giveup_confirmed(details): on_backoff=__backoff_handler, on_giveup=__on_giveup_confirmed, ) -def wait_for_confirmed(self, *, props=None, **kwargs): +def wait_for_confirmed(self, *, props=None, **kwargs) -> bool: """docstring""" newprops = deepcopy(props) if props else {} newprops[CONFIRMATION_STATUS] = CONFIRMATION_PENDING diff --git a/archivist/errors.py b/archivist/errors.py index d3b5571b..87200135 100644 --- a/archivist/errors.py +++ b/archivist/errors.py @@ -40,7 +40,7 @@ class ArchivistForbiddenError(ArchivistError): class ArchivistNotFoundError(ArchivistError): - """Enetity does not exist (404)""" + """Entity does not exist (404)""" class Archivist4xxError(ArchivistError): diff --git a/archivist/events.py b/archivist/events.py index ef448381..9ea35236 100644 --- a/archivist/events.py +++ b/archivist/events.py @@ -23,9 +23,13 @@ """ import logging - +from typing import Optional from copy import deepcopy +# pylint:disable=unused-import # To prevent cyclical import errors forward referencing is used +# pylint:disable=cyclic-import # but pylint doesn't understand this feature +from archivist import archivist as type_helper + from .constants import ( SEP, ASSETS_SUBPATH, @@ -43,6 +47,61 @@ LOGGER = logging.getLogger(__name__) +class Event(dict): + """Event + + Event object has dictionary attributes and properties. + + """ + + @property + def when(self): + """when + + Timestamp of event + + """ + try: + when = self["timestamp_declared"] + except KeyError: + pass + else: + return when + + try: + when = self["timestamp_accepted"] + except KeyError: + pass + else: + return when + + return None + + @property + def who(self): + """who + + Principal identity. + + """ + + try: + who = self["principal_declared"]["display_name"] + except (KeyError, TypeError): + pass + else: + return who + + try: + who = self["principal_accepted"]["display_name"] + except (KeyError, TypeError): + pass + else: + return who + + return None + + class _EventsClient: """EventsClient @@ -54,10 +113,18 @@ class _EventsClient: """ - def __init__(self, archivist): + def __init__(self, archivist: "type_helper.Archivist"): self._archivist = archivist - def create(self, asset_id, props, attrs, *, asset_attrs=None, confirm=False): + def create( + self, + asset_id: str, + props: dict, + attrs: dict, + *, + asset_attrs: Optional[dict] = None, + confirm: bool = False, + ) -> Event: """Create event Creates event for given asset. @@ -81,7 +148,7 @@ def create(self, asset_id, props, attrs, *, asset_attrs=None, confirm=False): confirm=confirm, ) - def create_from_data(self, asset_id, data, *, confirm=False): + def create_from_data(self, asset_id: str, data: dict, *, confirm=False) -> Event: """Create event Creates event for given asset from data. @@ -107,7 +174,7 @@ def create_from_data(self, asset_id, data, *, confirm=False): return wait_for_confirmation(self, event["identity"]) - def read(self, identity): + def read(self, identity: str) -> Event: """Read event Reads event. @@ -137,8 +204,13 @@ def __query(props, attrs, asset_attrs): return query def count( - self, *, asset_id=ASSETS_WILDCARD, props=None, attrs=None, asset_attrs=None - ): + self, + *, + asset_id: str = ASSETS_WILDCARD, + props: Optional[dict] = None, + attrs: Optional[dict] = None, + asset_attrs: Optional[dict] = None, + ) -> int: """Count events. Counts number of events that match criteria. @@ -160,8 +232,13 @@ def count( ) def wait_for_confirmed( - self, *, asset_id=ASSETS_WILDCARD, props=None, attrs=None, asset_attrs=None - ): + self, + *, + asset_id: str = ASSETS_WILDCARD, + props: Optional[dict] = None, + attrs: Optional[dict] = None, + asset_attrs: Optional[dict] = None, + ) -> bool: """Wait for events to be confirmed. Waits for all events that match criteria to be confirmed. @@ -183,11 +260,11 @@ def wait_for_confirmed( def list( self, *, - asset_id=ASSETS_WILDCARD, - page_size=DEFAULT_PAGE_SIZE, - props=None, - attrs=None, - asset_attrs=None, + asset_id: str = ASSETS_WILDCARD, + page_size: int = DEFAULT_PAGE_SIZE, + props: Optional[dict] = None, + attrs: Optional[dict] = None, + asset_attrs: Optional[dict] = None, ): """List events. @@ -198,7 +275,7 @@ def list( props (dict): e.g. {"tracked": "TRACKED" } attrs (dict): e.g. {"arc_display_type": "open" } asset_attrs (dict): optional asset_attributes e.g. {"arc_display_type": "door" } - page_sixe (int): optional page size. (Rarely used). + page_size (int): optional page size. (Rarely used). Returns: iterable that returns :class:`Event` instances @@ -217,11 +294,11 @@ def list( def read_by_signature( self, *, - asset_id=ASSETS_WILDCARD, - props=None, - attrs=None, - asset_attrs=None, - ): + asset_id: str = ASSETS_WILDCARD, + props: Optional[dict] = None, + attrs: Optional[dict] = None, + asset_attrs: Optional[dict] = None, + ) -> Event: """Read event by signature. Reads event that meets criteria. Only one event is expected. @@ -243,58 +320,3 @@ def read_by_signature( query=self.__query(props, attrs, asset_attrs), ) ) - - -class Event(dict): - """Event - - Event object has dictionary attributes and properties. - - """ - - @property - def when(self): - """when - - Timestamp of event - - """ - try: - when = self["timestamp_declared"] - except KeyError: - pass - else: - return when - - try: - when = self["timestamp_accepted"] - except KeyError: - pass - else: - return when - - return None - - @property - def who(self): - """who - - Principal identity. - - """ - - try: - who = self["principal_declared"]["display_name"] - except (KeyError, TypeError): - pass - else: - return who - - try: - who = self["principal_accepted"]["display_name"] - except (KeyError, TypeError): - pass - else: - return who - - return None diff --git a/archivist/locations.py b/archivist/locations.py index 229590ba..50cead0b 100644 --- a/archivist/locations.py +++ b/archivist/locations.py @@ -23,6 +23,11 @@ """ import logging +from typing import Optional + +# pylint:disable=unused-import # To prevent cyclical import errors forward referencing is used +# pylint:disable=cyclic-import # but pylint doesn't understand this feature +from archivist import archivist as type_helper from .constants import LOCATIONS_SUBPATH, LOCATIONS_LABEL @@ -35,6 +40,14 @@ LOGGER = logging.getLogger(__name__) +class Location(dict): + """Location + + Location object has dictionary attributes. + + """ + + class _LocationsClient: """LocationsClient @@ -46,10 +59,10 @@ class _LocationsClient: """ - def __init__(self, archivist): + def __init__(self, archivist: "type_helper.Archivist"): self._archivist = archivist - def create(self, props, *, attrs=None): + def create(self, props: dict, *, attrs: Optional[dict] = None) -> Location: """Create location Creates location with defined properties and attributes. @@ -65,7 +78,7 @@ def create(self, props, *, attrs=None): LOGGER.debug("Create Location %s", props) return self.create_from_data(self.__query(props, attrs)) - def create_from_data(self, data): + def create_from_data(self, data: dict) -> Location: """Create location Creates location with request body from data stream. @@ -85,7 +98,7 @@ def create_from_data(self, data): ) ) - def read(self, identity): + def read(self, identity: str) -> Location: """Read location Reads location. @@ -112,7 +125,9 @@ def __query(props, attrs): return query - def count(self, *, props=None, attrs=None): + def count( + self, *, props: Optional[dict] = None, attrs: Optional[dict] = None + ) -> int: """Count locations. Counts number of locations that match criteria. @@ -129,7 +144,13 @@ def count(self, *, props=None, attrs=None): f"{LOCATIONS_SUBPATH}/{LOCATIONS_LABEL}", query=self.__query(props, attrs) ) - def list(self, *, page_size=DEFAULT_PAGE_SIZE, props=None, attrs=None): + def list( + self, + *, + page_size: int = DEFAULT_PAGE_SIZE, + props: Optional[dict] = None, + attrs: Optional[dict] = None, + ): """List locations. Lists locations that match criteria. @@ -154,7 +175,9 @@ def list(self, *, page_size=DEFAULT_PAGE_SIZE, props=None, attrs=None): ) ) - def read_by_signature(self, *, props=None, attrs=None): + def read_by_signature( + self, *, props: Optional[dict] = None, attrs: Optional[dict] = None + ) -> Location: """Read location by signature. Reads location that meets criteria. Only one location is expected. @@ -174,11 +197,3 @@ def read_by_signature(self, *, props=None, attrs=None): query=self.__query(props, attrs), ) ) - - -class Location(dict): - """Location - - Location object has dictionary attributes. - - """ diff --git a/archivist/subjects.py b/archivist/subjects.py index ac7a3f5b..d64486cc 100644 --- a/archivist/subjects.py +++ b/archivist/subjects.py @@ -22,6 +22,11 @@ """ import logging +from typing import List, Optional + +# pylint:disable=unused-import # To prevent cyclical import errors forward referencing is used +# pylint:disable=cyclic-import # but pylint doesn't understand this feature +from archivist import archivist as type_helper from .constants import ( SUBJECTS_SUBPATH, @@ -36,10 +41,14 @@ LOGGER = logging.getLogger(__name__) +class Subject(dict): + """Subject object""" + + class _SubjectsClient: """SubjectsClient - Access to subjects entitiies using CRUD interface. This class is usually + Access to subjects entities using CRUD interface. This class is usually accessed as an attribute of the Archivist class. Args: @@ -47,16 +56,18 @@ class _SubjectsClient: """ - def __init__(self, archivist): + def __init__(self, archivist: "type_helper.Archivist"): self._archivist = archivist - def create(self, display_name, wallet_pub_keys, tessera_pub_keys): + def create( + self, display_name: str, wallet_pub_keys: List, tessera_pub_keys: List + ) -> Subject: """Create subject Creates subject with defined attributes. Args: - display_name (str): dispaly name of subject. + display_name (str): display name of subject. wallet_pub_keys (list): wallet public keys tessera_pub_keys (list): tessera public keys @@ -73,7 +84,7 @@ def create(self, display_name, wallet_pub_keys, tessera_pub_keys): ), ) - def create_from_data(self, data): + def create_from_data(self, data: dict) -> Subject: """Create subject Creates subject with request body from data stream. @@ -93,7 +104,7 @@ def create_from_data(self, data): ) ) - def read(self, identity): + def read(self, identity: str) -> Subject: """Read Subject Reads subject. @@ -114,12 +125,12 @@ def read(self, identity): def update( self, - identity, + identity: str, *, - display_name=None, - wallet_pub_keys=None, - tessera_pub_keys=None, - ): + display_name: Optional[dict] = None, + wallet_pub_keys: Optional[dict] = None, + tessera_pub_keys: Optional[dict] = None, + ) -> Subject: """Update Subject Update subject. @@ -146,7 +157,7 @@ def update( ) ) - def delete(self, identity): + def delete(self, identity: str): """Delete Subject Deletes subject. @@ -175,13 +186,13 @@ def __query(*, display_name=None, wallet_pub_keys=None, tessera_pub_keys=None): return query - def count(self, *, display_name=None): + def count(self, *, display_name: Optional[str] = None) -> int: """Count subjects. Counts number of subjects that match criteria. Args: - display_name (str): display name (optional0 + display_name (str): display name (optional) Returns: integer count of subjects. @@ -195,8 +206,8 @@ def count(self, *, display_name=None): def list( self, *, - page_size=DEFAULT_PAGE_SIZE, - display_name=None, + page_size: int = DEFAULT_PAGE_SIZE, + display_name: Optional[str] = None, ): """List subjects. @@ -220,7 +231,3 @@ def list( query=self.__query(display_name=display_name), ) ) - - -class Subject(dict): - """Subject object"""