python-jira-plus 1.0.12__tar.gz → 1.0.14__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-jira-plus
3
- Version: 1.0.12
3
+ Version: 1.0.14
4
4
  Summary: Enhanced Python client for JIRA with better error handling, pagination, and metadata validation.
5
5
  Home-page: https://github.com/aviz92/python-jira-plus
6
6
  Author: Avi Zaguri
@@ -7,6 +7,7 @@ import time
7
7
  from enum import Enum
8
8
  from typing import Any, Union, Optional
9
9
  import requests
10
+ from custom_python_logger import get_logger
10
11
  from jira import JIRA, JIRAError, Issue
11
12
  from jira.client import ResultList
12
13
  from retrying import retry
@@ -26,17 +27,17 @@ class ServerType(Enum):
26
27
 
27
28
  class JiraPlus:
28
29
  def __init__(
29
- self, base_url: Optional[str] = None,
30
- server_type: ServerType = ServerType.CLOUD,
31
- urllib3_log_level: int = logging.WARNING,
32
- jira_username: Optional[str] = None,
33
- jira_token: Optional[str] = None, # Use API token (not PAT)
34
- verify_ssl: bool = True,
35
- sso: bool = False,
36
- url_scheme: UrlScheme = UrlScheme.HTTPS
30
+ self, base_url: Optional[str] = None,
31
+ server_type: ServerType = ServerType.CLOUD,
32
+ urllib3_log_level: int = logging.WARNING,
33
+ jira_username: Optional[str] = None,
34
+ jira_token: Optional[str] = None, # Use API token (not PAT)
35
+ verify_ssl: bool = True,
36
+ sso: bool = False,
37
+ url_scheme: UrlScheme = UrlScheme.HTTPS
37
38
  ) -> None:
38
- self.logger = logging.getLogger()
39
- logging.getLogger("urllib3").setLevel(urllib3_log_level)
39
+ self.logger = get_logger(self.__class__.__name__)
40
+ get_logger("urllib3").setLevel(urllib3_log_level)
40
41
 
41
42
  self.jira_username = jira_username or os.getenv('JIRA_USER_NAME')
42
43
  self.jira_token = jira_token or os.getenv('JIRA_TOKEN')
@@ -51,8 +52,7 @@ class JiraPlus:
51
52
  self.jira_client = self.create_connection()
52
53
  self.check_client_connection()
53
54
 
54
- @retry(stop_max_attempt_number=3,
55
- wait_fixed=180000) # Retry 3 times with a 3-min (180000) delay between each attempt
55
+ @retry(stop_max_attempt_number=3, wait_fixed=180000)
56
56
  def create_connection(self, timeout=580) -> Optional[JIRA]:
57
57
  if self.server_type == ServerType.ON_PREMISE and not self.sso:
58
58
  jira_client = JIRA(
@@ -99,10 +99,10 @@ class JiraPlus:
99
99
  return False
100
100
 
101
101
  def get_issue_by_key(
102
- self,
103
- key: str,
104
- specific_fields: str | list[str] = '*all',
105
- json_result: bool = True
102
+ self,
103
+ key: str,
104
+ specific_fields: str | list[str] = '*all',
105
+ json_result: bool = True
106
106
  ) -> None | Issue | dict[str, Any]:
107
107
  try:
108
108
  jira_issue = self.jira_client.issue(id=key, fields=specific_fields)
@@ -117,12 +117,12 @@ class JiraPlus:
117
117
  return None
118
118
 
119
119
  def get_objects_by_query(
120
- self,
121
- query: str,
122
- max_results: int = 5000,
123
- specific_fields: Union[str, list[str]] = "*all",
124
- jira_err_count: int = 3,
125
- json_result: bool = True,
120
+ self,
121
+ query: str,
122
+ max_results: int = 5000,
123
+ specific_fields: Union[str, list[str]] = "*all",
124
+ jira_err_count: int = 3,
125
+ json_result: bool = True,
126
126
  ) -> Optional[Union[ResultList[Issue], dict]]:
127
127
  return self._paginate_query(
128
128
  query=query,
@@ -133,12 +133,12 @@ class JiraPlus:
133
133
  )
134
134
 
135
135
  def _paginate_query(
136
- self,
137
- query: str,
138
- max_results: int,
139
- specific_fields: Union[str, list[str]],
140
- jira_err_limit: int,
141
- json_result: bool
136
+ self,
137
+ query: str,
138
+ max_results: int,
139
+ specific_fields: Union[str, list[str]],
140
+ jira_err_limit: int,
141
+ json_result: bool
142
142
  ) -> Union[ResultList[Issue] | list]:
143
143
  start_at = 0
144
144
  all_issues = []
@@ -162,6 +162,9 @@ class JiraPlus:
162
162
  break
163
163
  retries = 0 # reset on success
164
164
  except JIRAError as err:
165
+ if err.status_code == 400:
166
+ self.logger.error(f"Bad Request: {err.text}")
167
+ raise JIRAError(f"Bad Request: {err.text}")
165
168
  retries += 1
166
169
  self.logger.warning(f"Retry {retries}/{jira_err_limit} after JIRAError: {err}")
167
170
  if retries >= jira_err_limit:
@@ -190,10 +193,10 @@ class JiraPlus:
190
193
  return meta, issue_meta
191
194
 
192
195
  def get_allowed_values(
193
- self,
194
- project_key: str,
195
- issue_type: str,
196
- field_id_or_name: str,
196
+ self,
197
+ project_key: str,
198
+ issue_type: str,
199
+ field_id_or_name: str,
197
200
  ) -> Optional[list]:
198
201
  """
199
202
  Returns the allowed values for a specific field in a project + issue type context.
@@ -253,10 +256,10 @@ class JiraPlus:
253
256
  return {f.fieldId: f.raw for f in field_list}
254
257
 
255
258
  def validate_fields(
256
- self,
257
- project_key: str,
258
- issue_type: str,
259
- fields: Optional[dict] = None
259
+ self,
260
+ project_key: str,
261
+ issue_type: str,
262
+ fields: Optional[dict] = None
260
263
  ) -> None:
261
264
  fields_metadata = self.get_project_fields_metadata(
262
265
  project_key=project_key,
@@ -291,13 +294,13 @@ class JiraPlus:
291
294
  # Add more field type checks as needed
292
295
 
293
296
  def create_issue(
294
- self,
295
- project_key: str,
296
- summary: str,
297
- description: str,
298
- issue_type: str,
299
- assignee: Optional[str] = None,
300
- custom_fields: Optional[dict] = None,
297
+ self,
298
+ project_key: str,
299
+ summary: str,
300
+ description: str,
301
+ issue_type: str,
302
+ assignee: Optional[str] = None,
303
+ custom_fields: Optional[dict] = None,
301
304
  ) -> Optional[Issue]:
302
305
  issue_fields = {
303
306
  "project": {"key": project_key},
@@ -318,9 +321,9 @@ class JiraPlus:
318
321
  return issue
319
322
 
320
323
  def update_issue(
321
- self,
322
- issue_key: str,
323
- fields_to_update: dict
324
+ self,
325
+ issue_key: str,
326
+ fields_to_update: dict
324
327
  ) -> Optional[Issue]:
325
328
  try:
326
329
  issue = self.jira_client.issue(issue_key)
@@ -393,11 +396,11 @@ class JiraPlus:
393
396
  self.logger.exception(f"Exception - Attachment {file_path} was not uploaded to issue {issue_key}\n{err}")
394
397
 
395
398
  def transition_issue(
396
- self,
397
- issue_key: str,
398
- transition_name: str,
399
- fields: Optional[dict] = None,
400
- comment: Optional[str] = None,
399
+ self,
400
+ issue_key: str,
401
+ transition_name: str,
402
+ fields: Optional[dict] = None,
403
+ comment: Optional[str] = None,
401
404
  ) -> bool:
402
405
  try:
403
406
  transitions = self.jira_client.transitions(issue_key)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-jira-plus
3
- Version: 1.0.12
3
+ Version: 1.0.14
4
4
  Summary: Enhanced Python client for JIRA with better error handling, pagination, and metadata validation.
5
5
  Home-page: https://github.com/aviz92/python-jira-plus
6
6
  Author: Avi Zaguri
@@ -1,6 +1,6 @@
1
1
  from setuptools import setup, find_packages
2
2
 
3
- package_version = '1.0.12'
3
+ package_version = '1.0.14'
4
4
 
5
5
  package_name = 'python-jira-plus'
6
6
  package_description = 'Enhanced Python client for JIRA with better error handling, pagination, and metadata validation.'