Skip to content

Commit dba6e89

Browse files
committed
adding type hints
1 parent e0aaf38 commit dba6e89

File tree

2 files changed

+58
-57
lines changed

2 files changed

+58
-57
lines changed

atlassian/jira.py

Lines changed: 58 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import logging
55
import os
66
import re
7-
from typing import TYPE_CHECKING, Any, BinaryIO, Literal, cast
7+
from typing import TYPE_CHECKING, Any, BinaryIO, Literal, cast, Iterable
88
from warnings import warn
99

1010
from deprecated import deprecated
@@ -145,7 +145,7 @@ def get_permissions(
145145

146146
return self.get(url, params=params)
147147

148-
def get_all_permissions(self):
148+
def get_all_permissions(self) -> dict | None:
149149
"""
150150
Returns all permissions that are present in the Jira instance -
151151
Global, Project and the global ones added by plugins
@@ -159,7 +159,9 @@ def get_all_permissions(self):
159159
Reference: https://docs.atlassian.com/software/jira/docs/api/REST/8.5.0/#api/2/application-properties
160160
"""
161161

162-
def get_property(self, key: T_id | None = None, permission_level: str | None = None, key_filter: str | None = None):
162+
def get_property(
163+
self, key: T_id | None = None, permission_level: str | None = None, key_filter: str | None = None
164+
) -> dict | None:
163165
"""
164166
Returns an application property
165167
:param key: str
@@ -180,7 +182,7 @@ def get_property(self, key: T_id | None = None, permission_level: str | None = N
180182

181183
return self.get(url, params=params)
182184

183-
def set_property(self, property_id: T_id, value: str):
185+
def set_property(self, property_id: T_id, value: str) -> dict | None:
184186
"""
185187
Modify an application property via PUT. The "value" field present in the PUT will override the existing value.
186188
:param property_id:
@@ -207,15 +209,15 @@ def get_advanced_settings(self) -> dict | None:
207209
Reference: https://docs.atlassian.com/software/jira/docs/api/REST/8.5.0/#api/2/applicationrole
208210
"""
209211

210-
def get_all_application_roles(self):
212+
def get_all_application_roles(self) -> dict | None:
211213
"""
212214
Returns all ApplicationRoles in the system
213215
:return:
214216
"""
215217
url = self.resource_url("applicationrole")
216218
return self.get(url) or {}
217219

218-
def get_application_role(self, role_key: str):
220+
def get_application_role(self, role_key: str) -> dict | None:
219221
"""
220222
Returns the ApplicationRole with passed key if it exists
221223
:param role_key: str
@@ -242,7 +244,7 @@ def get_attachments_ids_from_issue(self, issue: T_id) -> list[dict[str, str]]:
242244
list_attachments_id.append({"filename": attachment["filename"], "attachment_id": attachment["id"]})
243245
return list_attachments_id
244246

245-
def get_attachment(self, attachment_id: T_id):
247+
def get_attachment(self, attachment_id: T_id) -> dict | None:
246248
"""
247249
Returns the meta-data for an attachment, including the URI of the actual attached file
248250
:param attachment_id: int
@@ -290,7 +292,7 @@ def download_attachments_from_issue(self, issue: T_id, path: str | None = None,
290292
except Exception as e:
291293
raise e
292294

293-
def get_attachment_content(self, attachment_id: T_id):
295+
def get_attachment_content(self, attachment_id: T_id) -> dict | None:
294296
"""
295297
Returns the content for an attachment
296298
:param attachment_id: int
@@ -300,7 +302,7 @@ def get_attachment_content(self, attachment_id: T_id):
300302
url = "{base_url}/content/{attachment_id}".format(base_url=base_url, attachment_id=attachment_id)
301303
return self.get(url)
302304

303-
def remove_attachment(self, attachment_id: T_id):
305+
def remove_attachment(self, attachment_id: T_id) -> dict | None:
304306
"""
305307
Remove an attachment from an issue
306308
:param attachment_id: int
@@ -310,7 +312,7 @@ def remove_attachment(self, attachment_id: T_id):
310312
url = "{base_url}/{attachment_id}".format(base_url=base_url, attachment_id=attachment_id)
311313
return self.delete(url)
312314

313-
def get_attachment_meta(self):
315+
def get_attachment_meta(self) -> dict | None:
314316
"""
315317
Returns the meta information for an attachments,
316318
specifically if they are enabled and the maximum upload size allowed
@@ -319,7 +321,7 @@ def get_attachment_meta(self):
319321
url = self.resource_url("attachment/meta")
320322
return self.get(url)
321323

322-
def get_attachment_expand_human(self, attachment_id: T_id):
324+
def get_attachment_expand_human(self, attachment_id: T_id) -> dict | None:
323325
"""
324326
Returns the information for an expandable attachment in human-readable format
325327
:param attachment_id: int
@@ -329,7 +331,7 @@ def get_attachment_expand_human(self, attachment_id: T_id):
329331
url = "{base_url}/{attachment_id}/expand/human".format(base_url=base_url, attachment_id=attachment_id)
330332
return self.get(url)
331333

332-
def get_attachment_expand_raw(self, attachment_id: T_id):
334+
def get_attachment_expand_raw(self, attachment_id: T_id) -> dict | None:
333335
"""
334336
Returns the information for an expandable attachment in raw format
335337
:param attachment_id: int
@@ -351,7 +353,7 @@ def get_audit_records(
351353
filter: str | None = None,
352354
from_date: str | None = None,
353355
to_date: str | None = None,
354-
):
356+
) -> dict | None:
355357
"""
356358
Returns auditing records filtered using provided parameters
357359
:param offset: the number of record from which search starts
@@ -381,7 +383,7 @@ def get_audit_records(
381383
url = self.resource_url("auditing/record")
382384
return self.get(url, params=params) or {}
383385

384-
def post_audit_record(self, audit_record: dict | str):
386+
def post_audit_record(self, audit_record: dict | str) -> dict | None:
385387
"""
386388
Store a record in Audit Log
387389
:param audit_record: json with compat https://docs.atlassian.com/jira/REST/schema/audit-record#
@@ -395,7 +397,7 @@ def post_audit_record(self, audit_record: dict | str):
395397
Reference: https://docs.atlassian.com/software/jira/docs/api/REST/8.5.0/#api/2/avatar
396398
"""
397399

398-
def get_all_system_avatars(self, avatar_type: str = "user"):
400+
def get_all_system_avatars(self, avatar_type: str = "user") -> dict | None:
399401
"""
400402
Returns all system avatars of the given type.
401403
:param avatar_type:
@@ -411,11 +413,11 @@ def get_all_system_avatars(self, avatar_type: str = "user"):
411413
Reference: https://docs.atlassian.com/software/jira/docs/api/REST/8.5.0/#api/2/cluster
412414
"""
413415

414-
def get_cluster_all_nodes(self):
416+
def get_cluster_all_nodes(self) -> dict | None:
415417
url = self.resource_url("cluster/nodes")
416418
return self.get(url)
417419

418-
def delete_cluster_node(self, node_id: T_id):
420+
def delete_cluster_node(self, node_id: T_id) -> dict | None:
419421
"""
420422
Delete the node from the cluster if state of node is OFFLINE
421423
:param node_id: str
@@ -425,7 +427,7 @@ def delete_cluster_node(self, node_id: T_id):
425427
url = "{base_url}/{node_id}".format(base_url=base_url, node_id=node_id)
426428
return self.delete(url)
427429

428-
def set_node_to_offline(self, node_id: T_id):
430+
def set_node_to_offline(self, node_id: T_id) -> dict | None:
429431
"""
430432
Change the node's state to offline if the node is reporting as active, but is not alive
431433
:param node_id: str
@@ -435,14 +437,15 @@ def set_node_to_offline(self, node_id: T_id):
435437
url = "{base_url}/{node_id}/offline".format(base_url=base_url, node_id=node_id)
436438
return self.put(url)
437439

438-
def get_cluster_alive_nodes(self):
440+
def get_cluster_alive_nodes(self) -> list:
439441
"""
440442
Get cluster nodes where alive = True
441443
:return: list of node dicts
442444
"""
443-
return [_ for _ in self.get_cluster_all_nodes() if _["alive"]]
445+
nodes = self.get_cluster_all_nodes()
446+
return [_ for _ in nodes.values() if _["alive"]] if nodes else []
444447

445-
def request_current_index_from_node(self, node_id: T_id):
448+
def request_current_index_from_node(self, node_id: T_id) -> dict | None:
446449
"""
447450
Request current index from node (the request is processed asynchronously)
448451
:return:
@@ -456,7 +459,7 @@ def request_current_index_from_node(self, node_id: T_id):
456459
Reference: https://confluence.atlassian.com/support/create-a-support-zip-using-the-rest-api-in-data-center-applications-952054641.html
457460
"""
458461

459-
def generate_support_zip_on_nodes(self, node_ids: list):
462+
def generate_support_zip_on_nodes(self, node_ids: list) -> dict | None:
460463
"""
461464
Generate a support zip on targeted nodes of a cluster
462465
:param node_ids: list
@@ -466,7 +469,7 @@ def generate_support_zip_on_nodes(self, node_ids: list):
466469
url = "/rest/troubleshooting/latest/support-zip/cluster"
467470
return self.post(url, data=data)
468471

469-
def check_support_zip_status(self, cluster_task_id: T_id):
472+
def check_support_zip_status(self, cluster_task_id: T_id) -> dict | None:
470473
"""
471474
Check status of support zip creation task
472475
:param cluster_task_id: str
@@ -475,7 +478,7 @@ def check_support_zip_status(self, cluster_task_id: T_id):
475478
url = "/rest/troubleshooting/latest/support-zip/status/cluster/{}".format(cluster_task_id)
476479
return self.get(url)
477480

478-
def download_support_zip(self, file_name: str):
481+
def download_support_zip(self, file_name: str) -> bytes:
479482
"""
480483
Download created support zip file
481484
:param file_name: str
@@ -489,12 +492,12 @@ def download_support_zip(self, file_name: str):
489492
Reference: https://docs.atlassian.com/software/jira/docs/api/REST/8.5.0/#api/2/cluster/zdu
490493
"""
491494

492-
def get_cluster_zdu_state(self):
495+
def get_cluster_zdu_state(self) -> dict | None:
493496
url = self.resource_url("cluster/zdu/state")
494497
return self.get(url)
495498

496499
# Issue Comments
497-
def issue_get_comments(self, issue_id: T_id):
500+
def issue_get_comments(self, issue_id: T_id) -> dict | None:
498501
"""
499502
Get Comments on an Issue.
500503
:param issue_id: Issue ID
@@ -505,7 +508,7 @@ def issue_get_comments(self, issue_id: T_id):
505508
url = "{base_url}/{issue_id}/comment".format(base_url=base_url, issue_id=issue_id)
506509
return self.get(url)
507510

508-
def issues_get_comments_by_id(self, *args):
511+
def issues_get_comments_by_id(self, *args: int) -> dict | None:
509512
"""
510513
Get Comments on Multiple Issues
511514
:param *args: int Issue ID's
@@ -840,7 +843,7 @@ def get_filter(self, filter_id: T_id):
840843
url = "{base_url}/{id}".format(base_url=base_url, id=filter_id)
841844
return self.get(url)
842845

843-
def update_filter(self, filter_id: T_id, jql: str, **kwargs):
846+
def update_filter(self, filter_id: T_id, jql: str, **kwargs: Any):
844847
"""
845848
:param filter_id: int
846849
:param jql: str
@@ -1407,7 +1410,7 @@ def issue_field_value_append(self, issue_id_or_key: str, field: str, value: str,
14071410
params=params,
14081411
)
14091412

1410-
def get_issue_labels(self, issue_key: str):
1413+
def get_issue_labels(self, issue_key: str) -> dict | None:
14111414
"""
14121415
Get issue labels.
14131416
:param issue_key:
@@ -1417,7 +1420,11 @@ def get_issue_labels(self, issue_key: str):
14171420
url = "{base_url}/{issue_key}?fields=labels".format(base_url=base_url, issue_key=issue_key)
14181421
if self.advanced_mode:
14191422
return self.get(url)
1420-
return (self.get(url) or {}).get("fields").get("labels")
1423+
d = self.get(url) or {}
1424+
f = d.get("fields")
1425+
if f:
1426+
return f.get("labels")
1427+
return None
14211428

14221429
def update_issue(self, issue_key: T_id, update: dict | str) -> dict | None:
14231430
"""
@@ -1741,7 +1748,7 @@ def scrap_regex_from_issue(self, issue: str, regex: str):
17411748
except HTTPError as e:
17421749
if e.response.status_code == 404:
17431750
# Raise ApiError as the documented reason is ambiguous
1744-
log.error("couldn't find issue: ", issue["key"])
1751+
log.error("couldn't find issue: ", issue)
17451752
raise ApiNotFoundError(
17461753
"There is no content with the given issue ud,"
17471754
"or the calling user does not have permission to view the issue",
@@ -1882,7 +1889,7 @@ def update_issue_remote_link_by_id(
18821889
)
18831890
return self.put(url, data=data)
18841891

1885-
def delete_issue_remote_link_by_id(self, issue_key: str, link_id: T_id):
1892+
def delete_issue_remote_link_by_id(self, issue_key: str, link_id: T_id) -> dict | None:
18861893
"""
18871894
Deletes Remote Link on Issue
18881895
:param issue_key: str
@@ -1894,27 +1901,23 @@ def delete_issue_remote_link_by_id(self, issue_key: str, link_id: T_id):
18941901
)
18951902
return self.delete(url)
18961903

1897-
def get_issue_transitions(self, issue_key: str):
1904+
def get_issue_transitions(self, issue_key: str) -> list[dict]:
18981905
if self.advanced_mode:
1899-
return [
1900-
{
1901-
"name": transition["name"],
1902-
"id": int(transition["id"]),
1903-
"to": transition["to"]["name"],
1904-
}
1905-
for transition in (self.get_issue_transitions_full(issue_key).json() or {}).get("transitions")
1906-
]
1906+
resp = cast(Response, self.get_issue_transitions_full(issue_key))
1907+
d: dict[str, list] = resp.json() or {}
19071908
else:
1908-
return [
1909-
{
1910-
"name": transition["name"],
1911-
"id": int(transition["id"]),
1912-
"to": transition["to"]["name"],
1913-
}
1914-
for transition in (self.get_issue_transitions_full(issue_key) or {}).get("transitions")
1915-
]
1909+
d = self.get_issue_transitions_full(issue_key) or {}
1910+
1911+
return [
1912+
{
1913+
"name": transition["name"],
1914+
"id": int(transition["id"]),
1915+
"to": transition["to"]["name"],
1916+
}
1917+
for transition in cast(list[dict], d.get("transitions"))
1918+
]
19161919

1917-
def issue_transition(self, issue_key: str, status: str):
1920+
def issue_transition(self, issue_key: str, status: str) -> dict | None:
19181921
return self.set_issue_status(issue_key, status)
19191922

19201923
def set_issue_status(
@@ -1970,12 +1973,12 @@ def set_issue_status_by_transition_id(self, issue_key: str, transition_id: T_id)
19701973
def get_issue_status(self, issue_key: str):
19711974
base_url = self.resource_url("issue")
19721975
url = "{base_url}/{issue_key}?fields=status".format(base_url=base_url, issue_key=issue_key)
1973-
return (((self.get(url) or {}).get("fields") or {}).get("status") or {}).get("name") or {}
1976+
return (self.get(url) or {}).__getitem__("fields").__getitem__("status").__getitem__("name")
19741977

1975-
def get_issue_status_id(self, issue_key: str):
1978+
def get_issue_status_id(self, issue_key: str) -> str:
19761979
base_url = self.resource_url("issue")
19771980
url = "{base_url}/{issue_key}?fields=status".format(base_url=base_url, issue_key=issue_key)
1978-
return (self.get(url) or {}).get("fields").get("status").get("id")
1981+
return (self.get(url) or {}).__getitem__("fields").__getitem__("status").__getitem__("id")
19791982

19801983
def get_issue_transitions_full(
19811984
self, issue_key: str, transition_id: T_id | None = None, expand: str | None = None
@@ -3160,7 +3163,7 @@ def get_assignable_users_for_issue(
31603163
def get_status_id_from_name(self, status_name: str):
31613164
base_url = self.resource_url("status")
31623165
url = "{base_url}/{name}".format(base_url=base_url, name=status_name)
3163-
return int((self.get(url) or {}).get("id"))
3166+
return int((self.get(url) or {}).__getitem__("id"))
31643167

31653168
def get_status_for_project(self, project_key: str):
31663169
base_url = self.resource_url("project")
@@ -3878,7 +3881,7 @@ def get_issue_security_scheme(self, scheme_id: T_id, only_levels: bool = False):
38783881
url = "{base_url}/{scheme_id}".format(base_url=base_url, scheme_id=scheme_id)
38793882

38803883
if only_levels is True:
3881-
return self.get(url).get("levels")
3884+
return (self.get(url) or {}).__getitem__("levels")
38823885
else:
38833886
return self.get(url)
38843887

atlassian/typehints.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,3 @@
55
_Data: TypeAlias = (
66
dict | str
77
)
8-
9-

0 commit comments

Comments
 (0)