Skip to content

Commit 5472d3d

Browse files
serhiyeccles
authored andcommitted
Add type hinting to all user facing interfaces
Problem: Auto-complete / intellisense does not work correctly on IDE's when using this SDK Solution: Add type hints to all user facing classes Signed-off-by: Serhiy Pikho <Serhiy1@live.co.uk>
1 parent f42c98f commit 5472d3d

9 files changed

Lines changed: 340 additions & 233 deletions

File tree

archivist/access_policies.py

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,14 @@
2121
2222
"""
2323

24+
from typing import List, Optional
2425
import logging
25-
2626
from copy import deepcopy
2727

28+
# pylint:disable=unused-import # To prevent cyclical import errors forward referencing is used
29+
# pylint:disable=cyclic-import # but pylint doesn't understand this feature
30+
from archivist import archivist as type_helper
31+
2832
from .constants import (
2933
SEP,
3034
ACCESS_POLICIES_SUBPATH,
@@ -42,21 +46,27 @@
4246
LOGGER = logging.getLogger(__name__)
4347

4448

49+
class AccessPolicy(dict):
50+
"""AccessPolicy object"""
51+
52+
4553
class _AccessPoliciesClient:
4654
"""AccessPoliciesClient
4755
48-
Access to access_policies entitiies using CRUD interface. This class is usually
56+
Access to access_policies entities using CRUD interface. This class is usually
4957
accessed as an attribute of the Archivist class.
5058
5159
Args:
5260
archivist (Archivist): :class:`Archivist` instance
5361
5462
"""
5563

56-
def __init__(self, archivist):
64+
def __init__(self, archivist: "type_helper.Archivist"):
5765
self._archivist = archivist
5866

59-
def create(self, props, filters, access_permissions):
67+
def create(
68+
self, props: dict, filters: List, access_permissions: List
69+
) -> AccessPolicy:
6070
"""Create access policy
6171
6272
Creates access policy with defined attributes.
@@ -75,7 +85,7 @@ def create(self, props, filters, access_permissions):
7585
self.__query(props, filters=filters, access_permissions=access_permissions),
7686
)
7787

78-
def create_from_data(self, data):
88+
def create_from_data(self, data: dict) -> AccessPolicy:
7989
"""Create access policy
8090
8191
Creates access policy with request body from data stream.
@@ -95,7 +105,7 @@ def create_from_data(self, data):
95105
)
96106
)
97107

98-
def read(self, identity):
108+
def read(self, identity: str) -> AccessPolicy:
99109
"""Read Access Policy
100110
101111
Reads access policy.
@@ -114,7 +124,13 @@ def read(self, identity):
114124
)
115125
)
116126

117-
def update(self, identity, props=None, filters=None, access_permissions=None):
127+
def update(
128+
self,
129+
identity,
130+
props: Optional[dict] = None,
131+
filters: Optional[list] = None,
132+
access_permissions: Optional[list] = None,
133+
) -> AccessPolicy:
118134
"""Update Access Policy
119135
120136
Update access policy.
@@ -139,7 +155,7 @@ def update(self, identity, props=None, filters=None, access_permissions=None):
139155
)
140156
)
141157

142-
def delete(self, identity):
158+
def delete(self, identity: str) -> dict:
143159
"""Delete Access Policy
144160
145161
Deletes access policy.
@@ -164,7 +180,7 @@ def __query(props, *, filters=None, access_permissions=None):
164180

165181
return query
166182

167-
def count(self, *, display_name=None):
183+
def count(self, *, display_name: Optional[str] = None) -> int:
168184
"""Count access policies.
169185
170186
Counts number of access policies that match criteria.
@@ -183,10 +199,7 @@ def count(self, *, display_name=None):
183199
)
184200

185201
def list(
186-
self,
187-
*,
188-
page_size=DEFAULT_PAGE_SIZE,
189-
display_name=None,
202+
self, *, page_size: int = DEFAULT_PAGE_SIZE, display_name: Optional[str] = None
190203
):
191204
"""List access policies.
192205
@@ -212,10 +225,10 @@ def list(
212225
)
213226

214227
# additional queries on different endpoints
215-
def count_matching_assets(self, access_policy_id):
228+
def count_matching_assets(self, access_policy_id: str) -> int:
216229
"""Count assets that match access_policy.
217230
218-
Counts number of assets that match an access_polocy.
231+
Counts number of assets that match an access_policy.
219232
220233
Args:
221234
access_policy_id (str): e.g. access_policies/xxxxxxxxxxxxxxx
@@ -229,10 +242,7 @@ def count_matching_assets(self, access_policy_id):
229242
)
230243

231244
def list_matching_assets(
232-
self,
233-
access_policy_id,
234-
*,
235-
page_size=DEFAULT_PAGE_SIZE,
245+
self, access_policy_id: str, *, page_size: int = DEFAULT_PAGE_SIZE
236246
):
237247
"""List matching assets.
238248
@@ -255,7 +265,7 @@ def list_matching_assets(
255265
)
256266
)
257267

258-
def count_matching_access_policies(self, asset_id):
268+
def count_matching_access_policies(self, asset_id: str) -> int:
259269
"""Count access policies that match asset.
260270
261271
Counts number of access policies that match asset.
@@ -271,7 +281,9 @@ def count_matching_access_policies(self, asset_id):
271281
SEP.join((ACCESS_POLICIES_SUBPATH, asset_id, ACCESS_POLICIES_LABEL)),
272282
)
273283

274-
def list_matching_access_policies(self, asset_id, *, page_size=DEFAULT_PAGE_SIZE):
284+
def list_matching_access_policies(
285+
self, asset_id: str, *, page_size: int = DEFAULT_PAGE_SIZE
286+
):
275287
"""List matching access policies.
276288
277289
List access policies that match asset.
@@ -292,7 +304,3 @@ def list_matching_access_policies(self, asset_id, *, page_size=DEFAULT_PAGE_SIZE
292304
page_size=page_size,
293305
)
294306
)
295-
296-
297-
class AccessPolicy(dict):
298-
"""AccessPolicy object"""

archivist/archivist.py

Lines changed: 57 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
the basic REST verbs to GET, POST, PATCH and DELETE entities..
77
88
The REST methods in this class should only be used directly when
9-
a CRUD endpoint for the specific type of entity is unavaliable.
9+
a CRUD endpoint for the specific type of entity is unavailable.
1010
Current CRUD endpoints are assets, events, locations, attachments.
1111
IAM subjects and IAM access policies.
1212
@@ -24,7 +24,7 @@
2424
auth=authtoken,
2525
)
2626
27-
The arch variable now has additonal endpoints assets,events,locations,
27+
The arch variable now has additional endpoints assets,events,locations,
2828
attachments, IAM subjects and IAM access policies documented elsewhere.
2929
3030
"""
@@ -33,7 +33,8 @@
3333

3434
import json
3535
from os.path import isfile as os_path_isfile
36-
from typing import Optional
36+
from typing import IO, Optional
37+
from requests.models import Response
3738

3839
from flatten_dict import flatten
3940
import requests
@@ -92,7 +93,15 @@ class Archivist: # pylint: disable=too-many-instance-attributes
9293
9394
"""
9495

95-
def __init__(self, url, *, auth=None, cert=None, verify=True):
96+
def __init__(
97+
self,
98+
url: str,
99+
*,
100+
auth: Optional[str] = None,
101+
cert: Optional[str] = None,
102+
verify: bool = True,
103+
):
104+
96105
self._headers = {"content-type": "application/json"}
97106
if auth is not None:
98107
self._headers["authorization"] = "Bearer " + auth.strip()
@@ -114,14 +123,14 @@ def __init__(self, url, *, auth=None, cert=None, verify=True):
114123
self._cert = cert
115124

116125
# keep these in sync with CLIENTS map above
117-
self.assets: Optional[_AssetsClient]
118-
self.events: Optional[_EventsClient]
119-
self.locations: Optional[_LocationsClient]
120-
self.attachments: Optional[_AttachmentsClient]
121-
self.access_policies: Optional[_AccessPoliciesClient]
122-
self.subjects: Optional[_SubjectsClient]
123-
124-
def __getattr__(self, value):
126+
self.assets: _AssetsClient
127+
self.events: _EventsClient
128+
self.locations: _LocationsClient
129+
self.attachments: _AttachmentsClient
130+
self.access_policies: _AccessPoliciesClient
131+
self.subjects: _SubjectsClient
132+
133+
def __getattr__(self, value: str):
125134
"""Create endpoints on demand"""
126135
client = CLIENTS.get(value)
127136

@@ -133,22 +142,22 @@ def __getattr__(self, value):
133142
return c
134143

135144
@property
136-
def headers(self):
145+
def headers(self) -> dict:
137146
"""dict: Headers REST headers from response"""
138147
return self._headers
139148

140149
@property
141-
def url(self):
150+
def url(self) -> str:
142151
"""str: URL of Archivist endpoint"""
143152
return self._url
144153

145154
@property
146-
def verify(self):
155+
def verify(self) -> bool:
147156
"""bool: Returns True if https connections are to be verified"""
148157
return self._verify
149158

150159
@property
151-
def cert(self):
160+
def cert(self) -> str:
152161
"""str: filepath containing authorisation certificate."""
153162
return self._cert
154163

@@ -161,7 +170,9 @@ def __add_headers(self, headers):
161170

162171
return newheaders
163172

164-
def get(self, subpath, identity, *, headers=None):
173+
def get(
174+
self, subpath: str, identity: str, *, headers: Optional[dict] = None
175+
) -> dict:
165176
"""GET method (REST)
166177
167178
Args:
@@ -173,7 +184,6 @@ def get(self, subpath, identity, *, headers=None):
173184
dict representing the response body (entity).
174185
175186
"""
176-
LOGGER.debug("get %s/%s", subpath, identity)
177187
response = requests.get(
178188
SEP.join((self.url, ROOT, subpath, identity)),
179189
headers=self.__add_headers(headers),
@@ -187,7 +197,9 @@ def get(self, subpath, identity, *, headers=None):
187197

188198
return response.json()
189199

190-
def get_file(self, subpath, identity, fd, *, headers=None):
200+
def get_file(
201+
self, subpath: str, identity: str, fd: IO, *, headers: Optional[dict] = None
202+
) -> Response:
191203
"""GET method (REST) - chunked
192204
193205
Downloads a binary object from upstream storage.
@@ -220,7 +232,7 @@ def get_file(self, subpath, identity, fd, *, headers=None):
220232

221233
return response
222234

223-
def post(self, path, request, *, headers=None):
235+
def post(self, path: str, request: dict, *, headers: Optional[dict] = None) -> dict:
224236
"""POST method (REST)
225237
226238
Creates an entity
@@ -249,7 +261,7 @@ def post(self, path, request, *, headers=None):
249261

250262
return response.json()
251263

252-
def post_file(self, path, fd, mtype):
264+
def post_file(self, path: str, fd: IO, mtype: str) -> dict:
253265
"""POST method (REST) - upload binary
254266
255267
Uploads a file to an endpoint
@@ -286,7 +298,9 @@ def post_file(self, path, fd, mtype):
286298

287299
return response.json()
288300

289-
def delete(self, subpath, identity, *, headers=None):
301+
def delete(
302+
self, subpath: str, identity: str, *, headers: Optional[dict] = None
303+
) -> dict:
290304
"""DELETE method (REST)
291305
292306
Deletes an entity
@@ -313,7 +327,14 @@ def delete(self, subpath, identity, *, headers=None):
313327

314328
return response.json()
315329

316-
def patch(self, subpath, identity, request, *, headers=None):
330+
def patch(
331+
self,
332+
subpath: str,
333+
identity: str,
334+
request: dict,
335+
*,
336+
headers: Optional[dict] = None,
337+
) -> dict:
317338
"""PATCH method (REST)
318339
319340
Updates the specified entity.
@@ -365,7 +386,9 @@ def __query(query):
365386
sorted(f"{k}={v}" for k, v in flatten(query, reducer="dot").items())
366387
)
367388

368-
def get_by_signature(self, path, field, query, *, headers=None):
389+
def get_by_signature(
390+
self, path: str, field: str, query: dict, *, headers: Optional[dict] = None
391+
) -> dict:
369392
"""GET method (REST) with query string
370393
371394
Reads an entity indirectly by searching for its signature
@@ -413,7 +436,7 @@ def get_by_signature(self, path, field, query, *, headers=None):
413436

414437
return records[0]
415438

416-
def count(self, path, *, query=None):
439+
def count(self, path: str, *, query: Optional[dict] = None) -> int:
417440
"""GET method (REST) with query string
418441
419442
Returns the count of objects that match query
@@ -439,7 +462,15 @@ def count(self, path, *, query=None):
439462

440463
return int(response.headers[HEADERS_TOTAL_COUNT])
441464

442-
def list(self, path, field, *, page_size=None, query=None, headers=None):
465+
def list(
466+
self,
467+
path: str,
468+
field: str,
469+
*,
470+
page_size: Optional[int] = None,
471+
query: Optional[dict] = None,
472+
headers: Optional[dict] = None,
473+
):
443474
"""GET method (REST) with query string
444475
445476
Lists entities that match the query dictionary.

0 commit comments

Comments
 (0)