Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-jira for openSUSE:Factory 
checked in at 2022-06-04 23:27:31
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-jira (Old)
 and      /work/SRC/openSUSE:Factory/.python-jira.new.1548 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-jira"

Sat Jun  4 23:27:31 2022 rev:8 rq:980788 version:3.2.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-jira/python-jira.changes  2022-01-31 
22:57:53.413351986 +0100
+++ /work/SRC/openSUSE:Factory/.python-jira.new.1548/python-jira.changes        
2022-06-04 23:27:37.476791520 +0200
@@ -1,0 +2,14 @@
+Sat Jun  4 18:05:47 UTC 2022 - Dirk M??ller <dmuel...@suse.com>
+
+- update to 3.2.0:
+  * Additional scheme endpoints for projects 
+  * Add subscriptable support for PropertyHolder 
+  * Fixing type hint to match documentation for move_to_backlog 
+  * improve ResultList types 
+  * Allow verify option as path to cert in config 
+  * Bugfixes
+  * Locate the exact user by key if there are multiple users returned from 
query 
+  * Fixing type hint to match documentation for move_to_backlog 
+  * Avoid printing parsed json response 
+
+-------------------------------------------------------------------

Old:
----
  jira-3.1.1.tar.gz

New:
----
  jira-3.2.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-jira.spec ++++++
--- /var/tmp/diff_new_pack.gbIcbG/_old  2022-06-04 23:27:37.888791937 +0200
+++ /var/tmp/diff_new_pack.gbIcbG/_new  2022-06-04 23:27:37.892791941 +0200
@@ -18,7 +18,7 @@
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-jira
-Version:        3.1.1
+Version:        3.2.0
 Release:        0
 Summary:        Python library for interacting with JIRA via REST APIs
 License:        BSD-3-Clause
@@ -40,8 +40,7 @@
 Requires:       python-requests >= 2.10.0
 Requires:       python-requests-oauthlib >= 0.6.1
 Requires:       python-requests-toolbelt
-Requires:       python-setuptools >= 20.10.1
-Requires:       python-six >= 1.10.0
+Requires:       python-typing_extensions >= 3.7.4.2
 Requires(post): update-alternatives
 Requires(postun):update-alternatives
 BuildArch:      noarch

++++++ jira-3.1.1.tar.gz -> jira-3.2.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jira-3.1.1/.pre-commit-config.yaml 
new/jira-3.2.0/.pre-commit-config.yaml
--- old/jira-3.1.1/.pre-commit-config.yaml      2021-11-11 11:47:14.000000000 
+0100
+++ new/jira-3.2.0/.pre-commit-config.yaml      2022-04-14 01:40:59.000000000 
+0200
@@ -1,12 +1,12 @@
 ---
 repos:
   - repo: https://github.com/psf/black
-    rev: 21.10b0
+    rev: 22.3.0
     hooks:
       - id: black
         language_version: python3
   - repo: https://github.com/pre-commit/pre-commit-hooks
-    rev: v4.0.1
+    rev: v4.1.0
     hooks:
       - id: end-of-file-fixer
       - id: trailing-whitespace
@@ -46,14 +46,15 @@
       - id: yamllint
         files: \.(yaml|yml)$
   - repo: https://github.com/pre-commit/mirrors-mypy.git
-    rev: v0.910-1
+    rev: v0.931
     hooks:
       - id: mypy
         additional_dependencies:
           - types-requests
           - types-pkg_resources
+        args: [--no-strict-optional, --ignore-missing-imports, 
--show-error-codes]
   - repo: https://github.com/asottile/pyupgrade
-    rev: v2.29.0
+    rev: v2.31.0
     hooks:
       - id: pyupgrade
         args: [ --py36-plus ]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jira-3.1.1/PKG-INFO new/jira-3.2.0/PKG-INFO
--- old/jira-3.1.1/PKG-INFO     2021-11-11 11:47:33.324146500 +0100
+++ new/jira-3.2.0/PKG-INFO     2022-04-14 01:41:21.476967000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: jira
-Version: 3.1.1
+Version: 3.2.0
 Summary: Python library for interacting with JIRA via REST APIs.
 Home-page: https://github.com/pycontribs/jira
 Author: Ben Speakmon
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jira-3.1.1/constraints.txt 
new/jira-3.2.0/constraints.txt
--- old/jira-3.1.1/constraints.txt      2021-11-11 11:47:14.000000000 +0100
+++ new/jira-3.2.0/constraints.txt      2022-04-14 01:40:59.000000000 +0200
@@ -8,7 +8,7 @@
     # via sphinx
 appnope==0.1.2
     # via ipython
-attrs==21.2.0
+attrs==21.4.0
     # via pytest
 babel==2.9.1
     # via sphinx
@@ -18,24 +18,24 @@
     # via requests
 cffi==1.15.0
     # via cryptography
-charset-normalizer==2.0.7
+charset-normalizer==2.0.12
     # via requests
 coverage==6.1.2
     # via pytest-cov
-cryptography==35.0.0
+cryptography==36.0.1
     # via
     #   pyspnego
     #   requests-kerberos
 dataclasses==0.8
     # via pyspnego
-decorator==5.1.0
+decorator==5.1.1
     # via
     #   gssapi
     #   ipython
     #   traitlets
 defusedxml==0.7.1
     # via jira (setup.cfg)
-docutils==0.17.1
+docutils==0.18.1
     # via
     #   jira (setup.cfg)
     #   sphinx
@@ -48,7 +48,7 @@
     # via jira (setup.cfg)
 flaky==3.7.0
     # via jira (setup.cfg)
-gssapi==1.7.2
+gssapi==1.7.3
     # via pyspnego
 idna==3.3
     # via requests
@@ -65,28 +65,28 @@
     # via jira (setup.cfg)
 ipython-genutils==0.2.0
     # via traitlets
-jedi==0.18.0
+jedi==0.18.1
     # via ipython
 jinja2==3.0.3
     # via sphinx
 keyring==23.2.1
     # via jira (setup.cfg)
-krb5==0.2.0
+krb5==0.3.0
     # via pyspnego
 markupsafe==2.0.1
     # via
     #   jinja2
     #   jira (setup.cfg)
-oauthlib==3.1.1
+oauthlib==3.2.0
     # via
     #   jira (setup.cfg)
     #   requests-oauthlib
-packaging==21.2
+packaging==21.3
     # via
     #   pytest
     #   pytest-sugar
     #   sphinx
-parso==0.8.2
+parso==0.8.3
     # via jedi
 pexpect==4.8.0
     # via ipython
@@ -94,7 +94,7 @@
     # via ipython
 pluggy==1.0.0
     # via pytest
-prompt-toolkit==3.0.22
+prompt-toolkit==3.0.28
     # via ipython
 ptyprocess==0.7.0
     # via pexpect
@@ -105,7 +105,7 @@
     #   pytest-forked
 pycparser==2.21
     # via cffi
-pygments==2.10.0
+pygments==2.11.2
     # via
     #   ipython
     #   sphinx
@@ -115,7 +115,7 @@
     #   requests-jwt
 pyparsing==2.4.7
     # via packaging
-pyspnego==0.3.1
+pyspnego==0.5.0
     # via requests-kerberos
 pytest==6.2.5
     # via
@@ -131,21 +131,21 @@
     # via jira (setup.cfg)
 pytest-cov==3.0.0
     # via jira (setup.cfg)
-pytest-forked==1.3.0
+pytest-forked==1.4.0
     # via pytest-xdist
 pytest-instafail==0.4.2
     # via jira (setup.cfg)
 pytest-sugar==0.9.4
     # via jira (setup.cfg)
-pytest-timeout==2.0.1
+pytest-timeout==2.1.0
     # via jira (setup.cfg)
-pytest-xdist==2.4.0
+pytest-xdist==2.5.0
     # via jira (setup.cfg)
 pytz==2021.3
     # via babel
 pyyaml==6.0
     # via jira (setup.cfg)
-requests==2.26.0
+requests==2.27.1
     # via
     #   jira (setup.cfg)
     #   requests-futures
@@ -158,13 +158,13 @@
     #   sphinx
 requests-futures==1.0.0
     # via jira (setup.cfg)
-requests-jwt==0.5.3
+requests-jwt==0.6.0
     # via jira (setup.cfg)
-requests-kerberos==0.13.0
+requests-kerberos==0.14.0
     # via jira (setup.cfg)
 requests-mock==1.9.3
     # via jira (setup.cfg)
-requests-oauthlib==1.3.0
+requests-oauthlib==1.3.1
     # via jira (setup.cfg)
 requests-toolbelt==0.9.1
     # via jira (setup.cfg)
@@ -174,9 +174,9 @@
     # via
     #   requests-mock
     #   traitlets
-snowballstemmer==2.1.0
+snowballstemmer==2.2.0
     # via sphinx
-sphinx==4.3.0
+sphinx==4.4.0
     # via
     #   jira (setup.cfg)
     #   sphinx-rtd-theme
@@ -200,17 +200,17 @@
     # via pytest-sugar
 toml==0.10.2
     # via pytest
-tomli==1.2.2
+tomli==1.2.3
     # via coverage
 traitlets==4.3.3
     # via ipython
-typing-extensions==3.10.0.2
+typing-extensions==4.1.1
     # via importlib-metadata
-urllib3==1.26.7
+urllib3==1.26.8
     # via requests
 wcwidth==0.2.5
     # via prompt-toolkit
-wheel==0.37.0
+wheel==0.37.1
     # via jira (setup.cfg)
 xmlrunner==1.7.7
     # via jira (setup.cfg)
@@ -218,6 +218,3 @@
     # via jira (setup.cfg)
 zipp==3.6.0
     # via importlib-metadata
-
-# The following packages are considered to be unsafe in a requirements file:
-# setuptools
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jira-3.1.1/docs/examples.rst 
new/jira-3.2.0/docs/examples.rst
--- old/jira-3.1.1/docs/examples.rst    2021-11-11 11:47:14.000000000 +0100
+++ new/jira-3.2.0/docs/examples.rst    2022-04-14 01:40:59.000000000 +0200
@@ -8,9 +8,9 @@
 
 .. literalinclude:: ../examples/basic_use.py
 
-Another example shows how to authenticate with your Jira username and password:
+Another example with methods to authenticate with your Jira:
 
-.. literalinclude:: ../examples/basic_auth.py
+.. literalinclude:: ../examples/auth.py
 
 This example shows how to work with GreenHopper:
 
@@ -23,7 +23,7 @@
 Initialization
 --------------
 
-Everything goes through the ``JIRA`` object, so make one::
+Everything goes through the :py:class:`jira.client.JIRA` object, so make one::
 
     from jira import JIRA
 
@@ -40,13 +40,18 @@
 --------------
 
 At initialization time, jira-python can optionally create an HTTP BASIC or use 
OAuth 1.0a access tokens for user
-authentication. These sessions will apply to all subsequent calls to the 
``JIRA`` object.
+authentication. These sessions will apply to all subsequent calls to the  
:py:class:`jira.client.JIRA` object.
 
 The library is able to load the credentials from inside the ~/.netrc file, so 
put them there instead of keeping them in your source code.
 
 Cookie Based Authentication
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+.. warning::
+    This method of authentication is no longer supported on Jira Cloud. You 
can find the deprecation notice `here 
<https://developer.atlassian.com/cloud/jira/platform/deprecation-notice-basic-auth-and-cookie-based-auth>`_.
+
+    For Jira Cloud use the basic_auth= :ref:`basic-auth-api-token` 
authentication
+
 Pass a tuple of (username, password) to the ``auth`` constructor argument::
 
     auth_jira = JIRA(auth=('username', 'password'))
@@ -54,10 +59,6 @@
 Using this method, authentication happens during the initialization of the 
object. If the authentication is successful,
 the retrieved session cookie will be used in future requests. Upon cookie 
expiration, authentication will happen again transparently.
 
-.. warning::
-    This method of authentication is no longer supported on Jira Cloud. You 
can find the deprecation notice `here 
<https://developer.atlassian.com/cloud/jira/platform/deprecation-notice-basic-auth-and-cookie-based-auth>`_.
-
-    For Jira Cloud use the basic_auth= :ref:`basic-auth-api-token` 
authentication
 
 HTTP BASIC
 ^^^^^^^^^^
@@ -65,24 +66,30 @@
 (username, password)
 """"""""""""""""""""
 
-Pass a tuple of (username, password) to the ``basic_auth`` constructor 
argument::
-
-    auth_jira = JIRA(basic_auth=('username', 'password'))
-
 .. warning::
     This method of authentication is no longer supported on Jira Cloud. You 
can find the deprecation notice `here 
<https://developer.atlassian.com/cloud/jira/platform/deprecation-notice-basic-auth-and-cookie-based-auth>`_
 
-    For Jira Cloud use the basic_auth= :ref:`basic-auth-api-token` 
authentication
+    For Jira Cloud use the basic_auth= :ref:`basic-auth-api-token` 
authentication.
+    For Self Hosted Jira (Server, Data Center), consider the `Token Auth`_ 
authentication.
+
+Pass a tuple of (username, password) to the ``basic_auth`` constructor 
argument::
+
+    auth_jira = JIRA(basic_auth=('username', 'password'))
 
 .. _basic-auth-api-token:
 
 (username, api_token)
 """""""""""""""""""""
 
-Or pass a tuple of (email, api_token) to the ``basic_auth`` constructor 
argument (JIRA cloud)::
+
+Or pass a tuple of (email, api_token) to the ``basic_auth`` constructor 
argument (JIRA Cloud)::
 
     auth_jira = JIRA(basic_auth=('email', 'API token'))
 
+.. seealso::
+    For Self Hosted Jira (Server, Data Center), refer to the `Token Auth`_ 
Section.
+
+
 OAuth
 ^^^^^
 
@@ -112,6 +119,29 @@
 See 
https://confluence.atlassian.com/display/JIRA/Configuring+OAuth+Authentication+for+an+Application+Link
 for details
 on configuring an OAuth provider for Jira.
 
+Token Auth
+^^^^^^^^^^
+
+
+Jira Cloud
+""""""""""
+
+This is also referred to as an API Token in the
+`Jira Cloud documentation 
<https://support.atlassian.com/atlassian-account/docs/manage-api-tokens-for-your-atlassian-account/>`_
 ::
+
+    auth_jira = JIRA(basic_auth=('email', 'API token'))
+
+
+Jira Self Hosted (incl. Jira Server/Data Center)
+""""""""""""""""""""""""""""""""""""""""""""""""
+
+This is also referred to as Personal Access Tokens (PATs) in the
+`Self-Hosted Documentation 
<https://confluence.atlassian.com/enterprise/using-personal-access-tokens-1026032365.html>`_.
+The is available from Jira Core >= 8.14::
+
+    auth_jira = JIRA(token_auth='API token')
+
+
 Kerberos
 ^^^^^^^^
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jira-3.1.1/examples/auth.py 
new/jira-3.2.0/examples/auth.py
--- old/jira-3.1.1/examples/auth.py     1970-01-01 01:00:00.000000000 +0100
+++ new/jira-3.2.0/examples/auth.py     2022-04-14 01:40:59.000000000 +0200
@@ -0,0 +1,32 @@
+"""Some simple authentication examples.
+"""
+
+from collections import Counter
+from typing import cast
+
+from jira import JIRA
+from jira.client import ResultList
+from jira.resources import Issue
+
+# Some Authentication Methods
+jira = JIRA(
+    basic_auth=("admin", "admin"),  # a username/password tuple [Not 
recommended]
+    # basic_auth=("email", "API token"),  # Jira Cloud: a username/token tuple
+    # token_auth="API token",  # Self-Hosted Jira (e.g. Server): the PAT token
+    # auth=("admin", "admin"),  # a username/password tuple for cookie auth 
[Not recommended]
+)
+
+# Who has authenticated
+myself = jira.myself()
+
+# Get the mutable application properties for this server (requires
+# jira-system-administrators permission)
+props = jira.application_properties()
+
+# Find all issues reported by the admin
+# Note: we cast() for mypy's benefit, as search_issues can also return the raw 
json !
+#   This is if the following argument is used: `json_result=True`
+issues = cast(ResultList[Issue], jira.search_issues("assignee=admin"))
+
+# Find the top three projects containing issues reported by admin
+top_three = Counter([issue.fields.project.key for issue in 
issues]).most_common(3)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jira-3.1.1/examples/basic_auth.py 
new/jira-3.2.0/examples/basic_auth.py
--- old/jira-3.1.1/examples/basic_auth.py       2021-11-11 11:47:14.000000000 
+0100
+++ new/jira-3.2.0/examples/basic_auth.py       1970-01-01 01:00:00.000000000 
+0100
@@ -1,27 +0,0 @@
-# This script shows how to connect to a Jira instance with a
-# username and password over HTTP BASIC authentication.
-
-from collections import Counter
-from typing import cast
-
-from jira import JIRA
-from jira.client import ResultList
-from jira.resources import Issue
-
-# By default, the client will connect to a Jira instance started from the 
Atlassian Plugin SDK.
-# See
-# 
https://developer.atlassian.com/display/DOCS/Installing+the+Atlassian+Plugin+SDK
-# for details.
-jira = JIRA(basic_auth=("admin", "admin"))  # a username/password tuple
-
-# Get the mutable application properties for this server (requires
-# jira-system-administrators permission)
-props = jira.application_properties()
-
-# Find all issues reported by the admin
-# Note: we cast() for mypy's benefit, as search_issues can also return the raw 
json !
-#   This is if the following argument is used: `json_result=True`
-issues = cast(ResultList[Issue], jira.search_issues("assignee=admin"))
-
-# Find the top three projects containing issues reported by admin
-top_three = Counter([issue.fields.project.key for issue in 
issues]).most_common(3)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jira-3.1.1/examples/cookie_auth.py 
new/jira-3.2.0/examples/cookie_auth.py
--- old/jira-3.1.1/examples/cookie_auth.py      2021-11-11 11:47:14.000000000 
+0100
+++ new/jira-3.2.0/examples/cookie_auth.py      1970-01-01 01:00:00.000000000 
+0100
@@ -1,29 +0,0 @@
-# This script shows how to connect to a Jira instance with a
-# username and password over HTTP BASIC authentication.
-
-from collections import Counter
-from typing import cast
-
-from jira import JIRA
-from jira.client import ResultList
-from jira.resources import Issue
-
-# By default, the client will connect to a Jira instance started from the 
Atlassian Plugin SDK.
-# See
-# 
https://developer.atlassian.com/display/DOCS/Installing+the+Atlassian+Plugin+SDK
-# for details.
-jira = JIRA(auth=("admin", "admin"))  # a username/password tuple for cookie 
auth
-
-# Get the mutable application properties for this server (requires
-# jira-system-administrators permission)
-props = jira.application_properties()
-
-# Find all issues reported by the admin
-issues = cast(ResultList[Issue], jira.search_issues("assignee=admin"))
-
-# Find the top three projects containing issues reported by admin
-top_three = Counter([issue.fields.project.key for issue in 
issues]).most_common(3)
-
-# import time; time.sleep(65)  # Fake cookie expiration
-
-issues = cast(ResultList[Issue], jira.search_issues("assignee=admin"))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jira-3.1.1/examples/maintenance.py 
new/jira-3.2.0/examples/maintenance.py
--- old/jira-3.1.1/examples/maintenance.py      2021-11-11 11:47:14.000000000 
+0100
+++ new/jira-3.2.0/examples/maintenance.py      2022-04-14 01:40:59.000000000 
+0200
@@ -16,11 +16,11 @@
 
 CI_JIRA_URL = os.environ["CI_JIRA_URL"]
 CI_JIRA_ADMIN = os.environ["CI_JIRA_ADMIN"]
-CI_JIRA_ADMIN_PASSWORD = os.environ["CI_JIRA_ADMIN_PASSWORD"]
+CI_JIRA_ADMIN_TOKEN = os.environ["CI_JIRA_ADMIN_TOKEN"]
 
 j = JIRA(
     CI_JIRA_URL,
-    basic_auth=(CI_JIRA_ADMIN, CI_JIRA_ADMIN_PASSWORD),
+    basic_auth=(CI_JIRA_ADMIN, CI_JIRA_ADMIN_TOKEN),
     logging=True,
     validate=True,
     async_=True,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jira-3.1.1/jira/client.py 
new/jira-3.2.0/jira/client.py
--- old/jira-3.1.1/jira/client.py       2021-11-11 11:47:14.000000000 +0100
+++ new/jira-3.2.0/jira/client.py       2022-04-14 01:40:59.000000000 +0200
@@ -1,4 +1,3 @@
-#!/usr/bin/python
 """
 This module implements a friendly (well, friendlier) interface between the raw 
JSON
 responses from Jira and the Resource/dict abstractions provided by this 
library. Users
@@ -28,6 +27,7 @@
     Callable,
     Dict,
     Generic,
+    Iterator,
     List,
     Optional,
     Tuple,
@@ -36,6 +36,7 @@
     Union,
     cast,
     no_type_check,
+    overload,
 )
 from urllib.parse import parse_qs, quote, urlparse
 
@@ -67,9 +68,13 @@
     Issue,
     IssueLink,
     IssueLinkType,
+    IssueSecurityLevelScheme,
     IssueType,
+    IssueTypeScheme,
+    NotificationScheme,
     PermissionScheme,
     Priority,
+    PriorityScheme,
     Project,
     RemoteLink,
     RequestType,
@@ -85,6 +90,7 @@
     Version,
     Votes,
     Watchers,
+    WorkflowScheme,
     Worklog,
 )
 from jira.utils import json_loads, threaded_requests
@@ -100,6 +106,10 @@
 except ImportError:
     pass
 
+try:
+    from typing import SupportsIndex  # type:ignore[attr-defined] # Py38+
+except ImportError:
+    from typing_extensions import SupportsIndex
 
 LOG = _logging.getLogger("jira")
 LOG.addHandler(_logging.NullHandler())
@@ -162,16 +172,32 @@
         self.isLast = _isLast
         self.total = _total if _total is not None else len(self)
 
-        self.iterable: List = list(iterable) if iterable else []
+        self.iterable: List[ResourceType] = list(iterable) if iterable else []
         self.current = self.startAt
 
-    def __next__(self) -> Type[ResourceType]:
+    def __next__(self) -> ResourceType:  # type:ignore[misc]
         self.current += 1
         if self.current > self.total:
             raise StopIteration
         else:
             return self.iterable[self.current - 1]
 
+    def __iter__(self) -> Iterator[ResourceType]:
+        return super().__iter__()
+
+    # fmt: off
+    # The mypy error we ignore is about returning a contravariant type.
+    # As this class is a List of a generic 'Resource' class
+    # this is the right way to specify that the output is the same as which
+    # the class was initialized with.
+    @overload
+    def __getitem__(self, i: SupportsIndex) -> ResourceType: ...  # 
type:ignore[misc]  # noqa: E704
+    @overload
+    def __getitem__(self, s: slice) -> List[ResourceType]: ...  # 
type:ignore[misc]  # noqa: E704
+    def __getitem__(self, slice_or_index): # noqa: E301,E261
+        return list.__getitem__(self, slice_or_index)
+    # fmt: on
+
 
 class QshGenerator:
     def __init__(self, context_path):
@@ -449,7 +475,7 @@
         """
         # force a copy of the tuple to be used in __del__() because
         # sys.version_info could have already been deleted in __del__()
-        self.sys_version_info = tuple(i for i in sys.version_info)
+        self.sys_version_info = tuple(sys.version_info)
 
         if options is None:
             options = {}
@@ -537,7 +563,7 @@
                 auth_method = (
                     oauth or basic_auth or jwt or kerberos or auth or 
"anonymous"
                 )
-                raise JIRAError(f"Can not log in with {str(auth_method)}")
+                raise JIRAError(f"Can not log in with {auth_method}")
 
         self.deploymentType = None
         if get_server_info:
@@ -641,7 +667,6 @@
         if "<!-- SecurityTokenMissing -->" in content:
             self.log.warning("Got SecurityTokenMissing")
             raise JIRAError(f"SecurityTokenMissing: {content}")
-            return False
         return True
 
     def _get_sprint_field_id(self):
@@ -1435,13 +1460,13 @@
 
         p = data["fields"]["project"]
 
-        if isinstance(p, str) or isinstance(p, int):
+        if isinstance(p, (str, int)):
             data["fields"]["project"] = {"id": self.project(str(p)).id}
 
         p = data["fields"]["issuetype"]
         if isinstance(p, int):
             data["fields"]["issuetype"] = {"id": p}
-        if isinstance(p, str) or isinstance(p, int):
+        if isinstance(p, (str, int)):
             data["fields"]["issuetype"] = {"id": 
self.issue_type_by_name(str(p)).id}
 
         url = self._get_url("issue")
@@ -1478,7 +1503,7 @@
             issue_data: Dict[str, Any] = _field_worker(field_dict)
             p = issue_data["fields"]["project"]
 
-            if isinstance(p, str) or isinstance(p, int):
+            if isinstance(p, (str, int)):
                 issue_data["fields"]["project"] = {"id": 
self.project(str(p)).id}
 
             p = issue_data["fields"]["issuetype"]
@@ -1579,7 +1604,6 @@
         url = self.server_url + "/rest/servicedeskapi/servicedesk"
         headers = {"X-ExperimentalApi": "opt-in"}
         r_json = json_loads(self._session.get(url, headers=headers))
-        print(r_json)
         projects = [
             ServiceDesk(self._options, self._session, raw_project_json)
             for raw_project_json in r_json["values"]
@@ -1628,7 +1652,7 @@
         p = data["serviceDeskId"]
         service_desk = None
 
-        if isinstance(p, str) or isinstance(p, int):
+        if isinstance(p, (str, int)):
             service_desk = self.service_desk(p)
         elif isinstance(p, ServiceDesk):
             service_desk = p
@@ -1736,9 +1760,15 @@
         try:
             user_obj: User
             if self._is_cloud:
-                user_obj = self.search_users(query=user, maxResults=1)[0]
+                users = self.search_users(query=user, maxResults=20)
             else:
-                user_obj = self.search_users(user=user, maxResults=1)[0]
+                users = self.search_users(user=user, maxResults=20)
+
+            matches = []
+            if len(users) > 1:
+                matches = [u for u in users if self._get_user_identifier(u) == 
user]
+            user_obj = matches[0] if matches else users[0]
+
         except Exception as e:
             raise JIRAError(str(e))
         return self._get_user_identifier(user_obj)
@@ -1756,7 +1786,7 @@
         Returns:
             bool
         """
-        url = self._get_latest_url(f"issue/{str(issue)}/assignee")
+        url = self._get_latest_url(f"issue/{issue}/assignee")
         user_id = self._get_user_id(assignee)
         payload = {"accountId": user_id} if self._is_cloud else {"name": 
user_id}
         r = self._session.put(url, data=json.dumps(payload))
@@ -1777,7 +1807,7 @@
         params = {}
         if expand is not None:
             params["expand"] = expand
-        r_json = self._get_json(f"issue/{str(issue)}/comment", params=params)
+        r_json = self._get_json(f"issue/{issue}/comment", params=params)
 
         comments = [
             Comment(self._options, self._session, raw_comment_json)
@@ -2109,6 +2139,32 @@
         return self._find_for_resource(Votes, issue)
 
     @translate_resource_args
+    def project_issue_security_level_scheme(
+        self, project: str
+    ) -> IssueSecurityLevelScheme:
+        """Get a IssueSecurityLevelScheme Resource from the server.
+
+        Args:
+            project (str): ID or key of the project to get the 
IssueSecurityLevelScheme for
+
+        Returns:
+            IssueSecurityLevelScheme: The issue security level scheme
+        """
+        return self._find_for_resource(IssueSecurityLevelScheme, project)
+
+    @translate_resource_args
+    def project_notification_scheme(self, project: str) -> NotificationScheme:
+        """Get a NotificationScheme Resource from the server.
+
+        Args:
+            project (str): ID or key of the project to get the 
NotificationScheme for
+
+        Returns:
+            NotificationScheme: The notification scheme
+        """
+        return self._find_for_resource(NotificationScheme, project)
+
+    @translate_resource_args
     def project_permissionscheme(self, project: str) -> PermissionScheme:
         """Get a PermissionScheme Resource from the server.
 
@@ -2122,6 +2178,30 @@
         return self._find_for_resource(PermissionScheme, project)
 
     @translate_resource_args
+    def project_priority_scheme(self, project: str) -> PriorityScheme:
+        """Get a PriorityScheme Resource from the server.
+
+        Args:
+            project (str): ID or key of the project to get the PriorityScheme 
for
+
+        Returns:
+            PriorityScheme: The priority scheme
+        """
+        return self._find_for_resource(PriorityScheme, project)
+
+    @translate_resource_args
+    def project_workflow_scheme(self, project: str) -> WorkflowScheme:
+        """Get a WorkflowScheme Resource from the server.
+
+        Args:
+            project (str): ID or key of the project to get the WorkflowScheme 
for
+
+        Returns:
+            WorkflowScheme: The workflow scheme
+        """
+        return self._find_for_resource(WorkflowScheme, project)
+
+    @translate_resource_args
     def add_vote(self, issue: str) -> Response:
         """Register a vote for the current authenticated user on an issue.
 
@@ -3608,15 +3688,14 @@
         """
         if self._magic is not None:
             return self._magic.id_buffer(buff)
-        else:
-            try:
-                return mimetypes.guess_type("f." + str(imghdr.what(0, 
buff)))[0]
-            except (OSError, TypeError):
-                self.log.warning(
-                    "Couldn't detect content type of avatar image"
-                    ". Specify the 'contentType' parameter explicitly."
-                )
-                return None
+        try:
+            return mimetypes.guess_type("f." + str(imghdr.what(0, buff)))[0]
+        except (OSError, TypeError):
+            self.log.warning(
+                "Couldn't detect content type of avatar image"
+                ". Specify the 'contentType' parameter explicitly."
+            )
+            return None
 
     def rename_user(self, old_user: str, new_user: str):
         """Rename a Jira user.
@@ -3657,9 +3736,8 @@
         r = self._session.delete(url)
         if 200 <= r.status_code <= 299:
             return True
-        else:
-            self.log.error(r.status_code)
-            return False
+        self.log.error(r.status_code)
+        return False
 
     def deactivate_user(self, username: str) -> Union[str, int]:
         """Disable/deactivate the user.
@@ -3697,11 +3775,10 @@
                 )
                 if r.status_code == 200:
                     return True
-                else:
-                    self.log.warning(
-                        f"Got response from deactivating {username}: 
{r.status_code}"
-                    )
-                    return r.status_code
+                self.log.warning(
+                    f"Got response from deactivating {username}: 
{r.status_code}"
+                )
+                return r.status_code
             except Exception as e:
                 self.log.error(f"Error Deactivating {username}: {e}")
                 raise JIRAError(f"Error Deactivating {username}: {e}")
@@ -3725,11 +3802,10 @@
                 )
                 if r.status_code == 200:
                     return True
-                else:
-                    self.log.warning(
-                        f"Got response from deactivating {username}: 
{r.status_code}"
-                    )
-                    return r.status_code
+                self.log.warning(
+                    f"Got response from deactivating {username}: 
{r.status_code}"
+                )
+                return r.status_code
             except Exception as e:
                 self.log.error(f"Error Deactivating {username}: {e}")
                 raise JIRAError(f"Error Deactivating {username}: {e}")
@@ -3748,11 +3824,7 @@
         """
         # /secure/admin/IndexAdmin.jspa
         # /secure/admin/jira/IndexProgress.jspa?taskId=1
-        if background:
-            indexingStrategy = "background"
-        else:
-            indexingStrategy = "stoptheworld"
-
+        indexingStrategy = "background" if background else "stoptheworld"
         url = self.server_url + "/secure/admin/jira/IndexReIndex.jspa"
 
         r = self._session.get(url, headers=self._options["headers"])
@@ -3762,7 +3834,7 @@
 
         if (
             not r.text.find("To perform the re-index now, please go to the")
-            and force is False
+            and not force
         ):
             return True
 
@@ -3796,9 +3868,8 @@
             r = self._session.post(url, headers=self._options["headers"], 
data=payload)
             if r.status_code == 200:
                 return True
-            else:
-                self.log.warning(f"Got {r.status_code} response from calling 
backup.")
-                return r.status_code
+            self.log.warning(f"Got {r.status_code} response from calling 
backup.")
+            return r.status_code
         except Exception as e:
             self.log.error("I see %s", e)
 
@@ -3974,6 +4045,21 @@
         return data["permissionSchemes"]
 
     @lru_cache(maxsize=None)
+    def issue_type_schemes(self) -> List[IssueTypeScheme]:
+        """Get all issue type schemes defined (Admin required).
+
+        Returns:
+            List[IssueTypeScheme]: All the Issue Type Schemes available to the 
currently logged in user.
+        """
+
+        url = self._get_url("issuetypescheme")
+
+        r = self._session.get(url)
+        data: Dict[str, Any] = json_loads(r)
+
+        return data["schemes"]
+
+    @lru_cache(maxsize=None)
     def issuesecurityschemes(self):
 
         url = self._get_url("issuesecurityschemes")
@@ -4059,6 +4145,20 @@
         self.permissionschemes.cache_clear()
         return data
 
+    def get_issue_type_scheme_associations(self, id: str) -> List[Project]:
+        """For the specified issue type scheme, returns all of the associated 
projects. (Admin required)
+
+        Args:
+            id (str): The issue type scheme id.
+
+        Returns:
+            List[Project]: Associated Projects for the Issue Type Scheme.
+        """
+        url = self._get_url(f"issuetypescheme/{id}/associations")
+        r = self._session.get(url)
+        data = json_loads(r)
+        return data
+
     def create_project(
         self,
         key: str,
@@ -4837,11 +4937,11 @@
                 )
             raise
 
-    def move_to_backlog(self, issue_keys: str) -> Response:
+    def move_to_backlog(self, issue_keys: List[str]) -> Response:
         """Move issues in ``issue_keys`` to the backlog, removing them from 
all sprints that have not been completed.
 
         Args:
-            issue_keys (str): the issues to move to the backlog
+            issue_keys (List[str]): the issues to move to the backlog
 
         Raises:
             JIRAError: If moving issues to backlog fails
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jira-3.1.1/jira/config.py 
new/jira-3.2.0/jira/config.py
--- old/jira-3.1.1/jira/config.py       2021-11-11 11:47:14.000000000 +0100
+++ new/jira-3.2.0/jira/config.py       2022-04-14 01:40:59.000000000 +0200
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
 """
 This module allows people to keep their jira server credentials outside their 
script, in a configuration file that is not saved in the source control.
 
@@ -9,7 +8,7 @@
 import logging
 import os
 import sys
-from typing import Optional
+from typing import Optional, Union
 
 from jira.client import JIRA
 
@@ -21,7 +20,7 @@
     password: str = "admin",
     appid=None,
     autofix=False,
-    verify: bool = True,
+    verify: Union[bool, str] = True,
 ):
     """Return a JIRA object by loading the connection details from the 
`config.ini` file.
 
@@ -32,7 +31,9 @@
         password (str): password to use for authentication
         appid: appid
         autofix: autofix
-        verify (bool): boolean indicating whether SSL certificates should be 
verified
+        verify (Union[bool, str]): boolean indicating whether SSL certificates 
should be
+            verified, or path to a CA_BUNDLE file or directory with 
certificates of
+            trusted CAs.
 
     Returns:
         JIRA: an instance to a JIRA object.
@@ -73,13 +74,18 @@
                 return possible
         return None
 
+    if isinstance(verify, bool):
+        verify = "yes" if verify else "no"
+    else:
+        verify = verify
+
     config = configparser.ConfigParser(
         defaults={
             "user": None,
             "pass": None,
             "appid": appid,
             "autofix": autofix,
-            "verify": "yes" if verify else "no",
+            "verify": verify,
         },
         allow_no_value=True,
     )
@@ -104,8 +110,10 @@
             password = config.get(profile, "pass")
             appid = config.get(profile, "appid")
             autofix = config.get(profile, "autofix")
-            verify = config.getboolean(profile, "verify")
-
+            try:
+                verify = config.getboolean(profile, "verify")
+            except ValueError:
+                verify = config.get(profile, "verify")
         else:
             raise OSError(
                 "%s was not able to locate the config.ini file in current 
directory, user home directory or PYTHONPATH."
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jira-3.1.1/jira/jirashell.py 
new/jira-3.2.0/jira/jirashell.py
--- old/jira-3.1.1/jira/jirashell.py    2021-11-11 11:47:14.000000000 +0100
+++ new/jira-3.2.0/jira/jirashell.py    2022-04-14 01:40:59.000000000 +0200
@@ -1,5 +1,3 @@
-#!/usr/bin/env python
-
 """Starts an interactive Jira session in an ipython terminal.
 
 Script arguments support changing the server and a persistent authentication
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jira-3.1.1/jira/resilientsession.py 
new/jira-3.2.0/jira/resilientsession.py
--- old/jira-3.1.1/jira/resilientsession.py     2021-11-11 11:47:14.000000000 
+0100
+++ new/jira-3.2.0/jira/resilientsession.py     2022-04-14 01:40:59.000000000 
+0200
@@ -129,7 +129,7 @@
                 msg = "Atlassian's bug 
https://jira.atlassian.com/browse/JRA-41559";
 
         # Exponential backoff with full jitter.
-        delay = min(self.max_retry_delay, 10 * 2 ** counter) * random.random()
+        delay = min(self.max_retry_delay, 10 * 2**counter) * random.random()
         logging.warning(
             "Got recoverable error from %s %s, will retry [%s/%s] in %ss. Err: 
%s"
             % (request, url, counter, self.max_retries, delay, msg)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jira-3.1.1/jira/resources.py 
new/jira-3.2.0/jira/resources.py
--- old/jira-3.1.1/jira/resources.py    2021-11-11 11:47:14.000000000 +0100
+++ new/jira-3.2.0/jira/resources.py    2022-04-14 01:40:59.000000000 +0200
@@ -42,9 +42,14 @@
     "Worklog",
     "IssueLink",
     "IssueLinkType",
+    "IssueSecurityLevelScheme",
     "IssueType",
+    "IssueTypeScheme",
+    "NotificationScheme",
     "Priority",
+    "PriorityScheme",
     "Version",
+    "WorkflowScheme",
     "Role",
     "Resolution",
     "SecurityLevel",
@@ -693,6 +698,27 @@
 
         super().update(async_=async_, jira=jira, notify=notify, fields=data)
 
+    def get_field(self, field_name: str) -> Any:
+        """Obtain the (parsed) value from the Issue's field.
+
+        Args:
+            field_name (str): The name of the field to get
+
+        Raises:
+            AttributeError: If the field does not exist or if the field starts 
with an ``_``
+
+        Returns:
+            Any: Returns the parsed data stored in the field. For example, 
"project" would be of class :py:class:`Project`
+        """
+
+        if field_name.startswith("_"):
+            raise AttributeError(
+                f"An issue field_name cannot start with underscore (_): 
{field_name}",
+                field_name,
+            )
+        else:
+            return getattr(self.fields, field_name)
+
     def add_field_value(self, field: str, value: str):
         """Add a value to a field that supports multiple values, without 
resetting the existing values.
 
@@ -799,6 +825,40 @@
         self.raw: Dict[str, Any] = cast(Dict[str, Any], self.raw)
 
 
+class IssueTypeScheme(Resource):
+    """An issue type scheme."""
+
+    def __init__(self, options, session, raw=None):
+        Resource.__init__(self, "issuetypescheme", options, session)
+        if raw:
+            self._parse_raw(raw)
+        self.raw: Dict[str, Any] = cast(Dict[str, Any], self.raw)
+
+
+class IssueSecurityLevelScheme(Resource):
+    """IssueSecurityLevelScheme information on an project."""
+
+    def __init__(self, options, session, raw=None):
+        Resource.__init__(
+            self, "project/{0}/issuesecuritylevelscheme?expand=user", options, 
session
+        )
+        if raw:
+            self._parse_raw(raw)
+        self.raw: Dict[str, Any] = cast(Dict[str, Any], self.raw)
+
+
+class NotificationScheme(Resource):
+    """NotificationScheme information on an project."""
+
+    def __init__(self, options, session, raw=None):
+        Resource.__init__(
+            self, "project/{0}/notificationscheme?expand=user", options, 
session
+        )
+        if raw:
+            self._parse_raw(raw)
+        self.raw: Dict[str, Any] = cast(Dict[str, Any], self.raw)
+
+
 class PermissionScheme(Resource):
     """Permissionscheme information on an project."""
 
@@ -811,6 +871,30 @@
         self.raw: Dict[str, Any] = cast(Dict[str, Any], self.raw)
 
 
+class PriorityScheme(Resource):
+    """PriorityScheme information on an project."""
+
+    def __init__(self, options, session, raw=None):
+        Resource.__init__(
+            self, "project/{0}/priorityscheme?expand=user", options, session
+        )
+        if raw:
+            self._parse_raw(raw)
+        self.raw: Dict[str, Any] = cast(Dict[str, Any], self.raw)
+
+
+class WorkflowScheme(Resource):
+    """WorkflowScheme information on an project."""
+
+    def __init__(self, options, session, raw=None):
+        Resource.__init__(
+            self, "project/{0}/workflowscheme?expand=user", options, session
+        )
+        if raw:
+            self._parse_raw(raw)
+        self.raw: Dict[str, Any] = cast(Dict[str, Any], self.raw)
+
+
 class Watchers(Resource):
     """Watcher information on an issue."""
 
@@ -1407,10 +1491,15 @@
     r"issueLink/[^/]+$": IssueLink,
     r"issueLinkType/[^/]+$": IssueLinkType,
     r"issuetype/[^/]+$": IssueType,
+    r"issuetypescheme/[^/]+$": IssueTypeScheme,
+    r"project/[^/]+/issuesecuritylevelscheme[^/]+$": IssueSecurityLevelScheme,
+    r"project/[^/]+/notificationscheme[^/]+$": NotificationScheme,
+    r"project/[^/]+/priorityscheme[^/]+$": PriorityScheme,
     r"priority/[^/]+$": Priority,
     r"project/[^/]+$": Project,
     r"project/[^/]+/role/[^/]+$": Role,
     r"project/[^/]+/permissionscheme[^/]+$": PermissionScheme,
+    r"project/[^/]+/workflowscheme[^/]+$": WorkflowScheme,
     r"resolution/[^/]+$": Resolution,
     r"securitylevel/[^/]+$": SecurityLevel,
     r"status/[^/]+$": Status,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jira-3.1.1/jira.egg-info/PKG-INFO 
new/jira-3.2.0/jira.egg-info/PKG-INFO
--- old/jira-3.1.1/jira.egg-info/PKG-INFO       2021-11-11 11:47:33.000000000 
+0100
+++ new/jira-3.2.0/jira.egg-info/PKG-INFO       2022-04-14 01:41:20.000000000 
+0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: jira
-Version: 3.1.1
+Version: 3.2.0
 Summary: Python library for interacting with JIRA via REST APIs.
 Home-page: https://github.com/pycontribs/jira
 Author: Ben Speakmon
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jira-3.1.1/jira.egg-info/SOURCES.txt 
new/jira-3.2.0/jira.egg-info/SOURCES.txt
--- old/jira-3.1.1/jira.egg-info/SOURCES.txt    2021-11-11 11:47:33.000000000 
+0100
+++ new/jira-3.2.0/jira.egg-info/SOURCES.txt    2022-04-14 01:41:21.000000000 
+0200
@@ -37,9 +37,8 @@
 docs/_static/css/custom_width.css
 docs/extra/jira.xml
 docs/templates/.placeholder
-examples/basic_auth.py
+examples/auth.py
 examples/basic_use.py
-examples/cookie_auth.py
 examples/greenhopper.py
 examples/maintenance.py
 jira/__init__.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jira-3.1.1/jira.egg-info/entry_points.txt 
new/jira-3.2.0/jira.egg-info/entry_points.txt
--- old/jira-3.1.1/jira.egg-info/entry_points.txt       2021-11-11 
11:47:33.000000000 +0100
+++ new/jira-3.2.0/jira.egg-info/entry_points.txt       2022-04-14 
01:41:21.000000000 +0200
@@ -1,3 +1,2 @@
 [console_scripts]
 jirashell = jira.jirashell:main
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jira-3.1.1/jira.egg-info/requires.txt 
new/jira-3.2.0/jira.egg-info/requires.txt
--- old/jira-3.1.1/jira.egg-info/requires.txt   2021-11-11 11:47:33.000000000 
+0100
+++ new/jira-3.2.0/jira.egg-info/requires.txt   2022-04-14 01:41:21.000000000 
+0200
@@ -3,7 +3,7 @@
 requests-oauthlib>=1.1.0
 requests>=2.10.0
 requests_toolbelt
-setuptools>=20.10.1
+typing_extensions>=3.7.4.2
 
 [async]
 requests-futures>=0.9.7
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/jira-3.1.1/setup.cfg new/jira-3.2.0/setup.cfg
--- old/jira-3.1.1/setup.cfg    2021-11-11 11:47:33.324146500 +0100
+++ new/jira-3.2.0/setup.cfg    2022-04-14 01:41:21.476967000 +0200
@@ -55,7 +55,7 @@
        requests-oauthlib>=1.1.0
        requests>=2.10.0
        requests_toolbelt
-       setuptools>=20.10.1
+       typing_extensions>=3.7.4.2
 
 [options.extras_require]
 cli = 

Reply via email to