Skip to content

Commit

Permalink
release-2.0.1 (#146)
Browse files Browse the repository at this point in the history
* fix: Update methods for custom fields (#114)

Add method `custom_field_choices()` in `App` class.
Rename method `custom_choices()` to `custom_fields()`.
Update docstings for both methods according to returning data.

* fix: Tests for methods for custom fields (#114)

Add test case `AppCustomFieldChoicesTestCase` for
`custom_field_choices()` method.
Rename test case for `custom_fields()` method.
Add using fixtures for mentioned test cases.

* fix: Fixtures for tests (custom fields) (#114)

Add missing JSON files with fixtures for tests for getting custom
fields.

* fix: Failing test for getting custom fields (#114)

Fix test cases `AppCustomFieldsTestCase` and
`AppCustomFieldChoicesTestCase` for python 3.7 stable.
Update logic for checking passed arguments of mock's `call_args`.

* Update api.py

* max_workers added

* max_workers added

* Update query.py

* Update query.py

* max_workers from api to request

* debug removed

* Update api.py

* Update query.py

* refactor: Update docstrings and naming (#114)

* (docs) update docstrings for `custom_fields()` and
  `custom_field_choices()` methods
* (refactor): use f-strings instead of `.format()` in
  `custom_fields()` and `custom_field_choices()`
* (tests): update naming in tests
* (tests): use `return_value` instead of `side_effect` for mocks

* fix: backward compatibility

* (fix): restore original method `custom_choices()` for application
  class to provide a compatibility with existing client code
* (enhance): add logging a deprecation warning

* refactor: update `custom_choices()` (#114)

* (refactor): call `custom_fields()` in `custom_choices()` since they
  represent essentially identical requests to Nautobot

* Add version constraint to divide into two release trains 1.x and 2.x (#130)

Add version constraint to divide into two release trains 1.x and 2.x

* Release 2.0 (#136)

* Release 2.0.0

---------

Co-authored-by: Jan Snasel <jan.snasel@networktocode.com>
Co-authored-by: Joe Wesch <10467633+joewesch@users.noreply.github.com>

* Fix SSL verify (#140) (#142)

* Fix custom_fields and custom_field_choices method overlap with endpoints (#141) (#144)

* Release 2.0.1

---------

Co-authored-by: nautics889 <cyberukr@gmail.com>
Co-authored-by: NobodyIsPerfect78 <46317624+NobodyIsPerfect78@users.noreply.github.com>
Co-authored-by: Josh VanDeraa <jv@networktocode.com>
Co-authored-by: Joe Wesch <10467633+joewesch@users.noreply.github.com>
Co-authored-by: Jan Snasel <jan.snasel@networktocode.com>
  • Loading branch information
6 people committed Oct 24, 2023
1 parent 365c287 commit f4e0384
Show file tree
Hide file tree
Showing 9 changed files with 208 additions and 240 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## v2.0.1

### Bug Fixes

- (#140) Fixes SSL
- (#141) Fixes methods and endpoints naming overlap

## v2.0.0

### Significant Updates
Expand Down
5 changes: 2 additions & 3 deletions docs/advanced/session.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ The example below shows how to update a Token if it has been cycled.
SSL Verification
----------------

Handling SSL verification is documented `here <https://requests.readthedocs.io/en/stable/user/advanced/#ssl-cert-verification>`_.
The below example shows how to disable SSL verification.

.. code-block:: python
Expand All @@ -42,9 +41,9 @@ The below example shows how to disable SSL verification.
from pynautobot import api
nautobot = api(
url='https://localhost:8000',
token=os.environ["NAUTOBOT_TOKEN"]
token=os.environ["NAUTOBOT_TOKEN"],
verify=False
)
nautobot.http_session.verify = False
Timeouts
--------
Expand Down
333 changes: 135 additions & 198 deletions poetry.lock

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions pynautobot/core/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class Api(object):
for all requests.
:param int,optional retries: Number of retries, for HTTP codes 429, 500, 502, 503, 504,
this client will try before dropping.
:param bool,optional verify: SSL cert verification.
:raises AttributeError: If app doesn't exist.
:Examples:
Expand All @@ -80,12 +81,14 @@ def __init__(
max_workers=4,
api_version=None,
retries=0,
verify=True,
):
base_url = "{}/api".format(url if url[-1] != "/" else url[:-1])
self.token = token
self.headers = {"Authorization": f"Token {self.token}"}
self.base_url = base_url
self.http_session = requests.Session()
self.http_session.verify = verify
if retries:
_adapter = HTTPAdapter(
max_retries=Retry(
Expand Down
38 changes: 6 additions & 32 deletions pynautobot/core/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,38 +86,14 @@ def choices(self):

return self._choices

def custom_choices(self):
"""Returns custom-fields response from app
.. note::
This method is deprecated and will be removed in pynautobot
2.0 or newer. Please use `custom_fields()` instead.
:Returns: Raw response from Nautobot's custom-fields endpoint.
:Raises: :py:class:`.RequestError` if called for an invalid endpoint.
:Example:
>>> nb.extras.custom_choices()
{'Testfield1': {'Testvalue2': 2, 'Testvalue1': 1},
'Testfield2': {'Othervalue2': 4, 'Othervalue1': 3}}
"""
logger.warning(
"WARNING: The method 'custom_choices()' will be removed in "
"the next major version (2.x) of pynautobot. Please use "
"`custom_fields()` instead."
)

return self.custom_fields()

def custom_fields(self):
def get_custom_fields(self):
"""Returns custom-fields response from app
:Returns: Raw response from Nautobot's custom-fields endpoint.
:Raises: :py:class:`.RequestError` if called for an invalid endpoint.
:Example:
>>> nb.extras.custom_fields()
>>> nb.extras.get_custom_fields()
[
{
"id": "5b39ba88-e5ab-4be2-89f5-5a016473b53c",
Expand All @@ -142,21 +118,20 @@ def custom_fields(self):
},
]
"""
custom_fields = Request(
return Request(
base=f"{self.api.base_url}/{self.name}/custom-fields/",
token=self.api.token,
http_session=self.api.http_session,
).get()
return custom_fields

def custom_field_choices(self):
def get_custom_field_choices(self):
"""Returns custom-field-choices response from app
:Returns: Raw response from Nautobot's custom-field-choices endpoint.
:Raises: :py:class:`.RequestError` if called for an invalid endpoint.
:Example:
>>> nb.extras.custom_field_choices()
>>> nb.extras.get_custom_field_choices()
[
{
"id": "5b39ba88-e5ab-4be2-89f5-5a016473b53c",
Expand All @@ -175,12 +150,11 @@ def custom_field_choices(self):
},
]
"""
custom_fields = Request(
return Request(
base=f"{self.api.base_url}/{self.name}/custom-field-choices/",
token=self.api.token,
http_session=self.api.http_session,
).get()
return custom_fields

def config(self):
"""Returns config response from app
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[tool.poetry]
name = "pynautobot"
version = "2.0.0"
version = "2.0.1"
description = "Nautobot API client library"
authors = ["Network to Code, LLC <opensource@networktocode.com>"]
readme = "README.md"
Expand Down
36 changes: 36 additions & 0 deletions tests/integration/test_extras.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import pytest


class TestCustomField:

"""Verify we can create, custom field, and custom field choices."""

@pytest.fixture(scope="session")
def create_custom_field(self, nb_client):
data = {
"label": "test_cf",
"key": "test_cf",
"content_types": ["dcim.device"],
"type": "select",
"weight": 100,
"filter_logic": "loose",
}
return nb_client.extras.custom_fields.create(**data)

@pytest.fixture(scope="session")
def create_custom_field_choices(self, nb_client, create_custom_field):
data = {
"value": "A",
"custom_field": create_custom_field["id"],
"weight": 100,
}
return nb_client.extras.custom_field_choices.create(**data)

def test_custom_field(self, create_custom_field):
assert create_custom_field["label"] == "test_cf"

def test_custom_field_choice(self, create_custom_field_choices):
assert create_custom_field_choices["value"] == "A"

def test_custom_field_choice_to_cf(self, create_custom_field_choices, create_custom_field):
assert create_custom_field_choices["custom_field"]["id"] == create_custom_field["id"]
12 changes: 12 additions & 0 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,18 @@ def test_sanitize_url(self, *_):
self.assertTrue(api)
self.assertEqual(api.base_url, "http://localhost:8000/api")

@patch("pynautobot.api.version", "2.0")
def test_verify_true(self, *_):
api = pynautobot.api("http://localhost:8000/", **def_kwargs)
self.assertTrue(api)
self.assertTrue(api.http_session.verify)

@patch("pynautobot.api.version", "2.0")
def test_verify_false(self, *_):
api = pynautobot.api("http://localhost:8000/", verify=False, **def_kwargs)
self.assertTrue(api)
self.assertFalse(api.http_session.verify)


class ApiVersionTestCase(unittest.TestCase):
class ResponseHeadersWithVersion:
Expand Down
12 changes: 6 additions & 6 deletions tests/test_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class AppCustomFieldsTestCase(unittest.TestCase):
@patch("pynautobot.api.version", "2.0")
def test_custom_fields(self, session_get_mock):
api = pynautobot.api(host, **def_kwargs)
cfs = api.extras.custom_fields()
cfs = api.extras.get_custom_fields()

session_get_mock.assert_called_once()
expect_url = f"{api.base_url}/extras/custom-fields/"
Expand All @@ -46,7 +46,7 @@ class AppCustomFieldChoicesTestCase(unittest.TestCase):
@patch("pynautobot.api.version", "2.0")
def test_custom_field_choices(self, session_get_mock):
api = pynautobot.api(host, **def_kwargs)
choices = api.extras.custom_field_choices()
choices = api.extras.get_custom_field_choices()

session_get_mock.assert_called_once()
expect_url = f"{api.base_url}/extras/custom-field-choices/"
Expand Down Expand Up @@ -85,11 +85,11 @@ class PluginAppCustomChoicesTestCase(unittest.TestCase):
return_value={"Testfield1": {"TF1_1": 1, "TF1_2": 2}, "Testfield2": {"TF2_1": 3, "TF2_2": 4}},
)
@patch("pynautobot.api.version", "2.0")
def test_custom_choices(self, *_):
def test_custom_fields(self, *_):
api = pynautobot.api(host, **def_kwargs)
choices = api.plugins.test_plugin.custom_fields()
self.assertEqual(len(choices), 2)
self.assertEqual(sorted(choices.keys()), ["Testfield1", "Testfield2"])
custom_fields = api.plugins.test_plugin.get_custom_fields()
self.assertEqual(len(custom_fields), 2)
self.assertEqual(sorted(custom_fields.keys()), ["Testfield1", "Testfield2"])

@patch(
"pynautobot.core.query.Request.get",
Expand Down

0 comments on commit f4e0384

Please sign in to comment.