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 2022-09-19 16:03:39
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-osc-tiny (Old)
 and      /work/SRC/openSUSE:Factory/.python-osc-tiny.new.2083 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-osc-tiny"

Mon Sep 19 16:03:39 2022 rev:21 rq:1004700 version:0.7.3

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-osc-tiny/python-osc-tiny.changes  
2022-08-17 18:25:19.387461136 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-osc-tiny.new.2083/python-osc-tiny.changes    
    2022-09-19 16:03:47.586223507 +0200
@@ -1,0 +2,19 @@
+Mon Sep 19 12:11:43 UTC 2022 - Andreas Hasenkopf <ahasenk...@suse.com>
+
+- Release 0.7.3
+  * Consider "boolean" parameters of specific API endpoints (fixes #97)
+    Workaround for
+    https://github.com/openSUSE/open-build-service/issues/9715
+
+-------------------------------------------------------------------
+Mon Sep 19 07:45:03 UTC 2022 - Andreas Hasenkopf <ahasenk...@suse.com>
+
+- Release 0.7.2
+  * Suppress logging of response content when streaming
+  * Fixed error in docstring
+  * Removed Python2 support libararies (closes #81)
+  * Removed warning about boolean query params
+  * Fixed issues in `Project.put_meta` (fixes #84)
+  * Deprecated `projects.put_meta` in favor of using `set_meta` (fixes #85)
+
+-------------------------------------------------------------------

Old:
----
  osc-tiny-0.7.1.tar.gz

New:
----
  osc-tiny-0.7.3.tar.gz

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

Other differences:
------------------
++++++ python-osc-tiny.spec ++++++
--- /var/tmp/diff_new_pack.fklWdO/_old  2022-09-19 16:03:48.942227129 +0200
+++ /var/tmp/diff_new_pack.fklWdO/_new  2022-09-19 16:03:48.946227140 +0200
@@ -19,7 +19,7 @@
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 %define skip_python2 1
 Name:           python-osc-tiny
-Version:        0.7.1
+Version:        0.7.3
 Release:        0
 Summary:        Client API for openSUSE BuildService
 License:        MIT

++++++ osc-tiny-0.7.1.tar.gz -> osc-tiny-0.7.3.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-tiny-0.7.1/PKG-INFO new/osc-tiny-0.7.3/PKG-INFO
--- old/osc-tiny-0.7.1/PKG-INFO 2022-08-16 14:32:49.240917400 +0200
+++ new/osc-tiny-0.7.3/PKG-INFO 2022-09-19 14:08:24.194599400 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: osc-tiny
-Version: 0.7.1
+Version: 0.7.3
 Summary: Client API for openSUSE BuildService
 Home-page: http://github.com/crazyscientist/osc-tiny
 Download-URL: http://github.com/crazyscientist/osc-tiny/tarball/master
@@ -23,9 +23,10 @@
 OSC Tiny
 ========
 
-![Build 
Status](https://github.com/crazyscientist/osc-tiny/actions/workflows/default.yml/badge.svg?branch=master)]
+![Build 
Status](https://github.com/crazyscientist/osc-tiny/actions/workflows/default.yml/badge.svg?branch=master)
 ![Publish 
Status](https://github.com/crazyscientist/osc-tiny/actions/workflows/publish.yml/badge.svg)
 [![PyPI 
version](https://badge.fury.io/py/osc-tiny.svg)](https://badge.fury.io/py/osc-tiny)
+[![Coverage 
badge](https://raw.githubusercontent.com/crazyscientist/osc-tiny/python-coverage-comment-action-data/badge.svg)](https://github.com/crazyscientist/osc-tiny/tree/python-coverage-comment-action-data)
 
 This project aims to provide a minimalistic and transparent client for 
accessing
 the [OpenBuildService](https://openbuildservice.org/) 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-tiny-0.7.1/README.md new/osc-tiny-0.7.3/README.md
--- old/osc-tiny-0.7.1/README.md        2022-08-16 14:32:35.000000000 +0200
+++ new/osc-tiny-0.7.3/README.md        2022-09-19 14:08:14.000000000 +0200
@@ -1,9 +1,10 @@
 OSC Tiny
 ========
 
-![Build 
Status](https://github.com/crazyscientist/osc-tiny/actions/workflows/default.yml/badge.svg?branch=master)]
+![Build 
Status](https://github.com/crazyscientist/osc-tiny/actions/workflows/default.yml/badge.svg?branch=master)
 ![Publish 
Status](https://github.com/crazyscientist/osc-tiny/actions/workflows/publish.yml/badge.svg)
 [![PyPI 
version](https://badge.fury.io/py/osc-tiny.svg)](https://badge.fury.io/py/osc-tiny)
+[![Coverage 
badge](https://raw.githubusercontent.com/crazyscientist/osc-tiny/python-coverage-comment-action-data/badge.svg)](https://github.com/crazyscientist/osc-tiny/tree/python-coverage-comment-action-data)
 
 This project aims to provide a minimalistic and transparent client for 
accessing
 the [OpenBuildService](https://openbuildservice.org/) 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-tiny-0.7.1/osc_tiny.egg-info/PKG-INFO 
new/osc-tiny-0.7.3/osc_tiny.egg-info/PKG-INFO
--- old/osc-tiny-0.7.1/osc_tiny.egg-info/PKG-INFO       2022-08-16 
14:32:49.000000000 +0200
+++ new/osc-tiny-0.7.3/osc_tiny.egg-info/PKG-INFO       2022-09-19 
14:08:24.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: osc-tiny
-Version: 0.7.1
+Version: 0.7.3
 Summary: Client API for openSUSE BuildService
 Home-page: http://github.com/crazyscientist/osc-tiny
 Download-URL: http://github.com/crazyscientist/osc-tiny/tarball/master
@@ -23,9 +23,10 @@
 OSC Tiny
 ========
 
-![Build 
Status](https://github.com/crazyscientist/osc-tiny/actions/workflows/default.yml/badge.svg?branch=master)]
+![Build 
Status](https://github.com/crazyscientist/osc-tiny/actions/workflows/default.yml/badge.svg?branch=master)
 ![Publish 
Status](https://github.com/crazyscientist/osc-tiny/actions/workflows/publish.yml/badge.svg)
 [![PyPI 
version](https://badge.fury.io/py/osc-tiny.svg)](https://badge.fury.io/py/osc-tiny)
+[![Coverage 
badge](https://raw.githubusercontent.com/crazyscientist/osc-tiny/python-coverage-comment-action-data/badge.svg)](https://github.com/crazyscientist/osc-tiny/tree/python-coverage-comment-action-data)
 
 This project aims to provide a minimalistic and transparent client for 
accessing
 the [OpenBuildService](https://openbuildservice.org/) 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-tiny-0.7.1/osctiny/__init__.py 
new/osc-tiny-0.7.3/osctiny/__init__.py
--- old/osc-tiny-0.7.1/osctiny/__init__.py      2022-08-16 14:32:35.000000000 
+0200
+++ new/osc-tiny-0.7.3/osctiny/__init__.py      2022-09-19 14:08:14.000000000 
+0200
@@ -6,4 +6,4 @@
 
 __all__ = ['Osc', 'bs_requests', 'buildresults', 'comments', 'packages',
            'projects', 'search', 'users']
-__version__ = "0.7.1"
+__version__ = "0.7.3"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-tiny-0.7.1/osctiny/extensions/bs_requests.py 
new/osc-tiny-0.7.3/osctiny/extensions/bs_requests.py
--- old/osc-tiny-0.7.1/osctiny/extensions/bs_requests.py        2022-08-16 
14:32:35.000000000 +0200
+++ new/osc-tiny-0.7.3/osctiny/extensions/bs_requests.py        2022-09-19 
14:08:14.000000000 +0200
@@ -2,9 +2,7 @@
 Requests extension
 ------------------
 """
-from __future__ import unicode_literals
-from six.moves.urllib.parse import urljoin
-from six import text_type
+from urllib.parse import urljoin
 
 from ..utils.base import ExtensionBase
 
@@ -17,7 +15,7 @@
 
     @staticmethod
     def _validate_id(request_id):
-        request_id = text_type(request_id)
+        request_id = str(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.7.1/osctiny/extensions/buildresults.py 
new/osc-tiny-0.7.3/osctiny/extensions/buildresults.py
--- old/osc-tiny-0.7.1/osctiny/extensions/buildresults.py       2022-08-16 
14:32:35.000000000 +0200
+++ new/osc-tiny-0.7.3/osctiny/extensions/buildresults.py       2022-09-19 
14:08:14.000000000 +0200
@@ -3,8 +3,7 @@
 ----------------------
 """
 # pylint: disable=too-few-public-methods
-from __future__ import unicode_literals
-from six.moves.urllib.parse import urljoin
+from urllib.parse import urljoin
 
 from ..utils.base import ExtensionBase
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-tiny-0.7.1/osctiny/extensions/comments.py 
new/osc-tiny-0.7.3/osctiny/extensions/comments.py
--- old/osc-tiny-0.7.1/osctiny/extensions/comments.py   2022-08-16 
14:32:35.000000000 +0200
+++ new/osc-tiny-0.7.3/osctiny/extensions/comments.py   2022-09-19 
14:08:14.000000000 +0200
@@ -2,10 +2,8 @@
 Comments extension
 ------------------
 """
-from __future__ import unicode_literals
 import os
-from six.moves.urllib.parse import urljoin
-from six import text_type
+from urllib.parse import urljoin
 
 from ..utils.base import ExtensionBase
 
@@ -53,7 +51,7 @@
         response = self.osc.request(
             url=urljoin(self.osc.url,
                         os.path.join(*([self.base_path, obj_type]
-                                       + [text_type(x) for x in ids]))),
+                                       + [str(x) for x in ids]))),
             method="GET",
         )
         return self.osc.get_objectified_xml(response)
@@ -81,9 +79,9 @@
         """
         self._validate(obj_type, ids)
         url = urljoin(self.osc.url,
-                      os.path.join(*([self.base_path, obj_type] + 
[text_type(x) for x in ids])))
+                      os.path.join(*([self.base_path, obj_type] + [str(x) for 
x in ids])))
         params = {}
-        if parent_id and text_type(parent_id).isnumeric():
+        if parent_id and str(parent_id).isnumeric():
             params["parent_id"] = parent_id
 
         response = self.osc.request(
@@ -109,7 +107,7 @@
         :return: ``True``, if successful. Otherwise API response
         :rtype: bool or lxml.objectify.ObjectifiedElement
         """
-        url = urljoin(self.osc.url, '/comment/' + text_type(comment_id))
+        url = urljoin(self.osc.url, '/comment/' + str(comment_id))
 
         response = self.osc.request(
             url=url,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-tiny-0.7.1/osctiny/extensions/distributions.py 
new/osc-tiny-0.7.3/osctiny/extensions/distributions.py
--- old/osc-tiny-0.7.1/osctiny/extensions/distributions.py      2022-08-16 
14:32:35.000000000 +0200
+++ new/osc-tiny-0.7.3/osctiny/extensions/distributions.py      2022-09-19 
14:08:14.000000000 +0200
@@ -2,10 +2,7 @@
 Distributions extension
 -----------------------
 """
-from __future__ import unicode_literals
-
-from six.moves.urllib.parse import urljoin
-from six import text_type
+from urllib.parse import urljoin
 
 from ..utils.base import ExtensionBase
 
@@ -49,7 +46,7 @@
         response = self.osc.request(
             url=urljoin(
                 self.osc.url,
-                "/".join((self.base_path, text_type(distribution_id)))
+                "/".join((self.base_path, str(distribution_id)))
             ),
             method="GET"
         )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-tiny-0.7.1/osctiny/extensions/issues.py 
new/osc-tiny-0.7.3/osctiny/extensions/issues.py
--- old/osc-tiny-0.7.1/osctiny/extensions/issues.py     2022-08-16 
14:32:35.000000000 +0200
+++ new/osc-tiny-0.7.3/osctiny/extensions/issues.py     2022-09-19 
14:08:14.000000000 +0200
@@ -2,11 +2,9 @@
 Issues extension
 ----------------
 """
-from __future__ import unicode_literals
 import os
 
-from six.moves.urllib.parse import urljoin
-from six import text_type
+from urllib.parse import urljoin
 
 from ..utils.backports import lru_cache
 from ..utils.base import ExtensionBase
@@ -22,7 +20,7 @@
 
     @staticmethod
     def _validate(value):
-        return text_type(value)
+        return str(value)
 
     @lru_cache(maxsize=1)
     def get_trackers(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-tiny-0.7.1/osctiny/extensions/origin.py 
new/osc-tiny-0.7.3/osctiny/extensions/origin.py
--- old/osc-tiny-0.7.1/osctiny/extensions/origin.py     2022-08-16 
14:32:35.000000000 +0200
+++ new/osc-tiny-0.7.3/osctiny/extensions/origin.py     2022-09-19 
14:08:14.000000000 +0200
@@ -27,17 +27,11 @@
 
 from yaml import load
 
-from ..utils.backports import lru_cache
+from ..utils.backports import lru_cache, cached_property
 from ..utils.base import ExtensionBase
 from ..utils.mapping import LazyOscMappable
 
 try:
-    from functools import cached_property
-except ImportError:
-    # Support for Python3 prior 3.8
-    from cached_property import cached_property
-
-try:
     from yaml import CSafeLoader as SafeLoader
 except ImportError:
     # If libyaml installed, we should fall back to the SafeLoader
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-tiny-0.7.1/osctiny/extensions/packages.py 
new/osc-tiny-0.7.3/osctiny/extensions/packages.py
--- old/osc-tiny-0.7.1/osctiny/extensions/packages.py   2022-08-16 
14:32:35.000000000 +0200
+++ new/osc-tiny-0.7.3/osctiny/extensions/packages.py   2022-09-19 
14:08:14.000000000 +0200
@@ -2,10 +2,8 @@
 Packages extension
 ------------------
 """
-from __future__ import unicode_literals
 import os
-from six.moves.urllib.parse import urljoin
-from six import text_type
+from urllib.parse import urljoin
 
 from lxml.etree import tounicode, SubElement, Element
 from lxml.objectify import fromstring
@@ -105,7 +103,7 @@
         :type meta: str or lxml.objectify.ObjectifiedElement
         :return:
         """
-        if isinstance(meta, text_type):
+        if isinstance(meta, (str, bytes)):
             meta = fromstring(meta)
 
         if meta is not None:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-tiny-0.7.1/osctiny/extensions/projects.py 
new/osc-tiny-0.7.3/osctiny/extensions/projects.py
--- old/osc-tiny-0.7.1/osctiny/extensions/projects.py   2022-08-16 
14:32:35.000000000 +0200
+++ new/osc-tiny-0.7.3/osctiny/extensions/projects.py   2022-09-19 
14:08:14.000000000 +0200
@@ -2,10 +2,9 @@
 Projects extension
 ------------------
 """
-from __future__ import unicode_literals
 import re
-from six.moves.urllib.parse import urljoin
-from six import text_type
+from urllib.parse import urljoin
+from warnings import warn
 
 from lxml.etree import tounicode
 from lxml.objectify import fromstring, SubElement
@@ -15,8 +14,6 @@
 
 TEMPLATE_CREATE_ATTR = "<attributes><attribute namespace='' 
name=''></attribute></attributes>"
 TEMPLATE_META = "<project name=''><title></title><description></description>" \
-                "<person userid='' role='bugowner'/>" \
-                "<person userid='' role='maintainer'/>" \
                 "<build><enable/></build><publish><disable/></publish>" \
                 "<debuginfo><enable/></debuginfo></project>"
 
@@ -73,6 +70,33 @@
 
         .. versionadded:: 0.1.5
 
+        .. deprecated:: 0.7.2
+           Use :meth:`set_meta` instead
+        :param project: name of project
+        :param metafile: Complete metafile
+        :type metafile: str or ElementTree
+        :param title: Title for meta file
+        :param description: Description for meta file
+        :param bugowner: Bugowner for meta file
+        :param maintainer: Maintainer for meta file
+        :return: ``True``, if successful. Otherwise API response
+        :rtype: bool or lxml.objectify.ObjectifiedElement
+        """
+        warn("Deprecated. Use projects.set_meta instead")
+
+        return self.set_meta(project, metafile, title, description, bugowner,
+                      maintainer)
+
+    # pylint: disable=too-many-arguments
+    def set_meta(self, project, metafile=None, title=None, description=None,
+                 bugowner=None, maintainer=None):
+        """
+        Edit project meta data or create a new project
+
+        If no ``metafile`` is provided, a default template is used.
+
+        .. versionadded:: 0.7.2
+
         :param project: name of project
         :param metafile: Complete metafile
         :type metafile: str or ElementTree
@@ -86,24 +110,34 @@
         if metafile is None:
             metafile = TEMPLATE_META
 
-        if isinstance(metafile, text_type):
+        if isinstance(metafile, (str, bytes)):
             metafile = fromstring(metafile)
 
         metafile.set("name", project)
 
-        # pylint: disable=protected-access
-        if title:
-            metafile.title._setText(title)
-        if description:
-            metafile.description._setText(description)
+        for required_field, text in (('title', title), ('description', 
description)):
+            elem = metafile.find(required_field)
+            if elem is None:
+                elem = SubElement(metafile, required_field)
+
+            if text is not None:
+                # pylint: disable=protected-access
+                elem._setText(text)
+
+        def add_person(role: str, userid: str) -> None:
+            person = metafile.xpath(f"person[@role='{role}']")
+            if not person:
+                person = [SubElement(metafile, 'person', role=role)]
+            person[0].set("userid", userid)
+
         if bugowner:
-            person = metafile.xpath("person[@role='bugowner']")
-            if person:
-                person[0].set("userid", bugowner)
+            add_person("bugowner", bugowner)
+
         if maintainer:
-            person = metafile.xpath("person[@role='maintainer']")
-            if person:
-                person[0].set("userid", maintainer)
+            add_person("maintainer", maintainer)
+
+        metafile.insert(0, metafile.title)
+        metafile.insert(1, metafile.description)
 
         response = self.osc.request(
             url=urljoin(self.osc.url,
@@ -134,7 +168,7 @@
         """
         kwargs["meta"] = meta
         if rev:
-            kwargs["rev"] = text_type(rev)
+            kwargs["rev"] = str(rev)
         response = self.osc.request(
             url=urljoin(
                 self.osc.url,
@@ -207,7 +241,7 @@
         for val in value:
             elem = SubElement(attr_xml.attribute, "value")
             # pylint: disable=protected-access
-            elem._setText(text_type(val))
+            elem._setText(str(val))
 
         response = self.osc.request(
             url=url,
@@ -352,7 +386,7 @@
         .. versionadded:: 0.1.2
 
         :param project: Project name
-        :return: ``True``, if package exists, otherwise ``False``
+        :return: ``True``, if project exists, otherwise ``False``
         """
         response = self.osc.request(
             url=urljoin(
@@ -365,4 +399,4 @@
 
         return response.status_code == 200
 
-    create = put_meta
+    create = set_meta
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-tiny-0.7.1/osctiny/extensions/search.py 
new/osc-tiny-0.7.3/osctiny/extensions/search.py
--- old/osc-tiny-0.7.1/osctiny/extensions/search.py     2022-08-16 
14:32:35.000000000 +0200
+++ new/osc-tiny-0.7.3/osctiny/extensions/search.py     2022-09-19 
14:08:14.000000000 +0200
@@ -2,8 +2,7 @@
 Search extension
 ----------------
 """
-from __future__ import unicode_literals
-from six.moves.urllib.parse import urljoin
+from urllib.parse import urljoin
 
 from ..utils.base import ExtensionBase
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-tiny-0.7.1/osctiny/extensions/users.py 
new/osc-tiny-0.7.3/osctiny/extensions/users.py
--- old/osc-tiny-0.7.1/osctiny/extensions/users.py      2022-08-16 
14:32:35.000000000 +0200
+++ new/osc-tiny-0.7.3/osctiny/extensions/users.py      2022-09-19 
14:08:14.000000000 +0200
@@ -2,8 +2,7 @@
 Persons and groups extension
 ----------------------------
 """
-from __future__ import unicode_literals
-from six.moves.urllib.parse import urljoin
+from urllib.parse import urljoin
 
 from ..utils.base import ExtensionBase
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-tiny-0.7.1/osctiny/osc.py 
new/osc-tiny-0.7.3/osctiny/osc.py
--- old/osc-tiny-0.7.1/osctiny/osc.py   2022-08-16 14:32:35.000000000 +0200
+++ new/osc-tiny-0.7.3/osctiny/osc.py   2022-09-19 14:08:14.000000000 +0200
@@ -36,6 +36,7 @@
 from .extensions.search import Search
 from .extensions.users import Group, Person
 from .utils.auth import HttpSignatureAuth
+from .utils.backports import cached_property
 from .utils.conf import BOOLEAN_PARAMS, get_credentials
 from .utils.errors import OscError
 
@@ -129,7 +130,7 @@
     default_connection_retries = 5
     default_retry_timeout = 5
 
-    def __init__(self, url: str = None, username: typing.Optional[str] = None,
+    def __init__(self, url: typing.Optional[str] = None, username: 
typing.Optional[str] = None,
                  password: typing.Optional[str] = None, verify: 
typing.Optional[str] = None,
                  cache: bool = False,
                  ssh_key_file: typing.Optional[typing.Union[Path, str]] = 
None):
@@ -301,8 +302,8 @@
         req = Request(
             method,
             url.replace("#", quote("#")).replace("?", quote("?")),
-            data=self.handle_params(data),
-            params=self.handle_params(params)
+            data=self.handle_params(url=url, method=method, params=data),
+            params=self.handle_params(url=url, method=method, params=params)
         )
         prepped_req = session.prepare_request(req)
         prepped_req.headers['Content-Type'] = "application/octet-stream"
@@ -341,15 +342,38 @@
                 logger.info("Server replied with status %d", 
response.status_code)
                 logger.debug("Response headers:\n%s\n---",
                              "\n".join(f"{k}: {v}" for k, v in 
response.headers.items()))
-                logger.debug("Response content:\n%s\n---", response.text)
+                if not stream:
+                    # The response content must not be accessed when streaming
+                    logger.debug("Response content:\n%s\n---", response.text)
                 if raise_for_status:
                     response.raise_for_status()
                 return response
 
         return None
 
-    @staticmethod
-    def handle_params(params):
+    @cached_property
+    def _boolean_param_map(self) -> typing.Dict[typing.Pattern, 
typing.Dict[str,
+                                                                            
typing.Tuple[str]]]:
+        """
+        Return mapping table to identify boolean parameters for a given API 
endpoint
+        """
+        return {re.compile(url): data for url, data in BOOLEAN_PARAMS.items()}
+
+    def get_boolean_params(self, url: str, method: str) -> typing.Tuple[str]:
+        """
+        Get the actual boolean parameter for ``url`` and ``method``
+
+        .. versionadded:: 0.7.3
+        """
+        parsed_url = urlparse(url)
+        for pattern, boolean_params_for_url in self._boolean_param_map.items():
+            match = pattern.match(parsed_url.path)
+            if match:
+                return boolean_params_for_url.get(method, ())
+
+        return ()
+
+    def handle_params(self, url, method, params):
         """
         Translate request parameters to API conform format
 
@@ -366,8 +390,16 @@
 
         :param params: Request parameter
         :type params: dict or str or io.BufferedReader
+        :param url: URL to which the parameters will be sent
+        :type url: str
+        :param method: HTTP method to send request
+        :type method: str
         :return: converted data ready to be used in HTTP request
         :rtype: dict or bytes
+
+        .. versionchanged:: 0.7.3
+
+            Added the ``url`` and ``method`` parameters
         """
         if isinstance(params, bytes):
             return params
@@ -391,22 +423,21 @@
         # See: https://github.com/openSUSE/open-build-service/issues/9715
         # Also, there are parameters giving the impression that they are 
boolean, but actually are
         # not.
+        boolean_params = self.get_boolean_params(url=url, method=method)
         unexpected_bools = {key for key, value in params.items()
-                            if isinstance(value, bool) and key not in 
BOOLEAN_PARAMS}
+                            if isinstance(value, bool) and key not in 
boolean_params}
         if unexpected_bools:
-            warnings.warn(f"Received boolean query params, which are not 
expected to be: "
-                          f"{', '.join(unexpected_bools)}")
             for key in unexpected_bools:
                 params[key] = '1' if params[key] else '0'
 
         return "&".join(
             quote(str(key))
-            if key in BOOLEAN_PARAMS
+            if key in boolean_params
             else f"{quote(str(key))}={quote(str(value))}"
             for key, value in (
                 (key, value)
                 for key, value in params.items()
-                if not (key in BOOLEAN_PARAMS and value in [False, "0", 0, 
None, ""])
+                if not (key in boolean_params and value in [False, "0", 0, 
None, ""])
             )
             if value is not None
         ).encode()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-tiny-0.7.1/osctiny/tests/test_basic.py 
new/osc-tiny-0.7.3/osctiny/tests/test_basic.py
--- old/osc-tiny-0.7.1/osctiny/tests/test_basic.py      2022-08-16 
14:32:35.000000000 +0200
+++ new/osc-tiny-0.7.3/osctiny/tests/test_basic.py      2022-09-19 
14:08:14.000000000 +0200
@@ -49,8 +49,9 @@
                 tmpfile2.unlink()
 
     def test_handle_params(self):
-        def _run(data, expected):
-            handled = self.osc.handle_params(data)
+        def _run(data, expected, 
url="https://api.example.com/source/PROJECT/PACKAGE";,
+                 method="GET"):
+            handled = self.osc.handle_params(url=url, method=method, 
params=data)
             self.assertEqual(handled, expected)
 
         data = (
@@ -79,7 +80,7 @@
                 {"view": "xml", "withissues": None},
                 b"view=xml"
             ),
-            # 'deleted' is a boolean param in the API
+            # 'deleted' is a boolean param in the project endpoint
             (
                 {"view": "xml", "deleted": 1},
                 b"view=xml&deleted"
@@ -104,11 +105,33 @@
                 {"view": "xml", "deleted": True},
                 b"view=xml&deleted"
             ),
+            # 'expand' is no boolean param in the project endpoint
+            (
+                {"expand": True},
+                b"expand=1",
+                "https://api.example.com/source/PROJECT";,
+            ),
+            (
+                {"expand": False},
+                b"expand=0",
+                "https://api.example.com/source/PROJECT";,
+            ),
+            # 'expand' is a boolean param in the package endpoint
+            (
+                {"expand": False},
+                b"",
+                "https://api.example.com/source/PROJECT/PACKAGE";,
+            ),
+            (
+                {"expand": True},
+                b"expand",
+                "https://api.example.com/source/PROJECT/PACKAGE";,
+            ),
         )
 
-        for params, expected in data:
-            with self.subTest(params):
-                _run(params, expected)
+        for dataset in data:
+            with self.subTest(dataset[0]):
+                _run(*dataset)
 
     def test_attrib_regexp(self):
         def _run(attr, expected):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-tiny-0.7.1/osctiny/tests/test_projects.py 
new/osc-tiny-0.7.3/osctiny/tests/test_projects.py
--- old/osc-tiny-0.7.1/osctiny/tests/test_projects.py   2022-08-16 
14:32:35.000000000 +0200
+++ new/osc-tiny-0.7.3/osctiny/tests/test_projects.py   2022-09-19 
14:08:14.000000000 +0200
@@ -1,7 +1,7 @@
 import re
 from urllib.parse import urlparse, parse_qs
 
-from lxml.objectify import fromstring
+from lxml.objectify import fromstring, Element
 from requests.exceptions import HTTPError
 import responses
 
@@ -25,7 +25,7 @@
             """
             parsed = urlparse(request.url)
             params.update(parse_qs(parsed.query, keep_blank_values=True))
-            if "deleted" in params:
+            if params["deleted"] == ["1"]:
                 status = 403
                 body = """<status code="no_permission_for_deleted">
                   <summary>only admins can see deleted projects</summary>
@@ -113,7 +113,7 @@
             )
 
     @responses.activate
-    def test_put_meta(self):
+    def test_set_meta(self):
         def callback(headers, params, request):
             status = 500
             body = "<status code='error'></status>"
@@ -122,9 +122,10 @@
             except Exception:
                 pass
             else:
-                match = re.search("source/(?P<project>[^/]+)/_meta",
-                                  request.url)
-                if match and meta.get("name") == match.group("project"):
+                match = re.search("source/(?P<project>[^/]+)/_meta", 
request.url)
+                children = meta.getchildren()
+                if match and meta.get("name") == match.group("project") \
+                        and children[0].tag == "title":
                     status = 200
                     body = """<status code='ok'></status>"""
 
@@ -138,7 +139,7 @@
         )
 
         with self.subTest("Valid request"):
-            self.assertTrue(self.osc.projects.put_meta(
+            self.assertTrue(self.osc.projects.set_meta(
                 project="test",
                 title="foo bar",
                 description="lorem ipsum dolor sit amet ..."
@@ -153,6 +154,29 @@
                 data=TEMPLATE_META
             )
 
+        with self.subTest("Valid Metafile"):
+            meta = fromstring(TEMPLATE_META)
+            meta.set("name", "project:foo")
+            meta.title._setText("Hello World")
+            self.assertTrue(self.osc.projects.set_meta(project="project:foo", 
metafile=meta))
+            sent_meta = fromstring(responses.calls[-1].request.body.decode())
+            self.assertEqual(sent_meta.title.text, "Hello World")
+
+        with self.subTest("Bare Metafile"):
+            meta = Element("project")
+            self.assertTrue(self.osc.projects.set_meta(
+                project="project:foo",
+                metafile=meta,
+                title="test title",
+                description="test description",
+                bugowner="bugowner",
+                maintainer="maintainer"
+            ))
+            sent_meta = fromstring(responses.calls[-1].request.body.decode())
+            self.assertEqual(sent_meta.title.text, "test title")
+            self.assertEqual(sent_meta.description.text, "test description")
+            self.assertEqual(len(sent_meta.xpath("person")), 2)
+
     @responses.activate
     def test_get_files(self):
         def callback(headers, params, request):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-tiny-0.7.1/osctiny/utils/backports.py 
new/osc-tiny-0.7.3/osctiny/utils/backports.py
--- old/osc-tiny-0.7.1/osctiny/utils/backports.py       2022-08-16 
14:32:35.000000000 +0200
+++ new/osc-tiny-0.7.3/osctiny/utils/backports.py       2022-09-19 
14:08:14.000000000 +0200
@@ -16,3 +16,11 @@
             return fun
 
         return wrapper
+
+
+try:
+    # pylint: disable=unused-import
+    from functools import cached_property
+except ImportError:
+    # Support for Python3 prior 3.8
+    from cached_property import cached_property
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-tiny-0.7.1/osctiny/utils/conf.py 
new/osc-tiny-0.7.3/osctiny/utils/conf.py
--- old/osc-tiny-0.7.1/osctiny/utils/conf.py    2022-08-16 14:32:35.000000000 
+0200
+++ new/osc-tiny-0.7.3/osctiny/utils/conf.py    2022-09-19 14:08:14.000000000 
+0200
@@ -23,27 +23,22 @@
 
 
 # Query parameters that are considered to be boolean by the build service
-BOOLEAN_PARAMS = (
-    "add_repositories",
-    "deleted",
-    "emptylink",
-    "expand",
-    "extend_package_names",
-    "extend_package_names",
-    "ignoredevel",
-    "keeplink",
-    "lastbuild",
-    "lastworking",
-    "locallink",
-    "meta",
-    "multibuild",
-    "noaccess",
-    "parse",
-    "repairlink",
-    "update_path_elements",
-    "withdownloadurl",
-    "withlinked",
-)
+BOOLEAN_PARAMS = {
+    "^/source/[^/]+/[^/]+/?$": {
+        'GET': ('emptylink', 'expand', 'meta', 'lastworking', 'withlinked', 
'deleted', 'parse'),
+        'POST': ('ignoredevel', 'add_repositories', 'noaccess', 
'update_path_elements',
+                 'extend_package_names', 'extend_package_names', 'keeplink', 
'repairlink')
+    },
+    "^/source/[^/]+/[^/]+/[^/]+$": {
+        'PUT': ('keeplink',)
+    },
+    "^/build/[^/]+/_result$": {
+        'GET': ('lastbuild', 'locallink', 'multibuild')
+    },
+    "search/published/(binary|repoinfo|pattern)/id$": {
+        'GET': ('withdownloadurl',)
+    }
+}
 
 
 def get_config_path() -> Path:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-tiny-0.7.1/setup.py new/osc-tiny-0.7.3/setup.py
--- old/osc-tiny-0.7.1/setup.py 2022-08-16 14:32:35.000000000 +0200
+++ new/osc-tiny-0.7.3/setup.py 2022-09-19 14:08:14.000000000 +0200
@@ -26,7 +26,7 @@
 
 setup(
     name='osc-tiny',
-    version='0.7.1',
+    version='0.7.3',
     description='Client API for openSUSE BuildService',
     long_description=long_description,
     long_description_content_type="text/markdown",

Reply via email to