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,
+ )