python-jira-plus 2.0.6__py3-none-any.whl → 2.0.8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- python_jira_plus/__init__.py +2 -2
- python_jira_plus/describe_allowed_value.py +3 -3
- python_jira_plus/jira_plus.py +28 -20
- {python_jira_plus-2.0.6.dist-info → python_jira_plus-2.0.8.dist-info}/METADATA +9 -7
- python_jira_plus-2.0.8.dist-info/RECORD +8 -0
- {python_jira_plus-2.0.6.dist-info → python_jira_plus-2.0.8.dist-info}/WHEEL +1 -1
- python_jira_plus-2.0.6.dist-info/RECORD +0 -8
- {python_jira_plus-2.0.6.dist-info → python_jira_plus-2.0.8.dist-info}/licenses/LICENSE +0 -0
- {python_jira_plus-2.0.6.dist-info → python_jira_plus-2.0.8.dist-info}/top_level.txt +0 -0
python_jira_plus/__init__.py
CHANGED
|
@@ -8,7 +8,7 @@ pagination, metadata validation, and more.
|
|
|
8
8
|
from dotenv import load_dotenv
|
|
9
9
|
|
|
10
10
|
from python_jira_plus.describe_allowed_value import describe_allowed_value
|
|
11
|
-
from python_jira_plus.jira_plus import JiraPlus, ServerType
|
|
11
|
+
from python_jira_plus.jira_plus import JiraPlus, ServerType, UrlScheme
|
|
12
12
|
|
|
13
13
|
load_dotenv()
|
|
14
14
|
|
|
@@ -27,4 +27,4 @@ BASIC_FIELDS = [
|
|
|
27
27
|
"resolution",
|
|
28
28
|
"parent",
|
|
29
29
|
]
|
|
30
|
-
__all__ = ["JiraPlus", "ServerType", "BASIC_FIELDS"]
|
|
30
|
+
__all__ = ["JiraPlus", "ServerType", "UrlScheme", "BASIC_FIELDS"]
|
|
@@ -11,17 +11,17 @@ def describe_allowed_value(value: Any, allowed_values: set = None) -> bool:
|
|
|
11
11
|
|
|
12
12
|
@describe_allowed_value.register
|
|
13
13
|
def _(value: int, allowed_values: list = None) -> bool:
|
|
14
|
-
return value
|
|
14
|
+
return value in allowed_values
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
@describe_allowed_value.register
|
|
18
18
|
def _(value: float, allowed_values: list = None) -> bool:
|
|
19
|
-
return value
|
|
19
|
+
return value in allowed_values
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
@describe_allowed_value.register
|
|
23
23
|
def _(value: str, allowed_values: list = None) -> bool:
|
|
24
|
-
return value
|
|
24
|
+
return value in allowed_values
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
@describe_allowed_value.register
|
python_jira_plus/jira_plus.py
CHANGED
|
@@ -12,7 +12,7 @@ from custom_python_logger import get_logger
|
|
|
12
12
|
from jira import JIRA, Issue, JIRAError
|
|
13
13
|
from jira.client import ResultList
|
|
14
14
|
from retrying import retry
|
|
15
|
-
|
|
15
|
+
from packaging.version import Version
|
|
16
16
|
from python_jira_plus.describe_allowed_value import describe_allowed_value
|
|
17
17
|
|
|
18
18
|
|
|
@@ -53,10 +53,12 @@ class JiraPlus:
|
|
|
53
53
|
|
|
54
54
|
self.jira_client = self.create_connection()
|
|
55
55
|
self.check_client_connection()
|
|
56
|
+
self.server_version = self.get_server_version()
|
|
57
|
+
self.use_legacy_api = self._resolve_use_legacy_api()
|
|
56
58
|
|
|
57
59
|
@retry(stop_max_attempt_number=3, wait_fixed=180000)
|
|
58
|
-
def create_connection(self, timeout: int = 580) -> JIRA
|
|
59
|
-
if self.server_type == ServerType.ON_PREMISE and not self.sso:
|
|
60
|
+
def create_connection(self, timeout: int = 580) -> JIRA:
|
|
61
|
+
if self.server_type == ServerType.ON_PREMISE and not self.sso:
|
|
60
62
|
jira_client = JIRA(
|
|
61
63
|
token_auth=self.jira_token, options={"server": self.server, "verify": self.verify_ssl}, timeout=timeout
|
|
62
64
|
)
|
|
@@ -142,12 +144,16 @@ class JiraPlus:
|
|
|
142
144
|
all_issues = []
|
|
143
145
|
retries = 0
|
|
144
146
|
page = None
|
|
145
|
-
while True:
|
|
147
|
+
while True:
|
|
146
148
|
try:
|
|
149
|
+
next_token = None
|
|
150
|
+
if page is not None:
|
|
151
|
+
next_token = page.get('nextPageToken') if json_result else page.nextPageToken
|
|
152
|
+
|
|
147
153
|
self.logger.debug(f"Fetching issues from startAt={len(all_issues)}")
|
|
148
154
|
page = self.jira_client.enhanced_search_issues(
|
|
149
155
|
jql_str=query,
|
|
150
|
-
nextPageToken=
|
|
156
|
+
nextPageToken=next_token,
|
|
151
157
|
maxResults=max_results,
|
|
152
158
|
fields=specific_fields,
|
|
153
159
|
json_result=json_result,
|
|
@@ -156,7 +162,8 @@ class JiraPlus:
|
|
|
156
162
|
break
|
|
157
163
|
|
|
158
164
|
all_issues += page["issues"] if json_result else page
|
|
159
|
-
|
|
165
|
+
is_last = page['isLast'] if json_result else page.isLast
|
|
166
|
+
if is_last:
|
|
160
167
|
break
|
|
161
168
|
retries = 0 # reset on success
|
|
162
169
|
except JIRAError as err:
|
|
@@ -268,18 +275,16 @@ class JiraPlus:
|
|
|
268
275
|
def get_server_version(self) -> tuple[int, ...]:
|
|
269
276
|
return tuple(self.jira_client.server_info()["versionNumbers"])
|
|
270
277
|
|
|
271
|
-
def
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
self.logger.
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
)
|
|
278
|
-
return False
|
|
278
|
+
def _resolve_use_legacy_api(self) -> bool:
|
|
279
|
+
if self.server_type == ServerType.ON_PREMISE:
|
|
280
|
+
use_legacy = Version(".".join(str(x) for x in self.server_version)) < Version("9.0.0")
|
|
281
|
+
self.logger.debug(f"Using {'legacy createmeta' if use_legacy else 'project_issue_types'} API (ON_PREMISE {self.server_version})")
|
|
282
|
+
return use_legacy
|
|
283
|
+
self.logger.debug("Using legacy createmeta API (Cloud)")
|
|
279
284
|
return True
|
|
280
285
|
|
|
281
286
|
def get_project_fields_metadata(self, project_key: str, issue_type: str) -> dict:
|
|
282
|
-
if self.
|
|
287
|
+
if self.use_legacy_api:
|
|
283
288
|
_, issue_meta = self._fetch_metadata(project_key=project_key, issue_type=issue_type)
|
|
284
289
|
return issue_meta["fields"]
|
|
285
290
|
_project_issue_types = self.jira_client.project_issue_types(project_key)
|
|
@@ -288,7 +293,7 @@ class JiraPlus:
|
|
|
288
293
|
return {f.fieldId: f.raw for f in field_list}
|
|
289
294
|
|
|
290
295
|
def validate_fields( # pylint: disable=R1260
|
|
291
|
-
self, project_key: str, issue_type: str, fields: dict
|
|
296
|
+
self, project_key: str, issue_type: str, fields: dict
|
|
292
297
|
) -> None:
|
|
293
298
|
fields_metadata = self.get_project_fields_metadata(project_key=project_key, issue_type=issue_type)
|
|
294
299
|
for custom_field, value in fields.items():
|
|
@@ -367,7 +372,7 @@ class JiraPlus:
|
|
|
367
372
|
|
|
368
373
|
def delete_issue(self, issue_key: str) -> bool:
|
|
369
374
|
try:
|
|
370
|
-
issue = self.get_issue_by_key(key=issue_key)
|
|
375
|
+
issue = self.get_issue_by_key(key=issue_key, json_result=False)
|
|
371
376
|
issue.delete()
|
|
372
377
|
self.logger.info(f"Issue {issue_key} deleted successfully.")
|
|
373
378
|
return True
|
|
@@ -452,10 +457,13 @@ class JiraPlus:
|
|
|
452
457
|
return False
|
|
453
458
|
|
|
454
459
|
def get_account_data(self, user_mail: str) -> list[dict]:
|
|
455
|
-
|
|
456
|
-
f"
|
|
460
|
+
response = requests.get(
|
|
461
|
+
f"{self.server}/rest/api/3/user/search",
|
|
462
|
+
params={"query": user_mail},
|
|
463
|
+
auth=(self.jira_username, self.jira_token),
|
|
464
|
+
timeout=30,
|
|
457
465
|
)
|
|
458
|
-
response
|
|
466
|
+
response.raise_for_status()
|
|
459
467
|
return response.json()
|
|
460
468
|
|
|
461
469
|
def get_account_id(self, user_mail: str) -> str:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-jira-plus
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.8
|
|
4
4
|
Summary: Enhanced Python client for JIRA with better error handling, pagination, and metadata validation.
|
|
5
5
|
Author: Avi Zaguri
|
|
6
6
|
License: MIT
|
|
@@ -17,14 +17,16 @@ Requires-Python: >=3.12
|
|
|
17
17
|
Description-Content-Type: text/markdown
|
|
18
18
|
License-File: LICENSE
|
|
19
19
|
Requires-Dist: custom-python-logger>=2.0.10
|
|
20
|
-
Requires-Dist: dotenv>=0.
|
|
20
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
21
21
|
Requires-Dist: jira>=3.10.5
|
|
22
|
-
Requires-Dist:
|
|
23
|
-
Requires-Dist: pytest>=9.0.1
|
|
22
|
+
Requires-Dist: packaging>=26.2
|
|
24
23
|
Requires-Dist: requests>=2.32.5
|
|
25
24
|
Requires-Dist: retrying>=1.4.2
|
|
26
|
-
|
|
27
|
-
Requires-Dist:
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: pre-commit>=4.5.0; extra == "dev"
|
|
27
|
+
Requires-Dist: pytest>=9.0.1; extra == "dev"
|
|
28
|
+
Requires-Dist: setuptools>=80.9.0; extra == "dev"
|
|
29
|
+
Requires-Dist: wheel>=0.45.1; extra == "dev"
|
|
28
30
|
Dynamic: license-file
|
|
29
31
|
|
|
30
32
|

|
|
@@ -59,7 +61,7 @@ pip install python-jira-plus
|
|
|
59
61
|
---
|
|
60
62
|
|
|
61
63
|
## Requirements
|
|
62
|
-
- Python 3.
|
|
64
|
+
- Python 3.12+
|
|
63
65
|
- `jira` package
|
|
64
66
|
- `retrying` package
|
|
65
67
|
- `custom-python-logger` package
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
python_jira_plus/__init__.py,sha256=BUKjGxQfkxWyZs-mKZs2bAgGnsYHQ4uOFjuB8MPmhfg,616
|
|
2
|
+
python_jira_plus/describe_allowed_value.py,sha256=fWfq0DkvJ2zmNIUXPH5rO5OgcY69bUqBIfTPQyxBt5E,1287
|
|
3
|
+
python_jira_plus/jira_plus.py,sha256=TNJkwFdDbkaVrsEaO3kBRGHi_GDFVhRcpoX6bAgyRTs,19568
|
|
4
|
+
python_jira_plus-2.0.8.dist-info/licenses/LICENSE,sha256=cSikHY6SZFsPZSBizCDAJ0-Bjjzxt-JtX6TVbKxwimo,1067
|
|
5
|
+
python_jira_plus-2.0.8.dist-info/METADATA,sha256=AdZUwcmuzp3qtoFVuaB1En8QQqjKxFz6_3U99X6G-o8,4285
|
|
6
|
+
python_jira_plus-2.0.8.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
7
|
+
python_jira_plus-2.0.8.dist-info/top_level.txt,sha256=3DxBdmf_naggoqDHSvLstG_GX3bW2XXYYorBDybBUiA,17
|
|
8
|
+
python_jira_plus-2.0.8.dist-info/RECORD,,
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
python_jira_plus/__init__.py,sha256=hi4PadXJu9vYDqslH0zxAm-UsU_zfVFHCImqbchHbDU,592
|
|
2
|
-
python_jira_plus/describe_allowed_value.py,sha256=ZU3SN0d3Xy_4qPaVhkhqQYabt3Q_tN64J2yJ3mV0Abc,1287
|
|
3
|
-
python_jira_plus/jira_plus.py,sha256=ZswRdySAqM0me5FEI9jSEdv3oxRklHYLGcAY2beQ9iI,19251
|
|
4
|
-
python_jira_plus-2.0.6.dist-info/licenses/LICENSE,sha256=cSikHY6SZFsPZSBizCDAJ0-Bjjzxt-JtX6TVbKxwimo,1067
|
|
5
|
-
python_jira_plus-2.0.6.dist-info/METADATA,sha256=3Fdm_jE2laIs9VjSBymL2DW8t84WX2CSX8HDci7Kt10,4162
|
|
6
|
-
python_jira_plus-2.0.6.dist-info/WHEEL,sha256=YLJXdYXQ2FQ0Uqn2J-6iEIC-3iOey8lH3xCtvFLkd8Q,91
|
|
7
|
-
python_jira_plus-2.0.6.dist-info/top_level.txt,sha256=3DxBdmf_naggoqDHSvLstG_GX3bW2XXYYorBDybBUiA,17
|
|
8
|
-
python_jira_plus-2.0.6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|