Hello community,
here is the log from the commit of package python-osc-tiny for openSUSE:Factory
checked in at 2020-01-16 18:14:25
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-osc-tiny (Old)
and /work/SRC/openSUSE:Factory/.python-osc-tiny.new.26092 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-osc-tiny"
Thu Jan 16 18:14:25 2020 rev:3 rq:763923 version:0.2.1
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-osc-tiny/python-osc-tiny.changes
2020-01-02 14:43:20.972959410 +0100
+++
/work/SRC/openSUSE:Factory/.python-osc-tiny.new.26092/python-osc-tiny.changes
2020-01-16 18:14:30.936746562 +0100
@@ -1,0 +2,9 @@
+Thu Jan 9 12:46:29 UTC 2020 - Chen Huang <[email protected]>
+
+- Updated to version 0.2.1
+- Allow invalid timestamps during changelog parsing
+- Removed dependency of the future package
+- Backport for Python2 compatibility
+- Bugfixes for :py:mod:`osctiny.utils.changelog`
+
+-------------------------------------------------------------------
Old:
----
osc-tiny-0.1.11.tar.gz
New:
----
osc-tiny-0.2.1.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-osc-tiny.spec ++++++
--- /var/tmp/diff_new_pack.ZYBqGs/_old 2020-01-16 18:14:32.380747379 +0100
+++ /var/tmp/diff_new_pack.ZYBqGs/_new 2020-01-16 18:14:32.380747379 +0100
@@ -1,7 +1,7 @@
#
# spec file for package python-osc-tiny
#
-# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2020 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -17,29 +17,36 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
-%define skip_python2 1
Name: python-osc-tiny
-Version: 0.1.11
+Version: 0.2.1
Release: 0
Summary: Client API for openSUSE BuildService
License: MIT
Group: Development/Languages/Python
URL: https://github.com/crazyscientist/osc-tiny
Source:
https://files.pythonhosted.org/packages/source/o/osc-tiny/osc-tiny-%{version}.tar.gz
-BuildRequires: %{python_module dateutil}
BuildRequires: %{python_module devel}
BuildRequires: %{python_module lxml}
+BuildRequires: %{python_module python-dateutil}
BuildRequires: %{python_module pytz}
BuildRequires: %{python_module requests}
BuildRequires: %{python_module responses}
BuildRequires: %{python_module setuptools}
+BuildRequires: %{python_module six}
BuildRequires: fdupes
+BuildRequires: python-mock
BuildRequires: python-rpm-macros
-Requires: python-dateutil
+BuildRequires: python-unittest2
Requires: python-lxml
+Requires: python-python-dateutil
Requires: python-pytz
Requires: python-requests
+Requires: python-six
BuildArch: noarch
+%ifpython2
+Requires: python-mock
+Requires: python-unittest2
+%endif
%python_subpackages
%description
++++++ osc-tiny-0.1.11.tar.gz -> osc-tiny-0.2.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.1.11/MANIFEST.in
new/osc-tiny-0.2.1/MANIFEST.in
--- old/osc-tiny-0.1.11/MANIFEST.in 2019-12-30 15:27:53.000000000 +0100
+++ new/osc-tiny-0.2.1/MANIFEST.in 2020-01-10 09:32:12.000000000 +0100
@@ -1,2 +1,3 @@
include *.md
-include LICENSE
\ No newline at end of file
+include LICENSE
+include requirements*.txt
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.1.11/PKG-INFO new/osc-tiny-0.2.1/PKG-INFO
--- old/osc-tiny-0.1.11/PKG-INFO 2019-12-30 15:28:12.000000000 +0100
+++ new/osc-tiny-0.2.1/PKG-INFO 2020-01-10 09:32:27.000000000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: osc-tiny
-Version: 0.1.11
+Version: 0.2.1
Summary: Client API for openSUSE BuildService
Home-page: http://github.com/crazyscientist/osc-tiny
Author: Andreas Hasenkopf
@@ -56,7 +56,7 @@
Classifier: Intended Audience :: System Administrators
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
-Classifier: Programming Language :: Python :: 3 :: Only
+Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.1.11/osc_tiny.egg-info/PKG-INFO
new/osc-tiny-0.2.1/osc_tiny.egg-info/PKG-INFO
--- old/osc-tiny-0.1.11/osc_tiny.egg-info/PKG-INFO 2019-12-30
15:28:12.000000000 +0100
+++ new/osc-tiny-0.2.1/osc_tiny.egg-info/PKG-INFO 2020-01-10
09:32:27.000000000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: osc-tiny
-Version: 0.1.11
+Version: 0.2.1
Summary: Client API for openSUSE BuildService
Home-page: http://github.com/crazyscientist/osc-tiny
Author: Andreas Hasenkopf
@@ -56,7 +56,7 @@
Classifier: Intended Audience :: System Administrators
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
-Classifier: Programming Language :: Python :: 3 :: Only
+Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.1.11/osc_tiny.egg-info/SOURCES.txt
new/osc-tiny-0.2.1/osc_tiny.egg-info/SOURCES.txt
--- old/osc-tiny-0.1.11/osc_tiny.egg-info/SOURCES.txt 2019-12-30
15:28:12.000000000 +0100
+++ new/osc-tiny-0.2.1/osc_tiny.egg-info/SOURCES.txt 2020-01-10
09:32:27.000000000 +0100
@@ -1,6 +1,10 @@
LICENSE
MANIFEST.in
README.md
+requirements.txt
+requirements27.txt
+requirements34.txt
+requirements_devel.txt
setup.py
osc_tiny.egg-info/PKG-INFO
osc_tiny.egg-info/SOURCES.txt
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.1.11/osc_tiny.egg-info/requires.txt
new/osc-tiny-0.2.1/osc_tiny.egg-info/requires.txt
--- old/osc-tiny-0.1.11/osc_tiny.egg-info/requires.txt 2019-12-30
15:28:12.000000000 +0100
+++ new/osc-tiny-0.2.1/osc_tiny.egg-info/requires.txt 2020-01-10
09:32:27.000000000 +0100
@@ -3,3 +3,4 @@
responses
python-dateutil
pytz
+six
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.1.11/osctiny/__init__.py
new/osc-tiny-0.2.1/osctiny/__init__.py
--- old/osc-tiny-0.1.11/osctiny/__init__.py 2019-12-30 15:27:53.000000000
+0100
+++ new/osc-tiny-0.2.1/osctiny/__init__.py 2020-01-10 09:32:12.000000000
+0100
@@ -6,4 +6,4 @@
__all__ = ['Osc', 'bs_requests', 'buildresults', 'comments', 'packages',
'projects', 'search', 'users']
-__version__ = "0.1.11"
+__version__ = "0.2.1"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.1.11/osctiny/extensions/bs_requests.py
new/osc-tiny-0.2.1/osctiny/extensions/bs_requests.py
--- old/osc-tiny-0.1.11/osctiny/extensions/bs_requests.py 2019-12-30
15:27:53.000000000 +0100
+++ new/osc-tiny-0.2.1/osctiny/extensions/bs_requests.py 2020-01-10
09:32:12.000000000 +0100
@@ -2,7 +2,9 @@
Requests extension
------------------
"""
-from urllib.parse import urljoin
+from __future__ import unicode_literals
+from six.moves.urllib.parse import urljoin
+from six import text_type
from ..utils.base import ExtensionBase
@@ -15,7 +17,7 @@
@staticmethod
def _validate_id(request_id):
- request_id = str(request_id)
+ request_id = text_type(request_id)
if not request_id.isnumeric():
raise ValueError(
"Request ID must be numeric! Got instead:
{}".format(request_id)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.1.11/osctiny/extensions/buildresults.py
new/osc-tiny-0.2.1/osctiny/extensions/buildresults.py
--- old/osc-tiny-0.1.11/osctiny/extensions/buildresults.py 2019-12-30
15:27:53.000000000 +0100
+++ new/osc-tiny-0.2.1/osctiny/extensions/buildresults.py 2020-01-10
09:32:12.000000000 +0100
@@ -3,7 +3,8 @@
----------------------
"""
# pylint: disable=too-few-public-methods
-from urllib.parse import urljoin
+from __future__ import unicode_literals
+from six.moves.urllib.parse import urljoin
from ..utils.base import ExtensionBase
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.1.11/osctiny/extensions/comments.py
new/osc-tiny-0.2.1/osctiny/extensions/comments.py
--- old/osc-tiny-0.1.11/osctiny/extensions/comments.py 2019-12-30
15:27:53.000000000 +0100
+++ new/osc-tiny-0.2.1/osctiny/extensions/comments.py 2020-01-10
09:32:12.000000000 +0100
@@ -2,8 +2,10 @@
Comments extension
------------------
"""
+from __future__ import unicode_literals
import os
-from urllib.parse import urljoin
+from six.moves.urllib.parse import urljoin
+from six import text_type
from ..utils.base import ExtensionBase
@@ -51,7 +53,7 @@
response = self.osc.request(
url=urljoin(self.osc.url,
os.path.join(*([self.base_path, obj_type]
- + [str(x) for x in ids]))),
+ + [text_type(x) for x in ids]))),
method="GET",
)
return self.osc.get_objectified_xml(response)
@@ -74,9 +76,9 @@
self._validate(obj_type, ids)
url = urljoin(self.osc.url,
os.path.join(*([self.base_path, obj_type]
- + [str(x) for x in ids])))
+ + [text_type(x) for x in ids])))
params = {}
- if parent_id and str(parent_id).isnumeric():
+ if parent_id and text_type(parent_id).isnumeric():
params["parent_id"] = parent_id
response = self.osc.request(
@@ -102,7 +104,7 @@
:return: ``True``, if successful. Otherwise API response
:rtype: bool or lxml.objectify.ObjectifiedElement
"""
- url = urljoin(self.osc.url, '/comment/' + str(comment_id))
+ url = urljoin(self.osc.url, '/comment/' + text_type(comment_id))
response = self.osc.request(
url=url,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.1.11/osctiny/extensions/packages.py
new/osc-tiny-0.2.1/osctiny/extensions/packages.py
--- old/osc-tiny-0.1.11/osctiny/extensions/packages.py 2019-12-30
15:27:53.000000000 +0100
+++ new/osc-tiny-0.2.1/osctiny/extensions/packages.py 2020-01-10
09:32:12.000000000 +0100
@@ -2,9 +2,11 @@
Packages extension
------------------
"""
+from __future__ import unicode_literals
import errno
import os
-from urllib.parse import urljoin
+from six.moves.urllib.parse import urljoin
+from six import text_type
from lxml.etree import tounicode, SubElement, Element
from lxml.objectify import fromstring
@@ -100,7 +102,7 @@
:type meta: str or lxml.objectify.ObjectifiedElement
:return:
"""
- if isinstance(meta, str):
+ if isinstance(meta, text_type):
meta = fromstring(meta)
if meta is not None:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.1.11/osctiny/extensions/projects.py
new/osc-tiny-0.2.1/osctiny/extensions/projects.py
--- old/osc-tiny-0.1.11/osctiny/extensions/projects.py 2019-12-30
15:27:53.000000000 +0100
+++ new/osc-tiny-0.2.1/osctiny/extensions/projects.py 2020-01-10
09:32:12.000000000 +0100
@@ -2,8 +2,10 @@
Projects extension
------------------
"""
+from __future__ import unicode_literals
import re
-from urllib.parse import urljoin
+from six.moves.urllib.parse import urljoin
+from six import text_type
from lxml.etree import tounicode
from lxml.objectify import fromstring
@@ -85,7 +87,7 @@
if metafile is None:
metafile = TEMPLATE_META
- if isinstance(metafile, str):
+ if isinstance(metafile, text_type):
metafile = fromstring(metafile)
metafile.set("name", project)
@@ -134,7 +136,7 @@
if meta:
kwargs["meta"] = '1'
if rev:
- kwargs["rev"] = str(rev)
+ kwargs["rev"] = text_type(rev)
response = self.osc.request(
url=urljoin(
self.osc.url,
@@ -201,7 +203,7 @@
attr_xml.attribute.set('namespace', match.group("prefix"))
attr_xml.attribute.set('name', match.group("name"))
# pylint: disable=protected-access
- attr_xml.attribute.value._setText(str(value))
+ attr_xml.attribute.value._setText(text_type(value))
response = self.osc.request(
url=url,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.1.11/osctiny/extensions/search.py
new/osc-tiny-0.2.1/osctiny/extensions/search.py
--- old/osc-tiny-0.1.11/osctiny/extensions/search.py 2019-12-30
15:27:53.000000000 +0100
+++ new/osc-tiny-0.2.1/osctiny/extensions/search.py 2020-01-10
09:32:12.000000000 +0100
@@ -2,7 +2,8 @@
Search extension
----------------
"""
-from urllib.parse import urljoin
+from __future__ import unicode_literals
+from six.moves.urllib.parse import urljoin
from ..utils.base import ExtensionBase
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.1.11/osctiny/extensions/users.py
new/osc-tiny-0.2.1/osctiny/extensions/users.py
--- old/osc-tiny-0.1.11/osctiny/extensions/users.py 2019-12-30
15:27:53.000000000 +0100
+++ new/osc-tiny-0.2.1/osctiny/extensions/users.py 2020-01-10
09:32:12.000000000 +0100
@@ -2,7 +2,8 @@
Persons and groups extension
----------------------------
"""
-from urllib.parse import urljoin
+from __future__ import unicode_literals
+from six.moves.urllib.parse import urljoin
from ..utils.base import ExtensionBase
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.1.11/osctiny/osc.py
new/osc-tiny-0.2.1/osctiny/osc.py
--- old/osc-tiny-0.1.11/osctiny/osc.py 2019-12-30 15:27:53.000000000 +0100
+++ new/osc-tiny-0.2.1/osctiny/osc.py 2020-01-10 09:32:12.000000000 +0100
@@ -2,6 +2,7 @@
Main API access
---------------
"""
+from __future__ import unicode_literals
from io import BufferedReader, BytesIO, StringIO
import gc
import re
@@ -14,6 +15,7 @@
from requests import Session, Request
from requests.auth import HTTPBasicAuth
from requests.exceptions import ConnectionError as _ConnectionError
+from six import text_type
from .extensions.buildresults import Build
from .extensions.comments import Comment
@@ -191,6 +193,7 @@
)
prepped_req = session.prepare_request(req)
prepped_req.headers['Content-Type'] = "application/octet-stream"
+ prepped_req.headers['Accept'] = "application/xml"
settings = session.merge_environment_settings(
prepped_req.url, {}, None, None, None
)
@@ -227,12 +230,12 @@
if isinstance(params, bytes):
return params
- if isinstance(params, str):
- return params.encode()
+ if isinstance(params, text_type):
+ return params.encode('utf-8')
if isinstance(params, StringIO):
params.seek(0)
- return params.read().encode()
+ return params.read().encode('utf-8')
if isinstance(params, (BufferedReader, BytesIO)):
params.seek(0)
@@ -265,7 +268,8 @@
except ValueError:
# Just in case OBS returns a Unicode string with encoding
# declaration
- if isinstance(response.text, str) and "encoding=" in response.text:
+ if isinstance(response.text, text_type) and \
+ "encoding=" in response.text:
return fromstring(
re.sub(r'encoding="[^"]+"', "", response.text)
)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.1.11/osctiny/tests/base.py
new/osc-tiny-0.2.1/osctiny/tests/base.py
--- old/osc-tiny-0.1.11/osctiny/tests/base.py 2019-12-30 15:27:53.000000000
+0100
+++ new/osc-tiny-0.2.1/osctiny/tests/base.py 2020-01-10 09:32:12.000000000
+0100
@@ -1,8 +1,14 @@
+from __future__ import unicode_literals
+import sys
+if sys.version_info.major < 3:
+ from unittest2 import TestCase
+else:
+ from unittest import TestCase
+
from io import IOBase
-from unittest import TestCase
-from urllib.parse import parse_qs
import responses
+from six.moves.urllib_parse import parse_qs
from osctiny import Osc
@@ -34,8 +40,8 @@
body.seek(0)
body = body.read()
if hasattr(body, "decode"):
- body = body.decode()
- params = parse_qs(body)
+ body = body.decode('utf-8')
+ params = parse_qs(body) if body else {}
headers = {
"Cache-Control": "max-age=0, private, must-revalidate",
"Connection": "Keep-Alive",
@@ -53,7 +59,7 @@
class OscTest(TestCase):
@classmethod
def setUpClass(cls):
- super().setUpClass()
+ super(OscTest, cls).setUpClass()
cls.osc = Osc(
url="http://api.example.com",
username="foobar",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.1.11/osctiny/tests/test_basic.py
new/osc-tiny-0.2.1/osctiny/tests/test_basic.py
--- old/osc-tiny-0.1.11/osctiny/tests/test_basic.py 2019-12-30
15:27:53.000000000 +0100
+++ new/osc-tiny-0.2.1/osctiny/tests/test_basic.py 2020-01-10
09:32:12.000000000 +0100
@@ -1,3 +1,5 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
from ..extensions import projects
from .base import OscTest
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.1.11/osctiny/tests/test_build.py
new/osc-tiny-0.2.1/osctiny/tests/test_build.py
--- old/osc-tiny-0.1.11/osctiny/tests/test_build.py 2019-12-30
15:27:53.000000000 +0100
+++ new/osc-tiny-0.2.1/osctiny/tests/test_build.py 2020-01-10
09:32:12.000000000 +0100
@@ -1,5 +1,6 @@
+from __future__ import unicode_literals
import re
-from urllib.parse import urlparse, parse_qs
+from six.moves.urllib_parse import urlparse, parse_qs
from requests.exceptions import HTTPError
import responses
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.1.11/osctiny/tests/test_comments.py
new/osc-tiny-0.2.1/osctiny/tests/test_comments.py
--- old/osc-tiny-0.1.11/osctiny/tests/test_comments.py 2019-12-30
15:27:53.000000000 +0100
+++ new/osc-tiny-0.2.1/osctiny/tests/test_comments.py 2020-01-10
09:32:12.000000000 +0100
@@ -1,3 +1,4 @@
+from __future__ import unicode_literals
import re
from lxml.objectify import ObjectifiedElement
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.1.11/osctiny/tests/test_datadir.py
new/osc-tiny-0.2.1/osctiny/tests/test_datadir.py
--- old/osc-tiny-0.1.11/osctiny/tests/test_datadir.py 2019-12-30
15:27:53.000000000 +0100
+++ new/osc-tiny-0.2.1/osctiny/tests/test_datadir.py 2020-01-10
09:32:12.000000000 +0100
@@ -1,4 +1,9 @@
-from unittest import mock
+from __future__ import unicode_literals
+
+try:
+ from unittest import mock
+except ImportError:
+ import mock
# Absolute import needed for mocking ;)
from ..utils.base import DataDir
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.1.11/osctiny/tests/test_packages.py
new/osc-tiny-0.2.1/osctiny/tests/test_packages.py
--- old/osc-tiny-0.1.11/osctiny/tests/test_packages.py 2019-12-30
15:27:53.000000000 +0100
+++ new/osc-tiny-0.2.1/osctiny/tests/test_packages.py 2020-01-10
09:32:12.000000000 +0100
@@ -1,7 +1,10 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
from io import StringIO, BytesIO, IOBase
import re
from unittest import skip
+from six import text_type
import responses
from .base import OscTest, CallbackFactory
@@ -156,7 +159,7 @@
response = self.osc.packages.get_meta(
"SUSE:SLE-12-SP1:Update", "python.8549", blame=True
)
- self.assertTrue(isinstance(response, str))
+ self.assertTrue(isinstance(response, text_type))
@skip("No test data available")
@responses.activate
@@ -245,7 +248,7 @@
response = self.osc.packages.cmd(
"SUSE:SLE-12-SP1:Update", "python.8549", "diff"
)
- self.assertTrue(isinstance(response, str))
+ self.assertTrue(isinstance(response, text_type))
self.assertIn(
"++#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE", response
)
@@ -368,22 +371,22 @@
with self.subTest("as unicode"):
self.osc.packages.push_file("prj", "pkg", "readme.txt", content)
- self.assertEqual(bodies[-1], content.encode())
+ self.assertEqual(bodies[-1], content.encode('utf-8'))
with self.subTest("as bytes"):
self.osc.packages.push_file("prj", "pkg", "readme.txt",
- content.encode())
- self.assertEqual(bodies[-1], content.encode())
+ content.encode('utf-8'))
+ self.assertEqual(bodies[-1], content.encode('utf-8'))
with self.subTest("as StringIO"):
self.osc.packages.push_file("prj", "pkg", "readme.txt",
StringIO(content))
- self.assertEqual(bodies[-1], content.encode())
+ self.assertEqual(bodies[-1], content.encode('utf-8'))
with self.subTest("as BytesIO"):
self.osc.packages.push_file("prj", "pkg", "readme.txt",
- BytesIO(content.encode()))
- self.assertEqual(bodies[-1], content.encode())
+ BytesIO(content.encode('utf-8')))
+ self.assertEqual(bodies[-1], content.encode('utf-8'))
@responses.activate
def test_aggregate(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.1.11/osctiny/tests/test_projects.py
new/osc-tiny-0.2.1/osctiny/tests/test_projects.py
--- old/osc-tiny-0.1.11/osctiny/tests/test_projects.py 2019-12-30
15:27:53.000000000 +0100
+++ new/osc-tiny-0.2.1/osctiny/tests/test_projects.py 2020-01-10
09:32:12.000000000 +0100
@@ -1,5 +1,6 @@
+from __future__ import unicode_literals
import re
-from urllib.parse import urlparse, parse_qs
+from six.moves.urllib_parse import urlparse, parse_qs
from lxml.objectify import fromstring
from requests.exceptions import HTTPError
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.1.11/osctiny/tests/test_requests.py
new/osc-tiny-0.2.1/osctiny/tests/test_requests.py
--- old/osc-tiny-0.1.11/osctiny/tests/test_requests.py 2019-12-30
15:27:53.000000000 +0100
+++ new/osc-tiny-0.2.1/osctiny/tests/test_requests.py 2020-01-10
09:32:12.000000000 +0100
@@ -1,5 +1,9 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
import re
-from urllib.parse import urlparse, parse_qs
+
+from six.moves.urllib_parse import urlparse, parse_qs
+from six import text_type
from lxml.objectify import ObjectifiedElement
import responses
@@ -318,7 +322,7 @@
class TestRequest(OscTest):
def setUp(self):
- super().setUp()
+ super(TestRequest, self).setUp()
self.mock_request(
method=responses.GET,
@@ -374,7 +378,7 @@
def test_cmd(self):
with self.subTest("plain diff"):
response = self.osc.requests.cmd(30902, "diff")
- self.assertTrue(isinstance(response, str))
+ self.assertTrue(isinstance(response, text_type))
self.assertIn("changes files:", response)
self.assertIn("+++ perl-XML-DOM-XPath.changes", response)
with self.subTest("xml diff"):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.1.11/osctiny/tests/test_search.py
new/osc-tiny-0.2.1/osctiny/tests/test_search.py
--- old/osc-tiny-0.1.11/osctiny/tests/test_search.py 2019-12-30
15:27:53.000000000 +0100
+++ new/osc-tiny-0.2.1/osctiny/tests/test_search.py 2020-01-10
09:32:12.000000000 +0100
@@ -1,6 +1,8 @@
+from __future__ import unicode_literals
+
import re
-from urllib.parse import urlparse, parse_qs
+from six.moves.urllib_parse import urlparse, parse_qs
import responses
from .base import OscTest, CallbackFactory
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.1.11/osctiny/tests/test_utils.py
new/osc-tiny-0.2.1/osctiny/tests/test_utils.py
--- old/osc-tiny-0.1.11/osctiny/tests/test_utils.py 2019-12-30
15:27:53.000000000 +0100
+++ new/osc-tiny-0.2.1/osctiny/tests/test_utils.py 2020-01-10
09:32:12.000000000 +0100
@@ -1,10 +1,24 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+import sys
+
+if sys.version_info.major < 3:
+ from unittest2 import TestCase
+ import mock
+else:
+ from unittest import TestCase, mock
+
from datetime import datetime
from io import StringIO
+from os import remove
+from tempfile import mkstemp
from types import GeneratorType
-from unittest import TestCase, mock
+from unittest import skipIf
from dateutil.parser import parse
from pytz import _UTC, timezone
+from six import text_type
from ..utils.changelog import ChangeLog, Entry
@@ -56,6 +70,17 @@
"""
+SAMPLE_CHANGES_3 = """
+Tue Dec 3 10:38:41 UTC 2019 - Andreas Hasenkopf <[email protected]>
+
+- Version 0.1.10
+
+-------------------------------------------------------------------
+Tue Dec 3 10:13:08 UTC 2019 - Andreas Hasenkopf <[email protected]>
+
+- New package osc-tiny (version 0.1.9)
+"""
+
class TestEntry(TestCase):
def test_timestamp(self):
@@ -111,6 +136,7 @@
timestamp = parse(match.group("timestamp"))
self.assertIsInstance(timestamp, datetime)
+ @skipIf(sys.version_info.major < 3, "Python2 does not support this")
def test_parse_non_generative(self):
with mock.patch("osctiny.utils.changelog.open",
mock.mock_open(read_data=SAMPLE_CHANGES),
@@ -135,6 +161,27 @@
self.assertIsInstance(cl.entries, list)
self.assertEqual(len(cl.entries), 2)
+ def test_parse_path(self):
+ _, path = mkstemp()
+ with open(path, "w") as handle:
+ handle.write(SAMPLE_CHANGES)
+
+ try:
+ with self.subTest("generative"):
+ cl = ChangeLog.parse(path, generative=True)
+
+ self.assertNotIsInstance(cl.entries, list)
+ self.assertEqual(len(list(cl.entries)), 2)
+
+ with self.subTest("non-generative"):
+ cl = ChangeLog.parse(path, generative=False)
+
+ self.assertIsInstance(cl.entries, list)
+ self.assertEqual(len(cl.entries), 2)
+ finally:
+ remove(path)
+
+ @skipIf(sys.version_info.major < 3, "Python2 does not support this")
def test_parse_generative(self):
with mock.patch("osctiny.utils.changelog.open",
mock.mock_open(read_data=SAMPLE_CHANGES),
@@ -179,7 +226,7 @@
cl.write(path="/who/cares/test.changes")
self.assertEqual(len(omock.mock_calls), 6)
- content = "".join(str(omock.mock_calls[x][1][0])
+ content = "".join(text_type(omock.mock_calls[x][1][0])
for x in range(2, 5))
self.assertEqual(
@@ -214,6 +261,7 @@
"Føø Bar\n\n"
)
+ @skipIf(sys.version_info.major < 3, "Python2 does not support this")
def test_write_append(self):
with mock.patch("osctiny.utils.changelog.open",
mock.mock_open(read_data=SAMPLE_CHANGES_2),
@@ -232,7 +280,7 @@
write_calls = [x for x in omock.mock_calls if x[0] == "().write"]
self.assertEqual(len(write_calls), 5)
self.assertEqual(
- str(write_calls[0][1][0]),
+ text_type(write_calls[0][1][0]),
"-------------------------------------------------------------------\n"
"Sat Oct 31 00:00:00 UTC 2020 - Andreas Hasenkopf
<[email protected]>\n\n"
"New entry at the top\n\n"
@@ -254,4 +302,24 @@
self.assertEqual(
len([x for x in outbuff.readlines() if x.startswith("-" * 67)]),
5
- )
\ No newline at end of file
+ )
+
+ def test_parse_missing_sep(self):
+ buffer = StringIO(SAMPLE_CHANGES_3)
+ cl = ChangeLog.parse(buffer, generative=False)
+
+ self.assertIsInstance(cl.entries, list)
+ self.assertEqual(len(cl.entries), 2)
+
+ @mock.patch("warnings.warn")
+ def test_parse_invalid_timestamp(self, wmock):
+ buffer = StringIO(SAMPLE_CHANGES.replace("10:38:41", "10::41"))
+ cl = ChangeLog.parse(buffer, generative=False)
+
+ self.assertIsInstance(cl.entries, list)
+ self.assertEqual(len(cl.entries), 2)
+ self.assertIsInstance(cl.entries[0].timestamp, text_type)
+ self.assertIsInstance(cl.entries[1].timestamp, datetime)
+
+ self.assertEqual(wmock.call_count, 1)
+ self.assertIn("Cannot parse changelog entry", wmock.call_args[0][0])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.1.11/osctiny/utils/changelog.py
new/osc-tiny-0.2.1/osctiny/utils/changelog.py
--- old/osc-tiny-0.1.11/osctiny/utils/changelog.py 2019-12-30
15:27:53.000000000 +0100
+++ new/osc-tiny-0.2.1/osctiny/utils/changelog.py 2020-01-10
09:32:12.000000000 +0100
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
"""
Changelog
^^^^^^^^^
@@ -10,12 +11,15 @@
.. versionadded:: 0.1.11
"""
+from __future__ import unicode_literals
from datetime import datetime
from io import TextIOBase
import re
+import warnings
from dateutil.parser import parse
from pytz import _UTC
+from six import text_type, binary_type
def is_aware(timestamp):
@@ -69,6 +73,9 @@
def __bool__(self):
return bool(self.timestamp and self.packager and self.content)
+ def __len__(self):
+ return 1 if self.timestamp and self.packager and self.content else 0
+
def now(self):
"""
Return current UTC timestamp
@@ -84,6 +91,9 @@
:return: str
"""
+ if not isinstance(self.timestamp, datetime):
+ return self.timestamp
+
return self.timestamp\
.astimezone(self.default_tz)\
.strftime("%a %b %d %H:%M:%S %Z %Y")
@@ -92,6 +102,9 @@
return "{sep}\n{self.formatted_timestamp} - {self.packager}\n\n" \
"{self.content}\n\n".format(sep="-" * 67, self=self)
+ def __unicode__(self):
+ return self.__str__()
+
class ChangeLog:
"""
@@ -138,44 +151,62 @@
:param handle: An open and iterable (file) handle
:type handle: Any derived object of :py:class:`io.IOBase`
"""
- entry = None
+ # pylint: disable=too-many-branches
+ entry = self.entry_factory()
+
+ if isinstance(handle, TextIOBase):
+ handle.seek(0)
+ elif isinstance(handle, (text_type, binary_type)):
+ handle = open(handle, "r")
+ else:
+ raise TypeError("Unexpected type for 'path': {}".format(
+ type(handle)))
- handle.seek(0)
- for line in handle:
- match = self.patterns["init"].match(line)
- if match:
- if entry:
- # We are at the beginning of a new entry. Time to emit
- # the finished one.
- yield entry
- entry = self.entry_factory()
- continue
-
- match = self.patterns["header"].match(line)
- if match:
- entry.timestamp = parse(match.group("timestamp"),
- ignoretz=False,
- tzinfos=self.additional_tzinfos)
- # Assuming UTC may not be correct, but beats dealing with
- # a mix of tz-aware and naive datetime objects
- if not is_aware(entry.timestamp):
- entry.timestamp = entry.default_tz.localize(
- parse(match.group("timestamp"), ignoretz=True,)
- )
- entry.packager = match.group("packager")
- continue
-
- if not line.strip():
- continue
-
- if entry.content:
- entry.content += "\n"
-
- entry.content += line.rstrip()
-
- if entry:
- # The last entry of the file is emitted explicitly
- yield entry
+ try:
+ for line in handle:
+ match = self.patterns["init"].match(line)
+ if match:
+ if entry:
+ # We are at the beginning of a new entry. Time to emit
+ # the finished one.
+ yield entry
+ entry = self.entry_factory()
+ continue
+
+ match = self.patterns["header"].match(line)
+ if match:
+ try:
+ entry.timestamp = parse(match.group("timestamp"),
+ ignoretz=False,
+
tzinfos=self.additional_tzinfos)
+ except ValueError as error:
+ warnings.warn(
+ "Cannot parse changelog entry's timestamp: "
+ "'{}'".format(error))
+ entry.timestamp = match.group("timestamp")
+ else:
+ # Assuming UTC may not be correct, but beats dealing
+ # with a mix of tz-aware and naive datetime objects
+ if not is_aware(entry.timestamp):
+ entry.timestamp = entry.default_tz.localize(
+ parse(match.group("timestamp"), ignoretz=True,)
+ )
+ entry.packager = match.group("packager")
+ continue
+
+ if not line.strip():
+ continue
+
+ if entry.content:
+ entry.content += "\n"
+
+ entry.content += line.rstrip()
+
+ if entry:
+ # The last entry of the file is emitted explicitly
+ yield entry
+ finally:
+ handle.close()
@classmethod
def parse(cls, path, generative=True):
@@ -207,22 +238,13 @@
:raises TypeError: if ``path`` is not a string or a subclass of
:py:class:`io.TextIOBase`
"""
- def _wrapped(handle):
- # pylint: disable=protected-access
- if generative:
- new.entries = new._parse(handle)
- else:
- new.entries = list(new._parse(handle))
-
new = cls()
- if isinstance(path, TextIOBase):
- _wrapped(path)
- elif isinstance(path, str):
- with open(path, "r") as handle:
- _wrapped(handle)
+ # pylint: disable=protected-access
+ if generative:
+ new.entries = new._parse(path)
else:
- raise TypeError("Unexpected type for 'path':
{}".format(type(path)))
+ new.entries = list(new._parse(path))
return new
@@ -239,11 +261,11 @@
def _wrapped(handle):
for entry in sorted(self.entries, key=lambda x: x.timestamp,
reverse=True):
- handle.write(str(entry))
+ handle.write(text_type(entry))
if isinstance(path, TextIOBase):
_wrapped(path)
- elif isinstance(path, str):
+ elif isinstance(path, (text_type, binary_type)):
with open(path, "w") as handle:
_wrapped(handle)
else:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.1.11/requirements.txt
new/osc-tiny-0.2.1/requirements.txt
--- old/osc-tiny-0.1.11/requirements.txt 1970-01-01 01:00:00.000000000
+0100
+++ new/osc-tiny-0.2.1/requirements.txt 2020-01-10 09:32:12.000000000 +0100
@@ -0,0 +1,6 @@
+lxml
+requests
+responses
+python-dateutil
+pytz
+six
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.1.11/requirements27.txt
new/osc-tiny-0.2.1/requirements27.txt
--- old/osc-tiny-0.1.11/requirements27.txt 1970-01-01 01:00:00.000000000
+0100
+++ new/osc-tiny-0.2.1/requirements27.txt 2020-01-10 09:32:12.000000000
+0100
@@ -0,0 +1,8 @@
+lxml
+mock
+requests
+responses
+python-dateutil
+pytz
+unittest2
+six
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.1.11/requirements34.txt
new/osc-tiny-0.2.1/requirements34.txt
--- old/osc-tiny-0.1.11/requirements34.txt 1970-01-01 01:00:00.000000000
+0100
+++ new/osc-tiny-0.2.1/requirements34.txt 2020-01-10 09:32:12.000000000
+0100
@@ -0,0 +1,6 @@
+lxml<4.4
+requests
+responses
+python-dateutil
+pytz
+six
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.1.11/requirements_devel.txt
new/osc-tiny-0.2.1/requirements_devel.txt
--- old/osc-tiny-0.1.11/requirements_devel.txt 1970-01-01 01:00:00.000000000
+0100
+++ new/osc-tiny-0.2.1/requirements_devel.txt 2020-01-10 09:32:12.000000000
+0100
@@ -0,0 +1,3 @@
+pylint
+Sphinx
+sphinx_rtd_theme
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.1.11/setup.py new/osc-tiny-0.2.1/setup.py
--- old/osc-tiny-0.1.11/setup.py 2019-12-30 15:27:53.000000000 +0100
+++ new/osc-tiny-0.2.1/setup.py 2020-01-10 09:32:12.000000000 +0100
@@ -1,16 +1,28 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python
# -*- coding: utf-8 -*-
-
+from __future__ import unicode_literals
+import sys
from setuptools import setup, find_packages
+def get_requires():
+ def _filter(requires):
+ return [req.strip() for req in requires if req.strip()]
+
+ filename = "requirements.txt" if sys.version_info.major >= 3 \
+ else "requirements27.txt"
+
+ with open(filename, "r") as fh:
+ return _filter(fh.readlines())
+
+
with open("README.md") as fh:
long_description = fh.read()
setup(
name='osc-tiny',
- version='0.1.11',
+ version='0.2.1',
description='Client API for openSUSE BuildService',
long_description=long_description,
long_description_content_type="text/markdown",
@@ -20,20 +32,14 @@
download_url='http://github.com/crazyscientist/osc-tiny/tarball/master',
packages=find_packages(),
license='MIT',
- install_requires=[
- "lxml",
- "requests",
- "responses",
- "python-dateutil",
- "pytz"
- ],
+ install_requires=get_requires(),
classifiers=[
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"Intended Audience :: System Administrators",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
- "Programming Language :: Python :: 3 :: Only",
+ "Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",