Hello community,

here is the log from the commit of package python-bugzilla for openSUSE:Factory 
checked in at 2019-09-18 13:10:18
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-bugzilla (Old)
 and      /work/SRC/openSUSE:Factory/.python-bugzilla.new.7948 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-bugzilla"

Wed Sep 18 13:10:18 2019 rev:27 rq:731151 version:2.3.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-bugzilla/python-bugzilla.changes  
2018-08-24 17:11:59.790634417 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-bugzilla.new.7948/python-bugzilla.changes    
    2019-09-18 13:10:42.404699152 +0200
@@ -1,0 +2,9 @@
+Sun Sep 15 13:41:23 UTC 2019 - John Vandenberg <jay...@gmail.com>
+
+- Update to v2.3.0
+  * restrict-login support
+  * cli: Add support for private attachments
+  * Fix python3 deprecation warnings
+  * Drop python 3.3 support, minimum python3 is python 3.4 now
+
+-------------------------------------------------------------------

Old:
----
  python-bugzilla-2.2.0.tar.gz

New:
----
  python-bugzilla-2.3.0.tar.gz

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

Other differences:
------------------
++++++ python-bugzilla.spec ++++++
--- /var/tmp/diff_new_pack.EXSbbO/_old  2019-09-18 13:10:42.976699032 +0200
+++ /var/tmp/diff_new_pack.EXSbbO/_new  2019-09-18 13:10:42.980699031 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package python-bugzilla
 #
-# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -12,14 +12,14 @@
 # license that conforms to the Open Source Definition (Version 1.9)
 # published by the Open Source Initiative.
 
-# Please submit bugfixes or comments via http://bugs.opensuse.org/
+# Please submit bugfixes or comments via https://bugs.opensuse.org/
 #
 
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 %define oldpython python
 Name:           python-bugzilla
-Version:        2.2.0
+Version:        2.3.0
 Release:        0
 Summary:        Python library for Bugzilla
 License:        GPL-2.0-or-later
@@ -75,6 +75,6 @@
 %python_alternative %{_bindir}/bugzilla
 %python_alternative %{_mandir}/man1/bugzilla.1%{ext_man}
 %{python_sitelib}/bugzilla
-%{python_sitelib}/python_bugzilla-%{version}-py%{py_ver}.egg-info
+%{python_sitelib}/python_bugzilla-%{version}-py*.egg-info
 
 %changelog

++++++ python-bugzilla-2.2.0.tar.gz -> python-bugzilla-2.3.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-bugzilla-2.2.0/NEWS.md 
new/python-bugzilla-2.3.0/NEWS.md
--- old/python-bugzilla-2.2.0/NEWS.md   2018-08-11 16:12:39.000000000 +0200
+++ new/python-bugzilla-2.3.0/NEWS.md   2019-08-26 23:31:03.000000000 +0200
@@ -1,5 +1,11 @@
 # python-bugzilla release news
 
+## Release 2.3.0 (August 26, 2019)
+- restrict-login suppot (Viliam Krizan)
+- cli: Add support for private attachments (Brian 'Redbeard' Harrington)
+- Fix python3 deprecation warnings
+- Drop python 3.3 support, minimum python3 is python 3.4 now
+
 ## Release 2.2.0 (August 11, 2018)
 - Port tests to pytest
 - cli: --cert Client side certificate support (Tobias Wolter)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-bugzilla-2.2.0/PKG-INFO 
new/python-bugzilla-2.3.0/PKG-INFO
--- old/python-bugzilla-2.2.0/PKG-INFO  2018-08-11 16:12:57.000000000 +0200
+++ new/python-bugzilla-2.3.0/PKG-INFO  2019-08-26 23:31:57.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: python-bugzilla
-Version: 2.2.0
+Version: 2.3.0
 Summary: Bugzilla XMLRPC access module
 Home-page: https://github.com/python-bugzilla/python-bugzilla
 Author: Cole Robinson
@@ -16,7 +16,7 @@
 Classifier: Programming Language :: Python :: 2
 Classifier: Programming Language :: Python :: 2.7
 Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.3
 Classifier: Programming Language :: Python :: 3.4
 Classifier: Programming Language :: Python :: 3.5
 Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-bugzilla-2.2.0/bugzilla/_cli.py 
new/python-bugzilla-2.3.0/bugzilla/_cli.py
--- old/python-bugzilla-2.2.0/bugzilla/_cli.py  2018-08-11 15:13:09.000000000 
+0200
+++ new/python-bugzilla-2.3.0/bugzilla/_cli.py  2019-08-20 19:20:32.000000000 
+0200
@@ -14,6 +14,7 @@
 
 from __future__ import print_function
 
+import errno
 import locale
 from logging import getLogger, DEBUG, INFO, WARN, StreamHandler, Formatter
 import argparse
@@ -85,7 +86,7 @@
         try:
             fd = os.open(name, os.O_CREAT | os.O_EXCL, 0o666)
         except OSError as err:
-            if err.errno == os.errno.EEXIST:
+            if err.errno == errno.EEXIST:
                 name = "%s.%i" % (orig_name, count)
                 count += 1
             else:
@@ -152,6 +153,9 @@
              'specified command.')
     p.add_argument('--username', help="Log in with this username")
     p.add_argument('--password', help="Log in with this password")
+    p.add_argument('--restrict-login', action="store_true",
+                   help="The session (login token) will be restricted to "
+                        "the current IP address.")
 
     p.add_argument('--ensure-logged-in', action="store_true",
         help="Raise an error if we aren't logged in to bugzilla. "
@@ -277,7 +281,7 @@
     p.add_argument('--field',
         metavar="FIELD=VALUE", action="append", dest="fields",
         help="Manually specify a bugzilla XMLRPC field. FIELD is "
-        "the raw name used by the bugzilla instance. For example if your "
+        "the raw name used by the bugzilla instance. For example, if your "
         "bugzilla instance has a custom field cf_my_field, do:\n"
         "  --field cf_my_field=VALUE")
 
@@ -418,11 +422,16 @@
             default=[], help="Download all attachments on the given bug")
     p.add_argument('-l', '--comment', '--long_desc',
             help="Add comment with attachment")
+    p.add_argument('--private', action='store_true', default=False,
+        help='Mark new comment as private')
 
 
 def _setup_action_login_parser(subparsers):
     usage = 'bugzilla login [username [password]]'
-    description = "Log into bugzilla and save a login cookie or token."
+    description = """Log into bugzilla and save a login cookie or token.
+Note: These tokens are short-lived, and future Bugzilla versions will no
+longer support token authentication at all. Please use a
+~/.config/python-bugzilla/bugzillarc file with an API key instead."""
     p = subparsers.add_parser("login", description=description, usage=usage)
     p.add_argument("pos_username", nargs="?", help="Optional username",
             metavar="username")
@@ -702,7 +711,7 @@
         if fieldname == "flag" and rest:
             val = b.get_flag_status(rest)
 
-        elif fieldname == "flags" or fieldname == "flags_requestee":
+        elif fieldname in ["flags", "flags_requestee"]:
             tmpstr = []
             for f in getattr(b, "flags", []):
                 requestee = f.get('requestee', "")
@@ -976,8 +985,6 @@
             data = att.read(4096)
         print("Wrote %s" % outfile.name)
 
-    return
-
 
 def _do_set_attach(bz, opt, parser):
     if not opt.ids:
@@ -1010,6 +1017,8 @@
         kwargs["ispatch"] = True
     if opt.comment:
         kwargs["comment"] = opt.comment
+    if opt.private:
+        kwargs["is_private"] = True
     desc = opt.desc or os.path.basename(fileobj.name)
 
     # Upload attachments
@@ -1031,15 +1040,18 @@
 
     cookiefile = None
     tokenfile = None
+    use_creds = False
     if opt.cache_credentials:
         cookiefile = opt.cookiefile or -1
         tokenfile = opt.tokenfile or -1
+        use_creds = True
 
     bz = bugzilla.Bugzilla(
         url=opt.bugzilla,
         cookiefile=cookiefile,
         tokenfile=tokenfile,
         sslverify=opt.sslverify,
+        use_creds=use_creds,
         cert=opt.cert)
     return bz
 
@@ -1059,7 +1071,8 @@
         if do_interactive_login:
             if bz.url:
                 print("Logging into %s" % urlparse(bz.url)[1])
-            bz.interactive_login(username, password)
+            bz.interactive_login(username, password,
+                    restrict_login=opt.restrict_login)
     except bugzilla.BugzillaError as e:
         print(str(e))
         sys.exit(1)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-bugzilla-2.2.0/bugzilla/apiversion.py 
new/python-bugzilla-2.3.0/bugzilla/apiversion.py
--- old/python-bugzilla-2.2.0/bugzilla/apiversion.py    2018-08-11 
16:12:39.000000000 +0200
+++ new/python-bugzilla-2.3.0/bugzilla/apiversion.py    2019-08-26 
23:31:03.000000000 +0200
@@ -7,5 +7,5 @@
 # option) any later version.  See http://www.gnu.org/copyleft/gpl.html for
 # the full text of the license.
 
-version = "2.2.0"
+version = "2.3.0"
 __version__ = version
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-bugzilla-2.2.0/bugzilla/base.py 
new/python-bugzilla-2.3.0/bugzilla/base.py
--- old/python-bugzilla-2.2.0/bugzilla/base.py  2018-08-11 15:13:16.000000000 
+0200
+++ new/python-bugzilla-2.3.0/bugzilla/base.py  2019-08-23 01:07:00.000000000 
+0200
@@ -9,10 +9,10 @@
 # option) any later version.  See http://www.gnu.org/copyleft/gpl.html for
 # the full text of the license.
 
-import collections
 import getpass
 import locale
 from logging import getLogger
+import mimetypes
 import os
 import sys
 
@@ -21,12 +21,14 @@
 # pylint: disable=import-error
 if sys.version_info[0] >= 3:
     # pylint: disable=no-name-in-module
-    from configparser import SafeConfigParser
+    from collections.abc import Mapping
+    from configparser import ConfigParser
     from http.cookiejar import LoadError, MozillaCookieJar
     from urllib.parse import urlparse, parse_qsl
     from xmlrpc.client import Binary, Fault
 else:
-    from ConfigParser import SafeConfigParser
+    from collections import Mapping
+    from ConfigParser import SafeConfigParser as ConfigParser
     from cookielib import LoadError, MozillaCookieJar
     from urlparse import urlparse, parse_qsl
     from xmlrpclib import Binary, Fault
@@ -40,39 +42,11 @@
 
 log = getLogger(__name__)
 
-mimemagic = None
-
-
-def _detect_filetype(fname):
-    global mimemagic
-
-    if mimemagic is None:
-        try:
-            # pylint: disable=import-error
-            import magic
-            mimemagic = magic.open(getattr(magic, "MAGIC_MIME_TYPE", 16))
-            mimemagic.load()
-        except ImportError as e:
-            log.debug("Could not load python-magic: %s", e)
-            mimemagic = None
-    if not mimemagic:
-        return None
-
-    if not os.path.isabs(fname):
-        return None
-
-    try:
-        return mimemagic.file(fname)
-    except Exception as e:
-        log.debug("Could not detect content_type: %s", e)
-    return None
-
 
 def _nested_update(d, u):
     # Helper for nested dict update()
-    # 
https://stackoverflow.com/questions/3232943/update-value-of-a-nested-dictionary-of-varying-depth
     for k, v in list(u.items()):
-        if isinstance(v, collections.Mapping):
+        if isinstance(v, Mapping):
             d[k] = _nested_update(d.get(k, {}), v)
         else:
             d[k] = v
@@ -131,7 +105,7 @@
     configpaths = [os.path.expanduser(p) for p in
                    Bugzilla._listify(configpaths)]
     # pylint: enable=protected-access
-    cfg = SafeConfigParser()
+    cfg = ConfigParser()
     read_files = cfg.read(configpaths)
     if not read_files:
         return
@@ -187,7 +161,7 @@
     log in, you can either pass auth options to __init__, or call a login
     helper like interactive_login().
 
-    If you are not logged in, you won be able to access restricted data like
+    If you are not logged in, you won't be able to access restricted data like
     user email, or perform write actions like bug create/update. But simple
     querys will work correctly.
 
@@ -261,7 +235,7 @@
 
     def __init__(self, url=-1, user=None, password=None, cookiefile=-1,
                  sslverify=True, tokenfile=-1, use_creds=True, api_key=None,
-                 cert=None):
+                 cert=None, configpaths=-1):
         """
         :param url: The bugzilla instance URL, which we will connect
             to immediately. Most users will want to specify this at
@@ -288,7 +262,8 @@
         :param sslverify: Maps to 'requests' sslverify parameter. Set to
             False to disable SSL verification, but it can also be a path
             to file or directory for custom certs.
-        :param api_key: A bugzilla
+        :param api_key: A bugzilla5+ API key
+        :param configpaths: A list of possible bugzillarc locations.
         """
         if url == -1:
             raise TypeError("Specify a valid bugzilla url, or pass url=None")
@@ -310,19 +285,22 @@
         self._field_aliases = []
         self._init_field_aliases()
 
-        self.configpath = _default_configpaths[:]
         if not use_creds:
             cookiefile = None
             tokenfile = None
-            self.configpath = []
+            configpaths = []
 
         if cookiefile == -1:
             cookiefile = _default_auth_location("bugzillacookies")
         if tokenfile == -1:
             tokenfile = _default_auth_location("bugzillatoken")
+        if configpaths == -1:
+            configpaths = _default_configpaths[:]
+
         log.debug("Using tokenfile=%s", tokenfile)
         self.cookiefile = cookiefile
         self.tokenfile = tokenfile
+        self.configpath = configpaths
 
         if url:
             self.connect(url)
@@ -485,11 +463,25 @@
         section = ""
         log.debug("bugzillarc: Searching for config section matching %s",
             self.url)
-        for s in sorted(cfg.sections()):
-            # Substring match - prefer the longest match found
-            if s in self.url:
-                log.debug("bugzillarc: Found matching section: %s", s)
-                section = s
+
+        def _parse_hostname(_u):
+            # If http://example.com is passed, netloc=example.com path=""
+            # If just example.com is passed, netloc="" path=example.com
+            parsedbits = urlparse(self.url)
+            return parsedbits.netloc or parsedbits.path
+
+        urlhost = _parse_hostname(self.url)
+        for sectionhost in sorted(cfg.sections()):
+            # If the section is just a hostname, make it match
+            # If the section has a / in it, do a substring match
+            if "/" not in sectionhost:
+                if sectionhost == urlhost:
+                    section = sectionhost
+            elif sectionhost in self.url:
+                section = sectionhost
+            if section:
+                log.debug("bugzillarc: Found matching section: %s", section)
+                break
 
         if not section:
             log.debug("bugzillarc: No section found")
@@ -570,12 +562,15 @@
         self._transport = None
         self._cache = _BugzillaAPICache()
 
-
-    def _login(self, user, password):
+    def _login(self, user, password, restrict_login=None):
         """
         Backend login method for Bugzilla3
         """
-        return self._proxy.User.login({'login': user, 'password': password})
+        payload = {'login': user, 'password': password}
+        if restrict_login:
+            payload['restrict_login'] = True
+
+        return self._proxy.User.login(payload)
 
     def _logout(self):
         """
@@ -583,7 +578,7 @@
         """
         return self._proxy.User.logout()
 
-    def login(self, user=None, password=None):
+    def login(self, user=None, password=None, restrict_login=None):
         """
         Attempt to log in using the given username and password. Subsequent
         method calls will use this username and password. Returns False if
@@ -594,6 +589,9 @@
         is not set, ValueError will be raised. If login fails, BugzillaError
         will be raised.
 
+        The login session can be restricted to current user IP address
+        with restrict_login argument. (Bugzilla 4.4+)
+
         This method will be called implicitly at the end of connect() if user
         and password are both set. So under most circumstances you won't need
         to call this yourself.
@@ -611,21 +609,26 @@
         if not self.password:
             raise ValueError("missing password")
 
+        if restrict_login:
+            log.info("logging in with restrict_login=True")
+
         try:
-            ret = self._login(self.user, self.password)
+            ret = self._login(self.user, self.password, restrict_login)
             self.password = ''
             log.info("login successful for user=%s", self.user)
             return ret
         except Fault as e:
             raise BugzillaError("Login failed: %s" % str(e.faultString))
 
-    def interactive_login(self, user=None, password=None, force=False):
+    def interactive_login(self, user=None, password=None, force=False,
+                          restrict_login=None):
         """
         Helper method to handle login for this bugzilla instance.
 
         :param user: bugzilla username. If not specified, prompt for it.
         :param password: bugzilla password. If not specified, prompt for it.
         :param force: Unused
+        :param restrict_login: restricts session to IP address
         """
         ignore = force
         log.debug('Calling interactive_login')
@@ -638,7 +641,7 @@
             password = getpass.getpass('Bugzilla Password: ')
 
         log.info('Logging in... ')
-        self.login(user, password)
+        self.login(user, password, restrict_login)
         log.info('Authorization cookie received.')
 
     def logout(self):
@@ -876,8 +879,10 @@
             product_id is None or
             product_id not in self._cache.component_names):
             self.refresh_products(names=[product],
-                                  include_fields=["names", "id"])
+                                  include_fields=["name", "id"])
             proddict = self._lookup_product_in_cache(product)
+            if "id" not in proddict:
+                raise BugzillaError("Product '%s' not found" % product)
             product_id = proddict["id"]
 
             opts = {'product_id': product_id, 'field': 'component'}
@@ -920,7 +925,7 @@
 
         product: The product to create the component in
         component: The name of the component to create
-        desription: A one sentence summary of the component
+        description: A one sentence summary of the component
         default_assignee: The bugzilla login (email address) of the initial
                           owner of the component
         default_qa_contact (optional): The bugzilla login of the
@@ -1042,7 +1047,7 @@
             else:
                 # Need to map an alias
                 for valdict in bugdict.values():
-                    if i in self._listify(valdict.get("alias", None)):
+                    if i in self._listify(valdict.get("alias", None) or []):
                         found = valdict
                         break
 
@@ -1144,7 +1149,7 @@
         Build a query string from passed arguments. Will handle
         query parameter differences between various bugzilla versions.
 
-        Most of the parameters should be self explanatory. However
+        Most of the parameters should be self-explanatory. However,
         if you want to perform a complex query, and easy way is to
         create it with the bugzilla web UI, copy the entire URL it
         generates, and pass it to the static method
@@ -1556,10 +1561,11 @@
         if 'file_name' not in kwargs and hasattr(f, "name"):
             kwargs['file_name'] = os.path.basename(f.name)
         if 'content_type' not in kwargs:
-            ctype = _detect_filetype(getattr(f, "name", None))
-            if not ctype:
-                ctype = 'application/octet-stream'
-            kwargs['content_type'] = ctype
+            ctype = None
+            if kwargs['file_name']:
+                ctype = mimetypes.guess_type(
+                    kwargs['file_name'], strict=False)[0]
+            kwargs['content_type'] = ctype or 'application/octet-stream'
 
         ret = self._proxy.Bug.add_attachment(kwargs)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-bugzilla-2.2.0/bugzilla/oldclasses.py 
new/python-bugzilla-2.3.0/bugzilla/oldclasses.py
--- old/python-bugzilla-2.2.0/bugzilla/oldclasses.py    2018-08-10 
22:32:30.000000000 +0200
+++ new/python-bugzilla-2.3.0/bugzilla/oldclasses.py    2019-01-27 
00:26:40.000000000 +0100
@@ -7,17 +7,45 @@
 from .base import Bugzilla
 from .rhbugzilla import RHBugzilla
 
-
 # These are old compat classes. Nothing new should be added here,
 # and these should not be altered
 
-class Bugzilla3(Bugzilla): pass
-class Bugzilla32(Bugzilla): pass
-class Bugzilla34(Bugzilla): pass
-class Bugzilla36(Bugzilla): pass
-class Bugzilla4(Bugzilla): pass
-class Bugzilla42(Bugzilla): pass
-class Bugzilla44(Bugzilla): pass
-class NovellBugzilla(Bugzilla): pass
-class RHBugzilla3(RHBugzilla): pass
-class RHBugzilla4(RHBugzilla): pass
+
+class Bugzilla3(Bugzilla):
+    pass
+
+
+class Bugzilla32(Bugzilla):
+    pass
+
+
+class Bugzilla34(Bugzilla):
+    pass
+
+
+class Bugzilla36(Bugzilla):
+    pass
+
+
+class Bugzilla4(Bugzilla):
+    pass
+
+
+class Bugzilla42(Bugzilla):
+    pass
+
+
+class Bugzilla44(Bugzilla):
+    pass
+
+
+class NovellBugzilla(Bugzilla):
+    pass
+
+
+class RHBugzilla3(RHBugzilla):
+    pass
+
+
+class RHBugzilla4(RHBugzilla):
+    pass
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-bugzilla-2.2.0/bugzilla/transport.py 
new/python-bugzilla-2.3.0/bugzilla/transport.py
--- old/python-bugzilla-2.2.0/bugzilla/transport.py     2018-08-11 
15:13:16.000000000 +0200
+++ new/python-bugzilla-2.3.0/bugzilla/transport.py     2019-01-09 
21:17:37.000000000 +0100
@@ -9,11 +9,11 @@
 
 # pylint: disable=import-error
 if sys.version_info[0] >= 3:
-    from configparser import SafeConfigParser
+    from configparser import ConfigParser
     from urllib.parse import urlparse  # pylint: disable=no-name-in-module
     from xmlrpc.client import Fault, ProtocolError, ServerProxy, Transport
 else:
-    from ConfigParser import SafeConfigParser
+    from ConfigParser import SafeConfigParser as ConfigParser
     from urlparse import urlparse
     from xmlrpclib import Fault, ProtocolError, ServerProxy, Transport
 # pylint: enable=import-error
@@ -39,7 +39,7 @@
 
     def __init__(self, uri, tokenfilename):
         self.tokenfilename = tokenfilename
-        self.tokenfile = SafeConfigParser()
+        self.tokenfile = ConfigParser()
         self.domain = urlparse(uri)[1]
 
         if self.tokenfilename:
@@ -159,6 +159,7 @@
         response.
         """
         response = None
+        # pylint: disable=try-except-raise
         try:
             response = self.session.post(
                 url, data=request_body, **self.request_defaults)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-bugzilla-2.2.0/bugzilla.1 
new/python-bugzilla-2.3.0/bugzilla.1
--- old/python-bugzilla-2.2.0/bugzilla.1        2018-04-16 17:32:40.000000000 
+0200
+++ new/python-bugzilla-2.3.0/bugzilla.1        2019-01-27 00:26:40.000000000 
+0100
@@ -40,6 +40,8 @@
 Log in with this username
 .IP "--password=PASSWORD"
 Log in with this password
+.IP "--restrict-login"
+The session (login token) will be restricted to the current IP address.
 .IP "--ensure-logged-in"
 Raise an error if we aren't logged in to bugzilla. Consider using this if you 
are depending on cached credentials, to ensure that when they expire the tool 
errors, rather than subtly change output.
 .IP "--no-cache-credentials"
@@ -223,23 +225,33 @@
 Only show active components. Combine with --components*
 
 
-.SH AUTHENTICATION COOKIES AND TOKENS
+.SH AUTHENTICATION CACHE AND API KEYS
 
-Older bugzilla instances use cookie-based authentication, and
-newer bugzilla instances (around 5.0) use a non-cookie token system.
-
-When you log into bugzilla with the "login" subcommand or the "--login"
-argument, we cache the login credentials in ~/.cache/python-bugzilla/
-Previously we cached credentials in ~/.<filename>. If you want to see
-which file the tool is using, check --debug output.
-
-To perform an authenticated bugzilla command on a new machine, run a one time
-"bugzilla login" to cache credentials before running the desired command. You
-can also run "bugzilla --login" and the login process will be initiated before
-invoking the command.
-
-Additionally, the --no-cache-credentials option will tell the bugzilla tool to
-_not_ save any credentials in $HOME, or use any previously cached credentials.
+Some command usage will require an active login to the bugzilla
+instance. For example, if the bugzilla instance has some private
+bugs, those bugs will be missing from 'query' output if you do
+not have an active login.
+
+If you are connecting to a bugzilla 5.0 or later instance, the
+best option is to use bugzilla API keys. From the bugzilla
+web UI, log in, navigate to Preferences->API Keys, and generate
+a key (it will be a long string of characters and numbers).
+Then create a ~/.config/python-bugzilla/bugzillarc like this:
+
+  $ cat ~/.config/python-bugzilla/bugzillarc
+  [bugzilla.example.com]
+  api_key=YOUR_API_KEY
+
+Replace 'bugzilla.example.com' with your bugzilla host name,
+and YOUR_API_KEY with the generated API Key from the Web UI.
+
+For older bugzilla instances, you will need to cache a login
+cookie or token with the "login" subcommand or the "--login"
+argument.
+
+Additionally, the --no-cache-credentials option will tell the
+bugzilla tool to _not_ save or use any authentication cache,
+including the bugzillarc file.
 
 .SH EXAMPLES
 .PP
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-bugzilla-2.2.0/python-bugzilla.spec 
new/python-bugzilla-2.3.0/python-bugzilla.spec
--- old/python-bugzilla-2.2.0/python-bugzilla.spec      2018-08-11 
16:12:39.000000000 +0200
+++ new/python-bugzilla-2.3.0/python-bugzilla.spec      2019-08-26 
23:31:03.000000000 +0200
@@ -15,7 +15,7 @@
 %endif
 
 Name:           python-bugzilla
-Version:        2.2.0
+Version:        2.3.0
 Release:        1%{?dist}
 Summary:        Python library for interacting with Bugzilla
 
@@ -49,7 +49,6 @@
 %package -n python2-bugzilla
 Summary: %summary
 Requires: python2-requests
-Requires: python2-magic
 # This dep is for back compat, so that installing python-bugzilla continues
 # to give the cli tool
 Requires: python-bugzilla-cli
@@ -64,7 +63,6 @@
 %package -n python3-bugzilla
 Summary: %summary
 Requires: python3-requests
-Requires: python3-magic
 %{?python_provide:%python_provide python3-bugzilla}
 
 %if %{without python2}
@@ -144,7 +142,8 @@
 
 %check
 %if %{with python2}
-pytest
+# py.test naming is needed for RHEL7 compat, works fine with Fedora
+py.test
 %endif # with python2
 %if %{with python3}
 pytest-3
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-bugzilla-2.2.0/python_bugzilla.egg-info/PKG-INFO 
new/python-bugzilla-2.3.0/python_bugzilla.egg-info/PKG-INFO
--- old/python-bugzilla-2.2.0/python_bugzilla.egg-info/PKG-INFO 2018-08-11 
16:12:57.000000000 +0200
+++ new/python-bugzilla-2.3.0/python_bugzilla.egg-info/PKG-INFO 2019-08-26 
23:31:57.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: python-bugzilla
-Version: 2.2.0
+Version: 2.3.0
 Summary: Bugzilla XMLRPC access module
 Home-page: https://github.com/python-bugzilla/python-bugzilla
 Author: Cole Robinson
@@ -16,7 +16,7 @@
 Classifier: Programming Language :: Python :: 2
 Classifier: Programming Language :: Python :: 2.7
 Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.3
 Classifier: Programming Language :: Python :: 3.4
 Classifier: Programming Language :: Python :: 3.5
 Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/python-bugzilla-2.2.0/python_bugzilla.egg-info/SOURCES.txt 
new/python-bugzilla-2.3.0/python_bugzilla.egg-info/SOURCES.txt
--- old/python-bugzilla-2.2.0/python_bugzilla.egg-info/SOURCES.txt      
2018-08-11 16:12:57.000000000 +0200
+++ new/python-bugzilla-2.3.0/python_bugzilla.egg-info/SOURCES.txt      
2019-08-26 23:31:57.000000000 +0200
@@ -32,7 +32,6 @@
 tests/__init__.py
 tests/conftest.py
 tests/pycodestyle.cfg
-tests/pylint.cfg
 tests/test_bug.py
 tests/test_createbug.py
 tests/test_misc.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-bugzilla-2.2.0/setup.py 
new/python-bugzilla-2.3.0/setup.py
--- old/python-bugzilla-2.2.0/setup.py  2018-03-12 22:56:02.000000000 +0100
+++ new/python-bugzilla-2.3.0/setup.py  2019-01-27 00:26:40.000000000 +0100
@@ -12,7 +12,7 @@
 
 def unsupported_python_version():
     return sys.version_info < (2, 7) \
-        or (sys.version_info > (3,) and sys.version_info < (3, 3))
+        or (sys.version_info > (3,) and sys.version_info < (3, 4))
 
 
 if unsupported_python_version():
@@ -23,7 +23,7 @@
     f = open("bugzilla/apiversion.py")
     for line in f:
         if line.startswith('version = '):
-            return eval(line.split('=')[-1])
+            return eval(line.split('=')[-1])  # pylint: disable=eval-used
 
 
 class TestCommand(Command):
@@ -51,26 +51,24 @@
         import pylint.lint
         import pycodestyle
 
-        files = (["bugzilla-cli", "bugzilla"] +
+        files = (["bugzilla-cli", "bugzilla", "setup.py"] +
             glob.glob("examples/*.py") +
             glob.glob("tests/*.py"))
         output_format = sys.stdout.isatty() and "colorized" or "text"
 
         print("running pycodestyle")
         style_guide = pycodestyle.StyleGuide(
-            config_file='tests/pycodestyle.cfg',
+            config_file='tox.ini',
+            format="pylint",
             paths=files,
         )
-        style_guide.options.exclude = pycodestyle.normalize_paths(
-            "bugzilla/oldclasses.py",
-        )
         report = style_guide.check_files()
         if style_guide.options.count:
             sys.stderr.write(str(report.total_errors) + '\n')
 
         print("running pylint")
         pylint_opts = [
-            "--rcfile", "tests/pylint.cfg",
+            "--rcfile", "pylintrc",
             "--output-format=%s" % output_format,
         ]
         pylint.lint.Run(files + pylint_opts)
@@ -108,37 +106,38 @@
     return ret
 
 
-setup(name='python-bugzilla',
-      version=get_version(),
-      description='Bugzilla XMLRPC access module',
-      author='Cole Robinson',
-      author_email='python-bugzi...@lists.fedorahosted.org',
-      license="GPLv2",
-      url='https://github.com/python-bugzilla/python-bugzilla',
-      classifiers=[
-          'Topic :: Software Development :: Libraries :: Python Modules',
-          'Intended Audience :: Developers',
-          'License :: OSI Approved :: Apache Software License',
-          'Operating System :: OS Independent',
-          'Programming Language :: Python',
-          'Programming Language :: Python :: 2',
-          'Programming Language :: Python :: 2.7',
-          'Programming Language :: Python :: 3',
-          'Programming Language :: Python :: 3.3',
-          'Programming Language :: Python :: 3.4',
-          'Programming Language :: Python :: 3.5',
-          'Programming Language :: Python :: 3.6',
-      ],
-      packages = ['bugzilla'],
-      entry_points={'console_scripts': ['bugzilla = bugzilla._cli:cli']},
-      data_files=[('share/man/man1', ['bugzilla.1'])],
-
-      install_requires=_parse_requirements("requirements.txt"),
-      tests_require=_parse_requirements("test-requirements.txt"),
-
-      cmdclass={
-        "pylint" : PylintCommand,
-        "rpm" : RPMCommand,
-        "test" : TestCommand,
-      },
+setup(
+    name='python-bugzilla',
+    version=get_version(),
+    description='Bugzilla XMLRPC access module',
+    author='Cole Robinson',
+    author_email='python-bugzi...@lists.fedorahosted.org',
+    license="GPLv2",
+    url='https://github.com/python-bugzilla/python-bugzilla',
+    classifiers=[
+        'Topic :: Software Development :: Libraries :: Python Modules',
+        'Intended Audience :: Developers',
+        'License :: OSI Approved :: Apache Software License',
+        'Operating System :: OS Independent',
+        'Programming Language :: Python',
+        'Programming Language :: Python :: 2',
+        'Programming Language :: Python :: 2.7',
+        'Programming Language :: Python :: 3',
+        'Programming Language :: Python :: 3.4',
+        'Programming Language :: Python :: 3.5',
+        'Programming Language :: Python :: 3.6',
+        'Programming Language :: Python :: 3.7',
+    ],
+    packages=['bugzilla'],
+    entry_points={'console_scripts': ['bugzilla = bugzilla._cli:cli']},
+    data_files=[('share/man/man1', ['bugzilla.1'])],
+
+    install_requires=_parse_requirements("requirements.txt"),
+    tests_require=_parse_requirements("test-requirements.txt"),
+
+    cmdclass={
+        "pylint": PylintCommand,
+        "rpm": RPMCommand,
+        "test": TestCommand,
+    },
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-bugzilla-2.2.0/tests/pycodestyle.cfg 
new/python-bugzilla-2.3.0/tests/pycodestyle.cfg
--- old/python-bugzilla-2.2.0/tests/pycodestyle.cfg     2018-03-04 
21:47:34.000000000 +0100
+++ new/python-bugzilla-2.3.0/tests/pycodestyle.cfg     2019-01-27 
00:26:40.000000000 +0100
@@ -1,12 +0,0 @@
-[pycodestyle]
-
-format = pylint
-
-# [E125] Continuation indent isn't different from next block
-# [E128] Not indented for visual style
-# [E129] visually indented line with same indent as next logical line
-# [E303] Too many blank lines
-# [E402] module level import not at top of file
-# [E731] do not assign a lambda expression, use a def
-
-ignore=E125,E128,E129,E303,E402,E731
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-bugzilla-2.2.0/tests/pylint.cfg 
new/python-bugzilla-2.3.0/tests/pylint.cfg
--- old/python-bugzilla-2.2.0/tests/pylint.cfg  2018-03-12 22:56:02.000000000 
+0100
+++ new/python-bugzilla-2.3.0/tests/pylint.cfg  1970-01-01 01:00:00.000000000 
+0100
@@ -1,41 +0,0 @@
-[MASTER]
-persistent=no
-
-
-[MESSAGES CONTROL]
-# Disable the message, report, category or checker with the given id(s). You
-# can either give multiple identifier separated by comma (,) or put this option
-# multiple time (only on the command line, not in the configuration file where
-# it should appear only once).
-disable=Design,Format,Similarities,invalid-name,missing-docstring,locally-disabled,unnecessary-lambda,star-args,fixme,global-statement,broad-except,no-self-use,bare-except,locally-enabled,wrong-import-position,consider-using-ternary,len-as-condition,no-else-return
-enable=fixme
-
-
-[REPORTS]
-# Tells whether to display a full report or only the messages
-reports=no
-score=no
-
-
-[FORMAT]
-# Maximum number of characters on a single line.
-max-line-length=80
-
-# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
-# tab).
-indent-string='    '
-
-
-[MISCELLANEOUS]
-# List of note tags to take in consideration, separated by a comma.
-notes=FIXME,XXX,TODO
-
-
-[VARIABLES]
-# A regular expression matching the beginning of the name of dummy variables
-# (i.e. not used).
-dummy-variables-rgx=ignore.*|.*_ignore
-
-# List of additional names supposed to be defined in builtins. Remember that
-# you should avoid to define new builtins when possible.
-additional-builtins=_
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-bugzilla-2.2.0/tests/test_misc.py 
new/python-bugzilla-2.3.0/tests/test_misc.py
--- old/python-bugzilla-2.2.0/tests/test_misc.py        2018-08-11 
15:13:09.000000000 +0200
+++ new/python-bugzilla-2.3.0/tests/test_misc.py        2019-01-10 
13:52:04.000000000 +0100
@@ -77,7 +77,7 @@
     def test_readconfig(self):
         # Testing for bugzillarc handling
         bzapi = tests.make_bz("4.4.0", rhbz=True)
-        bzapi.url = "foo.example.com"
+        bzapi.url = "example.com"
         temp = tempfile.NamedTemporaryFile(mode="w")
 
         content = """
@@ -92,6 +92,11 @@
         assert bzapi.password == "test2"
         assert bzapi.api_key is None
 
+        bzapi.url = "foo.example.com"
+        bzapi.user = None
+        bzapi.readconfig(temp.name)
+        assert bzapi.user is None
+
         content = """
 [foo.example.com]
 user=test3
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-bugzilla-2.2.0/tests/test_ro_functional.py 
new/python-bugzilla-2.3.0/tests/test_ro_functional.py
--- old/python-bugzilla-2.2.0/tests/test_ro_functional.py       2018-08-11 
15:13:09.000000000 +0200
+++ new/python-bugzilla-2.3.0/tests/test_ro_functional.py       2018-12-11 
18:53:15.000000000 +0100
@@ -211,7 +211,7 @@
     url = (tests.CLICONFIG.REDHAT_URL or
         "https://bugzilla.redhat.com/xmlrpc.cgi";)
     bzclass = RHBugzilla
-    bzversion = (4, 4)
+    bzversion = (5, 0)
 
     test0 = BaseTest._testBZVersion
     test01 = lambda s: BaseTest._testInfoProducts(s, 125,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-bugzilla-2.2.0/tests/test_rw_functional.py 
new/python-bugzilla-2.3.0/tests/test_rw_functional.py
--- old/python-bugzilla-2.2.0/tests/test_rw_functional.py       2018-08-11 
15:13:09.000000000 +0200
+++ new/python-bugzilla-2.3.0/tests/test_rw_functional.py       2019-01-09 
20:49:46.000000000 +0100
@@ -525,18 +525,21 @@
 
         setbug.refresh()
         assert len(setbug.attachments) == (orignumattach + 2)
-        assert setbug.attachments[-2]["summary"] == desc1
-        assert (setbug.attachments[-2]["id"] ==
-                int(out1.splitlines()[2].split()[2]))
-        assert setbug.attachments[-1]["summary"] == desc2
-        assert (setbug.attachments[-1]["id"] ==
-                int(out2.splitlines()[2].split()[2]))
-        attachid = setbug.attachments[-2]["id"]
+
+        att1 = setbug.attachments[-2]
+        attachid = att1["id"]
+        assert att1["summary"] == desc1
+        assert att1["id"] == int(out1.splitlines()[2].split()[2])
+        assert att1["content_type"] == "text/plain"
+
+        att2 = setbug.attachments[-1]
+        assert att2["summary"] == desc2
+        assert att2["id"] == int(out2.splitlines()[2].split()[2])
+        assert att2["content_type"] == "application/octet-stream"
 
         # Set attachment flags
-        assert setbug.attachments[-1]["flags"] == []
-        bz.updateattachmentflags(setbug.id, setbug.attachments[-1]["id"],
-                                 "review", status="+")
+        assert att1["flags"] == []
+        bz.updateattachmentflags(setbug.id, att2["id"], "review", status="+")
         setbug.refresh()
 
         assert len(setbug.attachments[-1]["flags"]) == 1
@@ -646,30 +649,28 @@
         getpass.getpass = fakegetpass
 
         try:
+            cmd = "bugzilla --no-cache-credentials --bugzilla %s" % self.url
             # Implied login with --username and --password
-            ret = tests.clicomm("bugzilla --bugzilla %s "
-                                "--user foo...@example.com "
-                                "--password foobar query -b 123456" % self.url,
+            ret = tests.clicomm("%s --user foo...@example.com "
+                                "--password foobar query -b 123456" % cmd,
                                 None, expectfail=True)
             assert "Login failed: " in ret
 
             # 'login' with explicit options
-            ret = tests.clicomm("bugzilla --bugzilla %s "
-                                "--user foo...@example.com "
-                                "--password foobar login" % self.url,
+            ret = tests.clicomm("%s --user foo...@example.com "
+                                "--password foobar login" % cmd,
                                 None, expectfail=True)
             assert "Login failed: " in ret
 
             # 'login' with positional options
-            ret = tests.clicomm("bugzilla --bugzilla %s "
-                                "login foo...@example.com foobar" % self.url,
+            ret = tests.clicomm("%s login foo...@example.com foobar" % cmd,
                                 None, expectfail=True)
             assert "Login failed: " in ret
 
 
             # bare 'login'
             stdinstr = StringIO("foo...@example.com\n\rfoobar\n\r")
-            ret = tests.clicomm("bugzilla --bugzilla %s login" % self.url,
+            ret = tests.clicomm("%s login" % cmd,
                                 None, expectfail=True, stdin=stdinstr)
             assert "Bugzilla Username:" in ret
             assert "Bugzilla Password:" in ret
@@ -812,7 +813,7 @@
 
     def test12SetCookie(self):
         bz = self.bzclass(self.url,
-            cookiefile=-1, tokenfile=None)
+                cookiefile=-1, tokenfile=None, configpaths=[])
 
         try:
             bz.cookiefile = None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/python-bugzilla-2.2.0/xmlrpc-api-notes.txt 
new/python-bugzilla-2.3.0/xmlrpc-api-notes.txt
--- old/python-bugzilla-2.2.0/xmlrpc-api-notes.txt      2018-03-18 
15:30:44.000000000 +0100
+++ new/python-bugzilla-2.3.0/xmlrpc-api-notes.txt      2019-01-09 
19:44:11.000000000 +0100
@@ -114,7 +114,7 @@
     https://bugzilla.readthedocs.io/en/latest/api/index.html
 
 
-Redhat Bugzilla: 4.4 based with extensions. Bits on top of 4.4
+Redhat Bugzilla: 5.0 based with extensions
     https://bugzilla.redhat.com/docs/en/html/api/
     Bug.search has --from-url extension
     Bug.update has more hashing support


Reply via email to