Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-osc-tiny for openSUSE:Factory
checked in at 2021-11-03 17:26:21
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-osc-tiny (Old)
and /work/SRC/openSUSE:Factory/.python-osc-tiny.new.1890 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-osc-tiny"
Wed Nov 3 17:26:21 2021 rev:10 rq:928959 version:0.4.1
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-osc-tiny/python-osc-tiny.changes
2021-03-02 12:46:10.284392588 +0100
+++
/work/SRC/openSUSE:Factory/.python-osc-tiny.new.1890/python-osc-tiny.changes
2021-11-03 17:27:17.481370874 +0100
@@ -1,0 +2,11 @@
+Wed Sep 22 10:45:07 UTC 2021 - Andreas Hasenkopf <[email protected]>
+
+- Release 0.4.1
+ * Bugfix for configuration utilities
+
+- Release 0.4.0
+ * Added support to parse `osc` configuration
+ * Bugfix for `origin` extension
+
+
+-------------------------------------------------------------------
Old:
----
osc-tiny-0.3.3.tar.gz
New:
----
osc-tiny-0.4.1.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-osc-tiny.spec ++++++
--- /var/tmp/diff_new_pack.ZIVeAq/_old 2021-11-03 17:27:17.921371114 +0100
+++ /var/tmp/diff_new_pack.ZIVeAq/_new 2021-11-03 17:27:17.925371116 +0100
@@ -19,7 +19,7 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
%define skip_python2 1
Name: python-osc-tiny
-Version: 0.3.3
+Version: 0.4.1
Release: 0
Summary: Client API for openSUSE BuildService
License: MIT
++++++ osc-tiny-0.3.3.tar.gz -> osc-tiny-0.4.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.3.3/PKG-INFO new/osc-tiny-0.4.1/PKG-INFO
--- old/osc-tiny-0.3.3/PKG-INFO 2021-02-24 11:35:58.000000000 +0100
+++ new/osc-tiny-0.4.1/PKG-INFO 2021-09-22 11:55:15.028164000 +0200
@@ -1,58 +1,12 @@
Metadata-Version: 2.1
Name: osc-tiny
-Version: 0.3.3
+Version: 0.4.1
Summary: Client API for openSUSE BuildService
Home-page: http://github.com/crazyscientist/osc-tiny
Author: Andreas Hasenkopf
Author-email: [email protected]
License: MIT
Download-URL: http://github.com/crazyscientist/osc-tiny/tarball/master
-Description: OSC Tiny
- ========
-
- [](https://travis-ci.com/crazyscientist/osc-tiny)
- [](https://coveralls.io/github/crazyscientist/osc-tiny)
- [](https://badge.fury.io/py/osc-tiny)
-
- This project aims to provide a minimalistic and transparent client for
accessing
- the [OpenBuildService](https://openbuildservice.org/)
- [API](https://build.opensuse.org/apidocs/index).
-
- Usage
- -----
-
- This is a very basic example:
-
- ```python
- from osctiny import Osc
-
- osc = Osc(
- url="https://api.opensuse.org",
- username="foobar",
- password="helloworld",
- )
-
- # This returns an LXML object
- osc.requests.get(request_id=1)
-
- # This returns an LXML object
- osc.search.request(xpath="state/@name='new'")
- ```
-
- For more documentation see https://osc-tiny.readthedocs.io/en/latest/
-
- Contributing
- ------------
-
- Any contributions are welcome.
-
- Links
- -----
-
- * https://osc-tiny.readthedocs.io/en/latest/
- * https://openbuildservice.org/
- * https://build.opensuse.org/apidocs/index
-
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
@@ -64,3 +18,52 @@
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Description-Content-Type: text/markdown
+License-File: LICENSE
+
+OSC Tiny
+========
+
+[](https://travis-ci.com/crazyscientist/osc-tiny)
+[](https://coveralls.io/github/crazyscientist/osc-tiny)
+[](https://badge.fury.io/py/osc-tiny)
+
+This project aims to provide a minimalistic and transparent client for
accessing
+the [OpenBuildService](https://openbuildservice.org/)
+[API](https://build.opensuse.org/apidocs/index).
+
+Usage
+-----
+
+This is a very basic example:
+
+```python
+from osctiny import Osc
+
+osc = Osc(
+ url="https://api.opensuse.org",
+ username="foobar",
+ password="helloworld",
+)
+
+# This returns an LXML object
+osc.requests.get(request_id=1)
+
+# This returns an LXML object
+osc.search.request(xpath="state/@name='new'")
+```
+
+For more documentation see https://osc-tiny.readthedocs.io/en/latest/
+
+Contributing
+------------
+
+Any contributions are welcome.
+
+Links
+-----
+
+* https://osc-tiny.readthedocs.io/en/latest/
+* https://openbuildservice.org/
+* https://build.opensuse.org/apidocs/index
+
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.3.3/osc_tiny.egg-info/PKG-INFO
new/osc-tiny-0.4.1/osc_tiny.egg-info/PKG-INFO
--- old/osc-tiny-0.3.3/osc_tiny.egg-info/PKG-INFO 2021-02-24
11:35:58.000000000 +0100
+++ new/osc-tiny-0.4.1/osc_tiny.egg-info/PKG-INFO 2021-09-22
11:55:15.000000000 +0200
@@ -1,58 +1,12 @@
Metadata-Version: 2.1
Name: osc-tiny
-Version: 0.3.3
+Version: 0.4.1
Summary: Client API for openSUSE BuildService
Home-page: http://github.com/crazyscientist/osc-tiny
Author: Andreas Hasenkopf
Author-email: [email protected]
License: MIT
Download-URL: http://github.com/crazyscientist/osc-tiny/tarball/master
-Description: OSC Tiny
- ========
-
- [](https://travis-ci.com/crazyscientist/osc-tiny)
- [](https://coveralls.io/github/crazyscientist/osc-tiny)
- [](https://badge.fury.io/py/osc-tiny)
-
- This project aims to provide a minimalistic and transparent client for
accessing
- the [OpenBuildService](https://openbuildservice.org/)
- [API](https://build.opensuse.org/apidocs/index).
-
- Usage
- -----
-
- This is a very basic example:
-
- ```python
- from osctiny import Osc
-
- osc = Osc(
- url="https://api.opensuse.org",
- username="foobar",
- password="helloworld",
- )
-
- # This returns an LXML object
- osc.requests.get(request_id=1)
-
- # This returns an LXML object
- osc.search.request(xpath="state/@name='new'")
- ```
-
- For more documentation see https://osc-tiny.readthedocs.io/en/latest/
-
- Contributing
- ------------
-
- Any contributions are welcome.
-
- Links
- -----
-
- * https://osc-tiny.readthedocs.io/en/latest/
- * https://openbuildservice.org/
- * https://build.opensuse.org/apidocs/index
-
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
@@ -64,3 +18,52 @@
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Description-Content-Type: text/markdown
+License-File: LICENSE
+
+OSC Tiny
+========
+
+[](https://travis-ci.com/crazyscientist/osc-tiny)
+[](https://coveralls.io/github/crazyscientist/osc-tiny)
+[](https://badge.fury.io/py/osc-tiny)
+
+This project aims to provide a minimalistic and transparent client for
accessing
+the [OpenBuildService](https://openbuildservice.org/)
+[API](https://build.opensuse.org/apidocs/index).
+
+Usage
+-----
+
+This is a very basic example:
+
+```python
+from osctiny import Osc
+
+osc = Osc(
+ url="https://api.opensuse.org",
+ username="foobar",
+ password="helloworld",
+)
+
+# This returns an LXML object
+osc.requests.get(request_id=1)
+
+# This returns an LXML object
+osc.search.request(xpath="state/@name='new'")
+```
+
+For more documentation see https://osc-tiny.readthedocs.io/en/latest/
+
+Contributing
+------------
+
+Any contributions are welcome.
+
+Links
+-----
+
+* https://osc-tiny.readthedocs.io/en/latest/
+* https://openbuildservice.org/
+* https://build.opensuse.org/apidocs/index
+
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.3.3/osc_tiny.egg-info/SOURCES.txt
new/osc-tiny-0.4.1/osc_tiny.egg-info/SOURCES.txt
--- old/osc-tiny-0.3.3/osc_tiny.egg-info/SOURCES.txt 2021-02-24
11:35:58.000000000 +0100
+++ new/osc-tiny-0.4.1/osc_tiny.egg-info/SOURCES.txt 2021-09-22
11:55:15.000000000 +0200
@@ -37,9 +37,12 @@
osctiny/tests/test_requests.py
osctiny/tests/test_search.py
osctiny/tests/test_utils.py
+osctiny/tests/osc/__init__.py
+osctiny/tests/osc/conf.py
osctiny/utils/__init__.py
osctiny/utils/backports.py
osctiny/utils/base.py
osctiny/utils/changelog.py
+osctiny/utils/conf.py
osctiny/utils/errors.py
osctiny/utils/mapping.py
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.3.3/osctiny/__init__.py
new/osc-tiny-0.4.1/osctiny/__init__.py
--- old/osc-tiny-0.3.3/osctiny/__init__.py 2021-02-24 11:35:35.000000000
+0100
+++ new/osc-tiny-0.4.1/osctiny/__init__.py 2021-09-22 11:55:07.000000000
+0200
@@ -6,4 +6,4 @@
__all__ = ['Osc', 'bs_requests', 'buildresults', 'comments', 'packages',
'projects', 'search', 'users']
-__version__ = "0.3.3"
+__version__ = "0.4.1"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.3.3/osctiny/extensions/origin.py
new/osc-tiny-0.4.1/osctiny/extensions/origin.py
--- old/osc-tiny-0.3.3/osctiny/extensions/origin.py 2021-02-24
11:35:35.000000000 +0100
+++ new/osc-tiny-0.4.1/osctiny/extensions/origin.py 2021-09-22
11:55:07.000000000 +0200
@@ -25,7 +25,6 @@
import re
from warnings import warn
-from lxml.objectify import ObjectifiedElement
from yaml import load
from ..utils.backports import lru_cache
@@ -280,10 +279,15 @@
This project is important, because it's meta can provide the list of
maintained projects.
- :return: Objectified XML element or ``None``
- :rtype: lxml.objectify.ObjectifiedElement
+ :return: Project name or ``None``
+ :rtype: str or None
+
+ .. versionchanged:: 0.4.0
+
+ Return string instead of XML object
"""
- response =
self.osc.search.project(xpath="attribute/@name='OBS:MaintenanceProject'")
+ response = self.osc.search.search(path="project/id",
+
xpath="attribute/@name='OBS:MaintenanceProject'")
projects = getattr(response, "project", [])
if len(projects) < 1:
warn("The build service defines no maintenance projects!")
@@ -291,25 +295,26 @@
if len(projects) > 1:
warn("The build service defines multiple maintenance projects!")
- return projects[0]
+ return projects[0].get("name")
@cached_property
- def maintained_projects(self, from_project=None):
+ def maintained_projects(self):
"""
Get the list of maintained projects
- By default this property uses :py:meth:`maintenance_project` and
allows usage of a specified
- ``from_project`` instead.
+ Maintained projects are identified by the presence of the
``OBS:Maintained`` attribute.
+
+ :return: Project names
+ :rtype: List of str
- :param from_project: The maintenance project to query
- :return: Objectified XML element
- :rtype: lxml.objectify.ObjectifiedElement
- """
- from_project = from_project or self.maintenance_project
- if not isinstance(from_project, ObjectifiedElement):
- from_project = self.osc.projects.get_meta(project=from_project)
+ .. versionchanged:: 0.4.0
- return [m.get("project") for m in
from_project.xpath("maintenance/maintains")]
+ Search maintained projects via the ``OBS:Maintained`` attribute
and not via the
+ maintenance project.
+ """
+ response = self.osc.search.search(path="project/id",
+
xpath="attribute/@name='OBS:Maintained'")
+ return [project.get("name") for project in getattr(response,
"project", [])]
@lru_cache(maxsize=16)
def get_project_origin_config(self, project):
@@ -529,6 +534,10 @@
:return: Generator of pairs: ('pkg', 'origin')
:rtype: generator
"""
+ if project not in self.expanded_origins:
+ warn("Project {} has no origin definition".format(project))
+ return
+
packages = self.osc.projects.get_files(project, expand='1')
for package in getattr(packages, "entry", []):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.3.3/osctiny/osc.py
new/osc-tiny-0.4.1/osctiny/osc.py
--- old/osc-tiny-0.3.3/osctiny/osc.py 2021-02-24 11:35:35.000000000 +0100
+++ new/osc-tiny-0.4.1/osctiny/osc.py 2021-09-22 11:55:07.000000000 +0200
@@ -26,6 +26,8 @@
from .extensions.bs_requests import Request as BsRequest
from .extensions.search import Search
from .extensions.users import Group, Person
+from .utils.conf import get_credentials
+from .utils.errors import OscError
try:
from cachecontrol import CacheControl
@@ -78,6 +80,7 @@
:param password: Password for login
:param verify: See `SSL Cert Verification`_ for more details
:param cache: Store API responses in a cache
+ :raises osctiny.errors.OscError: if no credentials are provided
.. versionadded:: 0.1.1
The ``cache`` parameter and the ``build`` extension
@@ -94,6 +97,9 @@
.. versionadded:: 0.3.0
The ``origins`` extension
+ .. versionchanged:: 0.4.0
+ Raises an exception when no credentials are provided
+
.. _SSL Cert Verification:
http://docs.python-requests.org/en/master/user/advanced/
#ssl-cert-verification
@@ -113,6 +119,13 @@
self.url = url or self.url
self.username = username or self.username
self.password = password or self.password
+
+ if not self.username and not self.password:
+ try:
+ self.username, self.password = get_credentials(self.url)
+ except (ValueError, NotImplementedError, FileNotFoundError) as
error:
+ raise OscError from error
+
self._session = Session()
self._session.verify = verify or get_default_verify_paths().capath
self.auth = HTTPBasicAuth(self.username, self.password)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.3.3/osctiny/tests/osc/__init__.py
new/osc-tiny-0.4.1/osctiny/tests/osc/__init__.py
--- old/osc-tiny-0.3.3/osctiny/tests/osc/__init__.py 1970-01-01
01:00:00.000000000 +0100
+++ new/osc-tiny-0.4.1/osctiny/tests/osc/__init__.py 2021-09-22
11:55:07.000000000 +0200
@@ -0,0 +1,5 @@
+"""
+Mocking of the `osc` package
+
+Without the presence of a dummy module like this one, mocking on Python 3.6
fails.
+"""
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.3.3/osctiny/tests/test_origin.py
new/osc-tiny-0.4.1/osctiny/tests/test_origin.py
--- old/osc-tiny-0.3.3/osctiny/tests/test_origin.py 2021-02-24
11:35:35.000000000 +0100
+++ new/osc-tiny-0.4.1/osctiny/tests/test_origin.py 2021-09-22
11:55:07.000000000 +0200
@@ -85,30 +85,29 @@
status = 200
body = """
<collection matches="1">
- <project name="openSUSE:Maintenance" kind="maintenance">
- <title>The openSUSE Maintenance project</title>
- <description/>
- <group groupid="maintenance-opensuse.org"
role="maintainer"/>
- <maintenance>
- <maintains project="openSUSE:Leap:15.1:Update"/>
- <maintains project="openSUSE:Leap:15.2:Update"/>
- </maintenance>
- </project>
- </collection>
+ <project name="openSUSE:Maintenance"/>
+ </collection>
+ """
+ elif "OBS:Maintained" in "".join(params.get("match", [])):
+ status = 200
+ body = """
+ <collection matches="2">
+ <project name="openSUSE:Leap:15.1:Update"/>
+ <project name="openSUSE:Leap:15.2:Update"/>
+ </collection>
"""
return status, headers, body
self.mock_request(
method=responses.GET,
- url=re.compile(self.osc.url + "/search/project/?"),
+ url=re.compile(self.osc.url + "/search/project/id"),
callback=CallbackFactory(callback)
)
with self.subTest("Maintenance Project"):
maint_project = self.osc.origins.maintenance_project
- self.assertEqual(maint_project.get("name"), "openSUSE:Maintenance")
- self.assertEqual(maint_project.get("kind"), "maintenance")
+ self.assertEqual(maint_project, "openSUSE:Maintenance")
with self.subTest("Maintained Projects"):
self.assertEqual(self.osc.origins.maintained_projects,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.3.3/osctiny/tests/test_utils.py
new/osc-tiny-0.4.1/osctiny/tests/test_utils.py
--- old/osc-tiny-0.3.3/osctiny/tests/test_utils.py 2021-02-24
11:35:35.000000000 +0100
+++ new/osc-tiny-0.4.1/osctiny/tests/test_utils.py 2021-09-22
11:55:07.000000000 +0200
@@ -1,8 +1,12 @@
# -*- coding: utf-8 -*-
+from base64 import b64encode
+from bz2 import compress
from unittest import TestCase, mock
from datetime import datetime
from io import StringIO
-from os import remove
+import os
+from pathlib import Path
+import sys
from tempfile import mkstemp
from types import GeneratorType
@@ -10,7 +14,9 @@
from pytz import _UTC, timezone
from ..utils.changelog import ChangeLog, Entry
+from ..utils.conf import get_config_path, get_credentials
+sys.path.append(os.path.dirname(__file__))
SAMPLE_CHANGES = """
-------------------------------------------------------------------
@@ -167,7 +173,7 @@
self.assertIsInstance(cl.entries, list)
self.assertEqual(len(cl.entries), 2)
finally:
- remove(path)
+ os.remove(path)
def test_parse_generative(self):
with mock.patch("osctiny.utils.changelog.open",
@@ -309,3 +315,62 @@
self.assertEqual(wmock.call_count, 1)
self.assertIn("Cannot parse changelog entry", wmock.call_args[0][0])
+
+
[email protected]("osc.conf", side_effect=ImportError, create=True)
[email protected]("pathlib.Path.is_file", return_value=True)
+class TestConfig(TestCase):
+ def test_get_config_path(self, *_):
+ with self.subTest("No env vars"):
+ with mock.patch.dict(os.environ, values={}, clear=True):
+ self.assertEqual(Path.home().joinpath(".oscrc"),
get_config_path())
+
+ with self.subTest("OSC_CONFIG"):
+ osc_config = "/foo/bar/oscrc"
+ with mock.patch.dict(os.environ, values={'OSC_CONFIG':
osc_config}, clear=True):
+ self.assertEqual(Path(osc_config), get_config_path())
+
+ def test_get_credentials(self, *_):
+ _, path1 = mkstemp()
+ _, path2 = mkstemp()
+
+ expected_insecure_credentials = ("my-dummy-user",
"my-insecure-dummy-password")
+ expected_secure_credentials = ('my-dummy-user',
'my-secure-dummy-password')
+
+ with open(path1, "w") as handle:
+ handle.write("[http://api.dummy-bs.org]\n")
+
handle.write("user={}\npass={}\n".format(*expected_insecure_credentials))
+
+ with open(path2, "w") as handle:
+ handle.write("[general]\n")
+ handle.write("apiurl=http://api.dummy-bs.org\n")
+ handle.write("[http://api.dummy-bs.org]\n")
+ handle.write("user={}\n".format(expected_secure_credentials[0]))
+ handle.write("passx={}\n".format(b64encode(compress(
+ expected_secure_credentials[1].encode("ascii")
+ )).decode("ascii")))
+
+ try:
+ with self.subTest("No URL, no default"):
+ with mock.patch.dict(os.environ, values={'OSC_CONFIG': path1},
clear=True):
+ self.assertRaises(ValueError, get_credentials)
+
+ with self.subTest("Wrong URL"):
+ with mock.patch.dict(os.environ, values={'OSC_CONFIG': path1},
clear=True):
+ self.assertRaises(ValueError, get_credentials,
"http://google.de")
+
+ with self.subTest("Wrong scheme"):
+ with mock.patch.dict(os.environ, values={'OSC_CONFIG': path1},
clear=True):
+ self.assertRaises(ValueError, get_credentials,
"https://api.dummy-bs.org")
+
+ with self.subTest("Correct URL"):
+ with mock.patch.dict(os.environ, values={'OSC_CONFIG': path1},
clear=True):
+ credentials = get_credentials("http://api.dummy-bs.org")
+ self.assertEqual(expected_insecure_credentials, credentials)
+
+ with self.subTest("No URL"):
+ with mock.patch.dict(os.environ, values={'OSC_CONFIG': path2},
clear=True):
+ self.assertEqual(expected_secure_credentials,
get_credentials())
+ finally:
+ os.remove(path1)
+ os.remove(path2)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.3.3/osctiny/utils/changelog.py
new/osc-tiny-0.4.1/osctiny/utils/changelog.py
--- old/osc-tiny-0.3.3/osctiny/utils/changelog.py 2021-02-24
11:35:35.000000000 +0100
+++ new/osc-tiny-0.4.1/osctiny/utils/changelog.py 2021-09-22
11:55:07.000000000 +0200
@@ -149,13 +149,13 @@
:param handle: An open and iterable (file) handle
:type handle: Any derived object of :py:class:`io.IOBase`
"""
- # pylint: disable=too-many-branches
+ # pylint: disable=too-many-branches,consider-using-with
entry = self.entry_factory()
if isinstance(handle, TextIOBase):
handle.seek(0)
elif isinstance(handle, (str, bytes)):
- handle = open(handle, "r")
+ handle = open(handle, "r") # pylint: disable=consider-using-with
else:
raise TypeError("Unexpected type for 'path': {}".format(
type(handle)))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.3.3/osctiny/utils/conf.py
new/osc-tiny-0.4.1/osctiny/utils/conf.py
--- old/osc-tiny-0.3.3/osctiny/utils/conf.py 1970-01-01 01:00:00.000000000
+0100
+++ new/osc-tiny-0.4.1/osctiny/utils/conf.py 2021-09-22 11:55:07.000000000
+0200
@@ -0,0 +1,107 @@
+"""
+Configuration utilities
+^^^^^^^^^^^^^^^^^^^^^^^
+
+This module provides a collection of utilities to access the configuration of
+`osc <https://github.com/openSUSE/osc>`_ in order to make it easier to create
command line tools
+with OSC Tiny.
+
+.. versionadded:: 0.4.0
+"""
+from base64 import b64decode
+from bz2 import decompress
+from configparser import ConfigParser, NoSectionError
+import os
+from pathlib import Path
+import warnings
+
+try:
+ from osc import conf as _conf
+except ImportError:
+ _conf = None
+
+
+def get_config_path():
+ """
+ Return path of ``osc`` configuration file
+
+ :return: Path
+ :raises FileNotFoundError: if no config file found
+ """
+ env_path = os.environ.get("OSC_CONFIG", None)
+ conf_path = os.environ.get('XDG_CONFIG_HOME', '~/.config')
+ if env_path:
+ path = Path(env_path)
+ if path.is_file():
+ return path
+
+ for path in (Path.home().joinpath(".oscrc"),
+ Path(conf_path).joinpath("osc/oscrc").expanduser()):
+ if path.is_file():
+ return path
+
+ raise FileNotFoundError("No `osc` configuration file found")
+
+
+def get_credentials(url=None):
+ """
+ Get credentials for Build Service instance identified by ``url``
+
+ .. important::
+
+ If the ``osc`` package is not installed, this function will only try
to extract the username
+ and password from the configuration file.
+
+ Any credentials stored on a keyring will not be accessible!
+
+ :param str url: URL of Build Service instance (including schema). If not
specified, the value
+ from the ``apiurl`` parameter in the config file will be
used.
+ :return: (username, password)
+ :raises ValueError: if config provides no credentials
+ """
+ if _conf is not None:
+ # pylint: disable=protected-access
+ parser = _conf.get_configParser()
+ try:
+ if url is None:
+ url = parser["general"].get("apiurl", url)
+ cred_mgr = _conf._get_credentials_manager(url, parser)
+ username = _conf._extract_user_compat(parser, url, cred_mgr)
+ except (KeyError, NoSectionError) as error:
+ raise ValueError("`osc` config does not provide the default API
URL") from error
+
+ if not username:
+ raise ValueError("`osc` config provides no username for URL
{}".format(url))
+ password = cred_mgr.get_password(url, username, defer=False)
+ if not password:
+ raise ValueError("`osc` config provides no password for URL
{}".format(url))
+ return username, password
+
+ warnings.warn("`osc` is not installed. Not all configuration backends of
`osc` will be "
+ "available.")
+ parser = ConfigParser()
+ path = get_config_path()
+ parser.read((path))
+ try:
+ if url is None:
+ url = parser["general"].get("apiurl", url)
+ except (KeyError, NoSectionError) as error:
+ raise ValueError("`osc` config does not provide the default API URL")
from error
+
+ if url not in parser.sections():
+ raise ValueError("`osc` config has no section for URL {}".format(url))
+
+ username = parser[url].get("user", None)
+ if not username:
+ raise ValueError("`osc` config provides no username for URL
{}".format(url))
+
+ password = parser[url].get("pass", None)
+ if not password:
+ password = parser[url].get("passx", None)
+ if password:
+ password =
decompress(b64decode(password.encode("ascii"))).decode("ascii")
+
+ if not password:
+ raise ValueError("`osc` config provides no password for URL
{}".format(url))
+
+ return username, password
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/osc-tiny-0.3.3/setup.py new/osc-tiny-0.4.1/setup.py
--- old/osc-tiny-0.3.3/setup.py 2021-02-24 11:35:35.000000000 +0100
+++ new/osc-tiny-0.4.1/setup.py 2021-09-22 11:55:07.000000000 +0200
@@ -19,7 +19,7 @@
setup(
name='osc-tiny',
- version='0.3.3',
+ version='0.4.1',
description='Client API for openSUSE BuildService',
long_description=long_description,
long_description_content_type="text/markdown",