Skip to content

Commit

Permalink
Merge pull request #121 from digitalocean/4-0-release
Browse files Browse the repository at this point in the history
4.0 Release
  • Loading branch information
Zach Moody authored Dec 5, 2018
2 parents 4270d62 + 31f20dd commit 2cada45
Show file tree
Hide file tree
Showing 37 changed files with 1,842 additions and 1,015 deletions.
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---

v4.0.0 (2018-12-04)

## Enhancements

* [#109](https://github.com/digitalocean/pynetbox/issues/109) - Clean up tests a bit.
* Added cable endpoint support coming in NetBox 2.5.
* Added some detail to the ValueError raised when `.get()` returns more than one object.
* Added reserved kwargs to `.get()` and `.filter()` ("id", "pk", "limit", "offset").
* Made RequestError more verbose when the NetBox API returns a json response. Also added more details when a 404 is returned (e.g. misspelled endpoints).

## API Changes

* [#22](https://github.com/digitalocean/pynetbox/issues/22) - Switch to using PATCH instead of PUTs for updates. Also added an `.update()` method to Response objects that takes a dictionary to update multiple values on the object.
* [#24](https://github.com/digitalocean/pynetbox/issues/24) - Add basic support for the `_choices` endpoint on each app by adding a `choices()` method to the App object.
* [#108](https://github.com/digitalocean/pynetbox/issues/108) - Return `Record` objects from `.create()`.

## Bug Fixes

* [#88](https://github.com/digitalocean/pynetbox/issues/88) - Raise an exception now if `.filter()` is passed no kwargs.
* [#90](https://github.com/digitalocean/pynetbox/issues/90) - Fixes some miscellaneous issues related to converting certain Record object's fields into netaddr.IPNetwork objects. That feature has been removed and it simply return strings now.
1 change: 0 additions & 1 deletion MANIFEST.in

This file was deleted.

2 changes: 1 addition & 1 deletion docs/IPAM.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
IPAM
========

.. autoclass:: pynetbox.ipam.Prefixes
.. autoclass:: pynetbox.models.ipam.Prefixes
:members:
8 changes: 4 additions & 4 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
#
import os
import sys
from pkg_resources import get_distribution
sys.path.insert(0, os.path.abspath('../'))
import pynetbox


# -- General configuration ------------------------------------------------
Expand Down Expand Up @@ -53,11 +53,11 @@
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
# The full version, including alpha/beta/rc tags.
release = get_distribution('pynetbox').version
#
# The short X.Y version.
version = pynetbox.__version__
# The full version, including alpha/beta/rc tags.
release = pynetbox.__version__
version = '.'.join(release.split('.')[:2])

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down
4 changes: 2 additions & 2 deletions docs/endpoint.rst
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
Endpoint
========

.. autoclass:: pynetbox.lib.endpoint.Endpoint
.. autoclass:: pynetbox.core.endpoint.Endpoint
:members:

.. autoclass:: pynetbox.lib.endpoint.DetailEndpoint
.. autoclass:: pynetbox.core.endpoint.DetailEndpoint
:members:
5 changes: 4 additions & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
request
IPAM

TL;DR
=====
Instantiate the :py:class:`.Api`. Use the methods available on :py:class:`.Endpoint` to return :py:class:`.Record` objects.

API
===
Expand All @@ -18,7 +21,7 @@ App
===

.. autoclass:: pynetbox.api.App

:members:

Indices and tables
==================
Expand Down
2 changes: 1 addition & 1 deletion docs/request.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Request
========

.. autoclass:: pynetbox.lib.query.RequestError
.. autoclass:: pynetbox.core.query.RequestError
:members:
5 changes: 1 addition & 4 deletions docs/response.rst
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
Response
========

.. autoclass:: pynetbox.lib.response.Record
:members:

.. autoclass:: pynetbox.lib.response.IPRecord
.. autoclass:: pynetbox.core.response.Record
:members:
2 changes: 1 addition & 1 deletion pynetbox/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from pkg_resources import get_distribution, DistributionNotFound

from pynetbox.core.query import RequestError
from pynetbox.api import Api as api
from pynetbox.lib import RequestError

try:
__version__ = get_distribution(__name__).version
Expand Down
99 changes: 57 additions & 42 deletions pynetbox/api.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
'''
"""
(c) 2017 DigitalOcean
Licensed under the Apache License, Version 2.0 (the "License");
Expand All @@ -12,9 +12,10 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
'''
from pynetbox.lib import Endpoint, Request
from pynetbox import dcim, ipam, virtualization, circuits
"""
from pynetbox.core.endpoint import Endpoint
from pynetbox.core.query import Request
from pynetbox.models import dcim, ipam, virtualization, circuits


class App(object):
Expand All @@ -26,16 +27,30 @@ class App(object):
:raises: :py:class:`.RequestError`
if requested endpoint doesn't exist.
"""
def __init__(self, app, api_kwargs=None):
self.app = app
self.api_kwargs = api_kwargs

def __init__(self, api, name, model=None):
self.api = api
self.name = name
self.model = model
self._choices = None

def __getattr__(self, name):
return Endpoint(
name,
api_kwargs=self.api_kwargs,
app=self.app
)
return Endpoint(self.api, self, name, model=self.model)

def choices(self):
""" Returns _choices response from App
:Returns: Raw response from NetBox's _choices endpoint.
"""
if self._choices:
return self._choices

self._choices = Request(
base="{}/{}/_choices/".format(self.api.base_url, self.name),
ssl_verify=self.api.ssl_verify,
).get()

return self._choices


class Api(object):
Expand Down Expand Up @@ -83,44 +98,44 @@ class Api(object):
.. _requests: http://docs.python-requests.org/en/master/user/advanced/#ssl-cert-verification
""" # noqa

def __init__(self, url, token=None, private_key=None,
private_key_file=None, version=None, ssl_verify=True):
def __init__(
self,
url,
token=None,
private_key=None,
private_key_file=None,
ssl_verify=True,
):
if private_key and private_key_file:
raise ValueError(
'"private_key" and "private_key_file" cannot be used together.'
)
base_url = "{}/api".format(url if url[-1] != '/' else url[:-1])

self.api_kwargs = {
"token": token,
"private_key": private_key,
"private_key_file": private_key_file,
"base_url": base_url,
"ssl_verify": ssl_verify,
}

if self.api_kwargs.get('private_key_file'):
with open(self.api_kwargs.get('private_key_file'), 'r') as kf:
base_url = "{}/api".format(url if url[-1] != "/" else url[:-1])
self.token = token
self.private_key = private_key
self.private_key_file = private_key_file
self.base_url = base_url
self.ssl_verify = ssl_verify
self.session_key = None

if self.private_key_file:
with open(self.private_key_file, "r") as kf:
private_key = kf.read()
self.api_kwargs.update(private_key=private_key)
if not version:
version = Request(base=base_url,
ssl_verify=ssl_verify).get_version()
self.api_kwargs.update(version=version)
self.private_key = private_key

req = Request(
base=base_url,
token=token,
private_key=private_key,
ssl_verify=ssl_verify
ssl_verify=ssl_verify,
)
if token and private_key:
self.api_kwargs.update(session_key=req.get_session_key())

self.dcim = App(dcim, api_kwargs=self.api_kwargs)
self.ipam = App(ipam, api_kwargs=self.api_kwargs)
self.circuits = App(circuits, api_kwargs=self.api_kwargs)
self.secrets = App('secrets', api_kwargs=self.api_kwargs)
self.tenancy = App('tenancy', api_kwargs=self.api_kwargs)
self.extras = App('extras', api_kwargs=self.api_kwargs)
self.virtualization = App(virtualization, api_kwargs=self.api_kwargs)
if self.token and self.private_key:
self.session_key = req.get_session_key()

self.dcim = App(self, "dcim", model=dcim)
self.ipam = App(self, "ipam", model=ipam)
self.circuits = App(self, "circuits", model=circuits)
self.secrets = App(self, "secrets", model=None)
self.tenancy = App(self, "tenancy", model=None)
self.extras = App(self, "extras", model=None)
self.virtualization = App(self, "virtualization", model=virtualization)
Empty file added pynetbox/core/__init__.py
Empty file.
Loading

0 comments on commit 2cada45

Please sign in to comment.