Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package Radicale for openSUSE:Factory 
checked in at 2022-04-20 16:55:13
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/Radicale (Old)
 and      /work/SRC/openSUSE:Factory/.Radicale.new.1941 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "Radicale"

Wed Apr 20 16:55:13 2022 rev:6 rq:970767 version:3.1.6

Changes:
--------
--- /work/SRC/openSUSE:Factory/Radicale/Radicale.changes        2022-02-18 
23:04:00.829407824 +0100
+++ /work/SRC/openSUSE:Factory/.Radicale.new.1941/Radicale.changes      
2022-04-20 16:55:18.286509541 +0200
@@ -1,0 +2,8 @@
+Tue Apr 19 09:30:05 UTC 2022 - Paolo Stivanin <[email protected]>
+
+- Update to 3.1.6:
+  * Ignore 'Not a directory' error for optional config paths
+  * Fix upload of whole address book/calendar with UIDs that collide on
+    case-insensitive filesystem
+
+-------------------------------------------------------------------

Old:
----
  Radicale-3.1.5.tar.gz

New:
----
  Radicale-3.1.6.tar.gz

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

Other differences:
------------------
++++++ Radicale.spec ++++++
--- /var/tmp/diff_new_pack.IbVO6y/_old  2022-04-20 16:55:19.222510415 +0200
+++ /var/tmp/diff_new_pack.IbVO6y/_new  2022-04-20 16:55:19.226510419 +0200
@@ -26,7 +26,7 @@
 %define vo_min_ver 0.9.6
 %define du_min_ver 2.7.3
 Name:           Radicale
-Version:        3.1.5
+Version:        3.1.6
 Release:        0
 Summary:        A CalDAV calendar and CardDav contact server
 License:        GPL-3.0-or-later

++++++ Radicale-3.1.5.tar.gz -> Radicale-3.1.6.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Radicale-3.1.5/CHANGELOG.md 
new/Radicale-3.1.6/CHANGELOG.md
--- old/Radicale-3.1.5/CHANGELOG.md     2022-02-08 16:44:08.000000000 +0100
+++ new/Radicale-3.1.6/CHANGELOG.md     2022-04-18 23:10:01.000000000 +0200
@@ -1,5 +1,13 @@
 # Changelog
 
+## 3.1.6
+
+* Ignore `Not a directory` error for optional config paths
+* Fix upload of whole address book/calendar with UIDs that collide on
+  case-insensitive filesystem
+* Remove runtime dependency on setuptools for Python>=3.9
+* Windows: Block ADS paths
+
 ## 3.1.5
 
 * Ignore configuration file if access is denied
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Radicale-3.1.5/radicale/__init__.py 
new/Radicale-3.1.6/radicale/__init__.py
--- old/Radicale-3.1.5/radicale/__init__.py     2022-02-08 16:44:08.000000000 
+0100
+++ new/Radicale-3.1.6/radicale/__init__.py     2022-04-18 23:10:01.000000000 
+0200
@@ -29,13 +29,11 @@
 import threading
 from typing import Iterable, Optional, cast
 
-import pkg_resources
-
-from radicale import config, log, types
+from radicale import config, log, types, utils
 from radicale.app import Application
 from radicale.log import logger
 
-VERSION: str = pkg_resources.get_distribution("radicale").version
+VERSION: str = utils.package_version("radicale")
 
 _application_instance: Optional[Application] = None
 _application_config_path: Optional[str] = None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Radicale-3.1.5/radicale/config.py 
new/Radicale-3.1.6/radicale/config.py
--- old/Radicale-3.1.5/radicale/config.py       2022-02-08 16:44:08.000000000 
+0100
+++ new/Radicale-3.1.6/radicale/config.py       2022-04-18 23:10:01.000000000 
+0200
@@ -283,8 +283,8 @@
                 config = {s: {o: parser[s][o] for o in parser.options(s)}
                           for s in parser.sections()}
         except Exception as e:
-            if not (ignore_if_missing and
-                    isinstance(e, (FileNotFoundError, PermissionError))):
+            if not (ignore_if_missing and isinstance(e, (
+                    FileNotFoundError, NotADirectoryError, PermissionError))):
                 raise RuntimeError("Failed to load %s: %s" % (config_source, e)
                                    ) from e
             config = Configuration.SOURCE_MISSING
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Radicale-3.1.5/radicale/httputils.py 
new/Radicale-3.1.6/radicale/httputils.py
--- old/Radicale-3.1.5/radicale/httputils.py    2022-02-08 16:44:08.000000000 
+0100
+++ new/Radicale-3.1.6/radicale/httputils.py    2022-04-18 23:10:01.000000000 
+0200
@@ -24,13 +24,25 @@
 
 import contextlib
 import os
+import pathlib
+import sys
 import time
 from http import client
-from typing import List, Mapping, cast
+from typing import List, Mapping, Union, cast
 
 from radicale import config, pathutils, types
 from radicale.log import logger
 
+if sys.version_info < (3, 9):
+    import pkg_resources
+
+    _TRAVERSABLE_LIKE_TYPE = pathlib.Path
+else:
+    import importlib.abc
+    from importlib import resources
+
+    _TRAVERSABLE_LIKE_TYPE = Union[importlib.abc.Traversable, pathlib.Path]
+
 NOT_ALLOWED: types.WSGIResponse = (
     client.FORBIDDEN, (("Content-Type", "text/plain"),),
     "Access to the requested resource forbidden.")
@@ -140,36 +152,63 @@
             "Redirected to %s" % location)
 
 
-def serve_folder(folder: str, base_prefix: str, path: str,
-                 path_prefix: str = "/.web", index_file: str = "index.html",
-                 mimetypes: Mapping[str, str] = MIMETYPES,
-                 fallback_mimetype: str = FALLBACK_MIMETYPE,
-                 ) -> types.WSGIResponse:
+def _serve_traversable(
+        traversable: _TRAVERSABLE_LIKE_TYPE, base_prefix: str, path: str,
+        path_prefix: str, index_file: str, mimetypes: Mapping[str, str],
+        fallback_mimetype: str) -> types.WSGIResponse:
     if path != path_prefix and not path.startswith(path_prefix):
         raise ValueError("path must start with path_prefix: %r --> %r" %
                          (path_prefix, path))
     assert pathutils.sanitize_path(path) == path
-    try:
-        filesystem_path = pathutils.path_to_filesystem(
-            folder, path[len(path_prefix):].strip("/"))
-    except ValueError as e:
-        logger.debug("Web content with unsafe path %r requested: %s",
-                     path, e, exc_info=True)
-        return NOT_FOUND
-    if os.path.isdir(filesystem_path) and not path.endswith("/"):
-        return redirect(base_prefix + path + "/")
-    if os.path.isdir(filesystem_path) and index_file:
-        filesystem_path = os.path.join(filesystem_path, index_file)
-    if not os.path.isfile(filesystem_path):
+    parts_path = path[len(path_prefix):].strip('/')
+    parts = parts_path.split("/") if parts_path else []
+    for part in parts:
+        if not pathutils.is_safe_filesystem_path_component(part):
+            logger.debug("Web content with unsafe path %r requested", path)
+            return NOT_FOUND
+        if (not traversable.is_dir() or
+                all(part != entry.name for entry in traversable.iterdir())):
+            return NOT_FOUND
+        traversable = traversable.joinpath(part)
+    if traversable.is_dir():
+        if not path.endswith("/"):
+            return redirect(base_prefix + path + "/")
+        if not index_file:
+            return NOT_FOUND
+        traversable = traversable.joinpath(index_file)
+    if not traversable.is_file():
         return NOT_FOUND
     content_type = MIMETYPES.get(
-        os.path.splitext(filesystem_path)[1].lower(), FALLBACK_MIMETYPE)
-    with open(filesystem_path, "rb") as f:
-        answer = f.read()
-        last_modified = time.strftime(
+        os.path.splitext(traversable.name)[1].lower(), FALLBACK_MIMETYPE)
+    headers = {"Content-Type": content_type}
+    if isinstance(traversable, pathlib.Path):
+        headers["Last-Modified"] = time.strftime(
             "%a, %d %b %Y %H:%M:%S GMT",
-            time.gmtime(os.fstat(f.fileno()).st_mtime))
-    headers = {
-        "Content-Type": content_type,
-        "Last-Modified": last_modified}
+            time.gmtime(traversable.stat().st_mtime))
+    answer = traversable.read_bytes()
     return client.OK, headers, answer
+
+
+def serve_resource(
+        package: str, resource: str, base_prefix: str, path: str,
+        path_prefix: str = "/.web", index_file: str = "index.html",
+        mimetypes: Mapping[str, str] = MIMETYPES,
+        fallback_mimetype: str = FALLBACK_MIMETYPE) -> types.WSGIResponse:
+    if sys.version_info < (3, 9):
+        traversable = pathlib.Path(
+            pkg_resources.resource_filename(package, resource))
+    else:
+        traversable = resources.files(package).joinpath(resource)
+    return _serve_traversable(traversable, base_prefix, path, path_prefix,
+                              index_file, mimetypes, fallback_mimetype)
+
+
+def serve_folder(
+        folder: str, base_prefix: str, path: str,
+        path_prefix: str = "/.web", index_file: str = "index.html",
+        mimetypes: Mapping[str, str] = MIMETYPES,
+        fallback_mimetype: str = FALLBACK_MIMETYPE) -> types.WSGIResponse:
+    # deprecated: use `serve_resource` instead
+    traversable = pathlib.Path(folder)
+    return _serve_traversable(traversable, base_prefix, path, path_prefix,
+                              index_file, mimetypes, fallback_mimetype)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Radicale-3.1.5/radicale/pathutils.py 
new/Radicale-3.1.6/radicale/pathutils.py
--- old/Radicale-3.1.5/radicale/pathutils.py    2022-02-08 16:44:08.000000000 
+0100
+++ new/Radicale-3.1.6/radicale/pathutils.py    2022-04-18 23:10:01.000000000 
+0200
@@ -257,6 +257,7 @@
     """
     return (
         bool(path) and not os.path.splitdrive(path)[0] and
+        (sys.platform != "win32" or ":" not in path) and  # Block NTFS-ADS
         not os.path.split(path)[0] and path not in (os.curdir, os.pardir) and
         not path.startswith(".") and not path.endswith("~") and
         is_safe_path_component(path))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Radicale-3.1.5/radicale/storage/__init__.py 
new/Radicale-3.1.6/radicale/storage/__init__.py
--- old/Radicale-3.1.5/radicale/storage/__init__.py     2022-02-08 
16:44:08.000000000 +0100
+++ new/Radicale-3.1.6/radicale/storage/__init__.py     2022-04-18 
23:10:01.000000000 +0200
@@ -29,7 +29,6 @@
 from typing import (Iterable, Iterator, Mapping, Optional, Sequence, Set,
                     Tuple, Union, overload)
 
-import pkg_resources
 import vobject
 
 from radicale import config
@@ -41,7 +40,7 @@
 
 CACHE_DEPS: Sequence[str] = ("radicale", "vobject", "python-dateutil",)
 CACHE_VERSION: bytes = "".join(
-    "%s=%s;" % (pkg, pkg_resources.get_distribution(pkg).version)
+    "%s=%s;" % (pkg, utils.package_version(pkg))
     for pkg in CACHE_DEPS).encode()
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/Radicale-3.1.5/radicale/storage/multifilesystem/upload.py 
new/Radicale-3.1.6/radicale/storage/multifilesystem/upload.py
--- old/Radicale-3.1.5/radicale/storage/multifilesystem/upload.py       
2022-02-08 16:44:08.000000000 +0100
+++ new/Radicale-3.1.6/radicale/storage/multifilesystem/upload.py       
2022-04-18 23:10:01.000000000 +0200
@@ -20,7 +20,7 @@
 import os
 import pickle
 import sys
-from typing import Iterable, Set, TextIO, cast
+from typing import Iterable, Iterator, TextIO, cast
 
 import radicale.item as radicale_item
 from radicale import pathutils
@@ -59,16 +59,23 @@
 
     def _upload_all_nonatomic(self, items: Iterable[radicale_item.Item],
                               suffix: str = "") -> None:
-        """Upload a new set of items.
+        """Upload a new set of items non-atomic"""
+        def is_safe_free_href(href: str) -> bool:
+            return (pathutils.is_safe_filesystem_path_component(href) and
+                    not os.path.lexists(
+                        os.path.join(self._filesystem_path, href)))
+
+        def get_safe_free_hrefs(uid: str) -> Iterator[str]:
+            for href in [uid if uid.lower().endswith(suffix.lower())
+                         else uid + suffix,
+                         radicale_item.get_etag(uid).strip('"') + suffix]:
+                if is_safe_free_href(href):
+                    yield href
+            yield radicale_item.find_available_uid(is_safe_free_href, suffix)
 
-        This takes a list of vobject items and
-        uploads them nonatomic and without existence checks.
-
-        """
         cache_folder = os.path.join(self._filesystem_path,
                                     ".Radicale.cache", "item")
         self._storage._makedirs_synced(cache_folder)
-        hrefs: Set[str] = set()
         for item in items:
             uid = item.uid
             try:
@@ -77,39 +84,24 @@
                 raise ValueError(
                     "Failed to store item %r in temporary collection %r: %s" %
                     (uid, self.path, e)) from e
-            href_candidate_funtions = [
-                lambda: uid if uid.lower().endswith(suffix.lower())
-                else uid + suffix,
-                lambda: radicale_item.get_etag(uid).strip('"') + suffix,
-                lambda: radicale_item.find_available_uid(
-                    hrefs.__contains__, suffix)]
-            href = f = None
-            while href_candidate_funtions:
-                href = href_candidate_funtions.pop(0)()
-                if href in hrefs:
-                    continue
-                if not pathutils.is_safe_filesystem_path_component(href):
-                    if not href_candidate_funtions:
-                        raise pathutils.UnsafePathError(href)
-                    continue
+            for href in get_safe_free_hrefs(uid):
                 try:
-                    f = open(pathutils.path_to_filesystem(
-                        self._filesystem_path, href),
-                        "w", newline="", encoding=self._encoding)
-                    break
+                    f = open(os.path.join(self._filesystem_path, href),
+                             "w", newline="", encoding=self._encoding)
                 except OSError as e:
-                    if href_candidate_funtions and (
-                            sys.platform != "win32" and
-                            e.errno == errno.EINVAL or
+                    if (sys.platform != "win32" and e.errno == errno.EINVAL or
                             sys.platform == "win32" and e.errno == 123):
+                        # not a valid filename
                         continue
                     raise
-            assert href is not None and f is not None
+                break
+            else:
+                raise RuntimeError("No href found for item %r in temporary "
+                                   "collection %r" % (uid, self.path))
             with f:
                 f.write(item.serialize())
                 f.flush()
                 self._storage._fsync(f)
-            hrefs.add(href)
             with open(os.path.join(cache_folder, href), "wb") as fb:
                 pickle.dump(cache_content, fb)
                 fb.flush()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/Radicale-3.1.5/radicale/tests/static/event_multiple_case_sensitive_uids.ics 
new/Radicale-3.1.6/radicale/tests/static/event_multiple_case_sensitive_uids.ics
--- 
old/Radicale-3.1.5/radicale/tests/static/event_multiple_case_sensitive_uids.ics 
    1970-01-01 01:00:00.000000000 +0100
+++ 
new/Radicale-3.1.6/radicale/tests/static/event_multiple_case_sensitive_uids.ics 
    2022-04-18 23:10:01.000000000 +0200
@@ -0,0 +1,16 @@
+BEGIN:VCALENDAR
+PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN
+VERSION:2.0
+BEGIN:VEVENT
+UID:event
+SUMMARY:Event 1
+DTSTART:20130901T190000
+DTEND:20130901T200000
+END:VEVENT
+BEGIN:VEVENT
+UID:EVENT
+SUMMARY:Event 2
+DTSTART:20130901T200000
+DTEND:20130901T210000
+END:VEVENT
+END:VCALENDAR
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Radicale-3.1.5/radicale/tests/test_base.py 
new/Radicale-3.1.6/radicale/tests/test_base.py
--- old/Radicale-3.1.5/radicale/tests/test_base.py      2022-02-08 
16:44:08.000000000 +0100
+++ new/Radicale-3.1.6/radicale/tests/test_base.py      2022-04-18 
23:10:01.000000000 +0200
@@ -243,6 +243,13 @@
             for uid2 in uids[i + 1:]:
                 assert uid1 != uid2
 
+    def test_put_whole_calendar_case_sensitive_uids(self) -> None:
+        """Create a whole calendar with case-sensitive UIDs."""
+        events = get_file_content("event_multiple_case_sensitive_uids.ics")
+        self.put("/calendar.ics/", events)
+        _, answer = self.get("/calendar.ics/")
+        assert "\r\nUID:event\r\n" in answer and "\r\nUID:EVENT\r\n" in answer
+
     def test_put_whole_addressbook(self) -> None:
         """Create and overwrite a whole addressbook."""
         contacts = get_file_content("contact_multiple.vcf")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Radicale-3.1.5/radicale/tests/test_server.py 
new/Radicale-3.1.6/radicale/tests/test_server.py
--- old/Radicale-3.1.5/radicale/tests/test_server.py    2022-02-08 
16:44:08.000000000 +0100
+++ new/Radicale-3.1.6/radicale/tests/test_server.py    2022-04-18 
23:10:01.000000000 +0200
@@ -28,7 +28,8 @@
 import threading
 import time
 from configparser import RawConfigParser
-from typing import Callable, Dict, NoReturn, Optional, Tuple, cast
+from http.client import HTTPMessage
+from typing import IO, Callable, Dict, Optional, Tuple, cast
 from urllib import request
 from urllib.error import HTTPError, URLError
 
@@ -40,26 +41,10 @@
 
 
 class DisabledRedirectHandler(request.HTTPRedirectHandler):
-
-    # HACK: typeshed annotation are wrong for `fp` and `msg`
-    #       (https://github.com/python/typeshed/pull/5728)
-    #       `headers` is incompatible with `http.client.HTTPMessage`
-    #       (https://github.com/python/typeshed/issues/5729)
-    def http_error_301(self, req: request.Request, fp, code: int,
-                       msg, headers) -> NoReturn:
-        raise HTTPError(req.full_url, code, msg, headers, fp)
-
-    def http_error_302(self, req: request.Request, fp, code: int,
-                       msg, headers) -> NoReturn:
-        raise HTTPError(req.full_url, code, msg, headers, fp)
-
-    def http_error_303(self, req: request.Request, fp, code: int,
-                       msg, headers) -> NoReturn:
-        raise HTTPError(req.full_url, code, msg, headers, fp)
-
-    def http_error_307(self, req: request.Request, fp, code: int,
-                       msg, headers) -> NoReturn:
-        raise HTTPError(req.full_url, code, msg, headers, fp)
+    def redirect_request(
+            self, req: request.Request, fp: IO[bytes], code: int, msg: str,
+            headers: HTTPMessage, newurl: str) -> None:
+        return None
 
 
 class TestBaseServerRequests(BaseTest):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Radicale-3.1.5/radicale/utils.py 
new/Radicale-3.1.6/radicale/utils.py
--- old/Radicale-3.1.5/radicale/utils.py        2022-02-08 16:44:08.000000000 
+0100
+++ new/Radicale-3.1.6/radicale/utils.py        2022-04-18 23:10:01.000000000 
+0200
@@ -16,12 +16,18 @@
 # You should have received a copy of the GNU General Public License
 # along with Radicale.  If not, see <http://www.gnu.org/licenses/>.
 
+import sys
 from importlib import import_module
 from typing import Callable, Sequence, Type, TypeVar, Union
 
 from radicale import config
 from radicale.log import logger
 
+if sys.version_info < (3, 8):
+    import pkg_resources
+else:
+    from importlib import metadata
+
 _T_co = TypeVar("_T_co", covariant=True)
 
 
@@ -43,3 +49,9 @@
                            (module_name, module, e)) from e
     logger.info("%s type is %r", module_name, module)
     return class_(configuration)
+
+
+def package_version(name):
+    if sys.version_info < (3, 8):
+        return pkg_resources.get_distribution(name).version
+    return metadata.version(name)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Radicale-3.1.5/radicale/web/internal.py 
new/Radicale-3.1.6/radicale/web/internal.py
--- old/Radicale-3.1.5/radicale/web/internal.py 2022-02-08 16:44:08.000000000 
+0100
+++ new/Radicale-3.1.6/radicale/web/internal.py 2022-04-18 23:10:01.000000000 
+0200
@@ -25,9 +25,7 @@
 
 """
 
-import pkg_resources
-
-from radicale import config, httputils, types, web
+from radicale import httputils, types, web
 
 MIMETYPES = httputils.MIMETYPES  # deprecated
 FALLBACK_MIMETYPE = httputils.FALLBACK_MIMETYPE  # deprecated
@@ -35,13 +33,7 @@
 
 class Web(web.BaseWeb):
 
-    folder: str
-
-    def __init__(self, configuration: config.Configuration) -> None:
-        super().__init__(configuration)
-        self.folder = pkg_resources.resource_filename(
-            __name__, "internal_data")
-
     def get(self, environ: types.WSGIEnviron, base_prefix: str, path: str,
             user: str) -> types.WSGIResponse:
-        return httputils.serve_folder(self.folder, base_prefix, path)
+        return httputils.serve_resource("radicale.web", "internal_data",
+                                        base_prefix, path)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Radicale-3.1.5/setup.py new/Radicale-3.1.6/setup.py
--- old/Radicale-3.1.5/setup.py 2022-02-08 16:44:08.000000000 +0100
+++ new/Radicale-3.1.6/setup.py 2022-04-18 23:10:01.000000000 +0200
@@ -43,12 +43,16 @@
 
 # When the version is updated, a new section in the CHANGELOG.md file must be
 # added too.
-VERSION = "3.1.5"
+VERSION = "3.1.6"
 WEB_FILES = ["web/internal_data/css/icon.png",
              "web/internal_data/css/main.css",
              "web/internal_data/fn.js",
              "web/internal_data/index.html"]
 
+install_requires = ["defusedxml", "passlib", "vobject>=0.9.6",
+                    "python-dateutil>=2.7.3"]
+if sys.version_info < (3, 9):
+    install_requires.append("setuptools")
 setup_requires = []
 if {"pytest", "test", "ptr"}.intersection(sys.argv):
     setup_requires.append("pytest-runner")
@@ -76,8 +80,7 @@
         exclude=["*.tests", "*.tests.*", "tests.*", "tests"]),
     package_data={"radicale": [*WEB_FILES, "py.typed"]},
     entry_points={"console_scripts": ["radicale = radicale.__main__:run"]},
-    install_requires=["defusedxml", "passlib", "vobject>=0.9.6",
-                      "python-dateutil>=2.7.3", "setuptools"],
+    install_requires=install_requires,
     setup_requires=setup_requires,
     tests_require=tests_require,
     extras_require={"test": tests_require,

Reply via email to