Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-pynetbox for openSUSE:Factory 
checked in at 2021-12-06 23:59:46
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pynetbox (Old)
 and      /work/SRC/openSUSE:Factory/.python-pynetbox.new.31177 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-pynetbox"

Mon Dec  6 23:59:46 2021 rev:26 rq:935857 version:6.3.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-pynetbox/python-pynetbox.changes  
2021-11-01 18:35:53.761342083 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-pynetbox.new.31177/python-pynetbox.changes   
    2021-12-07 00:00:57.856228697 +0100
@@ -1,0 +2,12 @@
+Sun Dec  5 14:59:12 UTC 2021 - Martin Hauke <[email protected]>
+
+- Update to version 6.3.0
+  * Handle list results in DetailEndpoint.create().
+  * Define Permissions.constraints as JSON field to fix #398.
+  * Fixes manual pagination (#412) and argless filter.
+  * Makes .filter() with no args equivalent to .all(), 7.0 will
+    remove the latter.
+  * Add Api.create_token() (for NetBox 3.0+)
+  * Add custom model name lookup to fix.
+
+-------------------------------------------------------------------

Old:
----
  pynetbox-6.2.0.tar.gz

New:
----
  pynetbox-6.3.0.tar.gz

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

Other differences:
------------------
++++++ python-pynetbox.spec ++++++
--- /var/tmp/diff_new_pack.wvvTOp/_old  2021-12-07 00:00:58.408226745 +0100
+++ /var/tmp/diff_new_pack.wvvTOp/_new  2021-12-07 00:00:58.412226731 +0100
@@ -19,7 +19,7 @@
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 %define         skip_python2 1
 Name:           python-pynetbox
-Version:        6.2.0
+Version:        6.3.0
 Release:        0
 Summary:        NetBox API client library
 License:        Apache-2.0

++++++ pynetbox-6.2.0.tar.gz -> pynetbox-6.3.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pynetbox-6.2.0/PKG-INFO new/pynetbox-6.3.0/PKG-INFO
--- old/pynetbox-6.2.0/PKG-INFO 2021-10-29 23:53:37.552109200 +0200
+++ new/pynetbox-6.3.0/PKG-INFO 2021-12-04 23:55:32.527155400 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: pynetbox
-Version: 6.2.0
+Version: 6.3.0
 Summary: NetBox API client library
 Home-page: https://github.com/digitalocean/pynetbox
 Author: Zach Moody
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pynetbox-6.2.0/pynetbox/core/api.py 
new/pynetbox-6.3.0/pynetbox/core/api.py
--- old/pynetbox-6.2.0/pynetbox/core/api.py     2021-10-29 23:53:20.000000000 
+0200
+++ new/pynetbox-6.3.0/pynetbox/core/api.py     2021-12-04 23:55:21.000000000 
+0100
@@ -19,6 +19,7 @@
 
 from pynetbox.core.query import Request
 from pynetbox.core.app import App, PluginsApp
+from pynetbox.core.response import Record
 
 
 class Api(object):
@@ -183,3 +184,44 @@
             base=self.base_url, token=self.token, 
http_session=self.http_session,
         ).get_status()
         return status
+
+    def create_token(self, username, password):
+        """ Creates an API token using a valid NetBox username and password.
+        Saves the created token automatically in the API object.
+
+        Requires NetBox 3.0.0 or newer.
+
+        :Returns: The token as a ``Record`` object.
+        :Raises: :py:class:`.RequestError` if the request is not successful.
+
+        :Example:
+
+        >>> import pynetbox
+        >>> nb = pynetbox.api("https://netbox-server";)
+        >>> token = nb.create_token("admin", "netboxpassword")
+        >>> nb.token
+        '96d02e13e3f1fdcd8b4c089094c0191dcb045bef'
+        >>> from pprint import pprint
+        >>> pprint(dict(token))
+        {'created': '2021-11-27T11:26:49.360185+02:00',
+         'description': '',
+         'display': '045bef (admin)',
+         'expires': None,
+         'id': 2,
+         'key': '96d02e13e3f1fdcd8b4c089094c0191dcb045bef',
+         'url': 'https://netbox-server/api/users/tokens/2/',
+         'user': {'display': 'admin',
+                  'id': 1,
+                  'url': 'https://netbox-server/api/users/users/1/',
+                  'username': 'admin'},
+         'write_enabled': True}
+        >>>
+        """
+        resp = Request(
+            base="{}/users/tokens/provision/".format(self.base_url),
+            http_session=self.http_session,
+        ).post(data={"username": username, "password": password})
+        # Save the newly created API token, otherwise populating the Record
+        # object details will fail
+        self.token = resp["key"]
+        return Record(resp, self, None)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pynetbox-6.2.0/pynetbox/core/endpoint.py 
new/pynetbox-6.3.0/pynetbox/core/endpoint.py
--- old/pynetbox-6.2.0/pynetbox/core/endpoint.py        2021-10-29 
23:53:20.000000000 +0200
+++ new/pynetbox-6.3.0/pynetbox/core/endpoint.py        2021-12-04 
23:55:21.000000000 +0100
@@ -16,7 +16,7 @@
 from pynetbox.core.query import Request, RequestError
 from pynetbox.core.response import Record, RecordSet
 
-RESERVED_KWARGS = ("offset",)
+RESERVED_KWARGS = ()
 
 
 class Endpoint(object):
@@ -71,13 +71,14 @@
             ret = Record
         return ret
 
-    def all(self, limit=0):
+    def all(self, limit=0, offset=None):
         """Queries the 'ListView' of a given endpoint.
 
         Returns all objects from an endpoint.
 
         :arg int,optional limit: Overrides the max page size on
             paginated returns.
+        :arg int,optional offset: Overrides the offset on paginated returns.
 
         :Returns: A :py:class:`.RecordSet` object.
 
@@ -92,6 +93,8 @@
         test1-leaf3
         >>>
         """
+        if limit == 0 and offset is not None:
+            raise ValueError("offset requires a positive limit value")
         req = Request(
             base="{}/".format(self.url),
             token=self.token,
@@ -99,6 +102,7 @@
             http_session=self.api.http_session,
             threading=self.api.threading,
             limit=limit,
+            offset=offset,
         )
 
         return RecordSet(self, req)
@@ -180,6 +184,7 @@
             endpoint accepts can be added as a keyword arg.
         :arg int,optional limit: Overrides the max page size on
             paginated returns.
+        :arg int,optional offset: Overrides the offset on paginated returns.
 
         :Returns: A :py:class:`.RecordSet` object.
 
@@ -231,14 +236,15 @@
         if args:
             kwargs.update({"q": args[0]})
 
-        if not kwargs:
-            raise ValueError("filter must be passed kwargs. Perhaps use all() 
instead.")
         if any(i in RESERVED_KWARGS for i in kwargs):
             raise ValueError(
                 "A reserved kwarg was passed ({}). Please remove it "
                 "and try again.".format(RESERVED_KWARGS)
             )
-
+        limit = kwargs.pop("limit") if "limit" in kwargs else 0
+        offset = kwargs.pop("offset") if "offset" in kwargs else None
+        if limit == 0 and offset is not None:
+            raise ValueError("offset requires a positive limit value")
         req = Request(
             filters=kwargs,
             base=self.url,
@@ -246,7 +252,8 @@
             session_key=self.session_key,
             http_session=self.api.http_session,
             threading=self.api.threading,
-            limit=kwargs.get("limit", 0),
+            limit=limit,
+            offset=offset,
         )
 
         return RecordSet(self, req)
@@ -595,9 +602,17 @@
         data = data or {}
         req = Request(**self.request_kwargs).post(data)
         if self.custom_return:
-            return self.custom_return(
-                req, self.parent_obj.endpoint.api, self.parent_obj.endpoint
-            )
+            if isinstance(req, list):
+                return [
+                    self.custom_return(
+                        req_item, self.parent_obj.endpoint.api, 
self.parent_obj.endpoint
+                    )
+                    for req_item in req
+                ]
+            else:
+                return self.custom_return(
+                    req, self.parent_obj.endpoint.api, self.parent_obj.endpoint
+                )
         return req
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pynetbox-6.2.0/pynetbox/core/query.py 
new/pynetbox-6.3.0/pynetbox/core/query.py
--- old/pynetbox-6.2.0/pynetbox/core/query.py   2021-10-29 23:53:20.000000000 
+0200
+++ new/pynetbox-6.3.0/pynetbox/core/query.py   2021-12-04 23:55:21.000000000 
+0100
@@ -131,6 +131,7 @@
         http_session,
         filters=None,
         limit=None,
+        offset=None,
         key=None,
         token=None,
         private_key=None,
@@ -151,7 +152,7 @@
                 string.
         """
         self.base = self.normalize_url(base)
-        self.filters = filters
+        self.filters = filters or None
         self.key = key
         self.token = token
         self.private_key = private_key
@@ -160,6 +161,7 @@
         self.url = self.base if not key else "{}{}/".format(self.base, key)
         self.threading = threading
         self.limit = limit
+        self.offset = offset
 
     def get_openapi(self):
         """ Gets the OpenAPI Spec """
@@ -309,10 +311,17 @@
 
         if not add_params and self.limit is not None:
             add_params = {"limit": self.limit}
+            if self.limit and self.offset is not None:
+                # if non-zero limit and some offset -> add offset
+                add_params["offset"] = self.offset
         req = self._make_call(add_params=add_params)
         if isinstance(req, dict) and req.get("results") is not None:
             self.count = req["count"]
-            if self.threading:
+            if self.offset is not None:
+                # only yield requested page results if paginating
+                for i in req["results"]:
+                    yield i
+            elif self.threading:
                 ret = req["results"]
                 if req.get("next"):
                     page_size = len(req["results"])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pynetbox-6.2.0/pynetbox/core/response.py 
new/pynetbox-6.3.0/pynetbox/core/response.py
--- old/pynetbox-6.2.0/pynetbox/core/response.py        2021-10-29 
23:53:20.000000000 +0200
+++ new/pynetbox-6.3.0/pynetbox/core/response.py        2021-12-04 
23:55:21.000000000 +0100
@@ -349,9 +349,16 @@
         values within.
         """
 
-        def list_parser(list_item):
+        def list_parser(key_name, list_item):
             if isinstance(list_item, dict):
-                return self.default_ret(list_item, self.api, self.endpoint)
+                lookup = getattr(self.__class__, key_name, None)
+                if not isinstance(lookup, list):
+                    # This is *list_parser*, so if the custom model field is 
not
+                    # a list (or is not defined), just return the default model
+                    return self.default_ret(list_item, self.api, self.endpoint)
+                else:
+                    model = lookup[0]
+                    return model(list_item, self.api, self.endpoint)
             return list_item
 
         for k, v in values.items():
@@ -370,7 +377,7 @@
                 self._add_cache((k, v))
 
             elif isinstance(v, list):
-                v = [list_parser(i) for i in v]
+                v = [list_parser(k, i) for i in v]
                 to_cache = list(v)
                 self._add_cache((k, to_cache))
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pynetbox-6.2.0/pynetbox/models/users.py 
new/pynetbox-6.3.0/pynetbox/models/users.py
--- old/pynetbox-6.2.0/pynetbox/models/users.py 2021-10-29 23:53:20.000000000 
+0200
+++ new/pynetbox-6.3.0/pynetbox/models/users.py 2021-12-04 23:55:21.000000000 
+0100
@@ -13,9 +13,14 @@
 See the License for the specific language governing permissions and
 limitations under the License.
 """
-from pynetbox.core.response import Record
+from pynetbox.core.response import Record, JsonField
 
 
 class Users(Record):
     def __str__(self):
         return self.username
+
+
+class Permissions(Record):
+    users = [Users]
+    constraints = JsonField
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pynetbox-6.2.0/pynetbox.egg-info/PKG-INFO 
new/pynetbox-6.3.0/pynetbox.egg-info/PKG-INFO
--- old/pynetbox-6.2.0/pynetbox.egg-info/PKG-INFO       2021-10-29 
23:53:37.000000000 +0200
+++ new/pynetbox-6.3.0/pynetbox.egg-info/PKG-INFO       2021-12-04 
23:55:32.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: pynetbox
-Version: 6.2.0
+Version: 6.3.0
 Summary: NetBox API client library
 Home-page: https://github.com/digitalocean/pynetbox
 Author: Zach Moody
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pynetbox-6.2.0/pynetbox.egg-info/SOURCES.txt 
new/pynetbox-6.3.0/pynetbox.egg-info/SOURCES.txt
--- old/pynetbox-6.2.0/pynetbox.egg-info/SOURCES.txt    2021-10-29 
23:53:37.000000000 +0200
+++ new/pynetbox-6.3.0/pynetbox.egg-info/SOURCES.txt    2021-12-04 
23:55:32.000000000 +0100
@@ -46,6 +46,7 @@
 tests/test_virtualization.py
 tests/util.py
 tests/fixtures/api/get_session_key.json
+tests/fixtures/api/token_provision.json
 tests/fixtures/circuits/circuit.json
 tests/fixtures/circuits/circuit_termination.json
 tests/fixtures/circuits/circuit_terminations.json
@@ -159,6 +160,7 @@
 tests/integration/test_dcim.py
 tests/integration/test_ipam.py
 tests/unit/__init__.py
+tests/unit/test_detailendpoint.py
 tests/unit/test_endpoint.py
 tests/unit/test_extras.py
 tests/unit/test_query.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/pynetbox-6.2.0/tests/fixtures/api/token_provision.json 
new/pynetbox-6.3.0/tests/fixtures/api/token_provision.json
--- old/pynetbox-6.2.0/tests/fixtures/api/token_provision.json  1970-01-01 
01:00:00.000000000 +0100
+++ new/pynetbox-6.3.0/tests/fixtures/api/token_provision.json  2021-12-04 
23:55:21.000000000 +0100
@@ -0,0 +1,3 @@
+{
+    "key": "1234567890123456789012345678901234567890"
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pynetbox-6.2.0/tests/fixtures/users/permission.json 
new/pynetbox-6.3.0/tests/fixtures/users/permission.json
--- old/pynetbox-6.2.0/tests/fixtures/users/permission.json     2021-10-29 
23:53:20.000000000 +0200
+++ new/pynetbox-6.3.0/tests/fixtures/users/permission.json     2021-12-04 
23:55:21.000000000 +0100
@@ -1,4 +1,9 @@
 {
     "id": 1,
-    "name": "permission1"
+    "name": "permission1",
+    "users": [
+        {
+            "username": "user1"
+        }
+    ]
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pynetbox-6.2.0/tests/test_api.py 
new/pynetbox-6.3.0/tests/test_api.py
--- old/pynetbox-6.2.0/tests/test_api.py        2021-10-29 23:53:20.000000000 
+0200
+++ new/pynetbox-6.3.0/tests/test_api.py        2021-12-04 23:55:21.000000000 
+0100
@@ -85,3 +85,16 @@
     def test_api_status(self, *_):
         api = pynetbox.api(host,)
         self.assertEqual(api.status()["netbox-version"], "0.9.9")
+
+
+class ApiCreateTokenTestCase(unittest.TestCase):
+    @patch(
+        "requests.sessions.Session.post",
+        return_value=Response(fixture="api/token_provision.json"),
+    )
+    def test_create_token(self, *_):
+        api = pynetbox.api(host)
+        token = api.create_token("user", "pass")
+        self.assertTrue(isinstance(token, pynetbox.core.response.Record))
+        self.assertEqual(token.key, "1234567890123456789012345678901234567890")
+        self.assertEqual(api.token, "1234567890123456789012345678901234567890")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pynetbox-6.2.0/tests/test_users.py 
new/pynetbox-6.3.0/tests/test_users.py
--- old/pynetbox-6.2.0/tests/test_users.py      2021-10-29 23:53:20.000000000 
+0200
+++ new/pynetbox-6.3.0/tests/test_users.py      2021-12-04 23:55:21.000000000 
+0100
@@ -95,3 +95,13 @@
 
 class PermissionsTestCase(Generic.Tests):
     name = "permissions"
+
+    @patch(
+        "requests.sessions.Session.get",
+        return_value=Response(fixture="users/permission.json"),
+    )
+    def test_username(self, _):
+        permission = nb.permissions.get(1)
+        self.assertEqual(len(permission.users), 1)
+        user = permission.users[0]
+        self.assertEqual(str(user), "user1")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pynetbox-6.2.0/tests/unit/test_detailendpoint.py 
new/pynetbox-6.3.0/tests/unit/test_detailendpoint.py
--- old/pynetbox-6.2.0/tests/unit/test_detailendpoint.py        1970-01-01 
01:00:00.000000000 +0100
+++ new/pynetbox-6.3.0/tests/unit/test_detailendpoint.py        2021-12-04 
23:55:21.000000000 +0100
@@ -0,0 +1,44 @@
+import unittest
+
+import six
+
+import pynetbox
+
+if six.PY3:
+    from unittest.mock import patch
+else:
+    from mock import patch
+
+
+nb = pynetbox.api("http://localhost:8000";)
+
+
+class DetailEndpointTestCase(unittest.TestCase):
+    def test_detail_endpoint_create_single(self):
+        with patch(
+            "pynetbox.core.query.Request._make_call",
+            return_value={"id": 123, "prefix": "1.2.3.0/24"},
+        ):
+            prefix_obj = nb.ipam.prefixes.get(123)
+            self.assertEqual(prefix_obj.prefix, "1.2.3.0/24")
+        with patch(
+            "pynetbox.core.query.Request._make_call",
+            return_value={"address": "1.2.3.1/24"},
+        ):
+            ip_obj = prefix_obj.available_ips.create()
+            self.assertEqual(ip_obj.address, "1.2.3.1/24")
+
+    def test_detail_endpoint_create_list(self):
+        with patch(
+            "pynetbox.core.query.Request._make_call",
+            return_value={"id": 123, "prefix": "1.2.3.0/24"},
+        ):
+            prefix_obj = nb.ipam.prefixes.get(123)
+            self.assertEqual(prefix_obj.prefix, "1.2.3.0/24")
+        with patch(
+            "pynetbox.core.query.Request._make_call",
+            return_value=[{"address": "1.2.3.1/24"}, {"address": 
"1.2.3.2/24"}],
+        ):
+            ip_list = prefix_obj.available_ips.create([{} for _ in range(2)])
+            self.assertTrue(isinstance(ip_list, list))
+            self.assertEqual(len(ip_list), 2)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pynetbox-6.2.0/tests/unit/test_endpoint.py 
new/pynetbox-6.3.0/tests/unit/test_endpoint.py
--- old/pynetbox-6.2.0/tests/unit/test_endpoint.py      2021-10-29 
23:53:20.000000000 +0200
+++ new/pynetbox-6.3.0/tests/unit/test_endpoint.py      2021-12-04 
23:55:21.000000000 +0100
@@ -22,21 +22,21 @@
             test = test_obj.filter(test="test")
             self.assertEqual(len(test), 2)
 
-    def test_filter_empty_kwargs(self):
+    def test_filter_invalid_pagination_args(self):
 
         api = Mock(base_url="http://localhost:8000/api";)
         app = Mock(name="test")
         test_obj = Endpoint(api, app, "test")
         with self.assertRaises(ValueError) as _:
-            test_obj.filter()
+            test_obj.filter(offset=1)
 
-    def test_filter_reserved_kwargs(self):
+    def test_all_invalid_pagination_args(self):
 
         api = Mock(base_url="http://localhost:8000/api";)
         app = Mock(name="test")
         test_obj = Endpoint(api, app, "test")
         with self.assertRaises(ValueError) as _:
-            test_obj.filter(offset=1)
+            test_obj.all(offset=1)
 
     def test_choices(self):
         with patch("pynetbox.core.query.Request.options", return_value=Mock()) 
as mock:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pynetbox-6.2.0/tests/unit/test_query.py 
new/pynetbox-6.3.0/tests/unit/test_query.py
--- old/pynetbox-6.2.0/tests/unit/test_query.py 2021-10-29 23:53:20.000000000 
+0200
+++ new/pynetbox-6.3.0/tests/unit/test_query.py 2021-12-04 23:55:21.000000000 
+0100
@@ -57,3 +57,31 @@
             headers={"accept": "application/json;"},
             json=None,
         )
+
+    def test_get_manual_pagination(self):
+        test_obj = Request(
+            http_session=Mock(),
+            base="http://localhost:8001/api/dcim/devices";,
+            limit=10,
+            offset=20,
+        )
+        test_obj.http_session.get.return_value.json.return_value = {
+            "count": 4,
+            "next": 
"http://localhost:8001/api/dcim/devices?limit=10&offset=30";,
+            "previous": False,
+            "results": [1, 2, 3, 4],
+        }
+        expected = call(
+            "http://localhost:8001/api/dcim/devices/";,
+            params={"offset": 20, "limit": 10},
+            headers={"accept": "application/json;"},
+        )
+        test_obj.http_session.get.ok = True
+        generator = test_obj.get()
+        self.assertEqual(len(list(generator)), 4)
+        test_obj.http_session.get.assert_called_with(
+            "http://localhost:8001/api/dcim/devices/";,
+            params={"offset": 20, "limit": 10},
+            headers={"accept": "application/json;"},
+            json=None,
+        )

Reply via email to