././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1769619043.8233304
pynetbox-7.6.1/ 0000755 0001751 0001751 00000000000 15136437144 013053 5 ustar 00runner runner ././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1769619043.7933304
pynetbox-7.6.1/.github/ 0000755 0001751 0001751 00000000000 15136437144 014413 5 ustar 00runner runner ././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1769619043.7933304
pynetbox-7.6.1/.github/ISSUE_TEMPLATE/ 0000755 0001751 0001751 00000000000 15136437144 016576 5 ustar 00runner runner ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/.github/ISSUE_TEMPLATE/bug_report.yaml 0000644 0001751 0001751 00000004277 15136437134 021643 0 ustar 00runner runner ---
name: 🐛 Bug Report
description: Report a reproducible bug in the current release of pynetbox
labels: ["app: pynetbox", "type: bug", "status: needs triage"]
body:
- type: markdown
attributes:
value: >
**NOTE:** This form is only for reporting _reproducible bugs_ in a current pynetbox release.
- type: input
attributes:
label: pynetbox version
description: What version of pynetbox are you currently running?
placeholder: v7.6.1
validations:
required: true
- type: input
attributes:
label: NetBox version
description: What version of NetBox are you currently running?
placeholder: v4.3.1
validations:
required: true
- type: dropdown
attributes:
label: Python version
description: What version of Python are you currently running?
options:
- "3.10"
- "3.11"
- "3.12"
validations:
required: true
- type: textarea
attributes:
label: Steps to Reproduce
description: >
Please provide a minimal working example to demonstrate the bug. Begin with the
initialization of any necessary database objects and clearly enumerate each
operation carried out. Ensure that your example is as concise as possible
while adequately illustrating the issue. For example:
```python
>>> import pynetbox
>>> nb = pynebox.api('https://netbox.example.com', token='my-token')
```
Note: **do not utilize the demo instance** for replicating suspected bugs,
as its data is subject to change or removal at any time.
_Please refrain from including any confidential or sensitive
information in your example._
validations:
required: true
- type: textarea
attributes:
label: Expected Behavior
description: What did you expect to happen?
placeholder: The script should execute without raising any errors or exceptions
validations:
required: true
- type: textarea
attributes:
label: Observed Behavior
description: What happened instead?
placeholder: A TypeError exception was raised
validations:
required: true
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/.github/ISSUE_TEMPLATE/config.yml 0000644 0001751 0001751 00000001371 15136437134 020567 0 ustar 00runner runner # Reference: https://help.github.com/en/github/building-a-strong-community/configuring-issue-templates-for-your-repository#configuring-the-template-chooser
blank_issues_enabled: false
contact_links:
- name: 📖 Contributing Policy
url: https://github.com/netbox-community/netbox/blob/develop/CONTRIBUTING.md
about: "Please read through our contributing policy before opening an issue or pull request."
- name: ❓ Discussion
url: https://github.com/netbox-community/pynetbox/discussions
about: "If you're just looking for help, try starting a discussion instead."
- name: 💬 Community Slack
url: https://netdev.chat
about: "Join #netbox on the NetDev Community Slack for assistance with installation issues and other problems."
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/.github/ISSUE_TEMPLATE/deprecation.yaml 0000644 0001751 0001751 00000001273 15136437134 021761 0 ustar 00runner runner ---
name: 🗑️ Deprecation
description: The removal of an existing feature or resource
labels: ["app: pynetbox", "type: deprecation"]
body:
- type: textarea
attributes:
label: Proposed Changes
description: >
Describe in detail the proposed changes. What is being removed?
validations:
required: true
- type: textarea
attributes:
label: Justification
description: Please provide justification for the proposed change(s).
validations:
required: true
- type: textarea
attributes:
label: Impact
description: List all areas of the application that will be affected by this change.
validations:
required: true
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/.github/ISSUE_TEMPLATE/documentation_change.yaml 0000644 0001751 0001751 00000001644 15136437134 023644 0 ustar 00runner runner ---
name: 📖 Documentation Change
description: Suggest an addition or modification to the pynetbox documentation
labels: ["app: pynetbox", "type: documentation", "status: needs triage"]
body:
- type: dropdown
attributes:
label: Change Type
description: What type of change are you proposing?
options:
- Addition
- Correction
- Removal
- Cleanup (formatting, typos, etc.)
validations:
required: true
- type: dropdown
attributes:
label: Area
description: To what section of the documentation does this change primarily pertain?
options:
- Endpoint
- Response
- Request
- IPAM
- Other
validations:
required: true
- type: textarea
attributes:
label: Proposed Changes
description: Describe the proposed changes and why they are necessary.
validations:
required: true
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/.github/ISSUE_TEMPLATE/feature_request.yaml 0000644 0001751 0001751 00000004307 15136437134 022670 0 ustar 00runner runner ---
name: ✨ Feature Request
description: Propose a new pynetbox feature or enhancement
labels: ["app: pynetbox", "type: feature", "status: needs triage"]
body:
- type: markdown
attributes:
value: >
**NOTE:** This form is only for submitting well-formed proposals to extend or modify
pynetbox in some way. If you're trying to solve a problem but can't figure out how, or if
you still need time to work on the details of a proposed new feature, please start a
[discussion](https://github.com/netbox-community/pynetbox/discussions) instead.
- type: input
attributes:
label: pynetbox version
description: What version of pynetbox are you currently running?
placeholder: v7.1.0
validations:
required: true
- type: input
attributes:
label: NetBox version
description: What version of NetBox are you currently running?
placeholder: v3.6.0
validations:
required: true
- type: dropdown
attributes:
label: Feature type
options:
- Data model extension
- New functionality
- Change to existing functionality
validations:
required: true
- type: textarea
attributes:
label: Proposed functionality
description: >
Describe in detail the new feature or behavior you are proposing. Include any specific changes
to work flows, data models, and/or the user interface. The more detail you provide here, the
greater chance your proposal has of being discussed. Feature requests which don't include an
actionable implementation plan will be rejected.
validations:
required: true
- type: textarea
attributes:
label: Use case
description: >
Explain how adding this functionality would benefit pynetbox users. What need does it address?
validations:
required: true
- type: textarea
attributes:
label: External dependencies
description: >
List any new dependencies on external libraries or services that this new feature would
introduce. For example, does the proposal require the installation of a new Python package?
(Not all new features introduce new dependencies.)
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/.github/ISSUE_TEMPLATE/housekeeping.yaml 0000644 0001751 0001751 00000001514 15136437134 022150 0 ustar 00runner runner ---
name: 🏡 Housekeeping
description: A change pertaining to the codebase itself (developers only)
labels: ["app: pynetbox", "type: housekeeping"]
body:
- type: markdown
attributes:
value: >
**NOTE:** This template is for use by maintainers only. Please do not submit
an issue using this template unless you have been specifically asked to do so.
- type: textarea
attributes:
label: Proposed Changes
description: >
Describe in detail the new feature or behavior you'd like to propose.
Include any specific changes to work flows, data models, or the user interface.
validations:
required: true
- type: textarea
attributes:
label: Justification
description: Please provide justification for the proposed change(s).
validations:
required: true
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/.github/PULL_REQUEST_TEMPLATE.md 0000644 0001751 0001751 00000001134 15136437134 020212 0 ustar 00runner runner
### Fixes: #1234
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1769619043.7943304
pynetbox-7.6.1/.github/workflows/ 0000755 0001751 0001751 00000000000 15136437144 016450 5 ustar 00runner runner ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/.github/workflows/build-mkdocs.yml 0000644 0001751 0001751 00000000767 15136437134 021561 0 ustar 00runner runner name: Build MkDocs
on:
push:
branches:
- master
- main
permissions:
contents: write
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: 3.x
- run: pip install mkdocs-material mkdocs-autorefs mkdocs-material-extensions mkdocstrings mkdocstrings-python-legacy mkdocs-include-markdown-plugin pymdown-extensions markdown-include
- run: mkdocs gh-deploy --force
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/.github/workflows/publish.yml 0000644 0001751 0001751 00000002074 15136437134 020643 0 ustar 00runner runner # This workflow will upload a Python Package using Twine when a release is created
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
name: Upload Python Package
on:
release:
types: [published]
permissions:
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v3
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install build
- name: Build package
run: python -m build
- name: Publish package
uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/.github/workflows/py3.yml 0000644 0001751 0001751 00000001421 15136437134 017703 0 ustar 00runner runner name: Py3 Test
on:
pull_request: {}
push:
branches:
- master
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
python: ["3.10", "3.11", "3.12"]
netbox: ["4.2", "4.3", "4.4"]
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python }}
- name: Install dev requirements
run: pip install -r requirements-dev.txt .
- name: Free up Docker resources
run: |
docker system prune -af --volumes
docker network prune -f
- name: Run Linter
run: ruff check pynetbox/ tests/
- name: Run Tests
run: pytest --netbox-versions=${{ matrix.netbox }}
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/.gitignore 0000644 0001751 0001751 00000002363 15136437134 015046 0 ustar 00runner runner # Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib64/
lib/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
# Other git repos checked out locally
.netbox-docker-*/
.devicetype-library/
# Visual Studio Code settings
.vscode/
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/.pre-commit-config.yaml 0000644 0001751 0001751 00000000424 15136437134 017333 0 ustar 00runner runner # See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.14.1
hooks:
- id: ruff
name: "Ruff linter"
args: [ pynetbox/, tests/ ]
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/.readthedocs.yaml 0000644 0001751 0001751 00000000420 15136437134 016275 0 ustar 00runner runner version: 2
build:
os: ubuntu-22.04
tools:
python: "3.11"
# Build from the docs/ directory with Sphinx
sphinx:
configuration: docs/conf.py
# Explicitly set the version of Python and its requirements
python:
install:
- requirements: docs/requirements.txt
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/CHANGELOG.md 0000644 0001751 0001751 00000000127 15136437134 014663 0 ustar 00runner runner
For the list of changelog, please see the repository releases information in GitHub.
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/LICENSE 0000644 0001751 0001751 00000022614 15136437134 014064 0 ustar 00runner runner
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
Copyright 2017 DigitalOcean ././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1769619043.8223305
pynetbox-7.6.1/PKG-INFO 0000644 0001751 0001751 00000012146 15136437144 014154 0 ustar 00runner runner Metadata-Version: 2.4
Name: pynetbox
Version: 7.6.1
Summary: NetBox API client library
Home-page: https://github.com/netbox-community/pynetbox
Author: Zach Moody, Arthur Hanson
Author-email: ahanson@netboxlabs.com
License: Apache2
Keywords: netbox
Classifier: Intended Audience :: Developers
Classifier: Development Status :: 5 - Production/Stable
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests<3.0,>=2.20.0
Requires-Dist: packaging
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: keywords
Dynamic: license
Dynamic: license-file
Dynamic: requires-dist
Dynamic: summary
# Pynetbox
Python API client library for [NetBox](https://github.com/netbox-community/netbox).
> **Note:** Version 6.7 and later of the library only supports NetBox 3.3 and above.
## Compatibility
Each pyNetBox Version listed below has been tested with its corresponding NetBox Version.
| NetBox Version | Plugin Version |
|:--------------:|:--------------:|
| 4.5 | 7.6.1 |
| 4.5 | 7.6.0 |
| 4.4 | 7.5.0 |
| 4.3 | 7.5.0 |
| 4.2 | 7.5.0 |
| 4.1 | 7.5.0 |
| 4.0.6 | 7.4.1 |
| 4.0.0 | 7.3.4 |
| 3.7 | 7.3.0 |
| 3.6 | 7.2.0 |
| 3.5 | 7.1.0 |
| 3.3 | 7.0.0 |
## Installation
To install run `pip install pynetbox`.
Alternatively, you can clone the repo and run `python setup.py install`.
## Quick Start
The full pynetbox API is documented on [GitHub Pages](https://netbox-community.github.io/pynetbox/), but the following should be enough to get started using it.
To begin, import pynetbox and instantiate the API.
```
import pynetbox
nb = pynetbox.api(
'http://localhost:8000',
token='d6f4e314a5b5fefd164995169f28ae32d987704f'
)
```
The first argument the .api() method takes is the NetBox URL. There are a handful of named arguments you can provide, but in most cases none are required to simply pull data. In order to write, the `token` argument should to be provided.
## Queries
The pynetbox API is setup so that NetBox's apps are attributes of the `.api()` object, and in turn those apps have attribute representing each endpoint. Each endpoint has a handful of methods available to carry out actions on the endpoint. For example, in order to query all the objects in the `devices` endpoint you would do the following:
```
>>> devices = nb.dcim.devices.all()
>>> for device in devices:
... print(device.name)
...
test1-leaf1
test1-leaf2
test1-leaf3
>>>
```
Note that the all() and filter() methods are generators and return an object that can be iterated over only once. If you are going to be iterating over it repeatedly you need to either call the all() method again, or encapsulate the results in a `list` object like this:
```
>>> devices = list(nb.dcim.devices.all())
```
### Threading
pynetbox supports multithreaded calls for `.filter()` and `.all()` queries. It is **highly recommended** you have `MAX_PAGE_SIZE` in your Netbox install set to anything *except* `0` or `None`. The default value of `1000` is usually a good value to use. To enable threading, add `threading=True` parameter to the `.api`:
```python
nb = pynetbox.api(
'http://localhost:8000',
threading=True,
)
```
### Filters validation
NetBox doesn't validate filters passed to the GET API endpoints, which are accessed with `.get()` and `.filter()`. If a filter is incorrect, NetBox silently returns the entire database table content. Pynetbox allows to check provided parameters against NetBox OpenAPI specification before doing the call, and raise an exception if a parameter is incorrect.
This can be enabled globally by setting `strict_filters=True` in the API object initialization:
```python
nb = pynetbox.api(
'http://localhost:8000',
strict_filters=True,
)
```
This can also be enabled and disabled on a per-request basis:
```python
# Disable for one request when enabled globally.
# Will not raise an exception and return the entire Device table.
nb.dcim.devices.filter(non_existing_filter="aaaa", strict_filters=False)
# Enable for one request when not enabled globally.
# Will raise an exception.
nb.dcim.devices.filter(non_existing_filter="aaaa", strict_filters=True)
```
## Running Tests
First, create and activate a Python virtual environment in the pynetbox directory to isolate the project dependencies:
```python
python3 -m venv venv
source venv/bin/activate
```
Install both requirements files:
```python
pip install -r requirements.txt
pip install -r requirements-dev.txt
```
The test suite requires Docker to be installed and running, as it will download and launch netbox-docker containers during test execution.
With Docker installed and running, execute the following command to run the test suite:
```python
pytest
```
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/README.md 0000644 0001751 0001751 00000010337 15136437134 014335 0 ustar 00runner runner # Pynetbox
Python API client library for [NetBox](https://github.com/netbox-community/netbox).
> **Note:** Version 6.7 and later of the library only supports NetBox 3.3 and above.
## Compatibility
Each pyNetBox Version listed below has been tested with its corresponding NetBox Version.
| NetBox Version | Plugin Version |
|:--------------:|:--------------:|
| 4.5 | 7.6.1 |
| 4.5 | 7.6.0 |
| 4.4 | 7.5.0 |
| 4.3 | 7.5.0 |
| 4.2 | 7.5.0 |
| 4.1 | 7.5.0 |
| 4.0.6 | 7.4.1 |
| 4.0.0 | 7.3.4 |
| 3.7 | 7.3.0 |
| 3.6 | 7.2.0 |
| 3.5 | 7.1.0 |
| 3.3 | 7.0.0 |
## Installation
To install run `pip install pynetbox`.
Alternatively, you can clone the repo and run `python setup.py install`.
## Quick Start
The full pynetbox API is documented on [GitHub Pages](https://netbox-community.github.io/pynetbox/), but the following should be enough to get started using it.
To begin, import pynetbox and instantiate the API.
```
import pynetbox
nb = pynetbox.api(
'http://localhost:8000',
token='d6f4e314a5b5fefd164995169f28ae32d987704f'
)
```
The first argument the .api() method takes is the NetBox URL. There are a handful of named arguments you can provide, but in most cases none are required to simply pull data. In order to write, the `token` argument should to be provided.
## Queries
The pynetbox API is setup so that NetBox's apps are attributes of the `.api()` object, and in turn those apps have attribute representing each endpoint. Each endpoint has a handful of methods available to carry out actions on the endpoint. For example, in order to query all the objects in the `devices` endpoint you would do the following:
```
>>> devices = nb.dcim.devices.all()
>>> for device in devices:
... print(device.name)
...
test1-leaf1
test1-leaf2
test1-leaf3
>>>
```
Note that the all() and filter() methods are generators and return an object that can be iterated over only once. If you are going to be iterating over it repeatedly you need to either call the all() method again, or encapsulate the results in a `list` object like this:
```
>>> devices = list(nb.dcim.devices.all())
```
### Threading
pynetbox supports multithreaded calls for `.filter()` and `.all()` queries. It is **highly recommended** you have `MAX_PAGE_SIZE` in your Netbox install set to anything *except* `0` or `None`. The default value of `1000` is usually a good value to use. To enable threading, add `threading=True` parameter to the `.api`:
```python
nb = pynetbox.api(
'http://localhost:8000',
threading=True,
)
```
### Filters validation
NetBox doesn't validate filters passed to the GET API endpoints, which are accessed with `.get()` and `.filter()`. If a filter is incorrect, NetBox silently returns the entire database table content. Pynetbox allows to check provided parameters against NetBox OpenAPI specification before doing the call, and raise an exception if a parameter is incorrect.
This can be enabled globally by setting `strict_filters=True` in the API object initialization:
```python
nb = pynetbox.api(
'http://localhost:8000',
strict_filters=True,
)
```
This can also be enabled and disabled on a per-request basis:
```python
# Disable for one request when enabled globally.
# Will not raise an exception and return the entire Device table.
nb.dcim.devices.filter(non_existing_filter="aaaa", strict_filters=False)
# Enable for one request when not enabled globally.
# Will raise an exception.
nb.dcim.devices.filter(non_existing_filter="aaaa", strict_filters=True)
```
## Running Tests
First, create and activate a Python virtual environment in the pynetbox directory to isolate the project dependencies:
```python
python3 -m venv venv
source venv/bin/activate
```
Install both requirements files:
```python
pip install -r requirements.txt
pip install -r requirements-dev.txt
```
The test suite requires Docker to be installed and running, as it will download and launch netbox-docker containers during test execution.
With Docker installed and running, execute the following command to run the test suite:
```python
pytest
```
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1769619043.7963305
pynetbox-7.6.1/docs/ 0000755 0001751 0001751 00000000000 15136437144 014003 5 ustar 00runner runner ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/docs/IPAM.md 0000644 0001751 0001751 00000007641 15136437134 015062 0 ustar 00runner runner # IPAM
This page documents special methods available for IPAM models in pyNetBox.
!!! note "Standard API Operations"
Standard CRUD operations (`.all()`, `.filter()`, `.get()`, `.create()`, `.update()`, `.delete()`) follow NetBox's REST API patterns. Refer to the [NetBox API documentation](https://demo.netbox.dev/api/docs/) for details on available endpoints and filters.
## Prefixes
### Available IPs
The `available_ips` property provides access to view and create available IP addresses within a prefix.
::: pynetbox.models.ipam.Prefixes.available_ips
handler: python
options:
show_source: true
**Examples:**
```python
prefix = nb.ipam.prefixes.get(prefix='10.0.0.0/24')
# List available IP addresses
available = prefix.available_ips.list()
# [10.0.0.1/24, 10.0.0.2/24, 10.0.0.3/24, ...]
# Create a single IP from available pool
new_ip = prefix.available_ips.create()
# Create multiple IPs
new_ips = prefix.available_ips.create([{} for i in range(5)])
# Create IP with specific attributes
new_ip = prefix.available_ips.create({
'dns_name': 'server01.example.com',
'description': 'Web Server',
'status': 'active'
})
```
### Available Prefixes
The `available_prefixes` property provides access to view and create available child prefixes within a parent prefix.
::: pynetbox.models.ipam.Prefixes.available_prefixes
handler: python
options:
show_source: true
**Examples:**
```python
prefix = nb.ipam.prefixes.get(prefix='10.0.0.0/16')
# List available child prefixes
available = prefix.available_prefixes.list()
# [10.0.1.0/24, 10.0.2.0/23, 10.0.4.0/22, ...]
# Create a child prefix
new_prefix = prefix.available_prefixes.create({
'prefix_length': 24,
'status': 'active',
'description': 'Server subnet'
})
# Create multiple child prefixes
new_prefixes = prefix.available_prefixes.create([
{'prefix_length': 24},
{'prefix_length': 24},
{'prefix_length': 25}
])
```
## IP Ranges
### Available IPs
The `available_ips` property provides access to view and create available IP addresses within an IP range.
::: pynetbox.models.ipam.IpRanges.available_ips
handler: python
options:
show_source: true
**Examples:**
```python
ip_range = nb.ipam.ip_ranges.get(1)
# List available IPs in range
available = ip_range.available_ips.list()
# Create single IP from range
new_ip = ip_range.available_ips.create()
# Create multiple IPs
new_ips = ip_range.available_ips.create([{} for i in range(10)])
# Create IP with attributes
new_ip = ip_range.available_ips.create({
'description': 'DHCP reservation',
'status': 'reserved'
})
```
## VLAN Groups
### Available VLANs
The `available_vlans` property provides access to view and create available VLANs within a VLAN group.
::: pynetbox.models.ipam.VlanGroups.available_vlans
handler: python
options:
show_source: true
**Examples:**
```python
vlan_group = nb.ipam.vlan_groups.get(name='Production')
# List available VLAN IDs
available = vlan_group.available_vlans.list()
# [10, 11, 12, 13, ...]
# Create a VLAN from available IDs
new_vlan = vlan_group.available_vlans.create({
'name': 'NewVLAN',
'status': 'active'
})
# NewVLAN (VID: 10)
# Create VLAN with specific VID (must be in available range)
new_vlan = vlan_group.available_vlans.create({
'name': 'Servers',
'vid': 100,
'status': 'active'
})
```
## ASN Ranges
### Available ASNs
The `available_asns` property provides access to view and create available ASNs within an ASN range.
::: pynetbox.models.ipam.AsnRanges.available_asns
handler: python
options:
show_source: true
**Examples:**
```python
asn_range = nb.ipam.asn_ranges.get(name='Private ASN Pool')
# List available ASNs
available = asn_range.available_asns.list()
# [64512, 64513, 64514, ...]
# Allocate a single ASN
new_asn = asn_range.available_asns.create()
# 64512
# Allocate multiple ASNs
new_asns = asn_range.available_asns.create([{} for i in range(5)])
```
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/docs/advanced.md 0000644 0001751 0001751 00000017667 15136437134 016112 0 ustar 00runner runner # Advanced Usage
## Threading
PyNetBox supports multithreaded calls for `.filter()` and `.all()` queries to significantly improve performance when fetching large datasets.
!!! warning "NetBox Configuration Required"
It is **highly recommended** you have `MAX_PAGE_SIZE` in your NetBox installation set to anything *except* `0` or `None`. The default value of `1000` is usually a good value to use.
### Enabling Threading
Enable threading globally by passing `threading=True` to the API initialization:
```python
import pynetbox
nb = pynetbox.api(
'http://localhost:8000',
token='your-token',
threading=True
)
# Now all .all() and .filter() calls will use threading
devices = nb.dcim.devices.all() # Fetches pages in parallel
```
### How It Works
When threading is enabled:
- PyNetBox fetches multiple pages of results in parallel
- Significantly faster for large result sets
- Especially useful for `.all()` queries that span many pages
- Works automatically with pagination
### Example
```python
import pynetbox
import time
nb = pynetbox.api('http://localhost:8000', token='your-token')
# Without threading
start = time.time()
devices = list(nb.dcim.devices.all())
print(f"Without threading: {time.time() - start:.2f}s")
# With threading
nb_threaded = pynetbox.api(
'http://localhost:8000',
token='your-token',
threading=True
)
start = time.time()
devices = list(nb_threaded.dcim.devices.all())
print(f"With threading: {time.time() - start:.2f}s")
```
## Filter Validation
NetBox doesn't validate filters passed to GET API endpoints (`.get()` and `.filter()`). If a filter is incorrect, NetBox silently returns the entire database table content, which can be slow and unexpected.
PyNetBox can validate filter parameters against NetBox's OpenAPI specification before making the request, raising an exception if a parameter is invalid.
### Enabling Strict Filters Globally
```python
import pynetbox
nb = pynetbox.api(
'http://localhost:8000',
token='your-token',
strict_filters=True # Enable validation globally
)
# This will raise ParameterValidationError
try:
devices = nb.dcim.devices.filter(non_existing_filter='value')
except pynetbox.core.query.ParameterValidationError as e:
print(f"Invalid filter: {e}")
```
### Per-Request Validation
You can also enable or disable validation on a per-request basis:
```python
nb = pynetbox.api('http://localhost:8000', token='your-token')
# Enable for one request (when not globally enabled)
try:
devices = nb.dcim.devices.filter(
non_existing_filter='aaaa',
strict_filters=True
)
except pynetbox.core.query.ParameterValidationError as e:
print(f"Invalid filter: {e}")
# Disable for one request (when globally enabled)
nb_strict = pynetbox.api(
'http://localhost:8000',
token='your-token',
strict_filters=True
)
# This won't raise an exception, but returns entire table
devices = nb_strict.dcim.devices.filter(
non_existing_filter='aaaa',
strict_filters=False
)
```
### Benefits of Strict Filters
- **Catch typos early**: Find misspelled filter names before making requests
- **Prevent full table scans**: Avoid accidentally fetching entire tables
- **Better error messages**: Get clear feedback about invalid parameters
- **Development aid**: Helpful during development to ensure correct filter usage
### Example
```python
import pynetbox
nb = pynetbox.api(
'http://localhost:8000',
token='your-token',
strict_filters=True
)
# Valid filter - works fine
devices = nb.dcim.devices.filter(site='datacenter1')
# Invalid filter - raises exception
try:
devices = nb.dcim.devices.filter(iste='datacenter1') # Typo: 'iste' instead of 'site'
except pynetbox.core.query.ParameterValidationError as e:
print(f"Error: {e}")
# Error: 'iste' is not a valid filter parameter for dcim.devices
```
## Custom Sessions
Custom sessions can be used to modify the default HTTP behavior. Below are a few examples, most of them from [here](https://hodovi.ch/blog/advanced-usage-python-requests-timeouts-retries-hooks/).
### Headers
To set a custom header on all requests. These headers are automatically merged with headers pynetbox sets itself.
Example:
```python
import pynetbox
import requests
session = requests.Session()
session.headers = {"mycustomheader": "test"}
nb = pynetbox.api(
'http://localhost:8000',
token='d6f4e314a5b5fefd164995169f28ae32d987704f'
)
nb.http_session = session
```
### SSL Verification
To disable SSL verification. See [the docs](https://requests.readthedocs.io/en/stable/user/advanced/#ssl-cert-verification).
Example:
```python
import pynetbox
import requests
session = requests.Session()
session.verify = False
nb = pynetbox.api(
'http://localhost:8000',
token='d6f4e314a5b5fefd164995169f28ae32d987704f'
)
nb.http_session = session
```
### Timeouts
Setting timeouts requires the use of Adapters.
Example:
```python
from requests.adapters import HTTPAdapter
class TimeoutHTTPAdapter(HTTPAdapter):
def __init__(self, *args, **kwargs):
self.timeout = kwargs.get("timeout", 5)
super().__init__(*args, **kwargs)
def send(self, request, **kwargs):
kwargs['timeout'] = self.timeout
return super().send(request, **kwargs)
adapter = TimeoutHTTPAdapter()
session = requests.Session()
session.mount("http://", adapter)
session.mount("https://", adapter)
nb = pynetbox.api(
'http://localhost:8000',
token='d6f4e314a5b5fefd164995169f28ae32d987704f'
)
nb.http_session = session
```
## File Uploads (Image Attachments)
Pynetbox supports file uploads for endpoints that accept them, such as image attachments. When you pass a file-like object (anything with a `.read()` method) to `create()`, pynetbox automatically detects it and uses multipart/form-data encoding instead of JSON.
### Creating an Image Attachment
```python
import pynetbox
nb = pynetbox.api(
'http://localhost:8000',
token='d6f4e314a5b5fefd164995169f28ae32d987704f'
)
# Attach an image to a device
with open('/path/to/image.png', 'rb') as f:
attachment = nb.extras.image_attachments.create(
object_type='dcim.device',
object_id=1,
image=f,
name='rack-photo.png'
)
```
### Using io.BytesIO
You can also use in-memory file objects:
```python
import io
import pynetbox
nb = pynetbox.api(
'http://localhost:8000',
token='d6f4e314a5b5fefd164995169f28ae32d987704f'
)
# Create image from bytes
image_data = b'...' # Your image bytes
file_obj = io.BytesIO(image_data)
file_obj.name = 'generated-image.png' # Optional: set filename
attachment = nb.extras.image_attachments.create(
object_type='dcim.device',
object_id=1,
image=file_obj
)
```
### Custom Filename and Content-Type
For more control, pass a tuple instead of a file object:
```python
with open('/path/to/image.png', 'rb') as f:
attachment = nb.extras.image_attachments.create(
object_type='dcim.device',
object_id=1,
image=('custom-name.png', f, 'image/png')
)
```
The tuple format is `(filename, file_object)` or `(filename, file_object, content_type)`.
## Multi-Format Responses
Some endpoints support multiple response formats. The rack elevation endpoint can return both JSON data and SVG diagrams.
### Getting Rack Elevation as JSON
By default, the elevation endpoint returns JSON data as a list of rack unit objects:
```python
import pynetbox
nb = pynetbox.api(
'http://localhost:8000',
token='d6f4e314a5b5fefd164995169f28ae32d987704f'
)
rack = nb.dcim.racks.get(123)
# Returns list of RU objects (default JSON response)
units = rack.elevation.list()
for unit in units:
print(unit.id, unit.name)
```
### Getting Rack Elevation as SVG
Use the `render='svg'` parameter to get a graphical SVG diagram:
```python
rack = nb.dcim.racks.get(123)
# Returns raw SVG string
svg_diagram = rack.elevation.list(render='svg')
print(svg_diagram) # ''
# Save to file
with open('rack-elevation.svg', 'w') as f:
f.write(svg_diagram)
```
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/docs/api.md 0000644 0001751 0001751 00000004131 15136437134 015074 0 ustar 00runner runner # API Core Classes
This page documents the core classes that form pyNetBox's API structure.
## Overview
PyNetBox uses a layered architecture to interact with NetBox:
1. **Api** - The main entry point that creates connections to NetBox
2. **App** - Represents NetBox applications (dcim, ipam, circuits, etc.)
3. **Endpoint** - Provides CRUD operations for specific API endpoints
```python
import pynetbox
# Create API connection (Api class)
nb = pynetbox.api('http://localhost:8000', token='your-token')
# Access an app (App class)
nb.dcim # Returns an App instance
# Access an endpoint (Endpoint class)
nb.dcim.devices # Returns an Endpoint instance
# Use endpoint methods
devices = nb.dcim.devices.all()
```
## Api Class
The `Api` class is the main entry point for interacting with NetBox. It manages the HTTP session, authentication, and provides access to NetBox applications.
::: pynetbox.core.api.Api
handler: python
options:
members:
- __init__
- create_token
- openapi
- status
- version
- activate_branch
show_source: true
show_root_heading: true
heading_level: 3
## App Class
The `App` class represents a NetBox application (such as dcim, ipam, circuits). When you access an attribute on the `Api` object, it returns an `App` instance. Accessing attributes on an `App` returns `Endpoint` objects.
::: pynetbox.core.app.App
handler: python
options:
members:
- config
show_source: true
show_root_heading: true
heading_level: 3
## Relationship to Endpoints
When you access an attribute on an `App` object, it returns an [Endpoint](endpoint.md) instance:
```python
# nb.dcim is an App instance
# nb.dcim.devices is an Endpoint instance
devices_endpoint = nb.dcim.devices
# Endpoint provides CRUD methods
all_devices = devices_endpoint.all()
device = devices_endpoint.get(1)
new_device = devices_endpoint.create(name='test', site=1, device_type=1, device_role=1)
```
See the [Endpoint documentation](endpoint.md) for details on available methods.
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/docs/branching.md 0000644 0001751 0001751 00000005330 15136437134 016260 0 ustar 00runner runner # Branching Plugin
The NetBox branching plugin allows you to create and work with branches in NetBox, similar to version control systems. This enables you to make changes in isolation and merge them back to the main branch when ready.
## Activating Branches
The `activate_branch` context manager allows you to perform operations within a specific branch's schema. All operations performed within the context manager will use that branch's schema.
```python
import pynetbox
# Initialize the API
nb = pynetbox.api(
"http://localhost:8000",
token="your-token-here"
)
# Get an existing branch
branch = nb.plugins.branching.branches.get(id=1)
# Activate the branch for operations
with nb.activate_branch(branch):
# All operations within this block will use the branch's schema
sites = nb.dcim.sites.all()
# Make changes to objects...
# These changes will only exist in this branch
```
## Waiting for Branch Status
When working with branches, you often need to wait for certain status changes, such as when a branch becomes ready after creation or when a merge operation completes. The [tenacity](https://github.com/jd/tenacity) library provides a robust way to handle these waiting scenarios.
First, install tenacity:
```bash
pip install tenacity
```
Here's how to create a reusable function to wait for branch status changes:
```python
from tenacity import retry, retry_if_result, stop_after_attempt, wait_exponential
import pynetbox
@retry(
stop=stop_after_attempt(30), # Try for up to 30 attempts
wait=wait_exponential(
multiplier=1, min=4, max=60
), # Wait between 4-60 seconds, increasing exponentially
retry=retry_if_result(lambda x: not x), # Retry if the status check returns False
)
def wait_for_branch_status(branch, target_status):
"""Wait for branch to reach a specific status, with exponential backoff."""
branch = nb.plugins.branching.branches.get(branch.id)
return str(branch.status) == target_status
# Example usage:
branch = nb.plugins.branching.branches.create(name="my-branch")
# Wait for branch to be ready
wait_for_branch_status(branch, "Ready")
# Get the latest branch status
branch = nb.plugins.branching.branches.get(branch.id)
print(f"Branch is now ready! Status: {branch.status}")
```
The function will:
1. Check the current status of the branch
2. If the status doesn't match the target status, it will retry with exponential backoff
3. Continue retrying until either:
- The branch reaches the target status
- The maximum number of attempts (30) is reached
- The maximum wait time (60 seconds) is exceeded
The exponential backoff ensures that we don't overwhelm the server with requests while still checking frequently enough to catch status changes quickly. ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/docs/circuits.md 0000644 0001751 0001751 00000007414 15136437134 016157 0 ustar 00runner runner # Circuits
This page documents special methods available for Circuits models in pyNetBox.
!!! note "Standard API Operations"
Standard CRUD operations (`.all()`, `.filter()`, `.get()`, `.create()`, `.update()`, `.delete()`) follow NetBox's REST API patterns. Refer to the [NetBox API documentation](https://demo.netbox.dev/api/docs/) for details on available endpoints and filters.
## Circuit Terminations
### Cable Path Tracing
Circuit terminations support cable path tracing through the `paths()` method. This method returns all cable paths that traverse through the circuit termination, showing the complete connectivity from origin to destination.
**Example:**
```python
# Get a circuit termination
circuit_term = nb.circuits.circuit_terminations.get(circuit_id=123, term_side='A')
# Get all cable paths through this termination
paths = circuit_term.paths()
# Each path contains origin, destination, and path segments
for path_info in paths:
print(f"Origin: {path_info['origin']}")
print(f"Destination: {path_info['destination']}")
print("Path segments:")
for segment in path_info['path']:
for obj in segment:
print(f" - {obj}")
# Example: Find what a circuit connects to
circuit = nb.circuits.circuits.get(cid='CIRCUIT-001')
terminations = nb.circuits.circuit_terminations.filter(circuit_id=circuit.id)
for term in terminations:
print(f"\nTermination {term.term_side}:")
paths = term.paths()
if paths:
for path in paths:
if path['destination']:
print(f" Connected to: {path['destination']}")
else:
print(" No destination (incomplete path)")
else:
print(" No cable paths")
```
**Path Structure:**
The `paths()` method returns a list of dictionaries, where each dictionary represents a complete cable path:
- `origin`: The starting endpoint of the path (Record object or None if unconnected)
- `destination`: The ending endpoint of the path (Record object or None if unconnected)
- `path`: A list of path segments, where each segment is a list of Record objects representing the components in that segment (cables, terminations, interfaces, etc.)
## Virtual Circuits
### Overview
Virtual circuits also support cable path tracing through the `paths()` method.
**Example:**
```python
# Get a virtual circuit
vcircuit = nb.circuits.virtual_circuits.get(cid='VPLS-001')
print(f"Virtual Circuit: {vcircuit.cid}")
print(f"Provider Network: {vcircuit.provider_network.name}")
print(f"Type: {vcircuit.type.name}")
# List all terminations for a virtual circuit
terminations = nb.circuits.virtual_circuit_terminations.filter(
virtual_circuit_id=vcircuit.id
)
for term in terminations:
print(f"Termination Role: {term.role}")
```
### Virtual Circuit Termination Path Tracing
Virtual circuit terminations also support cable path tracing through the `paths()` method.
**Example:**
```python
# Get a virtual circuit termination
vterm = nb.circuits.virtual_circuit_terminations.get(
virtual_circuit_id=123, role='hub'
)
# Get all cable paths through this termination
paths = vterm.paths()
# Analyze the connectivity
for path_info in paths:
print(f"Origin: {path_info['origin']}")
print(f"Destination: {path_info['destination']}")
print("Path segments:")
for segment in path_info['path']:
for obj in segment:
print(f" - {obj}")
# Example: Find all devices connected via a virtual circuit
vcircuit = nb.circuits.virtual_circuits.get(cid='VPLS-001')
terminations = nb.circuits.virtual_circuit_terminations.filter(
virtual_circuit_id=vcircuit.id
)
print(f"Virtual Circuit {vcircuit.cid} connectivity:")
for term in terminations:
paths = term.paths()
if paths and paths[0]['destination']:
print(f" {term.role}: {paths[0]['destination']}")
```
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/docs/dcim.md 0000644 0001751 0001751 00000011176 15136437134 015246 0 ustar 00runner runner # DCIM
This page documents special methods available for DCIM models in pyNetBox.
!!! note "Standard API Operations"
Standard CRUD operations (`.all()`, `.filter()`, `.get()`, `.create()`, `.update()`, `.delete()`) follow NetBox's REST API patterns. Refer to the [NetBox API documentation](https://demo.netbox.dev/api/docs/) for details on available endpoints and filters.
## Devices
### NAPALM Integration
The `napalm` property provides access to NAPALM device data.
::: pynetbox.models.dcim.Devices.napalm
handler: python
options:
show_source: true
**Example:**
```python
device = nb.dcim.devices.get(name='router1')
# Get device facts
facts = device.napalm.list(method='get_facts')
print(facts)
# Get interfaces
interfaces = device.napalm.list(method='get_interfaces')
# Get ARP table
arp = device.napalm.list(method='get_arp_table')
```
### Config Rendering
The `render_config` property renders device configuration based on config contexts and templates.
::: pynetbox.models.dcim.Devices.render_config
handler: python
options:
show_source: true
**Example:**
```python
device = nb.dcim.devices.get(name='switch1')
config = device.render_config.create()
print(config)
```
## Racks
### Rack Units
The `units` property provides access to rack unit information.
::: pynetbox.models.dcim.Racks.units
handler: python
options:
show_source: true
**Example:**
```python
rack = nb.dcim.racks.get(name='RACK-01')
units = rack.units.list()
for unit in units:
if unit.device:
print(f"U{unit.name}: {unit.device.name}")
else:
print(f"U{unit.name}: Empty")
```
### Rack Elevation
The `elevation` property supports both JSON and SVG output for rack elevation diagrams.
::: pynetbox.models.dcim.Racks.elevation
handler: python
options:
show_source: true
**Examples:**
```python
rack = nb.dcim.racks.get(name='RACK-01')
# Get elevation as JSON (returns list of RU objects)
elevation_data = rack.elevation.list()
# Get elevation as SVG diagram
svg_diagram = rack.elevation.list(render='svg')
# Save SVG to file
with open('rack-elevation.svg', 'w') as f:
f.write(svg_diagram)
```
## Cable Tracing
Several DCIM models support cable path tracing through the `trace()` method.
**Models with cable tracing:**
- Interfaces
- ConsolePorts
- ConsoleServerPorts
- PowerPorts
- PowerOutlets
- PowerFeeds
**Example:**
```python
# Trace a network interface
interface = nb.dcim.interfaces.get(name='eth0', device='switch1')
trace_result = interface.trace()
# The trace returns a list of [terminations, cable, terminations]
for item in trace_result:
if isinstance(item, list):
# Terminations
for term in item:
print(f" Termination: {term}")
else:
# Cable or None
if item:
print(f" Cable: {item.id} - {item.label}")
else:
print(" No cable")
# Trace console port
console = nb.dcim.console_ports.get(name='Console', device='router1')
console_trace = console.trace()
# Trace power connections
power_port = nb.dcim.power_ports.get(name='PSU1', device='server1')
power_trace = power_port.trace()
```
## Cable Path Tracing (Pass-Through Ports)
Front ports and rear ports use the `paths()` method instead of `trace()`.
**Models with cable path tracing:**
- FrontPorts
- RearPorts
**Example:**
```python
# Get paths through a front port
front_port = nb.dcim.front_ports.get(name='FrontPort1', device='patch-panel-1')
paths = front_port.paths()
# Each path contains origin, destination, and path segments
for path_info in paths:
print(f"Origin: {path_info['origin']}")
print(f"Destination: {path_info['destination']}")
print("Path segments:")
for segment in path_info['path']:
for obj in segment:
print(f" - {obj}")
# Get paths through a rear port
rear_port = nb.dcim.rear_ports.get(name='RearPort1', device='patch-panel-1')
rear_paths = rear_port.paths()
# Access the complete path from origin to destination
if rear_paths:
first_path = rear_paths[0]
if first_path['origin']:
print(f"Cable path starts at: {first_path['origin']}")
if first_path['destination']:
print(f"Cable path ends at: {first_path['destination']}")
```
**Path Structure:**
The `paths()` method returns a list of dictionaries, where each dictionary represents a complete cable path:
- `origin`: The starting endpoint of the path (Record object or None if unconnected)
- `destination`: The ending endpoint of the path (Record object or None if unconnected)
- `path`: A list of path segments, where each segment is a list of Record objects representing the components in that segment (cables, terminations, etc.)
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1769619043.7973304
pynetbox-7.6.1/docs/development/ 0000755 0001751 0001751 00000000000 15136437144 016325 5 ustar 00runner runner ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/docs/development/getting-started.md 0000644 0001751 0001751 00000005206 15136437134 021756 0 ustar 00runner runner # Getting Started
This guide will help you get started with development on pynetbox. It covers setting up your development environment and running tests.
## Development Environment
1. Fork the pynetbox repository on GitHub
2. Clone your fork locally
3. Create a virtual environment and install development dependencies:
```bash
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install -e ".[dev]"
```
## Running Tests
pynetbox uses pytest for testing. The test suite includes both unit tests and integration tests.
### Unit Tests
To run the unit tests:
```bash
pytest tests/unit
```
### Integration Tests
The integration tests require a running NetBox instance. The test suite uses pytest-docker to spin up NetBox instances in Docker containers.
To run the integration tests:
```bash
pytest tests/integration
```
You can specify which versions of NetBox to test against using the `--netbox-versions` flag:
```bash
pytest tests/integration --netbox-versions 4.2 4.3 4.4
```
### Running Specific Tests
You can run specific test files or test functions:
```bash
# Run a specific test file
pytest tests/unit/test_api.py
# Run a specific test function
pytest tests/unit/test_api.py::test_api_status
# Run tests matching a pattern
pytest -k "test_api"
```
### Test Coverage
To run tests with coverage reporting:
```bash
pytest --cov=pynetbox tests/
```
## Submitting Pull Requests
Once you're happy with your work and have verified that all tests pass, commit your changes and push it upstream to your fork. Always provide descriptive (but not excessively verbose) commit messages. Be sure to prefix your commit message with the word "Fixes" or "Closes" and the relevant issue number (with a hash mark). This tells GitHub to automatically close the referenced issue once the commit has been merged.
```bash
git commit -m "Closes #1234: Add IPv5 support"
git push origin
```
Once your fork has the new commit, submit a pull request to the pynetbox repo to propose the changes. Be sure to provide a detailed accounting of the changes being made and the reasons for doing so.
Once submitted, a maintainer will review your pull request and either merge it or request changes. If changes are needed, you can make them via new commits to your fork: The pull request will update automatically.
!!! warning
Remember, pull requests are permitted only for **accepted** issues. If an issue you want to work on hasn't been approved by a maintainer yet, it's best to avoid risking your time and effort on a change that might not be accepted. (The one exception to this is trivial changes to the documentation or other non-critical resources.) ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/docs/development/index.md 0000644 0001751 0001751 00000006201 15136437134 017754 0 ustar 00runner runner # Development
Thanks for your interest in contributing to pynetbox! This introduction covers a few important things to know before you get started.
## The Code
pynetbox is maintained on [GitHub](https://github.com/netbox-community/pynetbox). GitHub also serves as one of our primary discussion forums. While all the code and discussion is publicly accessible, you'll need to register for a free GitHub account to engage in participation. Most people begin by forking the pynetbox repository under their own GitHub account to begin working on the code.
There are two permanent branches in the repository:
* `master` - Active development for the upcoming patch release. Pull requests will typically be based on this branch unless they introduce breaking changes that must be deferred until the next major release.
* `feature` - New feature work to be introduced in the next major release.
pynetbox components are arranged into modules:
* `core/` - Core functionality including API interaction, response handling, and query building
* `models/` - Model definitions for different NetBox object types
* `tests/` - Test suite including unit and integration tests
* `docs/` - Documentation files
## Proposing Changes
All substantial changes made to the code base are tracked using GitHub issues. Feature requests, bug reports, and similar proposals must all be filed as issues and approved by a maintainer before work begins. This ensures that all changes to the code base are properly documented for future reference.
To submit a new feature request or bug report for pynetbox, select and complete the appropriate issue template. Once your issue has been approved, you're welcome to submit a pull request containing your proposed changes.
!!! note
Avoid starting work on a proposal before it has been accepted. Not all proposed changes will be accepted, and we'd hate for you to waste time working on code that might not make it into the project.
## Getting Help
There are two primary forums for getting assistance with pynetbox development:
* [GitHub discussions](https://github.com/netbox-community/pynetbox/discussions) - The preferred forum for general discussion and support issues. Ideal for shaping a feature requests prior to submitting an issue.
* [#netbox on NetDev Community Slack](https://netdev.chat) - Good for quick chats. Avoid any discussion that might need to be referenced later on, as the chat history is not retained indefinitely.
!!! note
Don't use GitHub issues to ask for help: These are reserved for proposed code changes only.
## Governance
pynetbox follows the benevolent dictator model of governance, with the lead maintainer ultimately responsible for all changes to the code base. While community contributions are welcomed and encouraged, the lead maintainer's primary role is to ensure the project's long-term maintainability and continued focus on its primary functions.
## Licensing
The entire pynetbox project is licensed as open source under the Apache 2.0 license. This is a very permissive license which allows unlimited redistribution of all code within the project. Note that all submissions to the project are subject to the same license. ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/docs/development/release-checklist.md 0000644 0001751 0001751 00000003162 15136437134 022237 0 ustar 00runner runner # Release Checklist
This document outlines the steps required to prepare and publish a new release of pynetbox.
## Pre-Release Tasks
1. Ensure all tests are passing:
```bash
pytest
```
2. Update version number in `pynetbox/__init__.py`
3. Update documentation for any new features or changes
4. Check NetBox Docker releases:
- Visit https://github.com/netbox-community/netbox-docker/releases
- Review the latest NetBox Docker releases and their corresponding NetBox versions
- Update supported NetBox versions in `tests/integration/conftest.py` if needed
- Ensure the `get_netbox_docker_version_tag` function in `tests/integration/conftest.py` is updated with any new version mappings
## Release Tasks
1. Create a new release branch from `master`:
```bash
git checkout master
git pull
git checkout -b release/vX.Y.Z
```
2. Commit version and changelog updates:
```bash
git commit -m "Prepare release vX.Y.Z"
```
3. Create a pull request to merge the release branch into `master`
4. Once merged, use github to create a new release:
1. Go to the GitHub repository
2. Click "Releases" in the right sidebar
3. Click "Create a new release"
4. Create a new tag (e.g., vX.Y.Z)
5. Use the changelog content as the release description
6. Publish the release
The GitHub release will automatically trigger the workflow to publish to PyPI.
## Supported NetBox Versions
pynetbox aims to support the current and previous two minor versions of NetBox. The supported versions are defined in `tests/integration/conftest.py` and should be updated as part of the release process. ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/docs/endpoint.md 0000644 0001751 0001751 00000002217 15136437134 016146 0 ustar 00runner runner # Endpoint
`Endpoint` objects provide CRUD operations for NetBox API endpoints. They are automatically created when you access attributes on [App](api.md#app-class) objects.
## Overview
```python
import pynetbox
nb = pynetbox.api('http://localhost:8000', token='your-token')
# Accessing an attribute on an App returns an Endpoint
devices = nb.dcim.devices # This is an Endpoint instance
# Use Endpoint methods for CRUD operations
all_devices = devices.all()
device = devices.get(1)
filtered = devices.filter(site='headquarters')
new_device = devices.create(name='test', site=1, device_type=1, device_role=1)
```
::: pynetbox.core.endpoint.Endpoint
handler: python
options:
members:
- all
- choices
- count
- create
- delete
- filter
- get
- update
show_source: true
show_root_heading: true
heading_level: 2
::: pynetbox.core.endpoint.DetailEndpoint
handler: python
options:
members:
- create
- list
show_source: true
show_root_heading: true
heading_level: 2
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/docs/getting-started.md 0000644 0001751 0001751 00000013237 15136437134 017437 0 ustar 00runner runner # Getting Started
This guide will walk you through the basics of using pyNetBox to interact with NetBox.
## Basic Connection
First, import pynetbox and create an API connection:
```python
import pynetbox
nb = pynetbox.api(
'http://localhost:8000',
token='d6f4e314a5b5fefd164995169f28ae32d987704f'
)
```
### Connection Parameters
The `api()` method accepts several parameters:
- **url** (required): The base URL of your NetBox instance
- **token** (optional): API authentication token (required for write operations)
- **threading** (optional): Enable multithreaded requests (default: `False`)
- **strict_filters** (optional): Enable filter validation (default: `False`)
```python
nb = pynetbox.api(
'http://localhost:8000',
token='your-token-here',
threading=True,
strict_filters=True
)
```
## Understanding the API Structure
PyNetBox mirrors NetBox's app structure. NetBox apps become attributes of the API object:
```python
nb.dcim # Data Center Infrastructure Management
nb.ipam # IP Address Management
nb.circuits # Circuit management
nb.virtualization # Virtual machines and clusters
nb.tenancy # Tenants and contacts
nb.extras # Tags, custom fields, etc.
nb.users # Users and permissions
nb.wireless # Wireless LANs and links
nb.core # Core objects (data sources, jobs)
nb.vpn # VPN tunnels and terminations
```
Each app has endpoints that correspond to NetBox's API endpoints:
```python
nb.dcim.devices
nb.dcim.sites
nb.dcim.racks
nb.ipam.ip_addresses
nb.ipam.prefixes
# ... and so on
```
## Querying Data
### Getting All Objects
Use `.all()` to retrieve all objects from an endpoint:
```python
# Get all devices
devices = nb.dcim.devices.all()
for device in devices:
print(device.name)
```
!!! warning "Generator Objects"
The `.all()` and `.filter()` methods return generators that can only be iterated once.
To iterate multiple times, wrap the result in a `list()`:
```python
devices = list(nb.dcim.devices.all())
```
### Filtering Objects
Use `.filter()` to query specific objects:
```python
# Get all devices with a specific role
leaf_switches = nb.dcim.devices.filter(role='leaf-switch')
# Multiple filters
devices = nb.dcim.devices.filter(
site='headquarters',
status='active',
role='access-switch'
)
# Filter by custom fields
devices = nb.dcim.devices.filter(cf_environment='production')
```
### Getting a Single Object
Use `.get()` to retrieve a specific object:
```python
# Get by ID
device = nb.dcim.devices.get(1)
# Get by name
device = nb.dcim.devices.get(name='spine1')
# Get returns None if not found
device = nb.dcim.devices.get(name='nonexistent')
if device is None:
print("Device not found")
```
## Working with Objects
### Accessing Attributes
Objects return attributes as properties:
```python
device = nb.dcim.devices.get(1)
print(device.name)
print(device.serial)
print(device.device_type)
print(device.site.name) # Nested objects
```
### Checking Available Attributes
```python
device = nb.dcim.devices.get(1)
# Convert to dict to see all attributes
print(dict(device))
# Or access the raw data
print(device.serialize())
```
## Creating Objects
Use `.create()` to create new objects:
```python
# Create a new site
new_site = nb.dcim.sites.create(
name='new-datacenter',
slug='new-datacenter',
status='planned'
)
# Create a device
new_device = nb.dcim.devices.create(
name='new-switch',
device_type=1, # Can use ID
site=new_site.id, # Or reference the created object
device_role=5
)
# Create with nested data
new_ip = nb.ipam.ip_addresses.create(
address='10.0.0.1/24',
status='active',
assigned_object_type='dcim.interface',
assigned_object_id=123
)
```
## Updating Objects
There are two ways to update objects:
### Method 1: Update and Save
```python
device = nb.dcim.devices.get(1)
device.serial = 'ABC123'
device.asset_tag = 'ASSET001'
device.save()
```
### Method 2: Using Update
```python
device = nb.dcim.devices.get(1)
device.update({
'serial': 'ABC123',
'asset_tag': 'ASSET001'
})
```
## Deleting Objects
Use `.delete()` to remove objects:
```python
device = nb.dcim.devices.get(1)
device.delete()
# Or delete directly by ID
nb.dcim.devices.delete(1)
```
## Working with Choices
Get available choices for choice fields:
```python
# Get all status choices for devices
statuses = nb.dcim.devices.choices()
print(statuses['status'])
# Get choices for a specific field
interface_types = nb.dcim.interfaces.choices()
print(interface_types['type'])
```
## Pagination
NetBox paginates results by default. PyNetBox handles pagination automatically:
```python
# This will automatically fetch all pages
devices = nb.dcim.devices.all()
# You can also limit results
devices = nb.dcim.devices.filter(limit=10)
```
## Error Handling
```python
from pynetbox.core.query import RequestError, ContentError
try:
device = nb.dcim.devices.create(
name='test-device',
device_type=1,
site=1,
device_role=1
)
except RequestError as e:
print(f"Request failed: {e}")
except ContentError as e:
print(f"Content error: {e}")
```
## Next Steps
- Review the [API Reference](api.md) for detailed documentation on core classes
- Learn about [Threading](advanced.md#threading) for faster queries
- Explore [Filter Validation](advanced.md#filter-validation) for safer queries
- Review special methods documentation:
- [DCIM Special Methods](dcim.md)
- [IPAM Special Methods](ipam.md)
- [Virtualization Special Methods](virtualization.md)
- Check out [Advanced Topics](advanced.md) for custom sessions and branching
- Refer to [NetBox API Documentation](https://demo.netbox.dev/api/docs/) for standard CRUD operations
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/docs/index.md 0000644 0001751 0001751 00000005146 15136437134 015441 0 ustar 00runner runner # PyNetBox Documentation
Python API client library for [NetBox](https://github.com/netbox-community/netbox).
## Overview
PyNetBox is a Python client library that provides a simple and intuitive interface to interact with the NetBox REST API. It abstracts the complexity of making HTTP requests and provides a Pythonic way to work with NetBox data.
## Features
- **Intuitive API**: Access NetBox endpoints through simple Python attributes
- **Full CRUD Support**: Create, read, update, and delete NetBox objects
- **Threading Support**: Parallel requests for improved performance on large queries
- **Filter Validation**: Optional strict validation of filters against NetBox's OpenAPI spec
- **Custom Sessions**: Support for custom HTTP sessions with SSL, timeouts, and retries
- **Branch Support**: Context manager for NetBox branching plugin
- **Comprehensive Coverage**: Support for all NetBox apps (DCIM, IPAM, Circuits, Virtualization, etc.)
## NetBox Version Compatibility
!!! warning "Version Requirements"
Version 6.7 and later of pyNetBox only supports NetBox 3.3 and above.
Each pyNetBox version has been tested with its corresponding NetBox version:
| NetBox Version | PyNetBox Version |
|:--------------:|:----------------:|
| 4.5 | 7.6.0 |
| 4.4 | 7.5.0 |
| 4.3 | 7.5.0 |
| 4.2 | 7.5.0 |
| 4.1 | 7.5.0 |
| 4.0.6 | 7.4.1 |
| 4.0.0 | 7.3.4 |
| 3.7 | 7.3.0 |
| 3.6 | 7.2.0 |
| 3.5 | 7.1.0 |
| 3.3 | 7.0.0 |
## Quick Example
```python
import pynetbox
# Initialize the API connection
nb = pynetbox.api(
'http://localhost:8000',
token='d6f4e314a5b5fefd164995169f28ae32d987704f'
)
# Query all devices
devices = nb.dcim.devices.all()
for device in devices:
print(device.name)
# Filter devices
leaf_switches = nb.dcim.devices.filter(role='leaf-switch')
# Get a specific device
device = nb.dcim.devices.get(name='spine1')
# Create a new device
new_device = nb.dcim.devices.create(
name='new-device',
device_type=1,
site=1,
device_role=1
)
# Update a device
device.serial = 'ABC123'
device.save()
```
## Getting Help
- **GitHub Issues**: Report bugs or request features at [github.com/netbox-community/pynetbox/issues](https://github.com/netbox-community/pynetbox/issues)
- **Documentation**: Full API reference and guides available in this documentation
- **Source Code**: Available at [github.com/netbox-community/pynetbox](https://github.com/netbox-community/pynetbox)
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/docs/installation.md 0000644 0001751 0001751 00000004617 15136437134 017035 0 ustar 00runner runner # Installation
## Requirements
- **Python**: 3.10 or higher
- **NetBox**: 3.3 or higher (for pyNetBox 6.7+)
- **Dependencies**:
- `requests>=2.20.0,<3.0`
- `packaging`
## Installation Methods
### Install from PyPI (Recommended)
The easiest way to install pyNetBox is using pip:
```bash
pip install pynetbox
```
### Install from Source
If you need the latest development version or want to contribute:
```bash
# Clone the repository
git clone https://github.com/netbox-community/pynetbox.git
cd pynetbox
# Install in development mode
pip install -e .
# Or install directly
python setup.py install
```
### Using a Virtual Environment (Recommended)
It's recommended to use a virtual environment to isolate pyNetBox dependencies:
```bash
# Create a virtual environment
python3 -m venv venv
# Activate it (Linux/macOS)
source venv/bin/activate
# Activate it (Windows)
venv\Scripts\activate
# Install pynetbox
pip install pynetbox
```
## Verifying Installation
After installation, verify pyNetBox is installed correctly:
```python
import pynetbox
print(pynetbox.version)
```
You can also test connectivity to your NetBox instance:
```python
import pynetbox
nb = pynetbox.api(
'http://localhost:8000',
token='your-api-token-here'
)
# Check NetBox version
print(nb.version)
# Check API status
print(nb.status())
```
## Upgrading
To upgrade to the latest version:
```bash
pip install --upgrade pynetbox
```
To upgrade to a specific version:
```bash
pip install pynetbox==7.6.0
```
## Development Installation
If you're planning to develop or contribute to pyNetBox:
```bash
# Clone the repository
git clone https://github.com/netbox-community/pynetbox.git
cd pynetbox
# Create and activate virtual environment
python3 -m venv venv
source venv/bin/activate
# Install development dependencies
pip install -r requirements.txt
pip install -r requirements-dev.txt
# Install in editable mode
pip install -e .
```
## Docker Setup for Testing
The test suite requires Docker for integration tests:
```bash
# Ensure Docker is installed and running
docker --version
# Run the test suite
pytest
```
For more information on running tests, see the [Development Guide](development/index.md).
## Next Steps
- Read the [Getting Started Guide](getting-started.md) for basic usage
- Explore the [API Reference](endpoint.md) for detailed documentation
- Check the [Advanced Topics](advanced.md) for custom configurations
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/docs/release-notes.md 0000644 0001751 0001751 00000011161 15136437134 017072 0 ustar 00runner runner # Release Notes
## Version 7.6.1 (January 28, 2026)
#### Enhancements
- [#726](https://github.com/netbox-community/pynetbox/issues/726) - Use `dict` instead of `OrderedDict` in Record serialization
#### New Features
- [#434](https://github.com/netbox-community/pynetbox/issues/434) - Add cable path tracing support for front ports, rear ports, and virtual circuit terminations
#### Bug Fixes
- [#586](https://github.com/netbox-community/pynetbox/issues/586) - Update internal object state after save operations to prevent attribute reset issues
---
## Version 7.6.0 (January 9, 2026)
#### Breaking Changes
- **ObjectChange** moved to `core` module for NetBox 4.1.0+ compatibility
- Previously located in `extras.object_changes`
- Now accessible via `nb.core.object_changes`
#### New Features
- Support for v2 Tokens introduced in NetBox 4.5.0
- Enhanced token management capabilities
#### Enhancements
- Added SVG support for Rack Elevation endpoint
- Rack elevation diagrams can now be rendered as SVG
- Access via `rack.elevation.list(render='svg')`
#### Bug Fixes
- Fixed token authentication when retrieving NetBox version
- Prevents 403 errors during version checks
- Token now properly included in version API requests
#### Compatibility
- Supports NetBox 4.5
---
## Version 7.5.0 (May 20, 2024)
#### Enhancements
- Expanded cable trace functionality to include:
- CircuitTerminations
- ConsolePorts
- ConsoleServerPorts
- PowerOutlets
- PowerPorts
- Added built-in function to activate a branch
- Use `nb.activate_branch()` context manager for NetBox branching plugin
#### Bug Fixes
- Fixed choices returned when API tokens have PUT but not POST permissions
- Fixed `nb.version` property when using OIDC proxy authentication
#### Compatibility
- Supports NetBox 4.1, 4.2, 4.3, 4.4
---
## Version 7.4.1 (October 25, 2024)
#### Security
- Updated `requests` and `urllib3` Python libraries to address security vulnerabilities
- No functional changes
---
## Version 7.4.0 (August 8, 2024)
#### Enhancements
- Added initial NetBox 4.0 support
- Added Python 3.12 support
#### Bug Fixes
- Fixed complex custom_fields insertion failures
- Replaced `None` with `'null'` in query parameters
- Corrected connected endpoints behavior
#### Testing
- Removed Python 3.8 and 3.9 from test matrix
- Added Python 3.12 to CI/CD pipeline
#### Compatibility
- Supports NetBox 4.0.6+
---
## Version 7.3.4 (July 2, 2024)
#### Bug Fixes
- Fixed API version detection for NetBox versions exceeding 4.x
- Removed linting errors
#### Testing
- Dropped NetBox 3.3 from test matrix
- Focus on NetBox 4.x support
---
## Version 7.3.3 (January 5, 2024)
#### Fixes
- PyPI release fix
- No functional changes
---
## Version 7.3.2 (January 4, 2024)
#### Fixes
- Fixed setup.py for new publish workflow
- No functional changes
---
## Version 7.3.1 (January 4, 2024)
#### Fixes
- Updated PyPI publish workflow
- No functional changes
---
## Version 7.3.0 (January 3, 2024)
#### New Features
- Added NetBox v3.7 support
#### Dependencies
- Added `pyyaml` dependency
#### Testing
- Updated test suite for NetBox 3.7 compatibility
#### Compatibility
- Supports NetBox 3.7
---
## Version 7.2.0 (September 7, 2023)
#### New Features
- Added NetBox v3.6 support
#### Compatibility
- Supports NetBox 3.6
---
## Version 7.1.0 (August 2023)
#### Code Quality
- Lint fixes and code cleanup
- Improved code formatting consistency
#### Compatibility
- Supports NetBox 3.5
---
## Version 7.0.1 (June 2023)
#### Enhancements
- Updated code formatting
- Documentation improvements
---
## Version 7.0.0 (June 2023)
#### Breaking Changes
- **Minimum NetBox version**: 3.3+
- Removed support for NetBox versions below 3.3
#### New Features
- Full NetBox 3.3 API support
- Updated test suite for NetBox 3.3
#### Testing
- Completely overhauled test scripts
- Updated test settings for NetBox 3.3 compatibility
- Improved integration test coverage
#### Compatibility
- **NetBox 3.3+ required**
- Python 3.8+ required
---
## Version 6.7.x and Earlier
For release notes for versions 6.7 and earlier, please refer to the [GitHub Releases page](https://github.com/netbox-community/pynetbox/releases).
Key highlights from earlier versions:
#### Version 6.7 (Last pre-7.0 release)
- Last version to support NetBox < 3.3
- Python 3.7+ support
#### Version 6.6
- Custom error pickling fixes
- VLAN __str__ improvements
- VirtualChassis enhancements
#### Version 6.5
- Added available-vlans support for VLAN groups
#### Version 6.4
- Added Wireless app support
- Data returned as dict improvements
#### Version 6.3
- Field name lookup improvements
- Enhanced filtering capabilities
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/docs/request.md 0000644 0001751 0001751 00000000447 15136437134 016021 0 ustar 00runner runner # Request
::: pynetbox.core.query.RequestError
handler: python
options:
members: false
::: pynetbox.core.query.ContentError
handler: python
options:
members: false
::: pynetbox.core.query.AllocationError
handler: python
options:
members: false ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/docs/response.md 0000644 0001751 0001751 00000000777 15136437134 016175 0 ustar 00runner runner # Response
::: pynetbox.core.response.Record
handler: python
options:
members:
- delete
- full_details
- save
- serialize
- update
- updates
show_source: true
show_root_heading: true
::: pynetbox.core.response.RecordSet
handler: python
options:
members: true
options:
members:
- delete
- update
show_source: true
show_root_heading: true
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1769619043.7973304
pynetbox-7.6.1/docs/stylesheets/ 0000755 0001751 0001751 00000000000 15136437144 016357 5 ustar 00runner runner ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/docs/stylesheets/extra.css 0000644 0001751 0001751 00000003560 15136437134 020217 0 ustar 00runner runner /* Custom styles for pynetbox documentation */
/* Improve code block appearance */
.md-typeset pre > code {
padding: 1em;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
/* Style method signatures */
.md-typeset .doc-contents .doc-heading {
border-bottom: 1px solid var(--md-default-fg-color--lightest);
padding-bottom: 0.5em;
margin-bottom: 1em;
}
/* Improve method documentation */
.md-typeset .doc-contents .doc-heading + p {
margin-top: 1em;
font-size: 0.9em;
color: var(--md-default-fg-color--light);
}
/* Style parameters and returns sections */
.md-typeset .doc-contents .doc-heading + p + h3 {
margin-top: 1.5em;
font-size: 1.1em;
color: var(--md-primary-fg-color);
}
/* Improve table appearance */
.md-typeset table {
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.md-typeset table th {
background-color: var(--md-primary-fg-color);
color: var(--md-primary-bg-color);
}
/* Style code examples */
.md-typeset .doc-contents .doc-heading + p + h3 + p + .highlight {
margin: 1em 0;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
/* Improve navigation */
.md-nav__item .md-nav__link--active {
color: var(--md-primary-fg-color);
font-weight: bold;
}
/* Style admonitions */
.md-typeset .admonition {
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
/* Improve method visibility */
.md-typeset .doc-contents .doc-heading {
scroll-margin-top: 100px;
}
/* Style method parameters */
.md-typeset .doc-contents .doc-heading + p + h3 + p + ul {
margin-left: 1em;
padding-left: 1em;
border-left: 2px solid var(--md-primary-fg-color);
}
/* Improve code block readability */
.md-typeset code {
padding: 0.2em 0.4em;
border-radius: 3px;
background-color: var(--md-code-bg-color);
box-shadow: 0 1px 2px rgba(0,0,0,0.1);
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/docs/virtualization.md 0000644 0001751 0001751 00000001456 15136437134 017416 0 ustar 00runner runner # Virtualization
This page documents special methods available for Virtualization models in pyNetBox.
!!! note "Standard API Operations"
Standard CRUD operations (`.all()`, `.filter()`, `.get()`, `.create()`, `.update()`, `.delete()`) follow NetBox's REST API patterns. Refer to the [NetBox API documentation](https://demo.netbox.dev/api/docs/) for details on available endpoints and filters.
## Virtual Machines
### Config Rendering
The `render_config` property renders virtual machine configuration based on config contexts and templates.
::: pynetbox.models.virtualization.VirtualMachines.render_config
handler: python
options:
show_source: true
**Example:**
```python
vm = nb.virtualization.virtual_machines.get(name='web-vm-01')
config = vm.render_config.create()
print(config)
```
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/mkdocs.yml 0000644 0001751 0001751 00000003252 15136437134 015057 0 ustar 00runner runner site_name: pynetbox
site_description: Python API client library for NetBox
theme:
name: material
features:
- navigation.tabs
- navigation.sections
- navigation.expand
- navigation.top
- navigation.indexes
- toc.follow
- search.suggest
- search.highlight
- content.code.copy
plugins:
- search
- mkdocstrings:
default_handler: python
handlers:
python:
options:
show_source: true
show_root_heading: true
heading_level: 3
nav:
- Home: index.md
- Getting Started:
- Installation: installation.md
- Quick Start: getting-started.md
- API Reference:
- Core Classes: api.md
- Endpoint: endpoint.md
- Response: response.md
- Request: request.md
- Circuits: circuits.md
- DCIM: dcim.md
- IPAM: ipam.md
- Virtualization: virtualization.md
- Advanced Topics:
- Advanced Usage: advanced.md
- Branching: branching.md
- Development:
- Development Guide: development/index.md
- Getting Started: development/getting-started.md
- Release Checklist: development/release-checklist.md
- Release Notes: release-notes.md
extra_css:
- stylesheets/extra.css
markdown_extensions:
- pymdownx.highlight:
anchor_linenums: true
line_spans: __span
pygments_lang_class: true
- pymdownx.inlinehilite
- pymdownx.snippets
- pymdownx.superfences
- admonition
- pymdownx.details
- pymdownx.emoji:
emoji_index: !!python/name:material.extensions.emoji.twemoji
emoji_generator: !!python/name:material.extensions.emoji.to_svg
- toc:
permalink: true
toc_depth: 3
- tables
- attr_list
- md_in_html
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1769619043.7973304
pynetbox-7.6.1/pynetbox/ 0000755 0001751 0001751 00000000000 15136437144 014723 5 ustar 00runner runner ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/pynetbox/__init__.py 0000644 0001751 0001751 00000000603 15136437134 017032 0 ustar 00runner runner from pynetbox.core.api import Api
from pynetbox.core.query import (
AllocationError,
ContentError,
RequestError,
ParameterValidationError,
)
__version__ = "7.6.1"
# Lowercase alias for backward compatibility
api = Api
__all__ = (
"Api",
"AllocationError",
"ContentError",
"RequestError",
"ParameterValidationError",
"api",
"__version__",
)
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1769619043.7993305
pynetbox-7.6.1/pynetbox/core/ 0000755 0001751 0001751 00000000000 15136437144 015653 5 ustar 00runner runner ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/pynetbox/core/__init__.py 0000644 0001751 0001751 00000000000 15136437134 017751 0 ustar 00runner runner ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/pynetbox/core/api.py 0000644 0001751 0001751 00000022033 15136437134 016775 0 ustar 00runner runner """
(c) 2017 DigitalOcean
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
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.
"""
import contextlib
import requests
from pynetbox.core.app import App, PluginsApp
from pynetbox.core.query import Request
from pynetbox.core.response import Record
class Api:
"""The API object is the point of entry to pynetbox.
After instantiating the Api() with the appropriate named arguments
you can specify which app and endpoint you wish to interact with.
Valid attributes currently are:
* circuits
* core (NetBox 3.5+)
* dcim
* extras
* ipam
* tenancy
* users
* virtualization
* vpn (NetBox 3.7+)
* wireless
Calling any of these attributes will return an `App` object which exposes endpoints as attributes.
## Additional Attributes
* **http_session(requests.Session)**: Override the default session with your own. This is used to control
a number of HTTP behaviors such as SSL verification, custom headers,
retires, and timeouts.
See [custom sessions](advanced.md#custom-sessions) for more info.
## Parameters
* **url** (str): The base URL to the instance of NetBox you wish to connect to.
* **token** (str): Your NetBox token.
* **threading** (bool, optional): Set to True to use threading in `.all()` and `.filter()` requests.
## Raises
* **AttributeError**: If app doesn't exist.
## Examples
```python
import pynetbox
nb = pynetbox.api(
'http://localhost:8000',
token='d6f4e314a5b5fefd164995169f28ae32d987704f'
)
list(nb.dcim.devices.all())
# [test1-leaf1, test1-leaf2, test1-leaf3]
```
"""
def __init__(
self,
url,
token=None,
threading=False,
strict_filters=False,
):
"""Initialize the API client.
Args:
url (str): The base URL to the instance of NetBox you wish to connect to.
token (str, optional): Your NetBox API token. If not provided, authentication will be required for each request.
threading (bool, optional): Set to True to use threading in `.all()` and `.filter()` requests, defaults to False.
strict_filters (bool, optional): Set to True to check GET call filters against OpenAPI specifications (intentionally not done in NetBox API), defaults to False.
"""
base_url = "{}/api".format(url if url[-1] != "/" else url[:-1])
self.token = token
self.base_url = base_url
self.http_session = requests.Session()
self.threading = threading
self.strict_filters = strict_filters
# Initialize NetBox apps
self.circuits = App(self, "circuits")
self.core = App(self, "core")
self.dcim = App(self, "dcim")
self.extras = App(self, "extras")
self.ipam = App(self, "ipam")
self.tenancy = App(self, "tenancy")
self.users = App(self, "users")
self.virtualization = App(self, "virtualization")
self.vpn = App(self, "vpn")
self.wireless = App(self, "wireless")
self.plugins = PluginsApp(self)
@property
def version(self):
"""Gets the API version of NetBox.
Can be used to check the NetBox API version if there are
version-dependent features or syntaxes in the API.
## Returns
Version number as a string.
## Example
```python
import pynetbox
nb = pynetbox.api(
'http://localhost:8000',
token='d6f4e314a5b5fefd164995169f28ae32d987704f'
)
nb.version
# '3.1'
```
"""
version = Request(
base=self.base_url,
token=self.token,
http_session=self.http_session,
).get_version()
return version
def openapi(self):
"""Returns the OpenAPI spec.
Quick helper function to pull down the entire OpenAPI spec.
It is stored in memory to avoid repeated calls on NetBox API.
## Returns
dict: The OpenAPI specification as a dictionary.
## Example
```python
import pynetbox
nb = pynetbox.api(
'http://localhost:8000',
token='d6f4e314a5b5fefd164995169f28ae32d987704f'
)
nb.openapi()
# {...}
```
"""
if not (openapi := getattr(self, "_openapi", None)):
openapi = self._openapi = Request(
base=self.base_url,
http_session=self.http_session,
).get_openapi()
return openapi
def status(self):
"""Gets the status information from NetBox.
## Returns
Dictionary containing NetBox status information.
## Raises
`RequestError`: If the request is not successful.
## Example
```python
from pprint import pprint
pprint(nb.status())
{
'django-version': '3.1.3',
'installed-apps': {
'cacheops': '5.0.1',
'debug_toolbar': '3.1.1',
'django_filters': '2.4.0',
'django_prometheus': '2.1.0',
'django_rq': '2.4.0',
'django_tables2': '2.3.3',
'drf_yasg': '1.20.0',
'mptt': '0.11.0',
'rest_framework': '3.12.2',
'taggit': '1.3.0',
'timezone_field': '4.0'
},
'netbox-version': '2.10.2',
'plugins': {},
'python-version': '3.7.3',
'rq-workers-running': 1
}
```
"""
status = Request(
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.
## Parameters
* **username** (str): NetBox username
* **password** (str): NetBox password
## Returns
`Record`: The token as a Record object.
## Raises
`RequestError`: If the request is not successful.
## Example
```python
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)
@contextlib.contextmanager
def activate_branch(self, branch):
"""Context manager to activate the branch by setting the schema ID in the headers.
**Note**: The NetBox branching plugin must be installed and enabled in your NetBox instance for this functionality to work.
## Parameters
* **branch** (Record): The NetBox branch to activate
## Raises
`ValueError`: If the branch is not a valid NetBox branch.
## Example
```python
import pynetbox
nb = pynetbox.api("https://netbox-server")
branch = nb.plugins.branching.branches.create(name="testbranch")
with nb.activate_branch(branch):
sites = nb.dcim.sites.all()
# All operations within this block will use the branch's schema
```
"""
if not isinstance(branch, Record) or "schema_id" not in dict(branch):
raise ValueError(
f"The specified branch is not a valid NetBox branch: {branch}."
)
self.http_session.headers["X-NetBox-Branch"] = branch.schema_id
try:
yield
finally:
self.http_session.headers.pop("X-NetBox-Branch", None)
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/pynetbox/core/app.py 0000644 0001751 0001751 00000007632 15136437134 017014 0 ustar 00runner runner """
(c) 2017 DigitalOcean
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
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.core.endpoint import Endpoint
from pynetbox.core.query import Request
from pynetbox.models import (
circuits,
core,
dcim,
extras,
ipam,
users,
virtualization,
wireless,
)
class App:
"""Represents apps in NetBox.
Calls to attributes are returned as Endpoint objects.
## Returns
Endpoint matching requested attribute.
## Raises
RequestError if requested endpoint doesn't exist.
"""
def __init__(self, api, name):
self.api = api
self.name = name
self._setmodel()
models = {
"circuits": circuits,
"core": core,
"dcim": dcim,
"extras": extras,
"ipam": ipam,
"users": users,
"virtualization": virtualization,
"wireless": wireless,
}
def _setmodel(self):
self.model = App.models[self.name] if self.name in App.models else None
def __getstate__(self):
return {"api": self.api, "name": self.name}
def __setstate__(self, d):
self.__dict__.update(d)
self._setmodel()
def __getattr__(self, name):
return Endpoint(self.api, self, name, model=self.model)
def config(self):
"""Returns config response from app.
## Returns
Raw response from NetBox's config endpoint.
## Raises
RequestError if called for an invalid endpoint.
## Examples
```python
pprint.pprint(nb.users.config())
{
'tables': {
'DeviceTable': {
'columns': [
'name',
'status',
'tenant',
'role',
'site',
'primary_ip',
'tags'
]
}
}
}
```
"""
config = Request(
base="{}/{}/config/".format(
self.api.base_url,
self.name,
),
token=self.api.token,
http_session=self.api.http_session,
).get()
return config
class PluginsApp:
"""Basically valid plugins api could be handled by same App class,
but you need to add plugins to request url path.
## Returns
App with added plugins into path.
"""
def __init__(self, api):
self.api = api
def __getstate__(self):
return self.__dict__
def __setstate__(self, d):
self.__dict__.update(d)
def __getattr__(self, name):
return App(self.api, "plugins/{}".format(name.replace("_", "-")))
def installed_plugins(self):
"""Returns raw response with installed plugins.
## Returns
Raw response NetBox's installed plugins.
## Examples
```python
nb.plugins.installed_plugins()
[
{
'name': 'test_plugin',
'package': 'test_plugin',
'author': 'Dmitry',
'description': 'Netbox test plugin',
'verison': '0.10'
}
]
```
"""
installed_plugins = Request(
base="{}/plugins/installed-plugins".format(
self.api.base_url,
),
token=self.api.token,
http_session=self.api.http_session,
).get()
return installed_plugins
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/pynetbox/core/endpoint.py 0000644 0001751 0001751 00000054240 15136437134 020051 0 ustar 00runner runner """
(c) 2017 DigitalOcean
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
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.core.query import Request, RequestError, ParameterValidationError
from pynetbox.core.response import Record, RecordSet
RESERVED_KWARGS = ()
class Endpoint:
"""Represent actions available on endpoints in the Netbox API.
Takes ``name`` and ``app`` passed from App() and builds the correct
url to make queries to and the proper Response object to return
results in.
## Parameters
* **api** (Api): Takes Api created at instantiation.
* **app** (App): Takes App.
* **name** (str): Name of endpoint passed to App().
* **model** (obj, optional): Custom model for given app.
## Note
In order to call NetBox endpoints with dashes in their
names you should convert the dash to an underscore.
(E.g. querying the ip-addresses endpoint is done with
``nb.ipam.ip_addresses.all()``.)
"""
def __init__(self, api, app, name, model=None):
self.return_obj = self._lookup_ret_obj(name, model)
self.name = name.replace("_", "-")
self.api = api
self.app = app
self.base_url = api.base_url
self.token = api.token
self.url = "{base_url}/{app}/{endpoint}".format(
base_url=self.base_url,
app=app.name,
endpoint=self.name,
)
self._choices = None
def _lookup_ret_obj(self, name, model):
"""Loads unique Response objects.
This method loads a unique response object for an endpoint if
it exists. Otherwise return a generic `Record` object.
## Parameters
* **name** (str): Endpoint name.
* **model** (obj): The application model that contains unique Record objects.
## Returns
Record (obj)
"""
if model:
name = name.title().replace("_", "")
ret = getattr(model, name, Record)
else:
ret = Record
return ret
def _validate_openapi_parameters(self, method: str, parameters: dict) -> None:
"""Validate GET request parameters against OpenAPI specification
This method raises a **ParameterValidationError** if parameters passed to NetBox API
do not match the OpenAPI specification or validation fails.
## Parameters
* **method** : Only "get" is supported as for other methods NetBox already does proper validation
* **parameters** : kwargs passed to filter() method
## Returns
None
"""
if method.lower() != "get":
raise RuntimeError(f"Unsupported method '{method}'.")
openapi_definition_path = "/api/{app}/{endpoint}/".format(
app=self.app.name,
endpoint=self.name,
)
# Parse NetBox OpenAPI definition
try:
openapi_definition = self.api.openapi()["paths"].get(
openapi_definition_path
)
if not openapi_definition:
raise ParameterValidationError(
f"Path '{openapi_definition_path}' does not exist in NetBox OpenAPI specification."
)
openapi_parameters = openapi_definition[method]["parameters"]
allowed_parameters = [p["name"] for p in openapi_parameters]
except KeyError as exc:
raise ParameterValidationError(
f"Error while parsing Netbox OpenAPI specification: {exc}"
)
# Validate all parameters
validation_errors = []
for p in parameters:
if p not in allowed_parameters:
validation_errors.append(
f"'{p}' is not allowed as parameter on path '{openapi_definition_path}'."
)
if len(validation_errors) > 0:
raise ParameterValidationError(validation_errors)
def all(self, limit=0, offset=None):
"""Queries the 'ListView' of a given endpoint.
Returns all objects from an endpoint.
## Parameters
* **limit** (int, optional): Overrides the max page size on
paginated returns. This defines the number of records that will
be returned with each query to the Netbox server. The queries
will be made as you iterate through the result set.
* **offset** (int, optional): Overrides the offset on paginated returns.
## Returns
A RecordSet object.
## Examples
```python
devices = list(nb.dcim.devices.all())
for device in devices:
print(device.name)
# test1-leaf1
# test1-leaf2
# test1-leaf3
```
If you want to iterate over the results multiple times then
encapsulate them in a list like this:
```python
devices = list(nb.dcim.devices.all())
```
This will cause the entire result set
to be fetched from the server.
"""
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,
http_session=self.api.http_session,
threading=self.api.threading,
limit=limit,
offset=offset,
)
return RecordSet(self, req)
def get(self, *args, **kwargs):
"""Queries the DetailsView of a given endpoint.
## Parameters
* **key** (int, optional): id for the item to be retrieved.
* **kwargs**: Accepts the same keyword args as filter(). Any search argument the endpoint accepts can
be added as a keyword arg.
* **strict_filters** (bool, optional): Overrides the global filter
validation per-request basis. Handled by the filter() method.
## Returns
A single Record object or None
## Raises
ValueError: if kwarg search return more than one value.
## Examples
Referencing with a kwarg that only returns one value:
```python
nb.dcim.devices.get(name='test1-a3-tor1b')
# test1-a3-tor1b
```
Referencing with an id:
```python
nb.dcim.devices.get(1)
# test1-edge1
```
Using multiple named arguments. For example, retrieving the location when the location name is not unique and used in multiple sites:
```python
nb.locations.get(site='site-1', name='Row 1')
# Row 1
```
"""
try:
key = args[0]
except IndexError:
key = None
if not key:
resp = self.filter(**kwargs)
ret = next(resp, None)
if not ret:
return ret
try:
next(resp)
raise ValueError(
"get() returned more than one result. "
"Check that the kwarg(s) passed are valid for this "
"endpoint or use filter() or all() instead."
)
except StopIteration:
return ret
req = Request(
key=key,
base=self.url,
token=self.token,
http_session=self.api.http_session,
)
try:
return next(RecordSet(self, req), None)
except RequestError as e:
if e.req.status_code == 404:
return None
else:
raise e
def filter(self, *args, **kwargs):
"""Queries the 'ListView' of a given endpoint.
Takes named arguments that match the usable filters on a
given endpoint. If an argument is passed then it's used as a
freeform search argument if the endpoint supports it.
## Parameters
* **args** (str, optional): Freeform search string that's
accepted on given endpoint.
* **kwargs** (str, optional): Any search argument the
endpoint accepts can be added as a keyword arg.
* **limit** (int, optional): Overrides the max page size on
paginated returns. This defines the number of records that will
be returned with each query to the Netbox server. The queries
will be made as you iterate through the result set.
* **offset** (int, optional): Overrides the offset on paginated returns.
* **strict_filters** (bool, optional): Overrides the global filter
validation per-request basis.
## Returns
A RecordSet object.
## Examples
To return a list of objects matching a named argument filter:
```python
devices = nb.dcim.devices.filter(role='leaf-switch')
for device in devices:
print(device.name)
# test1-leaf1
# test1-leaf2
# test1-leaf3
```
```python
devices = nb.dcim.devices.filter(site='site-1')
for device in devices:
print(device.name)
# test1-a2-leaf1
# test2-a2-leaf2
```
## Note
If a keyword argument is incorrect a `TypeError` will not be returned by pynetbox.
Instead, pynetbox will return all records filtered up to the last correct keyword argument. For example, if we used `site="Site 1"` instead of `site=site-1` when using filter on
the devices endpoint, then pynetbox will return **all** devices across all sites instead of devices at Site 1.
Using a freeform query along with a named argument:
```python
devices = nb.dcim.devices.filter('a3', role='leaf-switch')
for device in devices:
print(device.name)
# test1-a3-leaf1
# test1-a3-leaf2
```
"""
if args:
kwargs.update({"q": args[0]})
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
strict_filters = (
# kwargs value takes precedence on globally set value
kwargs.pop("strict_filters")
if "strict_filters" in kwargs
else self.api.strict_filters
)
if limit == 0 and offset is not None:
raise ValueError("offset requires a positive limit value")
filters = {x: y if y is not None else "null" for x, y in kwargs.items()}
if strict_filters:
self._validate_openapi_parameters("get", filters)
req = Request(
filters=filters,
base=self.url,
token=self.token,
http_session=self.api.http_session,
threading=self.api.threading,
limit=limit,
offset=offset,
)
return RecordSet(self, req)
def create(self, *args, **kwargs):
"""Creates an object on an endpoint.
Takes named arguments that match the given endpoint's
available fields. Returns a new object.
## Parameters
* **args**: Not used.
* **kwargs**: Fields and values to create the object with.
## Returns
A Record object.
## Examples
Creating a new device:
```python
new_device = nb.dcim.devices.create(
name='test-device',
device_type=1,
device_role=1,
site=1
)
```
Creating a new device with a nested object:
```python
new_device = nb.dcim.devices.create(
name='test-device',
device_type={'id': 1},
device_role={'id': 1},
site={'id': 1}
)
```
"""
req = Request(
base=self.url,
token=self.token,
http_session=self.api.http_session,
).post(args[0] if args else kwargs)
if isinstance(req, list):
return [self.return_obj(i, self.api, self) for i in req]
return self.return_obj(req, self.api, self)
def update(self, objects):
"""Updates objects in NetBox.
Takes a list of objects and updates them in NetBox.
## Parameters
* **objects** (list): A list of Record objects to update.
## Returns
A list of Record objects.
## Examples
```python
devices = nb.dcim.devices.filter(site='test1')
for device in devices:
device.status = 'active'
nb.dcim.devices.update(devices)
```
"""
series = []
if not isinstance(objects, list):
raise ValueError(
"Objects passed must be list[dict|Record] - was {}".format(
type(objects)
)
)
for o in objects:
if isinstance(o, Record):
data = o.updates()
if data:
data["id"] = o.id
series.append(data)
elif isinstance(o, dict):
if "id" not in o:
raise ValueError("id is missing from object: " + str(o))
series.append(o)
else:
raise ValueError(
"Object passed must be dict|Record - was {}".format(type(objects))
)
req = Request(
base=self.url,
token=self.token,
http_session=self.api.http_session,
).patch(series)
if isinstance(req, list):
return [self.return_obj(i, self.api, self) for i in req]
return self.return_obj(req, self.api, self)
def delete(self, objects):
"""Deletes objects from NetBox.
Takes a list of objects and deletes them from NetBox.
## Parameters
* **objects** (list): A list of Record objects to delete.
## Returns
True if the delete operation was successful.
## Examples
```python
devices = nb.dcim.devices.filter(site='test1')
nb.dcim.devices.delete(devices)
```
"""
cleaned_ids = []
if not isinstance(objects, list) and not isinstance(objects, RecordSet):
raise ValueError(
"objects must be list[str|int|Record]"
"|RecordSet - was " + str(type(objects))
)
for o in objects:
if isinstance(o, int):
cleaned_ids.append(o)
elif isinstance(o, str) and o.isnumeric():
cleaned_ids.append(int(o))
elif isinstance(o, Record):
if not hasattr(o, "id"):
raise ValueError(
"Record from '"
+ o.url
+ "' does not have an id and cannot be bulk deleted"
)
cleaned_ids.append(o.id)
else:
raise ValueError(
"Invalid object in list of objects to delete: " + str(type(o))
)
req = Request(
base=self.url,
token=self.token,
http_session=self.api.http_session,
)
return True if req.delete(data=[{"id": i} for i in cleaned_ids]) else False
def choices(self):
"""Returns all choices from the endpoint if it has them.
## Returns
Dictionary of available choices.
## Examples
```python
choices = nb.dcim.devices.choices()
print(choices['status'])
{
'label': 'Active',
'value': 'active'
}
```
"""
if self._choices:
return self._choices
req = Request(
base=self.url,
token=self.api.token,
http_session=self.api.http_session,
).options()
actions = req.get("actions", {})
post_data = actions.get("POST") or actions.get("PUT")
if post_data is None:
raise ValueError(
"Unexpected format in the OPTIONS response at {}".format(self.url)
)
self._choices = {}
for prop in post_data:
if "choices" in post_data[prop]:
self._choices[prop] = post_data[prop]["choices"]
return self._choices
def count(self, *args, **kwargs):
"""Returns the count of objects in a query.
Takes named arguments that match the usable filters on a
given endpoint. If an argument is passed then it's used as a
freeform search argument if the endpoint supports it.
## Parameters
* **args** (str, optional): Freeform search string that's
accepted on given endpoint.
* **kwargs** (str, optional): Any search argument the
endpoint accepts can be added as a keyword arg.
## Returns
Integer of count of objects.
## Examples
```python
nb.dcim.devices.count(site='test1')
# 27
```
"""
if args:
kwargs.update({"q": args[0]})
if any(i in RESERVED_KWARGS for i in kwargs):
raise ValueError(
"A reserved {} kwarg was passed. Please remove it "
"try again.".format(RESERVED_KWARGS)
)
ret = Request(
filters=kwargs,
base=self.url,
token=self.token,
http_session=self.api.http_session,
)
return ret.get_count()
class DetailEndpoint:
"""Enables read/write operations on detail endpoints.
Endpoints like `available-ips` that are detail routes off
traditional endpoints are handled with this class.
"""
def __init__(self, parent_obj, name, custom_return=None):
self.parent_obj = parent_obj
self.custom_return = custom_return
self.url = "{}/{}/{}/".format(parent_obj.endpoint.url, parent_obj.id, name)
self.request_kwargs = dict(
base=self.url,
token=parent_obj.api.token,
http_session=parent_obj.api.http_session,
)
def list(self, **kwargs):
"""The view operation for a detail endpoint.
Returns the response from NetBox for a detail endpoint.
## Parameters
* **kwargs**: Key/value pairs that get converted into URL
parameters when passed to the endpoint.
E.g. `.list(method='get_facts')` would be converted to
`.../?method=get_facts`.
## Returns
A Record object or list of Record objects created
from data retrieved from NetBox.
"""
req = Request(**self.request_kwargs).get(add_params=kwargs)
if self.custom_return:
return [
self.custom_return(
i, self.parent_obj.endpoint.api, self.parent_obj.endpoint
)
for i in req
]
return req
def create(self, data=None):
"""The write operation for a detail endpoint.
Creates objects on a detail endpoint in NetBox.
## Parameters
* **data** (dict/list, optional): A dictionary containing the
key/value pair of the items you're creating on the parent
object. Defaults to empty dict which will create a single
item with default values.
## Returns
A Record object or list of Record objects created
from data created in NetBox.
"""
data = data or {}
req = Request(**self.request_kwargs).post(data)
if self.custom_return:
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
class RODetailEndpoint(DetailEndpoint):
def create(self, data):
raise NotImplementedError("Writes are not supported for this endpoint.")
class ROMultiFormatDetailEndpoint(RODetailEndpoint):
"""Read-only detail endpoint supporting multiple response formats.
Handles endpoints that return data in different formats based on
query parameters. Supports both structured data (JSON) and raw formats
(e.g., SVG).
The endpoint inspects the 'render' parameter to determine response format:
- No parameter or render='json': Returns structured JSON data
- render='svg': Returns raw SVG content
## Examples
```python
rack = nb.dcim.racks.get(123)
rack.elevation.list() # Returns: list of rack unit objects
rack.elevation.list(render='svg') # Returns: SVG string
rack.elevation.list(render='json') # Returns: list of rack unit objects
```
"""
def list(self, **kwargs):
"""Returns data in the requested format.
## Parameters
* **kwargs**: Key/value pairs that get converted into URL
parameters. Supports 'render' parameter for format selection.
## Returns
- If render is non-JSON format: Raw content (string)
- If render is 'json' or absent: Structured data (list/generator)
"""
# Check if non-JSON format requested
render_format = kwargs.get("render")
if render_format == "svg":
# Pass expect_json=False for raw SVG response
req = Request(**self.request_kwargs, expect_json=False).get(
add_params=kwargs
)
# Return raw content for non-JSON formats
return next(req)
if render_format != "json" and render_format is not None:
raise ValueError(f"Unsupported render format: {render_format}")
# Return structured JSON response via parent class
return super().list(**kwargs)
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/pynetbox/core/query.py 0000644 0001751 0001751 00000045324 15136437134 017401 0 ustar 00runner runner """
(c) 2017 DigitalOcean
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
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.
"""
import concurrent.futures as cf
import io
import os
import json
from packaging import version
# NetBox v2 token prefix (introduced in NetBox 4.5.0)
TOKEN_PREFIX = "nbt_"
def _is_v2_token(token):
"""Detect if a token is NetBox v2 format.
V2 tokens (introduced in NetBox 4.5.0) have the format: nbt_.
The nbt_ prefix is used for secrets detection.
V1 tokens are simple strings without dots.
Returns True if token is v2 format, False otherwise.
"""
if not token or not token.startswith(TOKEN_PREFIX):
return False
# Remove nbt_ prefix
token_body = token[len(TOKEN_PREFIX) :]
# V2 tokens contain a dot separating the ID from the secret
return "." in token_body
def _is_file_like(obj):
if isinstance(obj, (str, bytes)):
return False
# Check if it's a standard library IO object OR has a callable read method
return isinstance(obj, io.IOBase) or (
hasattr(obj, "read") and callable(getattr(obj, "read"))
)
def _extract_files(data):
"""Extract file-like objects from data dict.
Returns a tuple of (clean_data, files) where clean_data has file objects
removed and files is a dict suitable for requests' files parameter.
"""
if not isinstance(data, dict):
return data, None
files = {}
clean_data = {}
for key, value in data.items():
if _is_file_like(value):
# Format: (filename, file_obj, content_type)
# Try to get filename from file object, fallback to key
filename = getattr(value, "name", None)
if filename:
# Extract just the filename, not the full path
filename = os.path.basename(filename)
else:
filename = key
files[key] = (filename, value)
elif isinstance(value, tuple) and len(value) >= 2 and _is_file_like(value[1]):
# Already in (filename, file_obj) or (filename, file_obj, content_type) format
files[key] = value
else:
clean_data[key] = value
return clean_data, files if files else None
def calc_pages(limit, count):
"""Calculate number of pages required for full results set."""
return int(count / limit) + (limit % count > 0)
class RequestError(Exception):
"""Basic Request Exception.
More detailed exception that returns the original requests object
for inspection. Along with some attributes with specific details
from the requests object. If return is json we decode and add it
to the message.
## Examples
```python
try:
nb.dcim.devices.create(name="destined-for-failure")
except pynetbox.RequestError as e:
print(e.error)
```
"""
def __init__(self, req):
if req.status_code == 404:
self.message = "The requested url: {} could not be found.".format(req.url)
else:
try:
self.message = "The request failed with code {} {}: {}".format(
req.status_code, req.reason, req.json()
)
except ValueError:
self.message = (
"The request failed with code {} {} but more specific "
"details were not returned in json. Check the NetBox Logs "
"or investigate this exception's error attribute.".format(
req.status_code, req.reason
)
)
super().__init__(self.message)
self.req = req
self.request_body = req.request.body
self.base = req.url
self.error = req.text
def __str__(self):
return self.message
class AllocationError(Exception):
"""Allocation Exception.
Used with available-ips/available-prefixes when there is no
room for allocation and NetBox returns 409 Conflict.
"""
def __init__(self, req):
super().__init__(req)
self.req = req
self.request_body = req.request.body
self.base = req.url
self.error = "The requested allocation could not be fulfilled."
def __str__(self):
return self.error
class ContentError(Exception):
"""Content Exception.
If the API URL does not point to a valid NetBox API, the server may
return a valid response code, but the content is not json. This
exception is raised in those cases.
"""
def __init__(self, req):
super().__init__(req)
self.req = req
self.request_body = req.request.body
self.base = req.url
self.error = (
"The server returned invalid (non-json) data. Maybe not a NetBox server?"
)
def __str__(self):
return self.error
class ParameterValidationError(Exception):
"""API parameter validation Exception.
Raised when filter parameters do not match Netbox OpenAPI specification.
## Examples
```python
try:
nb.dcim.devices.filter(field_which_does_not_exist="destined-for-failure")
except pynetbox.ParameterValidationError as e:
print(e.error)
```
"""
def __init__(self, errors):
super().__init__(errors)
self.error = f"The request parameter validation returned an error: {errors}"
def __str__(self):
return self.error
class Request:
"""Creates requests to the Netbox API.
Responsible for building the url and making the HTTP(S) requests to
Netbox's API.
## Parameters
* **base** (str): Base URL passed in api() instantiation.
* **filters** (dict, optional): Contains key/value pairs that
correlate to the filters a given endpoint accepts.
In (e.g. /api/dcim/devices/?name='test') 'name': 'test'
would be in the filters dict.
"""
def __init__(
self,
base,
http_session,
filters=None,
limit=None,
offset=None,
key=None,
token=None,
threading=False,
expect_json=True,
):
"""Instantiates a new Request object.
## Parameters
* **base** (string): Base URL passed in api() instantiation.
* **filters** (dict, optional): Contains key/value pairs that
correlate to the filters a given endpoint accepts.
In (e.g. /api/dcim/devices/?name='test') 'name': 'test'
would be in the filters dict.
* **key** (int, optional): Database id of the item being queried.
* **expect_json** (bool, optional): If True, expects JSON response
and sets appropriate Accept header. If False, expects raw content
(e.g., SVG, XML) and returns text. Defaults to True.
## Note
The `count` attribute is not initialized here. It is set dynamically
by the `get()` method when paginating results, or by `get_count()`
when explicitly requesting the count. This allows `get_count()` to
use `hasattr()` to determine if a count has already been fetched.
"""
self.base = self.normalize_url(base)
self.filters = filters or None
self.key = key
self.token = token
self.http_session = http_session
self.url = self.base if not key else "{}{}/".format(self.base, key)
self.threading = threading
self.limit = limit
self.offset = offset
self.expect_json = expect_json
def get_openapi(self):
"""Gets the OpenAPI Spec."""
headers = {
"Accept": "application/json",
"Content-Type": "application/json",
}
current_version = version.parse(self.get_version())
if current_version >= version.parse("3.5"):
req = self.http_session.get(
"{}schema/".format(self.normalize_url(self.base)),
headers=headers,
)
else:
req = self.http_session.get(
"{}docs/?format=openapi".format(self.normalize_url(self.base)),
headers=headers,
)
if req.ok:
return req.json()
else:
raise RequestError(req)
def get_version(self):
"""Gets the API version of NetBox.
Issues a GET request to the base URL to read the API version from the
response headers.
## Returns
Version number as a string. Empty string if version is not
present in the headers.
## Raises
RequestError if req.ok returns false.
"""
headers = {"Content-Type": "application/json"}
self._add_auth_header(headers)
req = self.http_session.get(
self.normalize_url(self.base),
headers=headers,
)
if req.ok or req.status_code == 403:
return req.headers.get("API-Version", "")
else:
raise RequestError(req)
def get_status(self):
"""Gets the status from /api/status/ endpoint in NetBox.
## Returns
Dictionary as returned by NetBox.
## Raises
RequestError if request is not successful.
"""
headers = {"Content-Type": "application/json"}
self._add_auth_header(headers)
req = self.http_session.get(
"{}status/".format(self.normalize_url(self.base)),
headers=headers,
)
if req.ok:
return req.json()
else:
raise RequestError(req)
def normalize_url(self, url):
"""Builds a url for POST actions."""
if url[-1] != "/":
return "{}/".format(url)
return url
def _add_auth_header(self, headers):
"""Add authorization header to headers dict if token is present.
## Parameters
* **headers** (dict): Headers dictionary to update with authorization.
"""
if self.token:
if _is_v2_token(self.token):
headers["authorization"] = "Bearer {}".format(self.token)
else:
headers["authorization"] = "Token {}".format(self.token)
def _make_call(self, verb="get", url_override=None, add_params=None, data=None):
# Extract any file-like objects from data
files = None
# Verbs that support request bodies with file uploads
body_verbs = ("post", "put", "patch")
# Set Accept header based on expected response type
if self.expect_json:
headers = {"accept": "application/json"}
else:
headers = {"accept": "*/*"}
# Extract files from data for applicable verbs
if data is not None and verb in body_verbs:
data, files = _extract_files(data)
# Set headers based on request type
should_be_json_body = not files and (
verb in body_verbs or (verb == "delete" and data)
)
if should_be_json_body:
headers["Content-Type"] = "application/json"
self._add_auth_header(headers)
params = {}
if not url_override:
if self.filters:
params.update(self.filters)
if add_params:
params.update(add_params)
if files:
# Use multipart/form-data for file uploads
req = getattr(self.http_session, verb)(
url_override or self.url,
headers=headers,
params=params,
data=data,
files=files,
)
else:
req = getattr(self.http_session, verb)(
url_override or self.url, headers=headers, params=params, json=data
)
if req.status_code == 409 and verb == "post":
raise AllocationError(req)
if verb == "delete":
if req.ok:
return True
else:
raise RequestError(req)
elif req.ok:
# Parse response based on expected type
if self.expect_json:
try:
return req.json()
except json.JSONDecodeError:
raise ContentError(req)
else:
# Return raw text for non-JSON responses
return req.text
else:
raise RequestError(req)
def concurrent_get(self, ret, page_size, page_offsets):
futures_to_results = []
with cf.ThreadPoolExecutor(max_workers=4) as pool:
for offset in page_offsets:
new_params = {"offset": offset, "limit": page_size}
futures_to_results.append(
pool.submit(self._make_call, add_params=new_params)
)
for future in cf.as_completed(futures_to_results):
result = future.result()
ret.extend(result["results"])
def get(self, add_params=None):
"""Makes a GET request.
Makes a GET request to NetBox's API, and automatically recurses
any paginated results.
## Returns
List of `Response` objects returned from the endpoint.
## Raises
* RequestError if req.ok returns false.
* ContentError if response is not json.
"""
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.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"])
pages = calc_pages(page_size, req["count"])
page_offsets = [
increment * page_size for increment in range(1, pages)
]
if pages == 1:
req = self._make_call(url_override=req.get("next"))
ret.extend(req["results"])
else:
self.concurrent_get(ret, page_size, page_offsets)
for i in ret:
yield i
else:
first_run = True
for i in req["results"]:
yield i
while req["next"]:
# Not worrying about making sure add_params kwargs is
# passed in here because results from detail routes aren't
# paginated, thus far.
if first_run:
req = self._make_call(
add_params={
"limit": self.limit or req["count"],
"offset": len(req["results"]),
}
)
else:
req = self._make_call(url_override=req["next"])
first_run = False
for i in req["results"]:
yield i
elif isinstance(req, list):
self.count = len(req)
for i in req:
yield i
else:
self.count = len(req)
yield req
def put(self, data):
"""Makes PUT request.
Makes a PUT request to NetBox's API.
## Parameters
* **data** (dict): Contains a dict that will be turned into a
json object and sent to the API.
## Returns
Dict containing the response from NetBox's API.
## Raises
* RequestError if req.ok returns false.
* ContentError if response is not json.
"""
return self._make_call(verb="put", data=data)
def post(self, data):
"""Makes POST request.
Makes a POST request to NetBox's API.
## Parameters
* **data** (dict): Contains a dict that will be turned into a
json object and sent to the API.
## Returns
Dict containing the response from NetBox's API.
## Raises
* RequestError if req.ok returns false.
* AllocationError if req.status_code is 409 (Conflict)
as with available-ips and available-prefixes when there is
no room for the requested allocation.
* ContentError if response is not json.
"""
return self._make_call(verb="post", data=data)
def delete(self, data=None):
"""Makes DELETE request.
Makes a DELETE request to NetBox's API.
## Parameters
* **data** (list): Contains a dict that will be turned into a
json object and sent to the API.
## Returns
True if successful.
## Raises
RequestError if req.ok doesn't return True.
"""
return self._make_call(verb="delete", data=data)
def patch(self, data):
"""Makes PATCH request.
Makes a PATCH request to NetBox's API.
## Parameters
* **data** (dict): Contains a dict that will be turned into a
json object and sent to the API.
## Returns
Dict containing the response from NetBox's API.
## Raises
* RequestError if req.ok returns false.
* ContentError if response is not json.
"""
return self._make_call(verb="patch", data=data)
def options(self):
"""Makes an OPTIONS request.
Makes an OPTIONS request to NetBox's API.
## Returns
Dict containing the response from NetBox's API.
## Raises
* RequestError if req.ok returns false.
* ContentError if response is not json.
"""
return self._make_call(verb="options")
def get_count(self, *args, **kwargs):
"""Returns object count for query.
Makes a query to the endpoint with ``limit=1`` set and only
returns the value of the "count" field.
## Returns
Int of number of objects query returned.
## Raises
* RequestError if req.ok returns false.
* ContentError if response is not json.
"""
if not hasattr(self, "count"):
self.count = self._make_call(add_params={"limit": 1, "brief": 1})["count"]
return self.count
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/pynetbox/core/response.py 0000644 0001751 0001751 00000057507 15136437134 020100 0 ustar 00runner runner """
(c) 2017 DigitalOcean
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
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.
"""
import copy
from urllib.parse import urlsplit
import pynetbox.core.app
from pynetbox.core.query import Request
from pynetbox.core.util import Hashabledict
# List of fields that are lists but should be treated as sets.
LIST_AS_SET = ("tags", "tagged_vlans")
def get_return(lookup, return_fields=None):
"""Returns simple representations for items passed to lookup.
Used to return a "simple" representation of objects and collections
sent to it via lookup. Otherwise, we look to see if
lookup is a "choices" field (dict with only 'id' and 'value')
or a nested_return. Finally, we check if it's a Record, if
so simply return a string. Order is important due to nested_return
being self-referential.
## Parameters
* **return_fields** (list, optional): A list of fields to reference when
calling values on lookup.
"""
for i in return_fields or ["id", "value", "nested_return"]:
if isinstance(lookup, dict) and lookup.get(i):
return lookup[i]
else:
if hasattr(lookup, i):
# check if this is a "choices" field record
# from a NetBox 2.7 server.
if sorted(dict(lookup)) == sorted(["id", "value", "label"]):
return getattr(lookup, "value")
return getattr(lookup, i)
if isinstance(lookup, Record):
return str(lookup)
else:
return lookup
def flatten_custom(custom_dict):
ret = {}
for k, val in custom_dict.items():
current_val = val
if isinstance(val, dict):
current_val = val.get("id", val)
if isinstance(val, list):
current_val = [v.get("id", v) if isinstance(v, dict) else v for v in val]
ret[k] = current_val
return ret
class JsonField:
"""Explicit field type for values that are not to be converted
to a Record object."""
_json_field = True
class RecordSet:
"""Iterator containing Record objects.
Returned by `Endpoint.all()` and `Endpoint.filter()` methods.
Allows iteration of and actions to be taken on the results from the aforementioned
methods. Contains Record objects.
## Examples
To see how many results are in a query by calling `len()`:
```python
x = nb.dcim.devices.all()
len(x)
# 123
```
Simple iteration of the results:
```python
devices = nb.dcim.devices.all()
for device in devices:
print(device.name)
# test1-leaf1
# test1-leaf2
# test1-leaf3
```
"""
def __init__(self, endpoint, request, **kwargs):
self.endpoint = endpoint
self.request = request
self.response = self.request.get()
self._response_cache = []
def __iter__(self):
return self
def __next__(self):
if self._response_cache:
return self.endpoint.return_obj(
self._response_cache.pop(), self.endpoint.api, self.endpoint
)
return self.endpoint.return_obj(
next(self.response), self.endpoint.api, self.endpoint
)
def __len__(self):
try:
return self.request.count
except AttributeError:
try:
self._response_cache.append(next(self.response))
except StopIteration:
return 0
return self.request.count
def update(self, **kwargs):
"""Updates kwargs onto all Records in the RecordSet and saves these.
Updates are only sent to the API if a value were changed, and only for
the Records which were changed.
## Returns
True if the update succeeded, None if no update were required.
## Examples
```python
result = nb.dcim.devices.filter(site_id=1).update(status='active')
# True
```
"""
updates = []
for record in self:
# Update each record and determine if anything was updated
for k, v in kwargs.items():
setattr(record, k, v)
record_updates = record.updates()
if record_updates:
# if updated, add the id to the dict and append to list of updates
record_updates["id"] = record.id
updates.append(record_updates)
if updates:
return self.endpoint.update(updates)
else:
return None
def delete(self):
"""Bulk deletes objects in a RecordSet.
Allows for batch deletion of multiple objects in a RecordSet.
## Returns
True if bulk DELETE operation was successful.
## Examples
Deleting offline `devices` on site 1:
```python
netbox.dcim.devices.filter(site_id=1, status="offline").delete()
```
"""
return self.endpoint.delete(self)
class Record:
"""Create Python objects from NetBox API responses.
Creates an object from a NetBox response passed as `values`.
Nested dicts that represent other endpoints are also turned
into Record objects. All fields are then assigned to the
object's attributes. If a missing attr is requested
(e.g. requesting a field that's only present on a full response on
a Record made from a nested response) then pynetbox will make a
request for the full object and return the requested value.
## Examples
Default representation of the object is usually its name:
```python
x = nb.dcim.devices.get(1)
x
# test1-switch1
```
Querying a string field:
```python
x = nb.dcim.devices.get(1)
x.serial
# 'ABC123'
```
Querying a field on a nested object:
```python
x = nb.dcim.devices.get(1)
x.device_type.model
# 'QFX5100-24Q'
```
Casting the object as a dictionary:
```python
from pprint import pprint
pprint(dict(x))
{
'asset_tag': None,
'cluster': None,
'comments': '',
'config_context': {},
'created': '2018-04-01',
'custom_fields': {},
'role': {
'id': 1,
'name': 'Test Switch',
'slug': 'test-switch',
'url': 'http://localhost:8000/api/dcim/device-roles/1/'
},
'device_type': {...},
'display_name': 'test1-switch1',
'face': {'label': 'Rear', 'value': 1},
'id': 1,
'name': 'test1-switch1',
'parent_device': None,
'platform': {...},
'position': 1,
'primary_ip': {
'address': '192.0.2.1/24',
'family': 4,
'id': 1,
'url': 'http://localhost:8000/api/ipam/ip-addresses/1/'
},
'primary_ip4': {...},
'primary_ip6': None,
'rack': {
'display_name': 'Test Rack',
'id': 1,
'name': 'Test Rack',
'url': 'http://localhost:8000/api/dcim/racks/1/'
},
'site': {
'id': 1,
'name': 'TEST',
'slug': 'TEST',
'url': 'http://localhost:8000/api/dcim/sites/1/'
},
'status': {'label': 'Active', 'value': 1},
'tags': [],
'tenant': None,
'vc_position': None,
'vc_priority': None,
'virtual_chassis': None
}
```
Iterating over a Record object:
```python
for i in x:
print(i)
# ('id', 1)
# ('name', 'test1-switch1')
# ('display_name', 'test1-switch1')
```
"""
url = None
def __init__(self, values, api, endpoint):
self.has_details = False
self._full_cache = []
self._init_cache = []
self.api = api
self.default_ret = Record
self.endpoint = (
self._endpoint_from_url(values["url"])
if values and "url" in values and values["url"]
else endpoint
)
if values:
self._parse_values(values)
def __getattr__(self, k):
"""Default behavior for missing attrs.
We'll call `full_details()` if we're asked for an attribute
we don't have.
In order to prevent non-explicit behavior,`k='keys'` is
excluded because casting to dict() calls this attr.
"""
if self.url:
if self.has_details is False and k != "keys":
if self.full_details():
ret = getattr(self, k, None)
if ret or hasattr(self, k):
return ret
raise AttributeError('object has no attribute "{}"'.format(k))
def __iter__(self):
for i in dict(self._init_cache):
cur_attr = getattr(self, i)
if isinstance(cur_attr, Record):
yield i, dict(cur_attr)
elif isinstance(cur_attr, list) and all(
isinstance(i, (Record, GenericListObject)) for i in cur_attr
):
yield i, [dict(x) for x in cur_attr]
else:
yield i, cur_attr
def __getitem__(self, k):
return dict(self)[k]
def __str__(self):
return (
getattr(self, "name", None)
or getattr(self, "label", None)
or getattr(self, "display", None)
or ""
)
def __repr__(self):
return str(self)
def __getstate__(self):
return self.__dict__
def __setstate__(self, d):
self.__dict__.update(d)
def __key__(self):
if hasattr(self, "id"):
return (self.endpoint.name, self.id)
else:
return self.endpoint.name
def __hash__(self):
return hash(self.__key__())
def __eq__(self, other):
if isinstance(other, Record):
return self.__key__() == other.__key__()
return NotImplemented
def _extract_app_endpoint(self, url):
"""Extract app/endpoint from a NetBox API URL.
Extracts the app and endpoint portion from a URL like:
https://netbox/api/dcim/rear-ports/12761/
Returns:
String like "dcim/rear-ports"
"""
app_endpoint = "/".join(
urlsplit(url).path[len(urlsplit(self.api.base_url).path) :].split("/")[1:3]
)
return app_endpoint
def _get_obj_class(self, url):
"""Map API URL to corresponding Record class for cable tracing.
Used by TraceableRecord and PathableRecord to deserialize objects
encountered in cable trace/path responses.
"""
# Import here to avoid circular dependency
from pynetbox.models.circuits import CircuitTerminations
from pynetbox.models.dcim import (
Cables,
ConsolePorts,
ConsoleServerPorts,
FrontPorts,
Interfaces,
PowerFeeds,
PowerOutlets,
PowerPorts,
RearPorts,
)
uri_to_obj_class_map = {
"circuits/circuit-terminations": CircuitTerminations,
"dcim/cables": Cables,
"dcim/console-ports": ConsolePorts,
"dcim/console-server-ports": ConsoleServerPorts,
"dcim/front-ports": FrontPorts,
"dcim/interfaces": Interfaces,
"dcim/power-feeds": PowerFeeds,
"dcim/power-outlets": PowerOutlets,
"dcim/power-ports": PowerPorts,
"dcim/rear-ports": RearPorts,
}
app_endpoint = self._extract_app_endpoint(url)
return uri_to_obj_class_map.get(app_endpoint, Record)
def _add_cache(self, item):
key, value = item
self._init_cache.append((key, get_return(value)))
def _parse_values(self, values):
"""Parses values init arg.
Parses values dict at init and sets object attributes with the
values within.
"""
def generic_list_parser(key_name, list_item):
from pynetbox.models.mapper import CONTENT_TYPE_MAPPER
if (
isinstance(list_item, dict)
and "object_type" in list_item
and "object" in list_item
):
lookup = list_item["object_type"]
if model := CONTENT_TYPE_MAPPER.get(lookup, None):
record = model(list_item["object"], self.api, self.endpoint)
return GenericListObject(record)
return list_item
def list_parser(key_name, list_item):
if isinstance(list_item, dict):
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():
if isinstance(v, dict):
lookup = getattr(self.__class__, k, None)
if k in ["custom_fields", "local_context_data"] or hasattr(
lookup, "_json_field"
):
self._add_cache((k, copy.deepcopy(v)))
setattr(self, k, v)
continue
if lookup:
v = lookup(v, self.api, self.endpoint)
else:
v = self.default_ret(v, self.api, self.endpoint)
self._add_cache((k, v))
elif isinstance(v, list):
# check if GFK
if len(v) and isinstance(v[0], dict) and "object_type" in v[0]:
v = [generic_list_parser(k, i) for i in v]
to_cache = [i.serialize() for i in v]
elif k == "constraints":
# Permissions constraints can be either dict or list
to_cache = copy.deepcopy(v)
else:
v = [list_parser(k, i) for i in v]
to_cache = list(v)
self._add_cache((k, to_cache))
else:
self._add_cache((k, v))
setattr(self, k, v)
def _endpoint_from_url(self, url):
url_path = urlsplit(url).path
base_url_path_parts = urlsplit(self.api.base_url).path.split("/")
if len(base_url_path_parts) > 2:
# There are some extra directories in the path, remove them from url
extra_path = "/".join(base_url_path_parts[:-1])
url_path = url_path[len(extra_path) :]
split_url_path = url_path.split("/")
if split_url_path[2] == "plugins":
app = "plugins/{}".format(split_url_path[3])
name = split_url_path[4]
else:
app, name = split_url_path[2:4]
return getattr(pynetbox.core.app.App(self.api, app), name)
def full_details(self):
"""Queries the hyperlinked endpoint if 'url' is defined.
This method will populate the attributes from the detail
endpoint when it's called. Sets the class-level `has_details`
attribute when it's called to prevent being called more
than once.
:returns: True
"""
if self.url:
req = Request(
base=self.url,
token=self.api.token,
http_session=self.api.http_session,
)
self._parse_values(next(req.get()))
self.has_details = True
return True
return False
def serialize(self, nested=False, init=False):
"""Serializes an object
Pulls all the attributes in an object and creates a dict that
can be turned into the json that netbox is expecting.
If an attribute's value is a ``Record`` type it's replaced with
the ``id`` field of that object.
.. note::
Using this to get a dictionary representation of the record
is discouraged. It's probably better to cast to dict()
instead. See Record docstring for example.
:returns: dict.
"""
if nested:
return get_return(self)
if init:
init_vals = dict(self._init_cache)
ret = {}
for i in dict(self):
current_val = getattr(self, i) if not init else init_vals.get(i)
if i == "custom_fields":
ret[i] = flatten_custom(current_val)
else:
if isinstance(current_val, Record):
current_val = getattr(current_val, "serialize")(nested=True)
if isinstance(current_val, list):
serialized_list = []
for v in current_val:
if isinstance(v, GenericListObject):
v = v.serialize()
elif isinstance(v, Record):
v = v.id
serialized_list.append(v)
current_val = serialized_list
if i in LIST_AS_SET and (
all([isinstance(v, str) for v in current_val])
or all([isinstance(v, int) for v in current_val])
):
current_val = list(dict.fromkeys(current_val))
ret[i] = current_val
return ret
def _diff(self):
def fmt_dict(k, v):
if isinstance(v, dict):
return k, Hashabledict(v)
if isinstance(v, list):
return k, ",".join(map(str, v))
return k, v
current = Hashabledict({fmt_dict(k, v) for k, v in self.serialize().items()})
init = Hashabledict(
{fmt_dict(k, v) for k, v in self.serialize(init=True).items()}
)
return set([i[0] for i in set(current.items()) ^ set(init.items())])
def updates(self):
"""Compiles changes for an existing object into a dict.
Takes a diff between the objects current state and its state at init
and returns them as a dictionary, which will be empty if no changes.
:returns: dict.
:example:
>>> x = nb.dcim.devices.get(name='test1-a3-tor1b')
>>> x.serial
''
>>> x.serial = '1234'
>>> x.updates()
{'serial': '1234'}
>>>
"""
if self.id:
diff = self._diff()
if diff:
serialized = self.serialize()
return {i: serialized[i] for i in diff}
return {}
def save(self):
"""Saves changes to an existing object.
Takes a diff between the objects current state and its state at init
and sends them as a dictionary to Request.patch().
:returns: True if PATCH request was successful.
:example:
>>> x = nb.dcim.devices.get(name='test1-a3-tor1b')
>>> x.serial
''
>>> x.serial = '1234'
>>> x.save()
True
>>>
"""
updates = self.updates()
if updates:
req = Request(
key=self.id,
base=self.endpoint.url,
token=self.api.token,
http_session=self.api.http_session,
)
result = req.patch(updates)
if result:
# Update object state with response from PATCH to keep cache in sync
self._parse_values(result)
return True
return False
def update(self, data):
"""Update an object with a dictionary.
Accepts a dict and uses it to update the record and call save().
For nested and choice fields you'd pass an int the same as
if you were modifying the attribute and calling save().
:arg dict data: Dictionary containing the k/v to update the
record object with.
:returns: True if PATCH request was successful.
:example:
>>> x = nb.dcim.devices.get(1)
>>> x.update({
... "name": "test-switch2",
... "serial": "ABC321",
... })
True
"""
for k, v in data.items():
setattr(self, k, v)
return self.save()
def delete(self):
"""Deletes an existing object.
:returns: True if DELETE operation was successful.
:example:
>>> x = nb.dcim.devices.get(name='test1-a3-tor1b')
>>> x.delete()
True
>>>
"""
req = Request(
key=self.id,
base=self.endpoint.url,
token=self.api.token,
http_session=self.api.http_session,
)
return True if req.delete() else False
class PathableRecord(Record):
"""Record class for objects that support cable path tracing via /paths endpoint.
Front ports, rear ports, and circuit terminations use the /paths endpoint
to show complete cable paths from origin to destination.
"""
def _build_endpoint_object(self, endpoint_data):
if not endpoint_data:
return None
return_obj_class = self._get_obj_class(endpoint_data["url"])
return return_obj_class(endpoint_data, self.endpoint.api, self.endpoint)
def paths(self):
"""Return all cable paths traversing this pass-through port.
Returns a list of dictionaries, each containing:
- origin: The starting endpoint of the path (or None if not connected)
- destination: The ending endpoint of the path (or None if not connected)
- path: List of path segments, where each segment is a list of Record objects
(similar to the trace() endpoint structure)
"""
req = Request(
key=str(self.id) + "/paths",
base=self.endpoint.url,
token=self.api.token,
http_session=self.api.http_session,
).get()
ret = []
for path_data in req:
path_segments = []
for segment_data in path_data.get("path", []):
segment_objects = []
if isinstance(segment_data, list):
for item_data in segment_data:
segment_obj = self._build_endpoint_object(item_data)
if segment_obj:
segment_objects.append(segment_obj)
else:
segment_obj = self._build_endpoint_object(segment_data)
if segment_obj:
segment_objects.append(segment_obj)
path_segments.append(segment_objects)
origin = self._build_endpoint_object(path_data.get("origin"))
destination = self._build_endpoint_object(path_data.get("destination"))
ret.append({
"origin": origin,
"destination": destination,
"path": path_segments,
})
return ret
class GenericListObject:
def __init__(self, record):
from pynetbox.models.mapper import TYPE_CONTENT_MAPPER
self.object = record
self.object_id = record.id
self.object_type = TYPE_CONTENT_MAPPER.get(record.__class__)
def __repr__(self):
return str(self.object)
def serialize(self):
ret = {k: getattr(self, k) for k in ["object_id", "object_type"]}
return ret
def __getattr__(self, k):
return getattr(self.object, k)
def __iter__(self):
for i in ["object_id", "object_type", "object"]:
cur_attr = getattr(self, i)
if isinstance(cur_attr, Record):
cur_attr = dict(cur_attr)
yield i, cur_attr
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/pynetbox/core/util.py 0000644 0001751 0001751 00000000127 15136437134 017201 0 ustar 00runner runner class Hashabledict(dict):
def __hash__(self):
return hash(frozenset(self))
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1769619043.8013303
pynetbox-7.6.1/pynetbox/models/ 0000755 0001751 0001751 00000000000 15136437144 016206 5 ustar 00runner runner ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/pynetbox/models/__init__.py 0000644 0001751 0001751 00000000000 15136437134 020304 0 ustar 00runner runner ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/pynetbox/models/circuits.py 0000644 0001751 0001751 00000003073 15136437134 020407 0 ustar 00runner runner """
(c) 2017 DigitalOcean
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
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.core.response import PathableRecord, Record
class Circuits(Record):
def __str__(self):
return self.cid
class CircuitTerminations(PathableRecord):
"""Circuit Termination Record with cable path tracing support.
Circuit terminations support cable path tracing via the paths() method,
which returns all cable paths traversing this circuit termination point.
"""
def __str__(self):
return self.circuit.cid
class VirtualCircuits(Record):
"""Virtual Circuit Record.
Virtual circuits represent L2VPN-like connections delivered across
one or more physical circuits.
"""
def __str__(self):
return self.cid
class VirtualCircuitTerminations(PathableRecord):
"""Virtual Circuit Termination Record with cable path tracing support.
Virtual circuit terminations support cable path tracing via the paths()
method, which returns all cable paths traversing this termination point.
"""
def __str__(self):
return self.virtual_circuit.cid
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/pynetbox/models/core.py 0000644 0001751 0001751 00000001525 15136437134 017512 0 ustar 00runner runner """
(c) 2017 DigitalOcean
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
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.core.response import JsonField, Record
class DataSources(Record):
pass
class Jobs(Record):
pass
class ObjectChanges(Record):
object_data = JsonField
postchange_data = JsonField
prechange_data = JsonField
def __str__(self):
return self.request_id
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/pynetbox/models/dcim.py 0000644 0001751 0001751 00000014660 15136437134 017502 0 ustar 00runner runner """
(c) 2017 DigitalOcean
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
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.core.endpoint import (
DetailEndpoint,
RODetailEndpoint,
ROMultiFormatDetailEndpoint,
)
from pynetbox.core.query import Request
from pynetbox.core.response import JsonField, PathableRecord, Record
from pynetbox.models.circuits import Circuits
from pynetbox.models.ipam import IpAddresses
class TraceableRecord(Record):
def _build_termination_data(self, termination_list):
terminations_data = []
for hop_item_data in termination_list:
return_obj_class = self._get_obj_class(hop_item_data["url"])
terminations_data.append(
return_obj_class(hop_item_data, self.endpoint.api, self.endpoint)
)
return terminations_data
def trace(self):
req = Request(
key=str(self.id) + "/trace",
base=self.endpoint.url,
token=self.api.token,
http_session=self.api.http_session,
).get()
ret = []
for a_terminations_data, cable_data, b_terminations_data in req:
ret.append(self._build_termination_data(a_terminations_data))
if not cable_data:
ret.append(cable_data)
else:
return_obj_class = self._get_obj_class(cable_data["url"])
ret.append(
return_obj_class(cable_data, self.endpoint.api, self.endpoint)
)
ret.append(self._build_termination_data(b_terminations_data))
return ret
class DeviceTypes(Record):
def __str__(self):
return self.model
class Devices(Record):
"""Devices Object.
Represents a device response from netbox.
## Attributes
* **primary_ip, ip4, ip6** (list): Tells __init__ in Record() to
take the `primary_ip` field's value from the API
response and return an initialized list of IpAddress
objects
* **device_type** (obj): Tells __init__ in Record() to take the
`device_type` field's value from the API response and
return an initialized DeviceType object
"""
has_details = True
device_type = DeviceTypes
primary_ip = IpAddresses
primary_ip4 = IpAddresses
primary_ip6 = IpAddresses
local_context_data = JsonField
config_context = JsonField
@property
def napalm(self):
"""Represents the ``napalm`` detail endpoint.
Returns a DetailEndpoint object that is the interface for
viewing response from the napalm endpoint.
## Returns
DetailEndpoint object.
## Examples
```python
device = nb.ipam.devices.get(123)
device.napalm.list(method='get_facts')
# {"get_facts": {"interface_list": ["ge-0/0/0"]}}
```
"""
return RODetailEndpoint(self, "napalm")
@property
def render_config(self):
"""Represents the ``render-config`` detail endpoint.
Returns a DetailEndpoint object that is the interface for
viewing response from the render-config endpoint.
## Returns
DetailEndpoint object.
## Examples
```python
device = nb.ipam.devices.get(123)
device.render_config.create()
```
"""
return DetailEndpoint(self, "render-config")
class InterfaceConnections(Record):
def __str__(self):
return self.interface_a.name
class InterfaceConnection(Record):
def __str__(self):
return self.interface.name
class Interfaces(TraceableRecord):
interface_connection = InterfaceConnection
class PowerFeeds(TraceableRecord):
pass
class PowerOutlets(TraceableRecord):
device = Devices
class PowerPorts(TraceableRecord):
device = Devices
class ConsolePorts(TraceableRecord):
device = Devices
class ConsoleServerPorts(TraceableRecord):
device = Devices
class RackReservations(Record):
def __str__(self):
return self.description
class VirtualChassis(Record):
master = Devices
class RUs(Record):
device = Devices
class FrontPorts(PathableRecord):
device = Devices
class RearPorts(PathableRecord):
device = Devices
class Racks(Record):
@property
def units(self):
"""Represents the ``units`` detail endpoint.
Returns a DetailEndpoint object that is the interface for
viewing response from the units endpoint.
## Returns
DetailEndpoint object.
## Examples
```python
rack = nb.dcim.racks.get(123)
rack.units.list()
# {"get_facts": {"interface_list": ["ge-0/0/0"]}}
```
"""
return RODetailEndpoint(self, "units", custom_return=RUs)
@property
def elevation(self):
"""Represents the ``elevation`` detail endpoint.
Returns a multi-format endpoint supporting both JSON and SVG responses.
The elevation endpoint provides rack unit information and can render
graphical elevation views.
## Returns
ROMultiFormatDetailEndpoint object supporting JSON and SVG formats.
## Examples
```python
rack = nb.dcim.racks.get(123)
# Get rack units as JSON (list of RU objects)
rack.elevation.list()
# Get elevation as SVG diagram
svg = rack.elevation.list(render='svg')
```
"""
return ROMultiFormatDetailEndpoint(self, "elevation", custom_return=RUs)
class Termination(Record):
def __str__(self):
# hacky check to see if we're a circuit termination to
# avoid another call to NetBox because of a non-existent attr
# in self.name
if "circuit" in str(self.url):
return self.circuit.cid
return self.name
device = Devices
circuit = Circuits
class Cables(Record):
def __str__(self):
if len(self.a_terminations) == 1 and len(self.b_terminations) == 1:
return "{} <> {}".format(self.a_terminations[0], self.b_terminations[0])
return "Cable #{}".format(self.id)
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/pynetbox/models/extras.py 0000644 0001751 0001751 00000001224 15136437134 020064 0 ustar 00runner runner """
(c) 2017 DigitalOcean
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
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.core.response import JsonField, Record
class ConfigContexts(Record):
data = JsonField
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/pynetbox/models/ipam.py 0000644 0001751 0001751 00000013026 15136437134 017507 0 ustar 00runner runner """
(c) 2017 DigitalOcean
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
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.core.endpoint import DetailEndpoint
from pynetbox.core.response import Record
class IpAddresses(Record):
def __str__(self):
return str(self.address)
class IpRanges(Record):
def __str__(self):
return str(self.display)
@property
def available_ips(self):
"""Represents the ``available-ips`` detail endpoint.
Returns a DetailEndpoint object that is the interface for
viewing and creating IP addresses inside an ip range.
## Returns
DetailEndpoint object.
## Examples
```python
ip_range = nb.ipam.ip_ranges.get(24)
ip_range.available_ips.list()
# [10.0.0.1/24, 10.0.0.2/24, 10.0.0.3/24, 10.0.0.4/24, 10.0.0.5/24, ...]
```
To create a single IP:
```python
ip_range = nb.ipam.ip_ranges.get(24)
ip_range.available_ips.create()
# 10.0.0.1/24
```
To create multiple IPs:
```python
ip_range = nb.ipam.ip_ranges.get(24)
create = ip_range.available_ips.create([{} for i in range(2)])
# [10.0.0.2/24, 10.0.0.3/24]
```
"""
return DetailEndpoint(self, "available-ips", custom_return=IpAddresses)
class Prefixes(Record):
def __str__(self):
return str(self.prefix)
@property
def available_ips(self):
"""Represents the ``available-ips`` detail endpoint.
Returns a DetailEndpoint object that is the interface for
viewing and creating IP addresses inside a prefix.
## Returns
DetailEndpoint object.
## Examples
```python
prefix = nb.ipam.prefixes.get(24)
prefix.available_ips.list()
# [10.0.0.1/24, 10.0.0.2/24, 10.0.0.3/24, 10.0.0.4/24, 10.0.0.5/24, ...]
```
To create a single IP:
```python
prefix = nb.ipam.prefixes.get(24)
prefix.available_ips.create()
# 10.0.0.1/24
```
To create multiple IPs:
```python
prefix = nb.ipam.prefixes.get(24)
create = prefix.available_ips.create([{} for i in range(2)])
# [10.0.0.2/24, 10.0.0.3/24]
```
"""
return DetailEndpoint(self, "available-ips", custom_return=IpAddresses)
@property
def available_prefixes(self):
"""Represents the ``available-prefixes`` detail endpoint.
Returns a DetailEndpoint object that is the interface for
viewing and creating prefixes inside a parent prefix.
Very similar to `available_ips`, except that dict (or list of dicts) passed to `.create()`
needs to have a `prefix_length` key/value specified.
## Returns
DetailEndpoint object.
## Examples
```python
prefix = nb.ipam.prefixes.get(3)
prefix
# 10.0.0.0/16
prefix.available_prefixes.list()
# [10.0.1.0/24, 10.0.2.0/23, 10.0.4.0/22, 10.0.8.0/21, 10.0.16.0/20, 10.0.32.0/19, 10.0.64.0/18, 10.0.128.0/17]
```
Creating a single child prefix:
```python
prefix = nb.ipam.prefixes.get(1)
prefix
# 10.0.0.0/24
new_prefix = prefix.available_prefixes.create(
{"prefix_length": 29}
)
# 10.0.0.16/29
```
"""
return DetailEndpoint(self, "available-prefixes", custom_return=Prefixes)
class Aggregates(Record):
def __str__(self):
return str(self.prefix)
class Vlans(Record):
def __str__(self):
return super().__str__() or str(self.vid)
class VlanGroups(Record):
@property
def available_vlans(self):
"""Represents the ``available-vlans`` detail endpoint.
Returns a DetailEndpoint object that is the interface for viewing
and creating VLANs inside a VLAN group.
## Returns
DetailEndpoint object.
## Examples
```python
vlan_group = nb.ipam.vlan_groups.get(1)
vlan_group.available_vlans.list()
# [10, 11, 12]
```
To create a new VLAN:
```python
vlan_group.available_vlans.create({"name": "NewVLAN"})
# NewVLAN (10)
```
"""
return DetailEndpoint(self, "available-vlans", custom_return=Vlans)
class AsnRanges(Record):
@property
def available_asns(self):
"""Represents the ``available-asns`` detail endpoint.
Returns a DetailEndpoint object that is the interface for
viewing and creating ASNs inside an ASN range.
## Returns
DetailEndpoint object.
## Examples
```python
asn_range = nb.ipam.asn_ranges.get(1)
asn_range.available_asns.list()
# [64512, 64513, 64514]
```
To create a new ASN:
```python
asn_range.available_asns.create()
# 64512
```
To create multiple ASNs:
```python
asn_range.available_asns.create([{} for i in range(2)])
# [64513, 64514]
```
"""
return DetailEndpoint(self, "available-asns")
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/pynetbox/models/mapper.py 0000644 0001751 0001751 00000007314 15136437134 020050 0 ustar 00runner runner from .circuits import (
Circuits,
CircuitTerminations,
VirtualCircuits,
VirtualCircuitTerminations,
)
from .core import DataSources, Jobs, ObjectChanges
from .dcim import (
Cables,
ConsolePorts,
ConsoleServerPorts,
Devices,
DeviceTypes,
FrontPorts,
Interfaces,
PowerFeeds,
PowerOutlets,
PowerPorts,
RackReservations,
Racks,
RearPorts,
Termination,
VirtualChassis,
)
from .ipam import Aggregates, IpAddresses, Prefixes, VlanGroups, Vlans
from .virtualization import VirtualMachines
from .wireless import WirelessLans
CONTENT_TYPE_MAPPER = {
"circuits.circuit": Circuits,
"circuits.circuittermination": CircuitTerminations,
"circuits.virtualcircuit": VirtualCircuits,
"circuits.virtualcircuittermination": VirtualCircuitTerminations,
"core.datasource": DataSources,
"core.job": Jobs,
"core.objectchange": ObjectChanges,
"dcim.cable": Cables,
"dcim.cablepath": None,
"dcim.cabletermination": Termination,
"dcim.consoleport": ConsolePorts,
"dcim.consoleporttemplate": None,
"dcim.consoleserverport": ConsoleServerPorts,
"dcim.consoleserverporttemplate": None,
"dcim.device": Devices,
"dcim.devicebay": None,
"dcim.devicebaytemplate": None,
"dcim.devicerole": None,
"dcim.devicetype": DeviceTypes,
"dcim.frontport": FrontPorts,
"dcim.frontporttemplate": None,
"dcim.interface": Interfaces,
"dcim.interfacetemplate": None,
"dcim.inventoryitem": None,
"dcim.inventoryitemrole": None,
"dcim.inventoryitemtemplate": None,
"dcim.location": None,
"dcim.manufacturer": None,
"dcim.module": None,
"dcim.modulebay": None,
"dcim.modulebaytemplate": None,
"dcim.moduletype": None,
"dcim.platform": None,
"dcim.powerfeed": PowerFeeds,
"dcim.poweroutlet": PowerOutlets,
"dcim.poweroutlettemplate": None,
"dcim.powerpanel": None,
"dcim.powerport": PowerPorts,
"dcim.powerporttemplate": None,
"dcim.rack": Racks,
"dcim.rackreservation": RackReservations,
"dcim.rackrole": None,
"dcim.rearport": RearPorts,
"dcim.rearporttemplate": None,
"dcim.region": None,
"dcim.site": None,
"dcim.sitegroup": None,
"dcim.virtualchassis": VirtualChassis,
"extras.configcontext": None,
"extras.configrevision": None,
"extras.customfield": None,
"extras.customlink": None,
"extras.exporttemplate": None,
"extras.imageattachment": None,
"extras.jobresult": None,
"extras.journalentry": None,
"extras.report": None,
"extras.script": None,
"extras.tag": None,
"extras.taggeditem": None,
"extras.webhook": None,
"ipam.aggregate": Aggregates,
"ipam.ASN": None,
"ipam.FHRPgroup": None,
"ipam.FHRPgroupassignment": None,
"ipam.IPaddress": IpAddresses,
"ipam.IPrange": None,
"ipam.L2VPN": None,
"ipam.L2VPNtermination": None,
"ipam.prefix": Prefixes,
"ipam.RIR": None,
"ipam.role": None,
"ipam.routetarget": None,
"ipam.service": None,
"ipam.servicetemplate": None,
"ipam.VLAN": Vlans,
"ipam.VLANgroup": VlanGroups,
"ipam.VRF": None,
"tenancy.contact": None,
"tenancy.contactassignment": None,
"tenancy.contactgroup": None,
"tenancy.contactrole": None,
"tenancy.tenant": None,
"tenancy.tenantgroup": None,
"virtualization.cluster": None,
"virtualization.clustergroup": None,
"virtualization.clustertype": None,
"virtualization.interface": None,
"virtualization.virtualmachine": VirtualMachines,
"wireless.WirelessLAN": WirelessLans,
"wireless.WirelessLANGroup": None,
"wireless.wirelesslink": None,
}
TYPE_CONTENT_MAPPER = {v: k for k, v in CONTENT_TYPE_MAPPER.items() if v is not None}
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/pynetbox/models/users.py 0000644 0001751 0001751 00000001367 15136437134 017727 0 ustar 00runner runner """
(c) 2017 DigitalOcean
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
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.core.response import JsonField, Record
class Users(Record):
def __str__(self):
return self.username
class Permissions(Record):
users = [Users]
constraints = JsonField
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/pynetbox/models/virtualization.py 0000644 0001751 0001751 00000002456 15136437134 021652 0 ustar 00runner runner """
(c) 2017 DigitalOcean
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
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.core.endpoint import DetailEndpoint
from pynetbox.core.response import JsonField, Record
from pynetbox.models.ipam import IpAddresses
class VirtualMachines(Record):
primary_ip = IpAddresses
primary_ip4 = IpAddresses
primary_ip6 = IpAddresses
config_context = JsonField
@property
def render_config(self):
"""
Represents the ``render-config`` detail endpoint.
Returns a DetailEndpoint object that is the interface for
viewing response from the render-config endpoint.
:returns: :py:class:`.DetailEndpoint`
:Examples:
>>> vm = nb.virtualization.virtual_machines.get(123)
>>> vm.render_config.create()
"""
return DetailEndpoint(self, "render-config")
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/pynetbox/models/wireless.py 0000644 0001751 0001751 00000001242 15136437134 020413 0 ustar 00runner runner """
(c) 2017 DigitalOcean
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
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.core.response import Record
class WirelessLans(Record):
def __str__(self):
return self.ssid
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1769619043.8223305
pynetbox-7.6.1/pynetbox.egg-info/ 0000755 0001751 0001751 00000000000 15136437144 016415 5 ustar 00runner runner ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619043.0
pynetbox-7.6.1/pynetbox.egg-info/PKG-INFO 0000644 0001751 0001751 00000012146 15136437143 017515 0 ustar 00runner runner Metadata-Version: 2.4
Name: pynetbox
Version: 7.6.1
Summary: NetBox API client library
Home-page: https://github.com/netbox-community/pynetbox
Author: Zach Moody, Arthur Hanson
Author-email: ahanson@netboxlabs.com
License: Apache2
Keywords: netbox
Classifier: Intended Audience :: Developers
Classifier: Development Status :: 5 - Production/Stable
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests<3.0,>=2.20.0
Requires-Dist: packaging
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: keywords
Dynamic: license
Dynamic: license-file
Dynamic: requires-dist
Dynamic: summary
# Pynetbox
Python API client library for [NetBox](https://github.com/netbox-community/netbox).
> **Note:** Version 6.7 and later of the library only supports NetBox 3.3 and above.
## Compatibility
Each pyNetBox Version listed below has been tested with its corresponding NetBox Version.
| NetBox Version | Plugin Version |
|:--------------:|:--------------:|
| 4.5 | 7.6.1 |
| 4.5 | 7.6.0 |
| 4.4 | 7.5.0 |
| 4.3 | 7.5.0 |
| 4.2 | 7.5.0 |
| 4.1 | 7.5.0 |
| 4.0.6 | 7.4.1 |
| 4.0.0 | 7.3.4 |
| 3.7 | 7.3.0 |
| 3.6 | 7.2.0 |
| 3.5 | 7.1.0 |
| 3.3 | 7.0.0 |
## Installation
To install run `pip install pynetbox`.
Alternatively, you can clone the repo and run `python setup.py install`.
## Quick Start
The full pynetbox API is documented on [GitHub Pages](https://netbox-community.github.io/pynetbox/), but the following should be enough to get started using it.
To begin, import pynetbox and instantiate the API.
```
import pynetbox
nb = pynetbox.api(
'http://localhost:8000',
token='d6f4e314a5b5fefd164995169f28ae32d987704f'
)
```
The first argument the .api() method takes is the NetBox URL. There are a handful of named arguments you can provide, but in most cases none are required to simply pull data. In order to write, the `token` argument should to be provided.
## Queries
The pynetbox API is setup so that NetBox's apps are attributes of the `.api()` object, and in turn those apps have attribute representing each endpoint. Each endpoint has a handful of methods available to carry out actions on the endpoint. For example, in order to query all the objects in the `devices` endpoint you would do the following:
```
>>> devices = nb.dcim.devices.all()
>>> for device in devices:
... print(device.name)
...
test1-leaf1
test1-leaf2
test1-leaf3
>>>
```
Note that the all() and filter() methods are generators and return an object that can be iterated over only once. If you are going to be iterating over it repeatedly you need to either call the all() method again, or encapsulate the results in a `list` object like this:
```
>>> devices = list(nb.dcim.devices.all())
```
### Threading
pynetbox supports multithreaded calls for `.filter()` and `.all()` queries. It is **highly recommended** you have `MAX_PAGE_SIZE` in your Netbox install set to anything *except* `0` or `None`. The default value of `1000` is usually a good value to use. To enable threading, add `threading=True` parameter to the `.api`:
```python
nb = pynetbox.api(
'http://localhost:8000',
threading=True,
)
```
### Filters validation
NetBox doesn't validate filters passed to the GET API endpoints, which are accessed with `.get()` and `.filter()`. If a filter is incorrect, NetBox silently returns the entire database table content. Pynetbox allows to check provided parameters against NetBox OpenAPI specification before doing the call, and raise an exception if a parameter is incorrect.
This can be enabled globally by setting `strict_filters=True` in the API object initialization:
```python
nb = pynetbox.api(
'http://localhost:8000',
strict_filters=True,
)
```
This can also be enabled and disabled on a per-request basis:
```python
# Disable for one request when enabled globally.
# Will not raise an exception and return the entire Device table.
nb.dcim.devices.filter(non_existing_filter="aaaa", strict_filters=False)
# Enable for one request when not enabled globally.
# Will raise an exception.
nb.dcim.devices.filter(non_existing_filter="aaaa", strict_filters=True)
```
## Running Tests
First, create and activate a Python virtual environment in the pynetbox directory to isolate the project dependencies:
```python
python3 -m venv venv
source venv/bin/activate
```
Install both requirements files:
```python
pip install -r requirements.txt
pip install -r requirements-dev.txt
```
The test suite requires Docker to be installed and running, as it will download and launch netbox-docker containers during test execution.
With Docker installed and running, execute the following command to run the test suite:
```python
pytest
```
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619043.0
pynetbox-7.6.1/pynetbox.egg-info/SOURCES.txt 0000644 0001751 0001751 00000014704 15136437143 020306 0 ustar 00runner runner .gitignore
.pre-commit-config.yaml
.readthedocs.yaml
CHANGELOG.md
LICENSE
README.md
mkdocs.yml
requirements-dev.txt
requirements.txt
setup.py
.github/PULL_REQUEST_TEMPLATE.md
.github/ISSUE_TEMPLATE/bug_report.yaml
.github/ISSUE_TEMPLATE/config.yml
.github/ISSUE_TEMPLATE/deprecation.yaml
.github/ISSUE_TEMPLATE/documentation_change.yaml
.github/ISSUE_TEMPLATE/feature_request.yaml
.github/ISSUE_TEMPLATE/housekeeping.yaml
.github/workflows/build-mkdocs.yml
.github/workflows/publish.yml
.github/workflows/py3.yml
docs/IPAM.md
docs/advanced.md
docs/api.md
docs/branching.md
docs/circuits.md
docs/dcim.md
docs/endpoint.md
docs/getting-started.md
docs/index.md
docs/installation.md
docs/release-notes.md
docs/request.md
docs/response.md
docs/virtualization.md
docs/development/getting-started.md
docs/development/index.md
docs/development/release-checklist.md
docs/stylesheets/extra.css
pynetbox/__init__.py
pynetbox.egg-info/PKG-INFO
pynetbox.egg-info/SOURCES.txt
pynetbox.egg-info/dependency_links.txt
pynetbox.egg-info/not-zip-safe
pynetbox.egg-info/requires.txt
pynetbox.egg-info/top_level.txt
pynetbox/core/__init__.py
pynetbox/core/api.py
pynetbox/core/app.py
pynetbox/core/endpoint.py
pynetbox/core/query.py
pynetbox/core/response.py
pynetbox/core/util.py
pynetbox/models/__init__.py
pynetbox/models/circuits.py
pynetbox/models/core.py
pynetbox/models/dcim.py
pynetbox/models/extras.py
pynetbox/models/ipam.py
pynetbox/models/mapper.py
pynetbox/models/users.py
pynetbox/models/virtualization.py
pynetbox/models/wireless.py
tests/__init__.py
tests/conftest.py
tests/test_api.py
tests/test_app.py
tests/test_circuits.py
tests/test_tenancy.py
tests/test_users.py
tests/test_virtualization.py
tests/test_wireless.py
tests/util.py
tests/fixtures/api/token_provision.json
tests/fixtures/circuits/circuit.json
tests/fixtures/circuits/circuit_termination.json
tests/fixtures/circuits/circuit_terminations.json
tests/fixtures/circuits/circuit_type.json
tests/fixtures/circuits/circuit_types.json
tests/fixtures/circuits/circuits.json
tests/fixtures/circuits/provider.json
tests/fixtures/circuits/providers.json
tests/fixtures/dcim/cable.json
tests/fixtures/dcim/cables.json
tests/fixtures/dcim/choices.json
tests/fixtures/dcim/console_port.json
tests/fixtures/dcim/console_port_template.json
tests/fixtures/dcim/console_port_templates.json
tests/fixtures/dcim/console_ports.json
tests/fixtures/dcim/console_server_port.json
tests/fixtures/dcim/console_server_port_template.json
tests/fixtures/dcim/console_server_port_templates.json
tests/fixtures/dcim/console_server_ports.json
tests/fixtures/dcim/device.json
tests/fixtures/dcim/device_bay.json
tests/fixtures/dcim/device_bay_template.json
tests/fixtures/dcim/device_bay_templates.json
tests/fixtures/dcim/device_bays.json
tests/fixtures/dcim/device_bulk_create.json
tests/fixtures/dcim/device_role.json
tests/fixtures/dcim/device_roles.json
tests/fixtures/dcim/device_type.json
tests/fixtures/dcim/device_types.json
tests/fixtures/dcim/devices.json
tests/fixtures/dcim/interface.json
tests/fixtures/dcim/interface_connection.json
tests/fixtures/dcim/interface_connections.json
tests/fixtures/dcim/interface_template.json
tests/fixtures/dcim/interface_templates.json
tests/fixtures/dcim/interface_trace.json
tests/fixtures/dcim/interfaces.json
tests/fixtures/dcim/interfaces_1.json
tests/fixtures/dcim/interfaces_2.json
tests/fixtures/dcim/inventory_item.json
tests/fixtures/dcim/inventory_items.json
tests/fixtures/dcim/manufacturer.json
tests/fixtures/dcim/manufacturers.json
tests/fixtures/dcim/napalm.json
tests/fixtures/dcim/platform.json
tests/fixtures/dcim/platforms.json
tests/fixtures/dcim/power_outlet.json
tests/fixtures/dcim/power_outlet_template.json
tests/fixtures/dcim/power_outlet_templates.json
tests/fixtures/dcim/power_outlets.json
tests/fixtures/dcim/power_port.json
tests/fixtures/dcim/power_port_template.json
tests/fixtures/dcim/power_port_templates.json
tests/fixtures/dcim/power_ports.json
tests/fixtures/dcim/rack.json
tests/fixtures/dcim/rack_group.json
tests/fixtures/dcim/rack_groups.json
tests/fixtures/dcim/rack_reservation.json
tests/fixtures/dcim/rack_reservations.json
tests/fixtures/dcim/rack_role.json
tests/fixtures/dcim/rack_roles.json
tests/fixtures/dcim/rack_u.json
tests/fixtures/dcim/racks.json
tests/fixtures/dcim/region.json
tests/fixtures/dcim/regions.json
tests/fixtures/dcim/site.json
tests/fixtures/dcim/sites.json
tests/fixtures/dcim/virtual_chassis_device.json
tests/fixtures/dcim/virtual_chassis_devices.json
tests/fixtures/ipam/aggregate.json
tests/fixtures/ipam/aggregates.json
tests/fixtures/ipam/available-ips-post.json
tests/fixtures/ipam/available-ips.json
tests/fixtures/ipam/available-prefixes-post.json
tests/fixtures/ipam/available-prefixes.json
tests/fixtures/ipam/ip_address.json
tests/fixtures/ipam/ip_addresses.json
tests/fixtures/ipam/prefix.json
tests/fixtures/ipam/prefixes.json
tests/fixtures/ipam/rir.json
tests/fixtures/ipam/rirs.json
tests/fixtures/ipam/role.json
tests/fixtures/ipam/roles.json
tests/fixtures/ipam/vlan.json
tests/fixtures/ipam/vlan_group.json
tests/fixtures/ipam/vlan_groups.json
tests/fixtures/ipam/vlans.json
tests/fixtures/ipam/vrf.json
tests/fixtures/ipam/vrfs.json
tests/fixtures/tenancy/tenant.json
tests/fixtures/tenancy/tenant_group.json
tests/fixtures/tenancy/tenant_groups.json
tests/fixtures/tenancy/tenants.json
tests/fixtures/users/group.json
tests/fixtures/users/groups.json
tests/fixtures/users/permission.json
tests/fixtures/users/permissions.json
tests/fixtures/users/unknown_model.json
tests/fixtures/users/user.json
tests/fixtures/users/users.json
tests/fixtures/virtualization/cluster.json
tests/fixtures/virtualization/cluster_group.json
tests/fixtures/virtualization/cluster_groups.json
tests/fixtures/virtualization/cluster_type.json
tests/fixtures/virtualization/cluster_types.json
tests/fixtures/virtualization/clusters.json
tests/fixtures/virtualization/interface.json
tests/fixtures/virtualization/interfaces.json
tests/fixtures/virtualization/virtual_machine.json
tests/fixtures/virtualization/virtual_machines.json
tests/fixtures/wireless/wireless_lan.json
tests/fixtures/wireless/wireless_lans.json
tests/integration/conftest.py
tests/integration/test_circuits.py
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_endpoint_strict_filter.py
tests/unit/test_extras.py
tests/unit/test_file_upload.py
tests/unit/test_multiformat_endpoint.py
tests/unit/test_query.py
tests/unit/test_request.py
tests/unit/test_response.py ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619043.0
pynetbox-7.6.1/pynetbox.egg-info/dependency_links.txt 0000644 0001751 0001751 00000000001 15136437143 022462 0 ustar 00runner runner
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619043.0
pynetbox-7.6.1/pynetbox.egg-info/not-zip-safe 0000644 0001751 0001751 00000000001 15136437143 020642 0 ustar 00runner runner
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619043.0
pynetbox-7.6.1/pynetbox.egg-info/requires.txt 0000644 0001751 0001751 00000000040 15136437143 021006 0 ustar 00runner runner requests<3.0,>=2.20.0
packaging
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619043.0
pynetbox-7.6.1/pynetbox.egg-info/top_level.txt 0000644 0001751 0001751 00000000011 15136437143 021136 0 ustar 00runner runner pynetbox
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/requirements-dev.txt 0000644 0001751 0001751 00000000157 15136437134 017115 0 ustar 00runner runner mkdocs-material==9.6.14
mkdocstrings[python]==0.29.1
pymdown-extensions>=10.0
pytest
pytest-docker
PyYAML
ruff
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/requirements.txt 0000644 0001751 0001751 00000000062 15136437134 016334 0 ustar 00runner runner requests>=2.32.3,<3.0
urllib3>=2.2.3,<3
packaging
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1769619043.8233304
pynetbox-7.6.1/setup.cfg 0000644 0001751 0001751 00000000046 15136437144 014674 0 ustar 00runner runner [egg_info]
tag_build =
tag_date = 0
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/setup.py 0000644 0001751 0001751 00000001700 15136437134 014562 0 ustar 00runner runner from setuptools import find_packages, setup
setup(
name="pynetbox",
description="NetBox API client library",
url="https://github.com/netbox-community/pynetbox",
author="Zach Moody, Arthur Hanson",
author_email="ahanson@netboxlabs.com",
license="Apache2",
include_package_data=True,
use_scm_version=True,
setup_requires=["setuptools_scm"],
packages=find_packages(exclude=["tests", "tests.*"]),
long_description=open("README.md").read(),
long_description_content_type="text/markdown",
install_requires=["requests>=2.20.0,<3.0", "packaging"],
zip_safe=False,
keywords=["netbox"],
classifiers=[
"Intended Audience :: Developers",
"Development Status :: 5 - Production/Stable",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
],
)
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1769619043.8023305
pynetbox-7.6.1/tests/ 0000755 0001751 0001751 00000000000 15136437144 014215 5 ustar 00runner runner ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/__init__.py 0000644 0001751 0001751 00000000000 15136437134 016313 0 ustar 00runner runner ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/conftest.py 0000644 0001751 0001751 00000004341 15136437134 016415 0 ustar 00runner runner from urllib import parse
import pytest
from packaging import version
DEFAULT_NETBOX_VERSIONS = "4.4"
def pytest_addoption(parser):
"""Hook on the pytest option parser setup.
Add some extra options to the parser.
"""
parser.addoption(
"--netbox-versions",
action="store",
default=DEFAULT_NETBOX_VERSIONS,
help=(
"The versions of netbox to run integration tests against, as a"
" comma-separated list. Default: %s" % DEFAULT_NETBOX_VERSIONS
),
)
parser.addoption(
"--no-cleanup",
dest="cleanup",
action="store_false",
help=(
"Skip any cleanup steps after the pytest session finishes. Any containers"
" created will be left running and the docker-compose files used to"
" create them will be left on disk."
),
)
parser.addoption(
"--url-override",
dest="url_override",
action="store",
help=(
"Overrides the URL to run tests to. This allows for testing to the same"
" containers for separate runs."
),
)
def pytest_configure(config):
"""Hook that runs after test collection is completed.
Here we can modify items in the collected tests or parser args.
"""
# verify the netbox versions parse correctly and split them
config.option.netbox_versions = [
version.Version(version_string)
for version_string in config.option.netbox_versions.split(",")
]
if "no:docker" in config.option.plugins and config.option.url_override:
url_parse = parse.urlparse(config.option.url_override)
class DockerServicesMock:
def __init__(self, ports):
self.ports = ports
def wait_until_responsive(self, *args, **kwargs):
return None
def port_for(self, *args):
return self.ports
class Plugin:
@pytest.fixture(scope="session")
def docker_ip(self):
return "127.0.0.1"
@pytest.fixture(scope="session")
def docker_services(self):
return DockerServicesMock(url_parse.port)
config.pluginmanager.register(Plugin())
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1769619043.7903304
pynetbox-7.6.1/tests/fixtures/ 0000755 0001751 0001751 00000000000 15136437144 016066 5 ustar 00runner runner ././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1769619043.8023305
pynetbox-7.6.1/tests/fixtures/api/ 0000755 0001751 0001751 00000000000 15136437144 016637 5 ustar 00runner runner ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/api/token_provision.json 0000644 0001751 0001751 00000000072 15136437134 022760 0 ustar 00runner runner {
"key": "1234567890123456789012345678901234567890"
}
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1769619043.8043303
pynetbox-7.6.1/tests/fixtures/circuits/ 0000755 0001751 0001751 00000000000 15136437144 017713 5 ustar 00runner runner ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/circuits/circuit.json 0000644 0001751 0001751 00000000753 15136437134 022254 0 ustar 00runner runner {
"id": 1,
"cid": "123456",
"provider": {
"id": 1,
"url": "http://localhost:8000/api/circuits/providers/1/",
"name": "TEST",
"slug": "test"
},
"type": {
"id": 1,
"url": "http://localhost:8000/api/circuits/circuit-types/1/",
"name": "Transit",
"slug": "transit"
},
"tenant": null,
"install_date": null,
"commit_rate": null,
"description": "",
"comments": "",
"custom_fields": {}
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/circuits/circuit_termination.json 0000644 0001751 0001751 00000001660 15136437134 024663 0 ustar 00runner runner {
"id": 1,
"circuit": {
"id": 1,
"url": "http://localhost:8000/api/circuits/circuits/1/",
"cid": "123456"
},
"term_side": "A",
"site": {
"id": 1,
"url": "http://localhost:8000/api/dcim/sites/1/",
"name": "TEST1",
"slug": "test1"
},
"interface": {
"id": 4,
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "test1-edge1",
"display_name": "test1-edge1"
},
"name": "xe-0/0/0",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "TEST",
"connection": null,
"connected_interface": null
},
"port_speed": 1000000,
"upstream_speed": null,
"xconnect_id": "",
"pp_info": ""
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/circuits/circuit_terminations.json 0000644 0001751 0001751 00000002473 15136437134 025051 0 ustar 00runner runner {
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"circuit": {
"id": 1,
"url": "http://localhost:8000/api/circuits/circuits/1/",
"cid": "123456"
},
"term_side": "A",
"site": {
"id": 1,
"url": "http://localhost:8000/api/dcim/sites/1/",
"name": "TEST1",
"slug": "test1"
},
"interface": {
"id": 4,
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "test1-edge1",
"display_name": "test1-edge1"
},
"name": "xe-0/0/0",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "TEST",
"connection": null,
"connected_interface": null
},
"port_speed": 1000000,
"upstream_speed": null,
"xconnect_id": "",
"pp_info": ""
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/circuits/circuit_type.json 0000644 0001751 0001751 00000000075 15136437134 023312 0 ustar 00runner runner {
"id": 1,
"name": "Transit",
"slug": "transit"
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/circuits/circuit_types.json 0000644 0001751 0001751 00000000270 15136437134 023472 0 ustar 00runner runner {
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"name": "Transit",
"slug": "transit"
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/circuits/circuits.json 0000644 0001751 0001751 00000001356 15136437134 022437 0 ustar 00runner runner {
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"cid": "123456",
"provider": {
"id": 1,
"url": "http://localhost:8000/api/circuits/providers/1/",
"name": "TEST",
"slug": "test"
},
"type": {
"id": 1,
"url": "http://localhost:8000/api/circuits/circuit-types/1/",
"name": "Transit",
"slug": "transit"
},
"tenant": null,
"install_date": null,
"commit_rate": null,
"description": "",
"comments": "",
"custom_fields": {}
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/circuits/provider.json 0000644 0001751 0001751 00000000316 15136437134 022437 0 ustar 00runner runner {
"id": 1,
"name": "TEST",
"slug": "test",
"asn": null,
"account": "",
"portal_url": "",
"noc_contact": "",
"admin_contact": "",
"comments": "",
"custom_fields": {}
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/circuits/providers.json 0000644 0001751 0001751 00000000601 15136437134 022617 0 ustar 00runner runner {
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"name": "TEST",
"slug": "test",
"asn": null,
"account": "",
"portal_url": "",
"noc_contact": "",
"admin_contact": "",
"comments": "",
"custom_fields": {}
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1769619043.8133304
pynetbox-7.6.1/tests/fixtures/dcim/ 0000755 0001751 0001751 00000000000 15136437144 017002 5 ustar 00runner runner ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/cable.json 0000644 0001751 0001751 00000002026 15136437134 020742 0 ustar 00runner runner {
"id": 1,
"termination_a_type": "dcim.consoleport",
"termination_a_id": 1,
"termination_a": {
"id": 1,
"url": "http://localhost:8000/api/dcim/console-ports/1/",
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "tst1-test1",
"display_name": "tst1-test1"
},
"name": "Console",
"cable": 1
},
"termination_b_type": "dcim.consoleserverport",
"termination_b_id": 2,
"termination_b": {
"id": 2,
"url": "http://localhost:8000/api/dcim/console-server-ports/2/",
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "tst1-test2",
"display_name": "tst1-test2"
},
"name": "Port 10",
"cable": 1
},
"type": null,
"status": {
"value": true,
"label": "Connected"
},
"label": "",
"color": "",
"length": null,
"length_unit": null
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/cables.json 0000644 0001751 0001751 00000010130 15136437134 021120 0 ustar 00runner runner {
"count": 3,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"termination_a_type": "dcim.consoleport",
"termination_a_id": 1,
"termination_a": {
"id": 1,
"url": "http://localhost:8000/api/dcim/console-ports/1/",
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "tst1-test1",
"display_name": "tst1-test1"
},
"name": "Console",
"cable": 1
},
"termination_b_type": "dcim.consoleserverport",
"termination_b_id": 2,
"termination_b": {
"id": 2,
"url": "http://localhost:8000/api/dcim/console-server-ports/2/",
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "tst1-test2",
"display_name": "tst1-test2"
},
"name": "Port 10",
"cable": 1
},
"type": null,
"status": {
"value": true,
"label": "Connected"
},
"label": "",
"color": "",
"length": null,
"length_unit": null
},
{
"id": 2,
"termination_a_type": "dcim.consoleport",
"termination_a_id": 3,
"termination_a": {
"id": 3,
"url": "http://localhost:8000/api/dcim/console-ports/3/",
"device": {
"id": 3,
"url": "http://localhost:8000/api/dcim/devices/3/",
"name": "tst1-test3",
"display_name": "tst1-test3"
},
"name": "Console",
"cable": 2
},
"termination_b_type": "dcim.consoleserverport",
"termination_b_id": 4,
"termination_b": {
"id": 4,
"url": "http://localhost:8000/api/dcim/console-server-ports/4/",
"device": {
"id": 4,
"url": "http://localhost:8000/api/dcim/devices/4/",
"name": "tst1-test4",
"display_name": "tst1-test4"
},
"name": "Port 11",
"cable": 2
},
"type": null,
"status": {
"value": true,
"label": "Connected"
},
"label": "",
"color": "",
"length": null,
"length_unit": null
},
{
"id": 3,
"termination_a_type": "dcim.consoleport",
"termination_a_id": 5,
"termination_a": {
"id": 5,
"url": "http://localhost:8000/api/dcim/console-ports/5/",
"device": {
"id": 5,
"url": "http://localhost:8000/api/dcim/devices/5/",
"name": "tst1-test5",
"display_name": "tst1-test5"
},
"name": "Console",
"cable": 3
},
"termination_b_type": "dcim.consoleserverport",
"termination_b_id": 6,
"termination_b": {
"id": 6,
"url": "http://localhost:8000/api/dcim/console-server-ports/6/",
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "tst1-test6",
"display_name": "tst1-test6"
},
"name": "Port 1",
"cable": 3
},
"type": null,
"status": {
"value": true,
"label": "Connected"
},
"label": "",
"color": "",
"length": null,
"length_unit": null
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/choices.json 0000644 0001751 0001751 00000023303 15136437134 021312 0 ustar 00runner runner {
"device:face": [
{
"label": "Front",
"value": 0
},
{
"label": "Rear",
"value": 1
}
],
"device:status": [
{
"label": "Active",
"value": 1
},
{
"label": "Offline",
"value": 0
},
{
"label": "Planned",
"value": 2
},
{
"label": "Staged",
"value": 3
},
{
"label": "Failed",
"value": 4
},
{
"label": "Inventory",
"value": 5
}
],
"console-port:connection_status": [
{
"label": "Planned",
"value": false
},
{
"label": "Connected",
"value": true
}
],
"interface:form_factor": [
{
"label": "Virtual",
"value": 0
},
{
"label": "Link Aggregation Group (LAG)",
"value": 200
},
{
"label": "100BASE-TX (10/100ME)",
"value": 800
},
{
"label": "1000BASE-T (1GE)",
"value": 1000
},
{
"label": "10GBASE-T (10GE)",
"value": 1150
},
{
"label": "10GBASE-CX4 (10GE)",
"value": 1170
},
{
"label": "GBIC (1GE)",
"value": 1050
},
{
"label": "SFP (1GE)",
"value": 1100
},
{
"label": "SFP+ (10GE)",
"value": 1200
},
{
"label": "XFP (10GE)",
"value": 1300
},
{
"label": "XENPAK (10GE)",
"value": 1310
},
{
"label": "X2 (10GE)",
"value": 1320
},
{
"label": "SFP28 (25GE)",
"value": 1350
},
{
"label": "QSFP+ (40GE)",
"value": 1400
},
{
"label": "CFP (100GE)",
"value": 1500
},
{
"label": "CFP2 (100GE)",
"value": 1510
},
{
"label": "CFP4 (100GE)",
"value": 1520
},
{
"label": "Cisco CPAK (100GE)",
"value": 1550
},
{
"label": "QSFP28 (100GE)",
"value": 1600
},
{
"label": "IEEE 802.11a",
"value": 2600
},
{
"label": "IEEE 802.11b/g",
"value": 2610
},
{
"label": "IEEE 802.11n",
"value": 2620
},
{
"label": "IEEE 802.11ac",
"value": 2630
},
{
"label": "IEEE 802.11ad",
"value": 2640
},
{
"label": "SFP (1GFC)",
"value": 3010
},
{
"label": "SFP (2GFC)",
"value": 3020
},
{
"label": "SFP (4GFC)",
"value": 3040
},
{
"label": "SFP+ (8GFC)",
"value": 3080
},
{
"label": "SFP+ (16GFC)",
"value": 3160
},
{
"label": "T1 (1.544 Mbps)",
"value": 4000
},
{
"label": "E1 (2.048 Mbps)",
"value": 4010
},
{
"label": "T3 (45 Mbps)",
"value": 4040
},
{
"label": "E3 (34 Mbps)",
"value": 4050
},
{
"label": "Cisco StackWise",
"value": 5000
},
{
"label": "Cisco StackWise Plus",
"value": 5050
},
{
"label": "Cisco FlexStack",
"value": 5100
},
{
"label": "Cisco FlexStack Plus",
"value": 5150
},
{
"label": "Juniper VCP",
"value": 5200
},
{
"label": "Extreme SummitStack",
"value": 5300
},
{
"label": "Extreme SummitStack-128",
"value": 5310
},
{
"label": "Extreme SummitStack-256",
"value": 5320
},
{
"label": "Extreme SummitStack-512",
"value": 5330
},
{
"label": "Other",
"value": 32767
}
],
"interface:mode": [
{
"label": "Access",
"value": 100
},
{
"label": "Tagged",
"value": 200
},
{
"label": "Tagged All",
"value": 300
}
],
"interface-connection:connection_status": [
{
"label": "Planned",
"value": false
},
{
"label": "Connected",
"value": true
}
],
"interface-template:form_factor": [
{
"label": "Virtual",
"value": 0
},
{
"label": "Link Aggregation Group (LAG)",
"value": 200
},
{
"label": "100BASE-TX (10/100ME)",
"value": 800
},
{
"label": "1000BASE-T (1GE)",
"value": 1000
},
{
"label": "10GBASE-T (10GE)",
"value": 1150
},
{
"label": "10GBASE-CX4 (10GE)",
"value": 1170
},
{
"label": "GBIC (1GE)",
"value": 1050
},
{
"label": "SFP (1GE)",
"value": 1100
},
{
"label": "SFP+ (10GE)",
"value": 1200
},
{
"label": "XFP (10GE)",
"value": 1300
},
{
"label": "XENPAK (10GE)",
"value": 1310
},
{
"label": "X2 (10GE)",
"value": 1320
},
{
"label": "SFP28 (25GE)",
"value": 1350
},
{
"label": "QSFP+ (40GE)",
"value": 1400
},
{
"label": "CFP (100GE)",
"value": 1500
},
{
"label": "CFP2 (100GE)",
"value": 1510
},
{
"label": "CFP4 (100GE)",
"value": 1520
},
{
"label": "Cisco CPAK (100GE)",
"value": 1550
},
{
"label": "QSFP28 (100GE)",
"value": 1600
},
{
"label": "IEEE 802.11a",
"value": 2600
},
{
"label": "IEEE 802.11b/g",
"value": 2610
},
{
"label": "IEEE 802.11n",
"value": 2620
},
{
"label": "IEEE 802.11ac",
"value": 2630
},
{
"label": "IEEE 802.11ad",
"value": 2640
},
{
"label": "SFP (1GFC)",
"value": 3010
},
{
"label": "SFP (2GFC)",
"value": 3020
},
{
"label": "SFP (4GFC)",
"value": 3040
},
{
"label": "SFP+ (8GFC)",
"value": 3080
},
{
"label": "SFP+ (16GFC)",
"value": 3160
},
{
"label": "T1 (1.544 Mbps)",
"value": 4000
},
{
"label": "E1 (2.048 Mbps)",
"value": 4010
},
{
"label": "T3 (45 Mbps)",
"value": 4040
},
{
"label": "E3 (34 Mbps)",
"value": 4050
},
{
"label": "Cisco StackWise",
"value": 5000
},
{
"label": "Cisco StackWise Plus",
"value": 5050
},
{
"label": "Cisco FlexStack",
"value": 5100
},
{
"label": "Cisco FlexStack Plus",
"value": 5150
},
{
"label": "Juniper VCP",
"value": 5200
},
{
"label": "Extreme SummitStack",
"value": 5300
},
{
"label": "Extreme SummitStack-128",
"value": 5310
},
{
"label": "Extreme SummitStack-256",
"value": 5320
},
{
"label": "Extreme SummitStack-512",
"value": 5330
},
{
"label": "Other",
"value": 32767
}
],
"power-port:connection_status": [
{
"label": "Planned",
"value": false
},
{
"label": "Connected",
"value": true
}
],
"rack:type": [
{
"label": "2-post frame",
"value": 100
},
{
"label": "4-post frame",
"value": 200
},
{
"label": "4-post cabinet",
"value": 300
},
{
"label": "Wall-mounted frame",
"value": 1000
},
{
"label": "Wall-mounted cabinet",
"value": 1100
}
],
"rack:width": [
{
"label": "19 inches",
"value": 19
},
{
"label": "23 inches",
"value": 23
}
],
"site:status": [
{
"label": "Active",
"value": 1
},
{
"label": "Planned",
"value": 2
},
{
"label": "Retired",
"value": 4
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/console_port.json 0000644 0001751 0001751 00000001026 15136437134 022401 0 ustar 00runner runner {
"id": 1,
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "test1-edge1",
"display_name": "test1-edge1"
},
"name": "Console (RE0)",
"cs_port": {
"id": 27,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 3",
"connected_console": 1
},
"connection_status": true
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/console_port_template.json 0000644 0001751 0001751 00000000611 15136437134 024273 0 ustar 00runner runner {
"id": 1,
"device_type": {
"id": 1,
"url": "http://localhost:8000/api/dcim/device-types/1/",
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "MX960",
"slug": "mx960"
},
"name": "Console (RE0)"
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/console_port_templates.json 0000644 0001751 0001751 00000007267 15136437134 024474 0 ustar 00runner runner {
"count": 7,
"next": null,
"previous": null,
"results": [
{
"id": 3,
"device_type": {
"id": 2,
"url": "http://localhost:8000/api/dcim/device-types/2/",
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "EX9214",
"slug": "ex9214"
},
"name": "Console (RE0)"
},
{
"id": 4,
"device_type": {
"id": 2,
"url": "http://localhost:8000/api/dcim/device-types/2/",
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "EX9214",
"slug": "ex9214"
},
"name": "Console (RE1)"
},
{
"id": 1,
"device_type": {
"id": 1,
"url": "http://localhost:8000/api/dcim/device-types/1/",
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "MX960",
"slug": "mx960"
},
"name": "Console (RE0)"
},
{
"id": 2,
"device_type": {
"id": 1,
"url": "http://localhost:8000/api/dcim/device-types/1/",
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "MX960",
"slug": "mx960"
},
"name": "Console (RE1)"
},
{
"id": 5,
"device_type": {
"id": 3,
"url": "http://localhost:8000/api/dcim/device-types/3/",
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "QFX5100-24Q",
"slug": "qfx5100-24q"
},
"name": "Console"
},
{
"id": 6,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Console"
},
{
"id": 7,
"device_type": {
"id": 6,
"url": "http://localhost:8000/api/dcim/device-types/6/",
"manufacturer": {
"id": 3,
"url": "http://localhost:8000/api/dcim/manufacturers/3/",
"name": "ServerTech",
"slug": "servertech"
},
"model": "CWG-24VYM415C9",
"slug": "cwg-24vym415c9"
},
"name": "Serial"
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/console_ports.json 0000644 0001751 0001751 00000016640 15136437134 022574 0 ustar 00runner runner {
"count": 15,
"next": null,
"previous": null,
"results": [
{
"id": 3,
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "Console (RE0)",
"cs_port": {
"id": 5,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 1",
"connected_console": 3
},
"connection_status": true
},
{
"id": 4,
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "Console (RE1)",
"cs_port": {
"id": 16,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 2",
"connected_console": 4
},
"connection_status": true
},
{
"id": 11,
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "Console (RE0)",
"cs_port": null,
"connection_status": true
},
{
"id": 12,
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "Console (RE1)",
"cs_port": null,
"connection_status": true
},
{
"id": 1,
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "test1-edge1",
"display_name": "test1-edge1"
},
"name": "Console (RE0)",
"cs_port": {
"id": 27,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 3",
"connected_console": 1
},
"connection_status": true
},
{
"id": 2,
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "test1-edge1",
"display_name": "test1-edge1"
},
"name": "Console (RE1)",
"cs_port": {
"id": 38,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 4",
"connected_console": 2
},
"connection_status": true
},
{
"id": 9,
"device": {
"id": 7,
"url": "http://localhost:8000/api/dcim/devices/7/",
"name": "test1-edge2",
"display_name": "test1-edge2"
},
"name": "Console (RE0)",
"cs_port": null,
"connection_status": true
},
{
"id": 10,
"device": {
"id": 7,
"url": "http://localhost:8000/api/dcim/devices/7/",
"name": "test1-edge2",
"display_name": "test1-edge2"
},
"name": "Console (RE1)",
"cs_port": null,
"connection_status": true
},
{
"id": 6,
"device": {
"id": 4,
"url": "http://localhost:8000/api/dcim/devices/4/",
"name": "test1-leaf1",
"display_name": "test1-leaf1"
},
"name": "Console",
"cs_port": {
"id": 48,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 5",
"connected_console": 6
},
"connection_status": true
},
{
"id": 7,
"device": {
"id": 5,
"url": "http://localhost:8000/api/dcim/devices/5/",
"name": "test1-leaf2",
"display_name": "test1-leaf2"
},
"name": "Console",
"cs_port": null,
"connection_status": true
},
{
"id": 13,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Console",
"cs_port": null,
"connection_status": true
},
{
"id": 15,
"device": {
"id": 11,
"url": "http://localhost:8000/api/dcim/devices/11/",
"name": "test1-pdu1",
"display_name": "test1-pdu1"
},
"name": "Serial",
"cs_port": null,
"connection_status": true
},
{
"id": 16,
"device": {
"id": 12,
"url": "http://localhost:8000/api/dcim/devices/12/",
"name": "test1-pdu2",
"display_name": "test1-pdu2"
},
"name": "Serial",
"cs_port": null,
"connection_status": true
},
{
"id": 5,
"device": {
"id": 3,
"url": "http://localhost:8000/api/dcim/devices/3/",
"name": "test1-spine1",
"display_name": "test1-spine1"
},
"name": "Console",
"cs_port": {
"id": 49,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 6",
"connected_console": 5
},
"connection_status": true
},
{
"id": 8,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "Console",
"cs_port": null,
"connection_status": true
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/console_server_port.json 0000644 0001751 0001751 00000000350 15136437134 023766 0 ustar 00runner runner {
"id": 1,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 1",
"connected_console": 3
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/console_server_port_template.json 0000644 0001751 0001751 00000000617 15136437134 025667 0 ustar 00runner runner {
"id": 1,
"device_type": {
"id": 3,
"url": "http://localhost:8000/api/dcim/device-types/3/",
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "QFX5100-24Q",
"slug": "qfx5100-24q"
},
"name": "Console"
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/console_server_port_templates.json 0000644 0001751 0001751 00000063105 15136437134 026053 0 ustar 00runner runner {
"count": 50,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"device_type": {
"id": 3,
"url": "http://localhost:8000/api/dcim/device-types/3/",
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "QFX5100-24Q",
"slug": "qfx5100-24q"
},
"name": "Console"
},
{
"id": 3,
"device_type": {
"id": 4,
"url": "http://localhost:8000/api/dcim/device-types/4/",
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "QFX5100-48S",
"slug": "qfx5100-48s"
},
"name": "Console"
},
{
"id": 4,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 1"
},
{
"id": 13,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 10"
},
{
"id": 14,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 11"
},
{
"id": 15,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 12"
},
{
"id": 16,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 13"
},
{
"id": 17,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 14"
},
{
"id": 18,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 15"
},
{
"id": 19,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 16"
},
{
"id": 20,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 17"
},
{
"id": 21,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 18"
},
{
"id": 22,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 19"
},
{
"id": 5,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 2"
},
{
"id": 23,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 20"
},
{
"id": 24,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 21"
},
{
"id": 25,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 22"
},
{
"id": 26,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 23"
},
{
"id": 27,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 24"
},
{
"id": 28,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 25"
},
{
"id": 29,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 26"
},
{
"id": 30,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 27"
},
{
"id": 31,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 28"
},
{
"id": 32,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 29"
},
{
"id": 6,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 3"
},
{
"id": 33,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 30"
},
{
"id": 34,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 31"
},
{
"id": 35,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 32"
},
{
"id": 36,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 33"
},
{
"id": 37,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 34"
},
{
"id": 38,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 35"
},
{
"id": 39,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 36"
},
{
"id": 40,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 37"
},
{
"id": 41,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 38"
},
{
"id": 42,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 39"
},
{
"id": 7,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 4"
},
{
"id": 43,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 40"
},
{
"id": 44,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 41"
},
{
"id": 45,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 42"
},
{
"id": 46,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 43"
},
{
"id": 47,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 44"
},
{
"id": 48,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 45"
},
{
"id": 49,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 46"
},
{
"id": 50,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 47"
},
{
"id": 51,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 48"
},
{
"id": 8,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 5"
},
{
"id": 9,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 6"
},
{
"id": 10,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 7"
},
{
"id": 11,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 8"
},
{
"id": 12,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "Port 9"
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/console_server_ports.json 0000644 0001751 0001751 00000036602 15136437134 024162 0 ustar 00runner runner {
"count": 48,
"next": null,
"previous": null,
"results": [
{
"id": 5,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 1",
"connected_console": 3
},
{
"id": 16,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 2",
"connected_console": 4
},
{
"id": 27,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 3",
"connected_console": 1
},
{
"id": 38,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 4",
"connected_console": 2
},
{
"id": 48,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 5",
"connected_console": 6
},
{
"id": 49,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 6",
"connected_console": 5
},
{
"id": 50,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 7",
"connected_console": null
},
{
"id": 51,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 8",
"connected_console": null
},
{
"id": 52,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 9",
"connected_console": null
},
{
"id": 6,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 10",
"connected_console": null
},
{
"id": 7,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 11",
"connected_console": null
},
{
"id": 8,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 12",
"connected_console": null
},
{
"id": 9,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 13",
"connected_console": null
},
{
"id": 10,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 14",
"connected_console": null
},
{
"id": 11,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 15",
"connected_console": null
},
{
"id": 12,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 16",
"connected_console": null
},
{
"id": 13,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 17",
"connected_console": null
},
{
"id": 14,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 18",
"connected_console": null
},
{
"id": 15,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 19",
"connected_console": null
},
{
"id": 17,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 20",
"connected_console": null
},
{
"id": 18,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 21",
"connected_console": null
},
{
"id": 19,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 22",
"connected_console": null
},
{
"id": 20,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 23",
"connected_console": null
},
{
"id": 21,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 24",
"connected_console": null
},
{
"id": 22,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 25",
"connected_console": null
},
{
"id": 23,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 26",
"connected_console": null
},
{
"id": 24,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 27",
"connected_console": null
},
{
"id": 25,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 28",
"connected_console": null
},
{
"id": 26,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 29",
"connected_console": null
},
{
"id": 28,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 30",
"connected_console": null
},
{
"id": 29,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 31",
"connected_console": null
},
{
"id": 30,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 32",
"connected_console": null
},
{
"id": 31,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 33",
"connected_console": null
},
{
"id": 32,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 34",
"connected_console": null
},
{
"id": 33,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 35",
"connected_console": null
},
{
"id": 34,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 36",
"connected_console": null
},
{
"id": 35,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 37",
"connected_console": null
},
{
"id": 36,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 38",
"connected_console": null
},
{
"id": 37,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 39",
"connected_console": null
},
{
"id": 39,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 40",
"connected_console": null
},
{
"id": 40,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 41",
"connected_console": null
},
{
"id": 41,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 42",
"connected_console": null
},
{
"id": 42,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 43",
"connected_console": null
},
{
"id": 43,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 44",
"connected_console": null
},
{
"id": 44,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 45",
"connected_console": null
},
{
"id": 45,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 46",
"connected_console": null
},
{
"id": 46,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 47",
"connected_console": null
},
{
"id": 47,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "Port 48",
"connected_console": null
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/device.json 0000644 0001751 0001751 00000003452 15136437134 021137 0 ustar 00runner runner {
"id": 1,
"name": "test1-edge1",
"display_name": "test1-edge1",
"device_type": {
"id": 1,
"url": "http://localhost:8000/api/dcim/device-types/1/",
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "MX960",
"slug": "mx960"
},
"role": {
"id": 1,
"url": "http://localhost:8000/api/dcim/device-roles/1/",
"name": "Router",
"slug": "router"
},
"tenant": null,
"platform": {
"id": 1,
"url": "http://localhost:8000/api/dcim/platforms/1/",
"name": "Juniper Junos",
"slug": "juniper-junos"
},
"serial": "5555555555",
"asset_tag": null,
"site": {
"id": 1,
"url": "http://localhost:8000/api/dcim/sites/1/",
"name": "TEST1",
"slug": "test1"
},
"rack": {
"id": 1,
"url": "http://localhost:8000/api/dcim/racks/1/",
"name": "A1R1",
"display_name": "A1R1 (T23A01)"
},
"position": 1,
"face": {
"value": 0,
"label": "Front"
},
"parent_device": null,
"status": {
"value": true,
"label": "Active"
},
"primary_ip": {
"id": 1,
"url": "http://localhost:8000/api/ipam/ip-addresses/1/",
"family": 4,
"address": "10.0.255.1/32"
},
"primary_ip4": {
"id": 1,
"url": "http://localhost:8000/api/ipam/ip-addresses/1/",
"family": 4,
"address": "10.0.255.1/32"
},
"primary_ip6": null,
"comments": "",
"local_context_data": {
"testing": "test"
},
"custom_fields": {},
"config_context": {
"test_key": "test_val"
}
}
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/device_bay.json 0000644 0001751 0001751 00000000371 15136437134 021767 0 ustar 00runner runner {
"id": 1,
"device": {
"id": 13,
"url": "http://localhost:8000/api/dcim/devices/13/",
"name": "test1-mothership",
"display_name": "test1-mothership"
},
"name": "thing-1",
"installed_device": null
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/device_bay_template.json 0000644 0001751 0001751 00000000623 15136437134 023662 0 ustar 00runner runner {
"id": 1,
"device_type": {
"id": 7,
"url": "http://localhost:8000/api/dcim/device-types/7/",
"manufacturer": {
"id": 3,
"url": "http://localhost:8000/api/dcim/manufacturers/3/",
"name": "ServerTech",
"slug": "servertech"
},
"model": "Mothership",
"slug": "mothership"
},
"name": "thing-1"
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/device_bay_templates.json 0000644 0001751 0001751 00000003220 15136437134 024041 0 ustar 00runner runner {
"count": 3,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"device_type": {
"id": 7,
"url": "http://localhost:8000/api/dcim/device-types/7/",
"manufacturer": {
"id": 3,
"url": "http://localhost:8000/api/dcim/manufacturers/3/",
"name": "ServerTech",
"slug": "servertech"
},
"model": "Mothership",
"slug": "mothership"
},
"name": "thing-1"
},
{
"id": 2,
"device_type": {
"id": 7,
"url": "http://localhost:8000/api/dcim/device-types/7/",
"manufacturer": {
"id": 3,
"url": "http://localhost:8000/api/dcim/manufacturers/3/",
"name": "ServerTech",
"slug": "servertech"
},
"model": "Mothership",
"slug": "mothership"
},
"name": "thing-2"
},
{
"id": 3,
"device_type": {
"id": 7,
"url": "http://localhost:8000/api/dcim/device-types/7/",
"manufacturer": {
"id": 3,
"url": "http://localhost:8000/api/dcim/manufacturers/3/",
"name": "ServerTech",
"slug": "servertech"
},
"model": "Mothership",
"slug": "mothership"
},
"name": "thing-3"
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/device_bays.json 0000644 0001751 0001751 00000002112 15136437134 022145 0 ustar 00runner runner {
"count": 3,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"device": {
"id": 13,
"url": "http://localhost:8000/api/dcim/devices/13/",
"name": "test1-mothership",
"display_name": "test1-mothership"
},
"name": "thing-1",
"installed_device": null
},
{
"id": 2,
"device": {
"id": 13,
"url": "http://localhost:8000/api/dcim/devices/13/",
"name": "test1-mothership",
"display_name": "test1-mothership"
},
"name": "thing-2",
"installed_device": null
},
{
"id": 3,
"device": {
"id": 13,
"url": "http://localhost:8000/api/dcim/devices/13/",
"name": "test1-mothership",
"display_name": "test1-mothership"
},
"name": "thing-3",
"installed_device": null
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/device_bulk_create.json 0000644 0001751 0001751 00000001514 15136437134 023474 0 ustar 00runner runner [
{
"id": 1,
"name": "test1-core3",
"device_type": 1,
"role": 3,
"tenant": null,
"platform": null,
"serial": "",
"asset_tag": null,
"site": 1,
"rack": null,
"position": null,
"face": null,
"status": 1,
"primary_ip4": null,
"primary_ip6": null,
"cluster": null,
"comments": ""
},
{
"id": 2,
"name": "test1-core4",
"device_type": 1,
"role": 3,
"tenant": null,
"platform": null,
"serial": "",
"asset_tag": null,
"site": 1,
"rack": null,
"position": null,
"face": null,
"status": 1,
"primary_ip4": null,
"primary_ip6": null,
"cluster": null,
"comments": ""
}
] ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/device_role.json 0000644 0001751 0001751 00000000122 15136437134 022147 0 ustar 00runner runner {
"id": 1,
"name": "Router",
"slug": "router",
"color": "purple"
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/device_roles.json 0000644 0001751 0001751 00000001605 15136437134 022341 0 ustar 00runner runner {
"count": 6,
"next": null,
"previous": null,
"results": [
{
"id": 3,
"name": "Core Switch",
"slug": "core-switch",
"color": "red"
},
{
"id": 4,
"name": "Leaf Switch",
"slug": "leaf-switch",
"color": "teal"
},
{
"id": 5,
"name": "OOB Switch",
"slug": "oob-switch",
"color": "purple"
},
{
"id": 6,
"name": "PDU",
"slug": "pdu",
"color": "yellow"
},
{
"id": 1,
"name": "Router",
"slug": "router",
"color": "purple"
},
{
"id": 2,
"name": "Spine Switch",
"slug": "spine-switch",
"color": "green"
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/device_type.json 0000644 0001751 0001751 00000001063 15136437134 022174 0 ustar 00runner runner {
"id": 1,
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "MX960",
"slug": "mx960",
"part_number": "",
"u_height": 16,
"is_full_depth": true,
"interface_ordering": {
"value": 1,
"label": "Slot/position"
},
"is_console_server": false,
"is_pdu": false,
"is_network_device": true,
"subdevice_role": null,
"comments": "",
"custom_fields": {},
"instance_count": 2
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/device_types.json 0000644 0001751 0001751 00000011162 15136437134 022360 0 ustar 00runner runner {
"count": 6,
"next": null,
"previous": null,
"results": [
{
"id": 2,
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "EX9214",
"slug": "ex9214",
"part_number": "",
"u_height": 16,
"is_full_depth": true,
"interface_ordering": {
"value": 1,
"label": "Slot/position"
},
"is_console_server": false,
"is_pdu": false,
"is_network_device": true,
"subdevice_role": null,
"comments": "",
"custom_fields": {},
"instance_count": 2
},
{
"id": 1,
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "MX960",
"slug": "mx960",
"part_number": "",
"u_height": 16,
"is_full_depth": true,
"interface_ordering": {
"value": 1,
"label": "Slot/position"
},
"is_console_server": false,
"is_pdu": false,
"is_network_device": true,
"subdevice_role": null,
"comments": "",
"custom_fields": {},
"instance_count": 2
},
{
"id": 3,
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "QFX5100-24Q",
"slug": "qfx5100-24q",
"part_number": "",
"u_height": 1,
"is_full_depth": true,
"interface_ordering": {
"value": 1,
"label": "Slot/position"
},
"is_console_server": false,
"is_pdu": false,
"is_network_device": true,
"subdevice_role": null,
"comments": "",
"custom_fields": {},
"instance_count": 2
},
{
"id": 4,
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "QFX5100-48S",
"slug": "qfx5100-48s",
"part_number": "",
"u_height": 1,
"is_full_depth": true,
"interface_ordering": {
"value": 1,
"label": "Slot/position"
},
"is_console_server": false,
"is_pdu": false,
"is_network_device": true,
"subdevice_role": null,
"comments": "",
"custom_fields": {},
"instance_count": 2
},
{
"id": 5,
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148",
"part_number": "",
"u_height": 1,
"is_full_depth": true,
"interface_ordering": {
"value": 1,
"label": "Slot/position"
},
"is_console_server": true,
"is_pdu": false,
"is_network_device": false,
"subdevice_role": null,
"comments": "",
"custom_fields": {},
"instance_count": 1
},
{
"id": 6,
"manufacturer": {
"id": 3,
"url": "http://localhost:8000/api/dcim/manufacturers/3/",
"name": "ServerTech",
"slug": "servertech"
},
"model": "CWG-24VYM415C9",
"slug": "cwg-24vym415c9",
"part_number": "",
"u_height": 0,
"is_full_depth": false,
"interface_ordering": {
"value": 1,
"label": "Slot/position"
},
"is_console_server": false,
"is_pdu": true,
"is_network_device": false,
"subdevice_role": null,
"comments": "",
"custom_fields": {},
"instance_count": 2
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/devices.json 0000644 0001751 0001751 00000053055 15136437134 021326 0 ustar 00runner runner {
"count": 11,
"next": null,
"previous": null,
"results": [
{
"id": 2,
"name": "test1-core1",
"display_name": "test1-core1",
"device_type": {
"id": 2,
"url": "http://localhost:8000/api/dcim/device-types/2/",
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "EX9214",
"slug": "ex9214"
},
"role": {
"id": 3,
"url": "http://localhost:8000/api/dcim/device-roles/3/",
"name": "Core Switch",
"slug": "core-switch"
},
"tenant": null,
"platform": {
"id": 1,
"url": "http://localhost:8000/api/dcim/platforms/1/",
"name": "Juniper Junos",
"slug": "juniper-junos"
},
"serial": "",
"asset_tag": null,
"site": {
"id": 1,
"url": "http://localhost:8000/api/dcim/sites/1/",
"name": "TEST1",
"slug": "test1"
},
"rack": {
"id": 1,
"url": "http://localhost:8000/api/dcim/racks/1/",
"name": "A1R1",
"display_name": "A1R1 (T23A01)"
},
"position": 17,
"face": {
"value": 0,
"label": "Front"
},
"parent_device": null,
"status": {
"value": true,
"label": "Active"
},
"primary_ip": {
"id": 5,
"url": "http://localhost:8000/api/ipam/ip-addresses/5/",
"family": 4,
"address": "10.0.254.1/24"
},
"primary_ip4": {
"id": 5,
"url": "http://localhost:8000/api/ipam/ip-addresses/5/",
"family": 4,
"address": "10.0.254.1/24"
},
"primary_ip6": null,
"comments": "",
"custom_fields": {}
},
{
"id": 8,
"name": "test1-core2",
"display_name": "test1-core2",
"device_type": {
"id": 2,
"url": "http://localhost:8000/api/dcim/device-types/2/",
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "EX9214",
"slug": "ex9214"
},
"role": {
"id": 3,
"url": "http://localhost:8000/api/dcim/device-roles/3/",
"name": "Core Switch",
"slug": "core-switch"
},
"tenant": null,
"platform": {
"id": 1,
"url": "http://localhost:8000/api/dcim/platforms/1/",
"name": "Juniper Junos",
"slug": "juniper-junos"
},
"serial": "67856734534",
"asset_tag": null,
"site": {
"id": 1,
"url": "http://localhost:8000/api/dcim/sites/1/",
"name": "TEST1",
"slug": "test1"
},
"rack": {
"id": 2,
"url": "http://localhost:8000/api/dcim/racks/2/",
"name": "A1R2",
"display_name": "A1R2 (T24A01)"
},
"position": 17,
"face": {
"value": 0,
"label": "Front"
},
"parent_device": null,
"status": {
"value": true,
"label": "Active"
},
"primary_ip": {
"id": 19,
"url": "http://localhost:8000/api/ipam/ip-addresses/19/",
"family": 4,
"address": "10.0.254.2/32"
},
"primary_ip4": {
"id": 19,
"url": "http://localhost:8000/api/ipam/ip-addresses/19/",
"family": 4,
"address": "10.0.254.2/32"
},
"primary_ip6": null,
"comments": "",
"custom_fields": {}
},
{
"id": 1,
"name": "test1-edge1",
"display_name": "test1-edge1",
"device_type": {
"id": 1,
"url": "http://localhost:8000/api/dcim/device-types/1/",
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "MX960",
"slug": "mx960"
},
"role": {
"id": 1,
"url": "http://localhost:8000/api/dcim/device-roles/1/",
"name": "Router",
"slug": "router"
},
"tenant": null,
"platform": {
"id": 1,
"url": "http://localhost:8000/api/dcim/platforms/1/",
"name": "Juniper Junos",
"slug": "juniper-junos"
},
"serial": "5555555555",
"asset_tag": null,
"site": {
"id": 1,
"url": "http://localhost:8000/api/dcim/sites/1/",
"name": "TEST1",
"slug": "test1"
},
"rack": {
"id": 1,
"url": "http://localhost:8000/api/dcim/racks/1/",
"name": "A1R1",
"display_name": "A1R1 (T23A01)"
},
"position": 1,
"face": {
"value": 0,
"label": "Front"
},
"parent_device": null,
"status": {
"value": true,
"label": "Active"
},
"primary_ip": {
"id": 1,
"url": "http://localhost:8000/api/ipam/ip-addresses/1/",
"family": 4,
"address": "10.0.255.1/32"
},
"primary_ip4": {
"id": 1,
"url": "http://localhost:8000/api/ipam/ip-addresses/1/",
"family": 4,
"address": "10.0.255.1/32"
},
"primary_ip6": null,
"comments": "",
"custom_fields": {}
},
{
"id": 7,
"name": "test1-edge2",
"display_name": "test1-edge2",
"device_type": {
"id": 1,
"url": "http://localhost:8000/api/dcim/device-types/1/",
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "MX960",
"slug": "mx960"
},
"role": {
"id": 1,
"url": "http://localhost:8000/api/dcim/device-roles/1/",
"name": "Router",
"slug": "router"
},
"tenant": null,
"platform": {
"id": 1,
"url": "http://localhost:8000/api/dcim/platforms/1/",
"name": "Juniper Junos",
"slug": "juniper-junos"
},
"serial": "7567356345",
"asset_tag": null,
"site": {
"id": 1,
"url": "http://localhost:8000/api/dcim/sites/1/",
"name": "TEST1",
"slug": "test1"
},
"rack": {
"id": 2,
"url": "http://localhost:8000/api/dcim/racks/2/",
"name": "A1R2",
"display_name": "A1R2 (T24A01)"
},
"position": 1,
"face": {
"value": 0,
"label": "Front"
},
"parent_device": null,
"status": {
"value": true,
"label": "Active"
},
"primary_ip": {
"id": 3,
"url": "http://localhost:8000/api/ipam/ip-addresses/3/",
"family": 4,
"address": "10.0.255.2/32"
},
"primary_ip4": {
"id": 3,
"url": "http://localhost:8000/api/ipam/ip-addresses/3/",
"family": 4,
"address": "10.0.255.2/32"
},
"primary_ip6": null,
"comments": "",
"custom_fields": {}
},
{
"id": 4,
"name": "test1-leaf1",
"display_name": "test1-leaf1",
"device_type": {
"id": 4,
"url": "http://localhost:8000/api/dcim/device-types/4/",
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "QFX5100-48S",
"slug": "qfx5100-48s"
},
"role": {
"id": 4,
"url": "http://localhost:8000/api/dcim/device-roles/4/",
"name": "Leaf Switch",
"slug": "leaf-switch"
},
"tenant": null,
"platform": {
"id": 1,
"url": "http://localhost:8000/api/dcim/platforms/1/",
"name": "Juniper Junos",
"slug": "juniper-junos"
},
"serial": "",
"asset_tag": null,
"site": {
"id": 1,
"url": "http://localhost:8000/api/dcim/sites/1/",
"name": "TEST1",
"slug": "test1"
},
"rack": {
"id": 1,
"url": "http://localhost:8000/api/dcim/racks/1/",
"name": "A1R1",
"display_name": "A1R1 (T23A01)"
},
"position": 34,
"face": {
"value": 0,
"label": "Front"
},
"parent_device": null,
"status": {
"value": true,
"label": "Active"
},
"primary_ip": null,
"primary_ip4": null,
"primary_ip6": null,
"comments": "",
"custom_fields": {}
},
{
"id": 5,
"name": "test1-leaf2",
"display_name": "test1-leaf2",
"device_type": {
"id": 4,
"url": "http://localhost:8000/api/dcim/device-types/4/",
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "QFX5100-48S",
"slug": "qfx5100-48s"
},
"role": {
"id": 4,
"url": "http://localhost:8000/api/dcim/device-roles/4/",
"name": "Leaf Switch",
"slug": "leaf-switch"
},
"tenant": null,
"platform": {
"id": 1,
"url": "http://localhost:8000/api/dcim/platforms/1/",
"name": "Juniper Junos",
"slug": "juniper-junos"
},
"serial": "9823478293748",
"asset_tag": null,
"site": {
"id": 1,
"url": "http://localhost:8000/api/dcim/sites/1/",
"name": "TEST1",
"slug": "test1"
},
"rack": {
"id": 2,
"url": "http://localhost:8000/api/dcim/racks/2/",
"name": "A1R2",
"display_name": "A1R2 (T24A01)"
},
"position": 34,
"face": {
"value": 0,
"label": "Front"
},
"parent_device": null,
"status": {
"value": true,
"label": "Active"
},
"primary_ip": null,
"primary_ip4": null,
"primary_ip6": null,
"comments": "",
"custom_fields": {}
},
{
"id": 9,
"name": "test1-oob1",
"display_name": "test1-oob1",
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"role": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-roles/5/",
"name": "OOB Switch",
"slug": "oob-switch"
},
"tenant": null,
"platform": {
"id": 2,
"url": "http://localhost:8000/api/dcim/platforms/2/",
"name": "Opengear",
"slug": "opengear"
},
"serial": "98273942938",
"asset_tag": null,
"site": {
"id": 1,
"url": "http://localhost:8000/api/dcim/sites/1/",
"name": "TEST1",
"slug": "test1"
},
"rack": {
"id": 1,
"url": "http://localhost:8000/api/dcim/racks/1/",
"name": "A1R1",
"display_name": "A1R1 (T23A01)"
},
"position": 42,
"face": {
"value": 0,
"label": "Front"
},
"parent_device": null,
"status": {
"value": true,
"label": "Active"
},
"primary_ip": null,
"primary_ip4": null,
"primary_ip6": null,
"comments": "",
"custom_fields": {}
},
{
"id": 11,
"name": "test1-pdu1",
"display_name": "test1-pdu1",
"device_type": {
"id": 6,
"url": "http://localhost:8000/api/dcim/device-types/6/",
"manufacturer": {
"id": 3,
"url": "http://localhost:8000/api/dcim/manufacturers/3/",
"name": "ServerTech",
"slug": "servertech"
},
"model": "CWG-24VYM415C9",
"slug": "cwg-24vym415c9"
},
"role": {
"id": 6,
"url": "http://localhost:8000/api/dcim/device-roles/6/",
"name": "PDU",
"slug": "pdu"
},
"tenant": null,
"platform": null,
"serial": "",
"asset_tag": null,
"site": {
"id": 1,
"url": "http://localhost:8000/api/dcim/sites/1/",
"name": "TEST1",
"slug": "test1"
},
"rack": {
"id": 1,
"url": "http://localhost:8000/api/dcim/racks/1/",
"name": "A1R1",
"display_name": "A1R1 (T23A01)"
},
"position": null,
"face": null,
"parent_device": null,
"status": {
"value": true,
"label": "Active"
},
"primary_ip": null,
"primary_ip4": null,
"primary_ip6": null,
"comments": "",
"custom_fields": {}
},
{
"id": 12,
"name": "test1-pdu2",
"display_name": "test1-pdu2",
"device_type": {
"id": 6,
"url": "http://localhost:8000/api/dcim/device-types/6/",
"manufacturer": {
"id": 3,
"url": "http://localhost:8000/api/dcim/manufacturers/3/",
"name": "ServerTech",
"slug": "servertech"
},
"model": "CWG-24VYM415C9",
"slug": "cwg-24vym415c9"
},
"role": {
"id": 6,
"url": "http://localhost:8000/api/dcim/device-roles/6/",
"name": "PDU",
"slug": "pdu"
},
"tenant": null,
"platform": null,
"serial": "",
"asset_tag": null,
"site": {
"id": 1,
"url": "http://localhost:8000/api/dcim/sites/1/",
"name": "TEST1",
"slug": "test1"
},
"rack": {
"id": 2,
"url": "http://localhost:8000/api/dcim/racks/2/",
"name": "A1R2",
"display_name": "A1R2 (T24A01)"
},
"position": null,
"face": null,
"parent_device": null,
"status": {
"value": true,
"label": "Active"
},
"primary_ip": null,
"primary_ip4": null,
"primary_ip6": null,
"comments": "",
"custom_fields": {}
},
{
"id": 3,
"name": "test1-spine1",
"display_name": "test1-spine1",
"device_type": {
"id": 3,
"url": "http://localhost:8000/api/dcim/device-types/3/",
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "QFX5100-24Q",
"slug": "qfx5100-24q"
},
"role": {
"id": 2,
"url": "http://localhost:8000/api/dcim/device-roles/2/",
"name": "Spine Switch",
"slug": "spine-switch"
},
"tenant": null,
"platform": {
"id": 1,
"url": "http://localhost:8000/api/dcim/platforms/1/",
"name": "Juniper Junos",
"slug": "juniper-junos"
},
"serial": "",
"asset_tag": null,
"site": {
"id": 1,
"url": "http://localhost:8000/api/dcim/sites/1/",
"name": "TEST1",
"slug": "test1"
},
"rack": {
"id": 1,
"url": "http://localhost:8000/api/dcim/racks/1/",
"name": "A1R1",
"display_name": "A1R1 (T23A01)"
},
"position": 33,
"face": {
"value": 0,
"label": "Front"
},
"parent_device": null,
"status": {
"value": true,
"label": "Active"
},
"primary_ip": null,
"primary_ip4": null,
"primary_ip6": null,
"comments": "",
"custom_fields": {}
},
{
"id": 6,
"name": "test1-spine2",
"display_name": "test1-spine2",
"device_type": {
"id": 3,
"url": "http://localhost:8000/api/dcim/device-types/3/",
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "QFX5100-24Q",
"slug": "qfx5100-24q"
},
"role": {
"id": 2,
"url": "http://localhost:8000/api/dcim/device-roles/2/",
"name": "Spine Switch",
"slug": "spine-switch"
},
"tenant": null,
"platform": {
"id": 1,
"url": "http://localhost:8000/api/dcim/platforms/1/",
"name": "Juniper Junos",
"slug": "juniper-junos"
},
"serial": "45649818158",
"asset_tag": null,
"site": {
"id": 1,
"url": "http://localhost:8000/api/dcim/sites/1/",
"name": "TEST1",
"slug": "test1"
},
"rack": {
"id": 2,
"url": "http://localhost:8000/api/dcim/racks/2/",
"name": "A1R2",
"display_name": "A1R2 (T24A01)"
},
"position": 33,
"face": {
"value": 0,
"label": "Front"
},
"parent_device": null,
"status": {
"value": true,
"label": "Active"
},
"primary_ip": null,
"primary_ip4": null,
"primary_ip6": null,
"comments": "",
"custom_fields": {}
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/interface.json 0000644 0001751 0001751 00000002724 15136437134 021641 0 ustar 00runner runner {
"id": 1,
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "et-0/0/0",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"enabled": true,
"lag": {
"id": 223,
"url": "http://localhost:8000/api/dcim/interfaces/223/",
"name": "ae0"
},
"mtu": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"is_connected": true,
"connected_endpoints": [
{
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"display": "tst-endpoint",
"name": "tst-endpoint"
}
],
"connected_endpoints_type": "dcim.device",
"connected_endpoints_reachable": true,
"cable": {
"id": 1,
"url": "http://localhost:8000/api/dcim/cables/1/",
"label": ""
},
"mode": {
"value": "tagged",
"label": "Tagged",
"id": 200
},
"untagged_vlan": {
"id": 2,
"url": "http://localhost:8000/api/ipam/vlans/792/",
"vid": 2069,
"name": "v2069",
"display_name": "2069 (v2069)"
},
"tagged_vlans": [
{
"id": 3,
"url": "http://localhost:8000/api/ipam/vlans/248/",
"vid": 1210,
"name": "v1210",
"display_name": "1210 (v1210)"
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/interface_connection.json 0000644 0001751 0001751 00000001737 15136437134 024063 0 ustar 00runner runner {
"id": 1,
"interface_a": {
"id": 99,
"url": "http://localhost:8000/api/dcim/interfaces/99/",
"device": {
"id": 5,
"url": "http://localhost:8000/api/dcim/devices/5/",
"name": "test1-leaf2",
"display_name": "test1-leaf2"
},
"name": "et-0/0/48",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"interface_b": {
"id": 15,
"url": "http://localhost:8000/api/dcim/interfaces/15/",
"device": {
"id": 3,
"url": "http://localhost:8000/api/dcim/devices/3/",
"name": "test1-spine1",
"display_name": "test1-spine1"
},
"name": "et-0/0/1",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"connection_status": {
"value": true,
"label": "Connected"
}
}
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/interface_connections.json 0000644 0001751 0001751 00000052760 15136437134 024250 0 ustar 00runner runner {
"count": 17,
"next": null,
"previous": null,
"results": [
{
"id": 22,
"interface_a": {
"id": 9,
"url": "http://localhost:8000/api/dcim/interfaces/9/",
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "test1-edge1",
"display_name": "test1-edge1"
},
"name": "xe-0/0/5",
"form_factor": 1200,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"interface_b": {
"id": 218,
"url": "http://localhost:8000/api/dcim/interfaces/218/",
"device": {
"id": 7,
"url": "http://localhost:8000/api/dcim/devices/7/",
"name": "test1-edge2",
"display_name": "test1-edge2"
},
"name": "xe-0/0/5",
"form_factor": 1200,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"connection_status": {
"value": true,
"label": "Connected"
}
},
{
"id": 23,
"interface_a": {
"id": 8,
"url": "http://localhost:8000/api/dcim/interfaces/8/",
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "test1-edge1",
"display_name": "test1-edge1"
},
"name": "xe-0/0/4",
"form_factor": 1200,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"interface_b": {
"id": 206,
"url": "http://localhost:8000/api/dcim/interfaces/206/",
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "xe-0/0/5",
"form_factor": 1200,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"connection_status": {
"value": true,
"label": "Connected"
}
},
{
"id": 24,
"interface_a": {
"id": 7,
"url": "http://localhost:8000/api/dcim/interfaces/7/",
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "test1-edge1",
"display_name": "test1-edge1"
},
"name": "xe-0/0/3",
"form_factor": 1200,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"interface_b": {
"id": 212,
"url": "http://localhost:8000/api/dcim/interfaces/212/",
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "xe-0/0/5",
"form_factor": 1200,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"connection_status": {
"value": true,
"label": "Connected"
}
},
{
"id": 21,
"interface_a": {
"id": 194,
"url": "http://localhost:8000/api/dcim/interfaces/194/",
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "et-0/1/2",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"interface_b": {
"id": 200,
"url": "http://localhost:8000/api/dcim/interfaces/200/",
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "et-0/1/2",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"connection_status": {
"value": true,
"label": "Connected"
}
},
{
"id": 17,
"interface_a": {
"id": 192,
"url": "http://localhost:8000/api/dcim/interfaces/192/",
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "et-0/1/0",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"interface_b": {
"id": 175,
"url": "http://localhost:8000/api/dcim/interfaces/175/",
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/1/0",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"connection_status": {
"value": true,
"label": "Connected"
}
},
{
"id": 20,
"interface_a": {
"id": 191,
"url": "http://localhost:8000/api/dcim/interfaces/191/",
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "et-0/0/2",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"interface_b": {
"id": 197,
"url": "http://localhost:8000/api/dcim/interfaces/197/",
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "et-0/0/2",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"connection_status": {
"value": true,
"label": "Connected"
}
},
{
"id": 16,
"interface_a": {
"id": 189,
"url": "http://localhost:8000/api/dcim/interfaces/189/",
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "et-0/0/0",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"interface_b": {
"id": 37,
"url": "http://localhost:8000/api/dcim/interfaces/37/",
"device": {
"id": 3,
"url": "http://localhost:8000/api/dcim/devices/3/",
"name": "test1-spine1",
"display_name": "test1-spine1"
},
"name": "et-0/1/0",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"connection_status": {
"value": true,
"label": "Connected"
}
},
{
"id": 8,
"interface_a": {
"id": 92,
"url": "http://localhost:8000/api/dcim/interfaces/92/",
"device": {
"id": 4,
"url": "http://localhost:8000/api/dcim/devices/4/",
"name": "test1-leaf1",
"display_name": "test1-leaf1"
},
"name": "xe-0/0/47",
"form_factor": 1200,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"interface_b": {
"id": 145,
"url": "http://localhost:8000/api/dcim/interfaces/145/",
"device": {
"id": 5,
"url": "http://localhost:8000/api/dcim/devices/5/",
"name": "test1-leaf2",
"display_name": "test1-leaf2"
},
"name": "xe-0/0/47",
"form_factor": 1200,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"connection_status": {
"value": true,
"label": "Connected"
}
},
{
"id": 7,
"interface_a": {
"id": 91,
"url": "http://localhost:8000/api/dcim/interfaces/91/",
"device": {
"id": 4,
"url": "http://localhost:8000/api/dcim/devices/4/",
"name": "test1-leaf1",
"display_name": "test1-leaf1"
},
"name": "xe-0/0/46",
"form_factor": 1200,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"interface_b": {
"id": 144,
"url": "http://localhost:8000/api/dcim/interfaces/144/",
"device": {
"id": 5,
"url": "http://localhost:8000/api/dcim/devices/5/",
"name": "test1-leaf2",
"display_name": "test1-leaf2"
},
"name": "xe-0/0/46",
"form_factor": 1200,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"connection_status": {
"value": true,
"label": "Connected"
}
},
{
"id": 6,
"interface_a": {
"id": 47,
"url": "http://localhost:8000/api/dcim/interfaces/47/",
"device": {
"id": 4,
"url": "http://localhost:8000/api/dcim/devices/4/",
"name": "test1-leaf1",
"display_name": "test1-leaf1"
},
"name": "et-0/0/49",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"interface_b": {
"id": 152,
"url": "http://localhost:8000/api/dcim/interfaces/152/",
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/0/0",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"connection_status": {
"value": true,
"label": "Connected"
}
},
{
"id": 5,
"interface_a": {
"id": 46,
"url": "http://localhost:8000/api/dcim/interfaces/46/",
"device": {
"id": 4,
"url": "http://localhost:8000/api/dcim/devices/4/",
"name": "test1-leaf1",
"display_name": "test1-leaf1"
},
"name": "et-0/0/48",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"interface_b": {
"id": 14,
"url": "http://localhost:8000/api/dcim/interfaces/14/",
"device": {
"id": 3,
"url": "http://localhost:8000/api/dcim/devices/3/",
"name": "test1-spine1",
"display_name": "test1-spine1"
},
"name": "et-0/0/0",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"connection_status": {
"value": true,
"label": "Connected"
}
},
{
"id": 4,
"interface_a": {
"id": 100,
"url": "http://localhost:8000/api/dcim/interfaces/100/",
"device": {
"id": 5,
"url": "http://localhost:8000/api/dcim/devices/5/",
"name": "test1-leaf2",
"display_name": "test1-leaf2"
},
"name": "et-0/0/49",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"interface_b": {
"id": 153,
"url": "http://localhost:8000/api/dcim/interfaces/153/",
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/0/1",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"connection_status": {
"value": true,
"label": "Connected"
}
},
{
"id": 3,
"interface_a": {
"id": 99,
"url": "http://localhost:8000/api/dcim/interfaces/99/",
"device": {
"id": 5,
"url": "http://localhost:8000/api/dcim/devices/5/",
"name": "test1-leaf2",
"display_name": "test1-leaf2"
},
"name": "et-0/0/48",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"interface_b": {
"id": 15,
"url": "http://localhost:8000/api/dcim/interfaces/15/",
"device": {
"id": 3,
"url": "http://localhost:8000/api/dcim/devices/3/",
"name": "test1-spine1",
"display_name": "test1-spine1"
},
"name": "et-0/0/1",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"connection_status": {
"value": true,
"label": "Connected"
}
},
{
"id": 25,
"interface_a": {
"id": 217,
"url": "http://localhost:8000/api/dcim/interfaces/217/",
"device": {
"id": 7,
"url": "http://localhost:8000/api/dcim/devices/7/",
"name": "test1-edge2",
"display_name": "test1-edge2"
},
"name": "xe-0/0/4",
"form_factor": 1200,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"interface_b": {
"id": 205,
"url": "http://localhost:8000/api/dcim/interfaces/205/",
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "xe-0/0/4",
"form_factor": 1200,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"connection_status": {
"value": true,
"label": "Connected"
}
},
{
"id": 26,
"interface_a": {
"id": 216,
"url": "http://localhost:8000/api/dcim/interfaces/216/",
"device": {
"id": 7,
"url": "http://localhost:8000/api/dcim/devices/7/",
"name": "test1-edge2",
"display_name": "test1-edge2"
},
"name": "xe-0/0/3",
"form_factor": 1200,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"interface_b": {
"id": 211,
"url": "http://localhost:8000/api/dcim/interfaces/211/",
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "xe-0/0/4",
"form_factor": 1200,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"connection_status": {
"value": true,
"label": "Connected"
}
},
{
"id": 19,
"interface_a": {
"id": 198,
"url": "http://localhost:8000/api/dcim/interfaces/198/",
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "et-0/1/0",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"interface_b": {
"id": 179,
"url": "http://localhost:8000/api/dcim/interfaces/179/",
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/2/0",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"connection_status": {
"value": true,
"label": "Connected"
}
},
{
"id": 18,
"interface_a": {
"id": 195,
"url": "http://localhost:8000/api/dcim/interfaces/195/",
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "et-0/0/0",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"interface_b": {
"id": 41,
"url": "http://localhost:8000/api/dcim/interfaces/41/",
"device": {
"id": 3,
"url": "http://localhost:8000/api/dcim/devices/3/",
"name": "test1-spine1",
"display_name": "test1-spine1"
},
"name": "et-0/2/0",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
},
"connection_status": {
"value": true,
"label": "Connected"
}
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/interface_template.json 0000644 0001751 0001751 00000000764 15136437134 023536 0 ustar 00runner runner {
"id": 1,
"device_type": {
"id": 1,
"url": "http://localhost:8000/api/dcim/device-types/1/",
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "MX960",
"slug": "mx960"
},
"name": "fxp0 (RE0)",
"form_factor": {
"value": 1000,
"label": "1000BASE-T (1GE)"
},
"mgmt_only": true
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/interface_templates.json 0000644 0001751 0001751 00000002621 15136437134 023713 0 ustar 00runner runner {
"count": 2,
"next": null,
"previous": null,
"results": [
{
"id": 4,
"device_type": {
"id": 2,
"url": "http://localhost:8000/api/dcim/device-types/2/",
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "EX9214",
"slug": "ex9214"
},
"name": "fxp0 (RE0)",
"form_factor": {
"value": 1000,
"label": "1000BASE-T (1GE)"
},
"mgmt_only": true
},
{
"id": 5,
"device_type": {
"id": 2,
"url": "http://localhost:8000/api/dcim/device-types/2/",
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "EX9214",
"slug": "ex9214"
},
"name": "fxp0 (RE1)",
"form_factor": {
"value": 1000,
"label": "1000BASE-T (1GE)"
},
"mgmt_only": true
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/interface_trace.json 0000644 0001751 0001751 00000006770 15136437134 023024 0 ustar 00runner runner [
[
{
"id": 39126,
"url": "http://localhost:8000/api/dcim/interfaces/39126/",
"device": {
"id": 4747,
"url": "http://localhost:8000/api/dcim/devices/4747/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "em1",
"cable": 9911,
"connection_status": {
"value": false,
"label": "Not Connected"
}
},
{
"id": 9911,
"url": "http://localhost:8000/api/dcim/cables/9911/",
"type": "",
"status": "planned",
"label": "",
"color": "",
"length": null,
"length_unit": ""
},
{
"id": 5583,
"url": "http://localhost:8000/api/dcim/front-ports/5583/",
"device": {
"id": 4430,
"url": "http://localhost:8000/api/dcim/devices/4430/",
"name": "test1-patchpanel1",
"display_name": "test1-patchpanel1"
},
"name": "pair-11 (ports 21-22)",
"cable": 9911
}
],
[
{
"id": 3736,
"url": "http://localhost:8000/api/dcim/rear-ports/3736/",
"device": {
"id": 4430,
"url": "http://localhost:8000/api/dcim/devices/4430/",
"name": "test1-patchpanel1",
"display_name": "test1-patchpanel1"
},
"name": "port-2",
"cable": 9229
},
{
"id": 9229,
"url": "http://localhost:8000/api/dcim/cables/9229/",
"type": "mmf-om4",
"status": "planned",
"label": "",
"color": "",
"length": null,
"length_unit": ""
},
{
"id": 3768,
"url": "http://localhost:8000/api/dcim/rear-ports/3768/",
"device": {
"id": 4436,
"url": "http://localhost:8000/api/dcim/devices/4436/",
"name": "test1-patchpanel2",
"display_name": "test1-patchpanel2"
},
"name": "port-2",
"cable": 9229
}
],
[
{
"id": 5655,
"url": "http://localhost:8000/api/dcim/front-ports/5655/",
"device": {
"id": 4436,
"url": "http://localhost:8000/api/dcim/devices/4436/",
"name": "test1-patchpanel2",
"display_name": "test1-patchpanel2"
},
"name": "pair-11 (ports 21-22)",
"cable": 9240
},
{
"id": 9240,
"url": "http://localhost:8000/api/dcim/cables/9240/",
"type": "mmf-om4",
"status": "planned",
"label": "",
"color": "",
"length": null,
"length_unit": ""
},
{
"id": 35473,
"url": "http://localhost:8000/api/dcim/interfaces/35473/",
"device": {
"id": 3930,
"url": "http://localhost:8000/api/dcim/devices/3930/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "Ethernet11",
"cable": 9240,
"connection_status": {
"value": false,
"label": "Not Connected"
}
}
]
]
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/interfaces.json 0000644 0001751 0001751 00000033567 15136437134 022035 0 ustar 00runner runner {
"count": 221,
"next": null,
"previous": "http://localhost:8000/api/dcim/interfaces/?limit=50&offset=150",
"results": [
{
"id": 162,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/0/18",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 163,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/0/19",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 164,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/0/2",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 165,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/0/20",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 166,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/0/21",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 167,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/0/22",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 168,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/0/3",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 169,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/0/4",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 170,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/0/5",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 171,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/0/6",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 172,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/0/7",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 173,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/0/8",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 174,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/0/9",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 175,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/1/0",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": {
"id": 17,
"url": "http://localhost:8000/api/dcim/interface-connections/17/",
"connection_status": true
},
"connected_interface": {
"id": 192,
"url": "http://localhost:8000/api/dcim/interfaces/192/",
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "et-0/1/0",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
}
},
{
"id": 176,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/1/1",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 177,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/1/2",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 178,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/1/3",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 179,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/2/0",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": {
"id": 19,
"url": "http://localhost:8000/api/dcim/interface-connections/19/",
"connection_status": true
},
"connected_interface": {
"id": 198,
"url": "http://localhost:8000/api/dcim/interfaces/198/",
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "et-0/1/0",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
}
},
{
"id": 180,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/2/1",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 181,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/2/2",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 182,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/2/3",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/interfaces_1.json 0000644 0001751 0001751 00000124507 15136437134 022250 0 ustar 00runner runner {
"count": 221,
"next": "http://localhost:8000/api/dcim/interfaces/?limit=50&offset=50",
"previous": null,
"results": [
{
"id": 189,
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "et-0/0/0",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": {
"id": 16,
"url": "http://localhost:8000/api/dcim/interface-connections/16/",
"connection_status": true
},
"connected_interface": {
"id": 37,
"url": "http://localhost:8000/api/dcim/interfaces/37/",
"device": {
"id": 3,
"url": "http://localhost:8000/api/dcim/devices/3/",
"name": "test1-spine1",
"display_name": "test1-spine1"
},
"name": "et-0/1/0",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
}
},
{
"id": 190,
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "et-0/0/1",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 191,
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "et-0/0/2",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": {
"id": 20,
"url": "http://localhost:8000/api/dcim/interface-connections/20/",
"connection_status": true
},
"connected_interface": {
"id": 197,
"url": "http://localhost:8000/api/dcim/interfaces/197/",
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "et-0/0/2",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
}
},
{
"id": 192,
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "et-0/1/0",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": {
"id": 17,
"url": "http://localhost:8000/api/dcim/interface-connections/17/",
"connection_status": true
},
"connected_interface": {
"id": 175,
"url": "http://localhost:8000/api/dcim/interfaces/175/",
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/1/0",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
}
},
{
"id": 193,
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "et-0/1/1",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 194,
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "et-0/1/2",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": {
"id": 21,
"url": "http://localhost:8000/api/dcim/interface-connections/21/",
"connection_status": true
},
"connected_interface": {
"id": 200,
"url": "http://localhost:8000/api/dcim/interfaces/200/",
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "et-0/1/2",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
}
},
{
"id": 10,
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "fxp0 (RE0)",
"form_factor": {
"value": 1000,
"label": "1000BASE-T (1GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": true,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 11,
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "fxp0 (RE1)",
"form_factor": {
"value": 1000,
"label": "1000BASE-T (1GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": true,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 12,
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "lo0",
"form_factor": {
"value": 0,
"label": "Virtual"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 201,
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "xe-0/0/0",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 202,
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "xe-0/0/1",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 203,
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "xe-0/0/2",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 204,
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "xe-0/0/3",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 205,
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "xe-0/0/4",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": {
"id": 25,
"url": "http://localhost:8000/api/dcim/interface-connections/25/",
"connection_status": true
},
"connected_interface": {
"id": 217,
"url": "http://localhost:8000/api/dcim/interfaces/217/",
"device": {
"id": 7,
"url": "http://localhost:8000/api/dcim/devices/7/",
"name": "test1-edge2",
"display_name": "test1-edge2"
},
"name": "xe-0/0/4",
"form_factor": 1200,
"mac_address": null,
"mgmt_only": false,
"description": ""
}
},
{
"id": 206,
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "xe-0/0/5",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": {
"id": 23,
"url": "http://localhost:8000/api/dcim/interface-connections/23/",
"connection_status": true
},
"connected_interface": {
"id": 8,
"url": "http://localhost:8000/api/dcim/interfaces/8/",
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "test1-edge1",
"display_name": "test1-edge1"
},
"name": "xe-0/0/4",
"form_factor": 1200,
"mac_address": null,
"mgmt_only": false,
"description": ""
}
},
{
"id": 195,
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "et-0/0/0",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": {
"id": 18,
"url": "http://localhost:8000/api/dcim/interface-connections/18/",
"connection_status": true
},
"connected_interface": {
"id": 41,
"url": "http://localhost:8000/api/dcim/interfaces/41/",
"device": {
"id": 3,
"url": "http://localhost:8000/api/dcim/devices/3/",
"name": "test1-spine1",
"display_name": "test1-spine1"
},
"name": "et-0/2/0",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
}
},
{
"id": 196,
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "et-0/0/1",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 197,
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "et-0/0/2",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": {
"id": 20,
"url": "http://localhost:8000/api/dcim/interface-connections/20/",
"connection_status": true
},
"connected_interface": {
"id": 191,
"url": "http://localhost:8000/api/dcim/interfaces/191/",
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "et-0/0/2",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
}
},
{
"id": 198,
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "et-0/1/0",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": {
"id": 19,
"url": "http://localhost:8000/api/dcim/interface-connections/19/",
"connection_status": true
},
"connected_interface": {
"id": 179,
"url": "http://localhost:8000/api/dcim/interfaces/179/",
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/2/0",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
}
},
{
"id": 199,
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "et-0/1/1",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 200,
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "et-0/1/2",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": {
"id": 21,
"url": "http://localhost:8000/api/dcim/interface-connections/21/",
"connection_status": true
},
"connected_interface": {
"id": 194,
"url": "http://localhost:8000/api/dcim/interfaces/194/",
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "et-0/1/2",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
}
},
{
"id": 186,
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "fxp0 (RE0)",
"form_factor": {
"value": 1000,
"label": "1000BASE-T (1GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": true,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 187,
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "fxp0 (RE1)",
"form_factor": {
"value": 1000,
"label": "1000BASE-T (1GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": true,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 188,
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "lo0",
"form_factor": {
"value": 0,
"label": "Virtual"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 207,
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "xe-0/0/0",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 208,
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "xe-0/0/1",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 209,
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "xe-0/0/2",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 210,
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "xe-0/0/3",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 211,
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "xe-0/0/4",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": {
"id": 26,
"url": "http://localhost:8000/api/dcim/interface-connections/26/",
"connection_status": true
},
"connected_interface": {
"id": 216,
"url": "http://localhost:8000/api/dcim/interfaces/216/",
"device": {
"id": 7,
"url": "http://localhost:8000/api/dcim/devices/7/",
"name": "test1-edge2",
"display_name": "test1-edge2"
},
"name": "xe-0/0/3",
"form_factor": 1200,
"mac_address": null,
"mgmt_only": false,
"description": ""
}
},
{
"id": 212,
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "xe-0/0/5",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": {
"id": 24,
"url": "http://localhost:8000/api/dcim/interface-connections/24/",
"connection_status": true
},
"connected_interface": {
"id": 7,
"url": "http://localhost:8000/api/dcim/interfaces/7/",
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "test1-edge1",
"display_name": "test1-edge1"
},
"name": "xe-0/0/3",
"form_factor": 1200,
"mac_address": null,
"mgmt_only": false,
"description": ""
}
},
{
"id": 1,
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "test1-edge1",
"display_name": "test1-edge1"
},
"name": "fxp0 (RE0)",
"form_factor": {
"value": 1000,
"label": "1000BASE-T (1GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": true,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 2,
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "test1-edge1",
"display_name": "test1-edge1"
},
"name": "fxp0 (RE1)",
"form_factor": {
"value": 800,
"label": "100BASE-TX (10/100ME)"
},
"lag": null,
"mac_address": null,
"mgmt_only": true,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 3,
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "test1-edge1",
"display_name": "test1-edge1"
},
"name": "lo0",
"form_factor": {
"value": 0,
"label": "Virtual"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 4,
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "test1-edge1",
"display_name": "test1-edge1"
},
"name": "xe-0/0/0",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "TEST",
"connection": null,
"connected_interface": null
},
{
"id": 5,
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "test1-edge1",
"display_name": "test1-edge1"
},
"name": "xe-0/0/1",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 6,
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "test1-edge1",
"display_name": "test1-edge1"
},
"name": "xe-0/0/2",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 7,
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "test1-edge1",
"display_name": "test1-edge1"
},
"name": "xe-0/0/3",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": {
"id": 24,
"url": "http://localhost:8000/api/dcim/interface-connections/24/",
"connection_status": true
},
"connected_interface": {
"id": 212,
"url": "http://localhost:8000/api/dcim/interfaces/212/",
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "xe-0/0/5",
"form_factor": 1200,
"mac_address": null,
"mgmt_only": false,
"description": ""
}
},
{
"id": 8,
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "test1-edge1",
"display_name": "test1-edge1"
},
"name": "xe-0/0/4",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": {
"id": 23,
"url": "http://localhost:8000/api/dcim/interface-connections/23/",
"connection_status": true
},
"connected_interface": {
"id": 206,
"url": "http://localhost:8000/api/dcim/interfaces/206/",
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "xe-0/0/5",
"form_factor": 1200,
"mac_address": null,
"mgmt_only": false,
"description": ""
}
},
{
"id": 9,
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "test1-edge1",
"display_name": "test1-edge1"
},
"name": "xe-0/0/5",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": {
"id": 22,
"url": "http://localhost:8000/api/dcim/interface-connections/22/",
"connection_status": true
},
"connected_interface": {
"id": 218,
"url": "http://localhost:8000/api/dcim/interfaces/218/",
"device": {
"id": 7,
"url": "http://localhost:8000/api/dcim/devices/7/",
"name": "test1-edge2",
"display_name": "test1-edge2"
},
"name": "xe-0/0/5",
"form_factor": 1200,
"mac_address": null,
"mgmt_only": false,
"description": ""
}
},
{
"id": 183,
"device": {
"id": 7,
"url": "http://localhost:8000/api/dcim/devices/7/",
"name": "test1-edge2",
"display_name": "test1-edge2"
},
"name": "fxp0 (RE0)",
"form_factor": {
"value": 1000,
"label": "1000BASE-T (1GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": true,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 184,
"device": {
"id": 7,
"url": "http://localhost:8000/api/dcim/devices/7/",
"name": "test1-edge2",
"display_name": "test1-edge2"
},
"name": "fxp0 (RE1)",
"form_factor": {
"value": 800,
"label": "100BASE-TX (10/100ME)"
},
"lag": null,
"mac_address": null,
"mgmt_only": true,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 185,
"device": {
"id": 7,
"url": "http://localhost:8000/api/dcim/devices/7/",
"name": "test1-edge2",
"display_name": "test1-edge2"
},
"name": "lo0",
"form_factor": {
"value": 0,
"label": "Virtual"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 213,
"device": {
"id": 7,
"url": "http://localhost:8000/api/dcim/devices/7/",
"name": "test1-edge2",
"display_name": "test1-edge2"
},
"name": "xe-0/0/0",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 214,
"device": {
"id": 7,
"url": "http://localhost:8000/api/dcim/devices/7/",
"name": "test1-edge2",
"display_name": "test1-edge2"
},
"name": "xe-0/0/1",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 215,
"device": {
"id": 7,
"url": "http://localhost:8000/api/dcim/devices/7/",
"name": "test1-edge2",
"display_name": "test1-edge2"
},
"name": "xe-0/0/2",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 216,
"device": {
"id": 7,
"url": "http://localhost:8000/api/dcim/devices/7/",
"name": "test1-edge2",
"display_name": "test1-edge2"
},
"name": "xe-0/0/3",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": {
"id": 26,
"url": "http://localhost:8000/api/dcim/interface-connections/26/",
"connection_status": true
},
"connected_interface": {
"id": 211,
"url": "http://localhost:8000/api/dcim/interfaces/211/",
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "xe-0/0/4",
"form_factor": 1200,
"mac_address": null,
"mgmt_only": false,
"description": ""
}
},
{
"id": 217,
"device": {
"id": 7,
"url": "http://localhost:8000/api/dcim/devices/7/",
"name": "test1-edge2",
"display_name": "test1-edge2"
},
"name": "xe-0/0/4",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": {
"id": 25,
"url": "http://localhost:8000/api/dcim/interface-connections/25/",
"connection_status": true
},
"connected_interface": {
"id": 205,
"url": "http://localhost:8000/api/dcim/interfaces/205/",
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "xe-0/0/4",
"form_factor": 1200,
"mac_address": null,
"mgmt_only": false,
"description": ""
}
},
{
"id": 218,
"device": {
"id": 7,
"url": "http://localhost:8000/api/dcim/devices/7/",
"name": "test1-edge2",
"display_name": "test1-edge2"
},
"name": "xe-0/0/5",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": {
"id": 22,
"url": "http://localhost:8000/api/dcim/interface-connections/22/",
"connection_status": true
},
"connected_interface": {
"id": 9,
"url": "http://localhost:8000/api/dcim/interfaces/9/",
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "test1-edge1",
"display_name": "test1-edge1"
},
"name": "xe-0/0/5",
"form_factor": 1200,
"mac_address": null,
"mgmt_only": false,
"description": ""
}
},
{
"id": 45,
"device": {
"id": 4,
"url": "http://localhost:8000/api/dcim/devices/4/",
"name": "test1-leaf1",
"display_name": "test1-leaf1"
},
"name": "em0",
"form_factor": {
"value": 1000,
"label": "1000BASE-T (1GE)"
},
"lag": null,
"mac_address": "FF:EE:DD:33:22:11",
"mgmt_only": true,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 46,
"device": {
"id": 4,
"url": "http://localhost:8000/api/dcim/devices/4/",
"name": "test1-leaf1",
"display_name": "test1-leaf1"
},
"name": "et-0/0/48",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": {
"id": 5,
"url": "http://localhost:8000/api/dcim/interface-connections/5/",
"connection_status": true
},
"connected_interface": {
"id": 14,
"url": "http://localhost:8000/api/dcim/interfaces/14/",
"device": {
"id": 3,
"url": "http://localhost:8000/api/dcim/devices/3/",
"name": "test1-spine1",
"display_name": "test1-spine1"
},
"name": "et-0/0/0",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
}
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/interfaces_2.json 0000644 0001751 0001751 00000033567 15136437134 022256 0 ustar 00runner runner {
"count": 221,
"next": null,
"previous": "http://localhost:8000/api/dcim/interfaces/?limit=50&offset=150",
"results": [
{
"id": 162,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/0/18",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 163,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/0/19",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 164,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/0/2",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 165,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/0/20",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 166,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/0/21",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 167,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/0/22",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 168,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/0/3",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 169,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/0/4",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 170,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/0/5",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 171,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/0/6",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 172,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/0/7",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 173,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/0/8",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 174,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/0/9",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 175,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/1/0",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": {
"id": 17,
"url": "http://localhost:8000/api/dcim/interface-connections/17/",
"connection_status": true
},
"connected_interface": {
"id": 192,
"url": "http://localhost:8000/api/dcim/interfaces/192/",
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "et-0/1/0",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
}
},
{
"id": 176,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/1/1",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 177,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/1/2",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 178,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/1/3",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 179,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/2/0",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": {
"id": 19,
"url": "http://localhost:8000/api/dcim/interface-connections/19/",
"connection_status": true
},
"connected_interface": {
"id": 198,
"url": "http://localhost:8000/api/dcim/interfaces/198/",
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "et-0/1/0",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
}
},
{
"id": 180,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/2/1",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 181,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/2/2",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
{
"id": 182,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "et-0/2/3",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/inventory_item.json 0000644 0001751 0001751 00000000036 15136437134 022746 0 ustar 00runner runner {
"detail": "Not found."
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/inventory_items.json 0000644 0001751 0001751 00000000115 15136437134 023127 0 ustar 00runner runner {
"count": 0,
"next": null,
"previous": null,
"results": []
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/manufacturer.json 0000644 0001751 0001751 00000000075 15136437134 022372 0 ustar 00runner runner {
"id": 1,
"name": "Juniper",
"slug": "juniper"
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/manufacturers.json 0000644 0001751 0001751 00000000616 15136437134 022556 0 ustar 00runner runner {
"count": 3,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"name": "Juniper",
"slug": "juniper"
},
{
"id": 2,
"name": "Opengear",
"slug": "opengear"
},
{
"id": 3,
"name": "ServerTech",
"slug": "servertech"
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/napalm.json 0000644 0001751 0001751 00000000446 15136437134 021150 0 ustar 00runner runner {
"get_facts": {
"interface_list": [
"xe-0/0/0"
],
"serial_number": "ABC!@#",
"vendor": "PacketPusher",
"os_version": "1.1",
"hostname": "test-1",
"model": "UnobtaniumX",
"fqdn": "None",
"uptime": 2
}
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/platform.json 0000644 0001751 0001751 00000000154 15136437134 021520 0 ustar 00runner runner {
"id": 1,
"name": "Juniper Junos",
"slug": "juniper-junos",
"rpc_client": "juniper-junos"
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/platforms.json 0000644 0001751 0001751 00000000576 15136437134 021713 0 ustar 00runner runner {
"count": 2,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"name": "Juniper Junos",
"slug": "juniper-junos",
"rpc_client": "juniper-junos"
},
{
"id": 2,
"name": "Opengear",
"slug": "opengear",
"rpc_client": "opengear"
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/power_outlet.json 0000644 0001751 0001751 00000000344 15136437134 022425 0 ustar 00runner runner {
"id": 1,
"device": {
"id": 11,
"url": "http://localhost:8000/api/dcim/devices/11/",
"name": "test1-pdu1",
"display_name": "test1-pdu1"
},
"name": "AA1",
"connected_port": 1
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/power_outlet_template.json 0000644 0001751 0001751 00000000627 15136437134 024324 0 ustar 00runner runner {
"id": 1,
"device_type": {
"id": 6,
"url": "http://localhost:8000/api/dcim/device-types/6/",
"manufacturer": {
"id": 3,
"url": "http://localhost:8000/api/dcim/manufacturers/3/",
"name": "ServerTech",
"slug": "servertech"
},
"model": "CWG-24VYM415C9",
"slug": "cwg-24vym415c9"
},
"name": "AA1"
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/power_outlet_templates.json 0000644 0001751 0001751 00000031274 15136437134 024511 0 ustar 00runner runner {
"count": 24,
"next": null,
"previous": null,
"results": [
{
"id": 4,
"device_type": {
"id": 6,
"url": "http://localhost:8000/api/dcim/device-types/6/",
"manufacturer": {
"id": 3,
"url": "http://localhost:8000/api/dcim/manufacturers/3/",
"name": "ServerTech",
"slug": "servertech"
},
"model": "CWG-24VYM415C9",
"slug": "cwg-24vym415c9"
},
"name": "AA1"
},
{
"id": 5,
"device_type": {
"id": 6,
"url": "http://localhost:8000/api/dcim/device-types/6/",
"manufacturer": {
"id": 3,
"url": "http://localhost:8000/api/dcim/manufacturers/3/",
"name": "ServerTech",
"slug": "servertech"
},
"model": "CWG-24VYM415C9",
"slug": "cwg-24vym415c9"
},
"name": "AA2"
},
{
"id": 6,
"device_type": {
"id": 6,
"url": "http://localhost:8000/api/dcim/device-types/6/",
"manufacturer": {
"id": 3,
"url": "http://localhost:8000/api/dcim/manufacturers/3/",
"name": "ServerTech",
"slug": "servertech"
},
"model": "CWG-24VYM415C9",
"slug": "cwg-24vym415c9"
},
"name": "AA3"
},
{
"id": 7,
"device_type": {
"id": 6,
"url": "http://localhost:8000/api/dcim/device-types/6/",
"manufacturer": {
"id": 3,
"url": "http://localhost:8000/api/dcim/manufacturers/3/",
"name": "ServerTech",
"slug": "servertech"
},
"model": "CWG-24VYM415C9",
"slug": "cwg-24vym415c9"
},
"name": "AA4"
},
{
"id": 8,
"device_type": {
"id": 6,
"url": "http://localhost:8000/api/dcim/device-types/6/",
"manufacturer": {
"id": 3,
"url": "http://localhost:8000/api/dcim/manufacturers/3/",
"name": "ServerTech",
"slug": "servertech"
},
"model": "CWG-24VYM415C9",
"slug": "cwg-24vym415c9"
},
"name": "AA5"
},
{
"id": 9,
"device_type": {
"id": 6,
"url": "http://localhost:8000/api/dcim/device-types/6/",
"manufacturer": {
"id": 3,
"url": "http://localhost:8000/api/dcim/manufacturers/3/",
"name": "ServerTech",
"slug": "servertech"
},
"model": "CWG-24VYM415C9",
"slug": "cwg-24vym415c9"
},
"name": "AA6"
},
{
"id": 10,
"device_type": {
"id": 6,
"url": "http://localhost:8000/api/dcim/device-types/6/",
"manufacturer": {
"id": 3,
"url": "http://localhost:8000/api/dcim/manufacturers/3/",
"name": "ServerTech",
"slug": "servertech"
},
"model": "CWG-24VYM415C9",
"slug": "cwg-24vym415c9"
},
"name": "AA7"
},
{
"id": 11,
"device_type": {
"id": 6,
"url": "http://localhost:8000/api/dcim/device-types/6/",
"manufacturer": {
"id": 3,
"url": "http://localhost:8000/api/dcim/manufacturers/3/",
"name": "ServerTech",
"slug": "servertech"
},
"model": "CWG-24VYM415C9",
"slug": "cwg-24vym415c9"
},
"name": "AA8"
},
{
"id": 12,
"device_type": {
"id": 6,
"url": "http://localhost:8000/api/dcim/device-types/6/",
"manufacturer": {
"id": 3,
"url": "http://localhost:8000/api/dcim/manufacturers/3/",
"name": "ServerTech",
"slug": "servertech"
},
"model": "CWG-24VYM415C9",
"slug": "cwg-24vym415c9"
},
"name": "AB1"
},
{
"id": 13,
"device_type": {
"id": 6,
"url": "http://localhost:8000/api/dcim/device-types/6/",
"manufacturer": {
"id": 3,
"url": "http://localhost:8000/api/dcim/manufacturers/3/",
"name": "ServerTech",
"slug": "servertech"
},
"model": "CWG-24VYM415C9",
"slug": "cwg-24vym415c9"
},
"name": "AB2"
},
{
"id": 14,
"device_type": {
"id": 6,
"url": "http://localhost:8000/api/dcim/device-types/6/",
"manufacturer": {
"id": 3,
"url": "http://localhost:8000/api/dcim/manufacturers/3/",
"name": "ServerTech",
"slug": "servertech"
},
"model": "CWG-24VYM415C9",
"slug": "cwg-24vym415c9"
},
"name": "AB3"
},
{
"id": 15,
"device_type": {
"id": 6,
"url": "http://localhost:8000/api/dcim/device-types/6/",
"manufacturer": {
"id": 3,
"url": "http://localhost:8000/api/dcim/manufacturers/3/",
"name": "ServerTech",
"slug": "servertech"
},
"model": "CWG-24VYM415C9",
"slug": "cwg-24vym415c9"
},
"name": "AB4"
},
{
"id": 16,
"device_type": {
"id": 6,
"url": "http://localhost:8000/api/dcim/device-types/6/",
"manufacturer": {
"id": 3,
"url": "http://localhost:8000/api/dcim/manufacturers/3/",
"name": "ServerTech",
"slug": "servertech"
},
"model": "CWG-24VYM415C9",
"slug": "cwg-24vym415c9"
},
"name": "AB5"
},
{
"id": 17,
"device_type": {
"id": 6,
"url": "http://localhost:8000/api/dcim/device-types/6/",
"manufacturer": {
"id": 3,
"url": "http://localhost:8000/api/dcim/manufacturers/3/",
"name": "ServerTech",
"slug": "servertech"
},
"model": "CWG-24VYM415C9",
"slug": "cwg-24vym415c9"
},
"name": "AB6"
},
{
"id": 18,
"device_type": {
"id": 6,
"url": "http://localhost:8000/api/dcim/device-types/6/",
"manufacturer": {
"id": 3,
"url": "http://localhost:8000/api/dcim/manufacturers/3/",
"name": "ServerTech",
"slug": "servertech"
},
"model": "CWG-24VYM415C9",
"slug": "cwg-24vym415c9"
},
"name": "AB7"
},
{
"id": 19,
"device_type": {
"id": 6,
"url": "http://localhost:8000/api/dcim/device-types/6/",
"manufacturer": {
"id": 3,
"url": "http://localhost:8000/api/dcim/manufacturers/3/",
"name": "ServerTech",
"slug": "servertech"
},
"model": "CWG-24VYM415C9",
"slug": "cwg-24vym415c9"
},
"name": "AB8"
},
{
"id": 20,
"device_type": {
"id": 6,
"url": "http://localhost:8000/api/dcim/device-types/6/",
"manufacturer": {
"id": 3,
"url": "http://localhost:8000/api/dcim/manufacturers/3/",
"name": "ServerTech",
"slug": "servertech"
},
"model": "CWG-24VYM415C9",
"slug": "cwg-24vym415c9"
},
"name": "AC1"
},
{
"id": 21,
"device_type": {
"id": 6,
"url": "http://localhost:8000/api/dcim/device-types/6/",
"manufacturer": {
"id": 3,
"url": "http://localhost:8000/api/dcim/manufacturers/3/",
"name": "ServerTech",
"slug": "servertech"
},
"model": "CWG-24VYM415C9",
"slug": "cwg-24vym415c9"
},
"name": "AC2"
},
{
"id": 22,
"device_type": {
"id": 6,
"url": "http://localhost:8000/api/dcim/device-types/6/",
"manufacturer": {
"id": 3,
"url": "http://localhost:8000/api/dcim/manufacturers/3/",
"name": "ServerTech",
"slug": "servertech"
},
"model": "CWG-24VYM415C9",
"slug": "cwg-24vym415c9"
},
"name": "AC3"
},
{
"id": 23,
"device_type": {
"id": 6,
"url": "http://localhost:8000/api/dcim/device-types/6/",
"manufacturer": {
"id": 3,
"url": "http://localhost:8000/api/dcim/manufacturers/3/",
"name": "ServerTech",
"slug": "servertech"
},
"model": "CWG-24VYM415C9",
"slug": "cwg-24vym415c9"
},
"name": "AC4"
},
{
"id": 24,
"device_type": {
"id": 6,
"url": "http://localhost:8000/api/dcim/device-types/6/",
"manufacturer": {
"id": 3,
"url": "http://localhost:8000/api/dcim/manufacturers/3/",
"name": "ServerTech",
"slug": "servertech"
},
"model": "CWG-24VYM415C9",
"slug": "cwg-24vym415c9"
},
"name": "AC5"
},
{
"id": 25,
"device_type": {
"id": 6,
"url": "http://localhost:8000/api/dcim/device-types/6/",
"manufacturer": {
"id": 3,
"url": "http://localhost:8000/api/dcim/manufacturers/3/",
"name": "ServerTech",
"slug": "servertech"
},
"model": "CWG-24VYM415C9",
"slug": "cwg-24vym415c9"
},
"name": "AC6"
},
{
"id": 26,
"device_type": {
"id": 6,
"url": "http://localhost:8000/api/dcim/device-types/6/",
"manufacturer": {
"id": 3,
"url": "http://localhost:8000/api/dcim/manufacturers/3/",
"name": "ServerTech",
"slug": "servertech"
},
"model": "CWG-24VYM415C9",
"slug": "cwg-24vym415c9"
},
"name": "AC7"
},
{
"id": 27,
"device_type": {
"id": 6,
"url": "http://localhost:8000/api/dcim/device-types/6/",
"manufacturer": {
"id": 3,
"url": "http://localhost:8000/api/dcim/manufacturers/3/",
"name": "ServerTech",
"slug": "servertech"
},
"model": "CWG-24VYM415C9",
"slug": "cwg-24vym415c9"
},
"name": "AC8"
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/power_outlets.json 0000644 0001751 0001751 00000036215 15136437134 022616 0 ustar 00runner runner {
"count": 48,
"next": null,
"previous": null,
"results": [
{
"id": 25,
"device": {
"id": 11,
"url": "http://localhost:8000/api/dcim/devices/11/",
"name": "test1-pdu1",
"display_name": "test1-pdu1"
},
"name": "AA1",
"connected_port": 1
},
{
"id": 26,
"device": {
"id": 11,
"url": "http://localhost:8000/api/dcim/devices/11/",
"name": "test1-pdu1",
"display_name": "test1-pdu1"
},
"name": "AA2",
"connected_port": 5
},
{
"id": 27,
"device": {
"id": 11,
"url": "http://localhost:8000/api/dcim/devices/11/",
"name": "test1-pdu1",
"display_name": "test1-pdu1"
},
"name": "AA3",
"connected_port": 13
},
{
"id": 28,
"device": {
"id": 11,
"url": "http://localhost:8000/api/dcim/devices/11/",
"name": "test1-pdu1",
"display_name": "test1-pdu1"
},
"name": "AA4",
"connected_port": 9
},
{
"id": 29,
"device": {
"id": 11,
"url": "http://localhost:8000/api/dcim/devices/11/",
"name": "test1-pdu1",
"display_name": "test1-pdu1"
},
"name": "AA5",
"connected_port": 16
},
{
"id": 30,
"device": {
"id": 11,
"url": "http://localhost:8000/api/dcim/devices/11/",
"name": "test1-pdu1",
"display_name": "test1-pdu1"
},
"name": "AA6",
"connected_port": 20
},
{
"id": 31,
"device": {
"id": 11,
"url": "http://localhost:8000/api/dcim/devices/11/",
"name": "test1-pdu1",
"display_name": "test1-pdu1"
},
"name": "AA7",
"connected_port": 24
},
{
"id": 32,
"device": {
"id": 11,
"url": "http://localhost:8000/api/dcim/devices/11/",
"name": "test1-pdu1",
"display_name": "test1-pdu1"
},
"name": "AA8",
"connected_port": 12
},
{
"id": 33,
"device": {
"id": 11,
"url": "http://localhost:8000/api/dcim/devices/11/",
"name": "test1-pdu1",
"display_name": "test1-pdu1"
},
"name": "AB1",
"connected_port": null
},
{
"id": 34,
"device": {
"id": 11,
"url": "http://localhost:8000/api/dcim/devices/11/",
"name": "test1-pdu1",
"display_name": "test1-pdu1"
},
"name": "AB2",
"connected_port": null
},
{
"id": 35,
"device": {
"id": 11,
"url": "http://localhost:8000/api/dcim/devices/11/",
"name": "test1-pdu1",
"display_name": "test1-pdu1"
},
"name": "AB3",
"connected_port": null
},
{
"id": 36,
"device": {
"id": 11,
"url": "http://localhost:8000/api/dcim/devices/11/",
"name": "test1-pdu1",
"display_name": "test1-pdu1"
},
"name": "AB4",
"connected_port": null
},
{
"id": 37,
"device": {
"id": 11,
"url": "http://localhost:8000/api/dcim/devices/11/",
"name": "test1-pdu1",
"display_name": "test1-pdu1"
},
"name": "AB5",
"connected_port": null
},
{
"id": 38,
"device": {
"id": 11,
"url": "http://localhost:8000/api/dcim/devices/11/",
"name": "test1-pdu1",
"display_name": "test1-pdu1"
},
"name": "AB6",
"connected_port": null
},
{
"id": 39,
"device": {
"id": 11,
"url": "http://localhost:8000/api/dcim/devices/11/",
"name": "test1-pdu1",
"display_name": "test1-pdu1"
},
"name": "AB7",
"connected_port": null
},
{
"id": 40,
"device": {
"id": 11,
"url": "http://localhost:8000/api/dcim/devices/11/",
"name": "test1-pdu1",
"display_name": "test1-pdu1"
},
"name": "AB8",
"connected_port": null
},
{
"id": 41,
"device": {
"id": 11,
"url": "http://localhost:8000/api/dcim/devices/11/",
"name": "test1-pdu1",
"display_name": "test1-pdu1"
},
"name": "AC1",
"connected_port": null
},
{
"id": 42,
"device": {
"id": 11,
"url": "http://localhost:8000/api/dcim/devices/11/",
"name": "test1-pdu1",
"display_name": "test1-pdu1"
},
"name": "AC2",
"connected_port": null
},
{
"id": 43,
"device": {
"id": 11,
"url": "http://localhost:8000/api/dcim/devices/11/",
"name": "test1-pdu1",
"display_name": "test1-pdu1"
},
"name": "AC3",
"connected_port": null
},
{
"id": 44,
"device": {
"id": 11,
"url": "http://localhost:8000/api/dcim/devices/11/",
"name": "test1-pdu1",
"display_name": "test1-pdu1"
},
"name": "AC4",
"connected_port": null
},
{
"id": 45,
"device": {
"id": 11,
"url": "http://localhost:8000/api/dcim/devices/11/",
"name": "test1-pdu1",
"display_name": "test1-pdu1"
},
"name": "AC5",
"connected_port": null
},
{
"id": 46,
"device": {
"id": 11,
"url": "http://localhost:8000/api/dcim/devices/11/",
"name": "test1-pdu1",
"display_name": "test1-pdu1"
},
"name": "AC6",
"connected_port": null
},
{
"id": 47,
"device": {
"id": 11,
"url": "http://localhost:8000/api/dcim/devices/11/",
"name": "test1-pdu1",
"display_name": "test1-pdu1"
},
"name": "AC7",
"connected_port": null
},
{
"id": 48,
"device": {
"id": 11,
"url": "http://localhost:8000/api/dcim/devices/11/",
"name": "test1-pdu1",
"display_name": "test1-pdu1"
},
"name": "AC8",
"connected_port": null
},
{
"id": 49,
"device": {
"id": 12,
"url": "http://localhost:8000/api/dcim/devices/12/",
"name": "test1-pdu2",
"display_name": "test1-pdu2"
},
"name": "AA1",
"connected_port": 2
},
{
"id": 50,
"device": {
"id": 12,
"url": "http://localhost:8000/api/dcim/devices/12/",
"name": "test1-pdu2",
"display_name": "test1-pdu2"
},
"name": "AA2",
"connected_port": 6
},
{
"id": 51,
"device": {
"id": 12,
"url": "http://localhost:8000/api/dcim/devices/12/",
"name": "test1-pdu2",
"display_name": "test1-pdu2"
},
"name": "AA3",
"connected_port": 14
},
{
"id": 52,
"device": {
"id": 12,
"url": "http://localhost:8000/api/dcim/devices/12/",
"name": "test1-pdu2",
"display_name": "test1-pdu2"
},
"name": "AA4",
"connected_port": 10
},
{
"id": 53,
"device": {
"id": 12,
"url": "http://localhost:8000/api/dcim/devices/12/",
"name": "test1-pdu2",
"display_name": "test1-pdu2"
},
"name": "AA5",
"connected_port": 15
},
{
"id": 54,
"device": {
"id": 12,
"url": "http://localhost:8000/api/dcim/devices/12/",
"name": "test1-pdu2",
"display_name": "test1-pdu2"
},
"name": "AA6",
"connected_port": 19
},
{
"id": 55,
"device": {
"id": 12,
"url": "http://localhost:8000/api/dcim/devices/12/",
"name": "test1-pdu2",
"display_name": "test1-pdu2"
},
"name": "AA7",
"connected_port": 23
},
{
"id": 56,
"device": {
"id": 12,
"url": "http://localhost:8000/api/dcim/devices/12/",
"name": "test1-pdu2",
"display_name": "test1-pdu2"
},
"name": "AA8",
"connected_port": 11
},
{
"id": 57,
"device": {
"id": 12,
"url": "http://localhost:8000/api/dcim/devices/12/",
"name": "test1-pdu2",
"display_name": "test1-pdu2"
},
"name": "AB1",
"connected_port": null
},
{
"id": 58,
"device": {
"id": 12,
"url": "http://localhost:8000/api/dcim/devices/12/",
"name": "test1-pdu2",
"display_name": "test1-pdu2"
},
"name": "AB2",
"connected_port": null
},
{
"id": 59,
"device": {
"id": 12,
"url": "http://localhost:8000/api/dcim/devices/12/",
"name": "test1-pdu2",
"display_name": "test1-pdu2"
},
"name": "AB3",
"connected_port": null
},
{
"id": 60,
"device": {
"id": 12,
"url": "http://localhost:8000/api/dcim/devices/12/",
"name": "test1-pdu2",
"display_name": "test1-pdu2"
},
"name": "AB4",
"connected_port": null
},
{
"id": 61,
"device": {
"id": 12,
"url": "http://localhost:8000/api/dcim/devices/12/",
"name": "test1-pdu2",
"display_name": "test1-pdu2"
},
"name": "AB5",
"connected_port": null
},
{
"id": 62,
"device": {
"id": 12,
"url": "http://localhost:8000/api/dcim/devices/12/",
"name": "test1-pdu2",
"display_name": "test1-pdu2"
},
"name": "AB6",
"connected_port": null
},
{
"id": 63,
"device": {
"id": 12,
"url": "http://localhost:8000/api/dcim/devices/12/",
"name": "test1-pdu2",
"display_name": "test1-pdu2"
},
"name": "AB7",
"connected_port": null
},
{
"id": 64,
"device": {
"id": 12,
"url": "http://localhost:8000/api/dcim/devices/12/",
"name": "test1-pdu2",
"display_name": "test1-pdu2"
},
"name": "AB8",
"connected_port": null
},
{
"id": 65,
"device": {
"id": 12,
"url": "http://localhost:8000/api/dcim/devices/12/",
"name": "test1-pdu2",
"display_name": "test1-pdu2"
},
"name": "AC1",
"connected_port": null
},
{
"id": 66,
"device": {
"id": 12,
"url": "http://localhost:8000/api/dcim/devices/12/",
"name": "test1-pdu2",
"display_name": "test1-pdu2"
},
"name": "AC2",
"connected_port": null
},
{
"id": 67,
"device": {
"id": 12,
"url": "http://localhost:8000/api/dcim/devices/12/",
"name": "test1-pdu2",
"display_name": "test1-pdu2"
},
"name": "AC3",
"connected_port": null
},
{
"id": 68,
"device": {
"id": 12,
"url": "http://localhost:8000/api/dcim/devices/12/",
"name": "test1-pdu2",
"display_name": "test1-pdu2"
},
"name": "AC4",
"connected_port": null
},
{
"id": 69,
"device": {
"id": 12,
"url": "http://localhost:8000/api/dcim/devices/12/",
"name": "test1-pdu2",
"display_name": "test1-pdu2"
},
"name": "AC5",
"connected_port": null
},
{
"id": 70,
"device": {
"id": 12,
"url": "http://localhost:8000/api/dcim/devices/12/",
"name": "test1-pdu2",
"display_name": "test1-pdu2"
},
"name": "AC6",
"connected_port": null
},
{
"id": 71,
"device": {
"id": 12,
"url": "http://localhost:8000/api/dcim/devices/12/",
"name": "test1-pdu2",
"display_name": "test1-pdu2"
},
"name": "AC7",
"connected_port": null
},
{
"id": 72,
"device": {
"id": 12,
"url": "http://localhost:8000/api/dcim/devices/12/",
"name": "test1-pdu2",
"display_name": "test1-pdu2"
},
"name": "AC8",
"connected_port": null
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/power_port.json 0000644 0001751 0001751 00000001016 15136437134 022072 0 ustar 00runner runner {
"id": 1,
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "test1-edge1",
"display_name": "test1-edge1"
},
"name": "PEM0",
"power_outlet": {
"id": 25,
"device": {
"id": 11,
"url": "http://localhost:8000/api/dcim/devices/11/",
"name": "test1-pdu1",
"display_name": "test1-pdu1"
},
"name": "AA1",
"connected_port": 1
},
"connection_status": true
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/power_port_template.json 0000644 0001751 0001751 00000000600 15136437134 023763 0 ustar 00runner runner {
"id": 1,
"device_type": {
"id": 1,
"url": "http://localhost:8000/api/dcim/device-types/1/",
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "MX960",
"slug": "mx960"
},
"name": "PEM0"
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/power_port_templates.json 0000644 0001751 0001751 00000015253 15136437134 024160 0 ustar 00runner runner {
"count": 13,
"next": null,
"previous": null,
"results": [
{
"id": 5,
"device_type": {
"id": 2,
"url": "http://localhost:8000/api/dcim/device-types/2/",
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "EX9214",
"slug": "ex9214"
},
"name": "PEM0"
},
{
"id": 6,
"device_type": {
"id": 2,
"url": "http://localhost:8000/api/dcim/device-types/2/",
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "EX9214",
"slug": "ex9214"
},
"name": "PEM1"
},
{
"id": 7,
"device_type": {
"id": 2,
"url": "http://localhost:8000/api/dcim/device-types/2/",
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "EX9214",
"slug": "ex9214"
},
"name": "PEM2"
},
{
"id": 8,
"device_type": {
"id": 2,
"url": "http://localhost:8000/api/dcim/device-types/2/",
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "EX9214",
"slug": "ex9214"
},
"name": "PEM3"
},
{
"id": 1,
"device_type": {
"id": 1,
"url": "http://localhost:8000/api/dcim/device-types/1/",
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "MX960",
"slug": "mx960"
},
"name": "PEM0"
},
{
"id": 2,
"device_type": {
"id": 1,
"url": "http://localhost:8000/api/dcim/device-types/1/",
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "MX960",
"slug": "mx960"
},
"name": "PEM1"
},
{
"id": 3,
"device_type": {
"id": 1,
"url": "http://localhost:8000/api/dcim/device-types/1/",
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "MX960",
"slug": "mx960"
},
"name": "PEM2"
},
{
"id": 4,
"device_type": {
"id": 1,
"url": "http://localhost:8000/api/dcim/device-types/1/",
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "MX960",
"slug": "mx960"
},
"name": "PEM3"
},
{
"id": 11,
"device_type": {
"id": 3,
"url": "http://localhost:8000/api/dcim/device-types/3/",
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "QFX5100-24Q",
"slug": "qfx5100-24q"
},
"name": "PSU0"
},
{
"id": 12,
"device_type": {
"id": 3,
"url": "http://localhost:8000/api/dcim/device-types/3/",
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "QFX5100-24Q",
"slug": "qfx5100-24q"
},
"name": "PSU1"
},
{
"id": 9,
"device_type": {
"id": 4,
"url": "http://localhost:8000/api/dcim/device-types/4/",
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "QFX5100-48S",
"slug": "qfx5100-48s"
},
"name": "PSU0"
},
{
"id": 13,
"device_type": {
"id": 4,
"url": "http://localhost:8000/api/dcim/device-types/4/",
"manufacturer": {
"id": 1,
"url": "http://localhost:8000/api/dcim/manufacturers/1/",
"name": "Juniper",
"slug": "juniper"
},
"model": "QFX5100-48S",
"slug": "qfx5100-48s"
},
"name": "PSU1"
},
{
"id": 14,
"device_type": {
"id": 5,
"url": "http://localhost:8000/api/dcim/device-types/5/",
"manufacturer": {
"id": 2,
"url": "http://localhost:8000/api/dcim/manufacturers/2/",
"name": "Opengear",
"slug": "opengear"
},
"model": "CM4148",
"slug": "cm4148"
},
"name": "PSU"
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/power_ports.json 0000644 0001751 0001751 00000034421 15136437134 022263 0 ustar 00runner runner {
"count": 25,
"next": null,
"previous": null,
"results": [
{
"id": 5,
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "PEM0",
"power_outlet": {
"id": 26,
"device": {
"id": 11,
"url": "http://localhost:8000/api/dcim/devices/11/",
"name": "test1-pdu1",
"display_name": "test1-pdu1"
},
"name": "AA2",
"connected_port": 5
},
"connection_status": true
},
{
"id": 6,
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "PEM1",
"power_outlet": {
"id": 50,
"device": {
"id": 12,
"url": "http://localhost:8000/api/dcim/devices/12/",
"name": "test1-pdu2",
"display_name": "test1-pdu2"
},
"name": "AA2",
"connected_port": 6
},
"connection_status": true
},
{
"id": 7,
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "PEM2",
"power_outlet": null,
"connection_status": true
},
{
"id": 8,
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "PEM3",
"power_outlet": null,
"connection_status": true
},
{
"id": 19,
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "PEM0",
"power_outlet": {
"id": 54,
"device": {
"id": 12,
"url": "http://localhost:8000/api/dcim/devices/12/",
"name": "test1-pdu2",
"display_name": "test1-pdu2"
},
"name": "AA6",
"connected_port": 19
},
"connection_status": true
},
{
"id": 20,
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "PEM1",
"power_outlet": {
"id": 30,
"device": {
"id": 11,
"url": "http://localhost:8000/api/dcim/devices/11/",
"name": "test1-pdu1",
"display_name": "test1-pdu1"
},
"name": "AA6",
"connected_port": 20
},
"connection_status": true
},
{
"id": 21,
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "PEM2",
"power_outlet": null,
"connection_status": true
},
{
"id": 22,
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "PEM3",
"power_outlet": null,
"connection_status": true
},
{
"id": 1,
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "test1-edge1",
"display_name": "test1-edge1"
},
"name": "PEM0",
"power_outlet": {
"id": 25,
"device": {
"id": 11,
"url": "http://localhost:8000/api/dcim/devices/11/",
"name": "test1-pdu1",
"display_name": "test1-pdu1"
},
"name": "AA1",
"connected_port": 1
},
"connection_status": true
},
{
"id": 2,
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "test1-edge1",
"display_name": "test1-edge1"
},
"name": "PEM1",
"power_outlet": {
"id": 49,
"device": {
"id": 12,
"url": "http://localhost:8000/api/dcim/devices/12/",
"name": "test1-pdu2",
"display_name": "test1-pdu2"
},
"name": "AA1",
"connected_port": 2
},
"connection_status": true
},
{
"id": 3,
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "test1-edge1",
"display_name": "test1-edge1"
},
"name": "PEM2",
"power_outlet": null,
"connection_status": true
},
{
"id": 4,
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "test1-edge1",
"display_name": "test1-edge1"
},
"name": "PEM3",
"power_outlet": null,
"connection_status": true
},
{
"id": 15,
"device": {
"id": 7,
"url": "http://localhost:8000/api/dcim/devices/7/",
"name": "test1-edge2",
"display_name": "test1-edge2"
},
"name": "PEM0",
"power_outlet": {
"id": 53,
"device": {
"id": 12,
"url": "http://localhost:8000/api/dcim/devices/12/",
"name": "test1-pdu2",
"display_name": "test1-pdu2"
},
"name": "AA5",
"connected_port": 15
},
"connection_status": true
},
{
"id": 16,
"device": {
"id": 7,
"url": "http://localhost:8000/api/dcim/devices/7/",
"name": "test1-edge2",
"display_name": "test1-edge2"
},
"name": "PEM1",
"power_outlet": {
"id": 29,
"device": {
"id": 11,
"url": "http://localhost:8000/api/dcim/devices/11/",
"name": "test1-pdu1",
"display_name": "test1-pdu1"
},
"name": "AA5",
"connected_port": 16
},
"connection_status": true
},
{
"id": 17,
"device": {
"id": 7,
"url": "http://localhost:8000/api/dcim/devices/7/",
"name": "test1-edge2",
"display_name": "test1-edge2"
},
"name": "PEM2",
"power_outlet": null,
"connection_status": true
},
{
"id": 18,
"device": {
"id": 7,
"url": "http://localhost:8000/api/dcim/devices/7/",
"name": "test1-edge2",
"display_name": "test1-edge2"
},
"name": "PEM3",
"power_outlet": null,
"connection_status": true
},
{
"id": 9,
"device": {
"id": 4,
"url": "http://localhost:8000/api/dcim/devices/4/",
"name": "test1-leaf1",
"display_name": "test1-leaf1"
},
"name": "PSU0",
"power_outlet": {
"id": 28,
"device": {
"id": 11,
"url": "http://localhost:8000/api/dcim/devices/11/",
"name": "test1-pdu1",
"display_name": "test1-pdu1"
},
"name": "AA4",
"connected_port": 9
},
"connection_status": true
},
{
"id": 10,
"device": {
"id": 4,
"url": "http://localhost:8000/api/dcim/devices/4/",
"name": "test1-leaf1",
"display_name": "test1-leaf1"
},
"name": "PSU1",
"power_outlet": {
"id": 52,
"device": {
"id": 12,
"url": "http://localhost:8000/api/dcim/devices/12/",
"name": "test1-pdu2",
"display_name": "test1-pdu2"
},
"name": "AA4",
"connected_port": 10
},
"connection_status": true
},
{
"id": 11,
"device": {
"id": 5,
"url": "http://localhost:8000/api/dcim/devices/5/",
"name": "test1-leaf2",
"display_name": "test1-leaf2"
},
"name": "PSU0",
"power_outlet": {
"id": 56,
"device": {
"id": 12,
"url": "http://localhost:8000/api/dcim/devices/12/",
"name": "test1-pdu2",
"display_name": "test1-pdu2"
},
"name": "AA8",
"connected_port": 11
},
"connection_status": true
},
{
"id": 12,
"device": {
"id": 5,
"url": "http://localhost:8000/api/dcim/devices/5/",
"name": "test1-leaf2",
"display_name": "test1-leaf2"
},
"name": "PSU1",
"power_outlet": {
"id": 32,
"device": {
"id": 11,
"url": "http://localhost:8000/api/dcim/devices/11/",
"name": "test1-pdu1",
"display_name": "test1-pdu1"
},
"name": "AA8",
"connected_port": 12
},
"connection_status": true
},
{
"id": 25,
"device": {
"id": 9,
"url": "http://localhost:8000/api/dcim/devices/9/",
"name": "test1-oob1",
"display_name": "test1-oob1"
},
"name": "PSU",
"power_outlet": null,
"connection_status": true
},
{
"id": 13,
"device": {
"id": 3,
"url": "http://localhost:8000/api/dcim/devices/3/",
"name": "test1-spine1",
"display_name": "test1-spine1"
},
"name": "PSU0",
"power_outlet": {
"id": 27,
"device": {
"id": 11,
"url": "http://localhost:8000/api/dcim/devices/11/",
"name": "test1-pdu1",
"display_name": "test1-pdu1"
},
"name": "AA3",
"connected_port": 13
},
"connection_status": true
},
{
"id": 14,
"device": {
"id": 3,
"url": "http://localhost:8000/api/dcim/devices/3/",
"name": "test1-spine1",
"display_name": "test1-spine1"
},
"name": "PSU1",
"power_outlet": {
"id": 51,
"device": {
"id": 12,
"url": "http://localhost:8000/api/dcim/devices/12/",
"name": "test1-pdu2",
"display_name": "test1-pdu2"
},
"name": "AA3",
"connected_port": 14
},
"connection_status": true
},
{
"id": 23,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "PSU0",
"power_outlet": {
"id": 55,
"device": {
"id": 12,
"url": "http://localhost:8000/api/dcim/devices/12/",
"name": "test1-pdu2",
"display_name": "test1-pdu2"
},
"name": "AA7",
"connected_port": 23
},
"connection_status": true
},
{
"id": 24,
"device": {
"id": 6,
"url": "http://localhost:8000/api/dcim/devices/6/",
"name": "test1-spine2",
"display_name": "test1-spine2"
},
"name": "PSU1",
"power_outlet": {
"id": 31,
"device": {
"id": 11,
"url": "http://localhost:8000/api/dcim/devices/11/",
"name": "test1-pdu1",
"display_name": "test1-pdu1"
},
"name": "AA7",
"connected_port": 24
},
"connection_status": true
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/rack.json 0000644 0001751 0001751 00000001153 15136437134 020614 0 ustar 00runner runner {
"id": 1,
"name": "A1R1",
"facility_id": "T23A01",
"display_name": "A1R1 (T23A01)",
"site": {
"id": 1,
"url": "http://localhost:8000/api/dcim/sites/1/",
"name": "TEST1",
"slug": "test1"
},
"group": null,
"tenant": null,
"role": {
"id": 1,
"url": "http://localhost:8000/api/dcim/rack-roles/1/",
"name": "Compute",
"slug": "compute"
},
"type": null,
"width": {
"value": 19,
"label": "19 inches"
},
"u_height": 42,
"desc_units": false,
"comments": "",
"custom_fields": {}
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/rack_group.json 0000644 0001751 0001751 00000000310 15136437134 022022 0 ustar 00runner runner {
"id": 1,
"name": "TEST",
"slug": "test",
"site": {
"id": 1,
"url": "http://localhost:8000/api/dcim/sites/1/",
"name": "TEST1",
"slug": "test1"
}
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/rack_groups.json 0000644 0001751 0001751 00000000563 15136437134 022217 0 ustar 00runner runner {
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"name": "TEST",
"slug": "test",
"site": {
"id": 1,
"url": "http://localhost:8000/api/dcim/sites/1/",
"name": "TEST1",
"slug": "test1"
}
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/rack_reservation.json 0000644 0001751 0001751 00000000464 15136437134 023241 0 ustar 00runner runner {
"id": 1,
"rack": {
"id": 2,
"url": "http://localhost:8000/api/dcim/racks/2/",
"name": "A1R2",
"display_name": "A1R2 (T24A01)"
},
"units": [
42
],
"created": "2017-03-22T04:10:47.307156Z",
"user": 1,
"description": "Test Reservation"
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/rack_reservations.json 0000644 0001751 0001751 00000000777 15136437134 023433 0 ustar 00runner runner {
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"rack": {
"id": 2,
"url": "http://localhost:8000/api/dcim/racks/2/",
"name": "A1R2",
"display_name": "A1R2 (T24A01)"
},
"units": [
42
],
"created": "2017-03-22T04:10:47.307156Z",
"user": 1,
"description": "Test Reservation"
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/rack_role.json 0000644 0001751 0001751 00000000116 15136437134 021633 0 ustar 00runner runner {
"id": 1,
"name": "Test",
"slug": "test",
"color": "aa1409"
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/rack_roles.json 0000644 0001751 0001751 00000000321 15136437134 022014 0 ustar 00runner runner {
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"name": "Test",
"slug": "test",
"color": "aa1409"
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/rack_u.json 0000644 0001751 0001751 00000001465 15136437134 021146 0 ustar 00runner runner {
"count": 3,
"next": null,
"previous": null,
"results": [
{
"id": 48,
"name": "U1",
"face": 0,
"device": {
"id": 130,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "tst-device1",
"display_name": "tst-device1"
}
},
{
"id": 47,
"name": "U2",
"face": 0,
"device": null
},
{
"id": 46,
"name": "U3",
"face": 0,
"device": {
"id": 1859,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "tst-device2",
"display_name": "tst-device2"
}
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/racks.json 0000644 0001751 0001751 00000002633 15136437134 021003 0 ustar 00runner runner {
"count": 2,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"name": "A1R1",
"facility_id": "T23A01",
"display_name": "A1R1 (T23A01)",
"site": {
"id": 1,
"url": "http://localhost:8000/api/dcim/sites/1/",
"name": "TEST1",
"slug": "test1"
},
"group": null,
"tenant": null,
"role": null,
"type": null,
"width": {
"value": 19,
"label": "19 inches"
},
"u_height": 42,
"desc_units": false,
"comments": "",
"custom_fields": {}
},
{
"id": 2,
"name": "A1R2",
"facility_id": "T24A01",
"display_name": "A1R2 (T24A01)",
"site": {
"id": 1,
"url": "http://localhost:8000/api/dcim/sites/1/",
"name": "TEST1",
"slug": "test1"
},
"group": null,
"tenant": null,
"role": null,
"type": null,
"width": {
"value": 19,
"label": "19 inches"
},
"u_height": 42,
"desc_units": false,
"comments": "",
"custom_fields": {}
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/region.json 0000644 0001751 0001751 00000000113 15136437134 021152 0 ustar 00runner runner {
"id": 1,
"name": "TEST",
"slug": "test",
"parent": null
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/regions.json 0000644 0001751 0001751 00000000316 15136437134 021342 0 ustar 00runner runner {
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"name": "TEST",
"slug": "test",
"parent": null
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/site.json 0000644 0001751 0001751 00000001132 15136437134 020635 0 ustar 00runner runner {
"id": 1,
"name": "TEST1",
"slug": "test1",
"region": null,
"tenant": null,
"facility": "Test Facility",
"asn": 65535,
"physical_address": "555 Test Ave.\r\nTest, NY 55555",
"shipping_address": "",
"contact_name": "",
"contact_phone": "",
"contact_email": "",
"comments": "",
"custom_fields": {
"test_custom": "Hello",
"test_selection": {
"value": 2,
"label": "second"
}
},
"count_prefixes": 2,
"count_vlans": 1,
"count_racks": 2,
"count_devices": 11,
"count_circuits": 0
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/sites.json 0000644 0001751 0001751 00000001410 15136437134 021017 0 ustar 00runner runner {
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"name": "TEST1",
"slug": "test1",
"region": null,
"tenant": null,
"facility": "Test Facility",
"asn": 65535,
"physical_address": "555 Test Ave.\r\nTest, NY 55555",
"shipping_address": "",
"contact_name": "",
"contact_phone": "",
"contact_email": "",
"comments": "",
"custom_fields": {
"test_custom": "Hello"
},
"count_prefixes": 2,
"count_vlans": 1,
"count_racks": 2,
"count_devices": 11,
"count_circuits": 0
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/virtual_chassis_device.json 0000644 0001751 0001751 00000000366 15136437134 024423 0 ustar 00runner runner {
"id": 1,
"master": {
"id": 5654,
"url": "http://localhost:8000/api/dcim/devices/5654/",
"name": "01-0001-e214-as01 (SW1)",
"display_name": "01-0001-e214-as01 (SW1)"
},
"domain": "test-domain-1"
}
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/dcim/virtual_chassis_devices.json 0000644 0001751 0001751 00000001363 15136437134 024604 0 ustar 00runner runner {
"count": 2,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"master": {
"id": 5654,
"url": "http://localhost:8000/api/dcim/devices/5654/",
"name": "01-0001-e214-as01 (SW1)",
"display_name": "01-0001-e214-as01 (SW1)"
},
"domain": "test-domain-1"
},
{
"id": 2,
"master": {
"id": 5635,
"url": "http://localhost:8000/netbox/api/dcim/devices/5635/",
"name": "hercules.router.com (VSS-SW1)",
"display_name": "hercules.router.com (VSS-SW1)"
},
"domain": "test-domain-2"
}
]
}
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1769619043.8163304
pynetbox-7.6.1/tests/fixtures/ipam/ 0000755 0001751 0001751 00000000000 15136437144 017014 5 ustar 00runner runner ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/ipam/aggregate.json 0000644 0001751 0001751 00000000427 15136437134 021637 0 ustar 00runner runner {
"id": 1,
"family": 4,
"prefix": "10.0.0.0/8",
"rir": {
"id": 1,
"url": "http://localhost:8000/api/ipam/rirs/1/",
"name": "RFC1918",
"slug": "rfc1918"
},
"date_added": null,
"description": "",
"custom_fields": {}
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/ipam/aggregates.json 0000644 0001751 0001751 00000000732 15136437134 022021 0 ustar 00runner runner {
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"family": 4,
"prefix": "10.0.0.0/8",
"rir": {
"id": 1,
"url": "http://localhost:8000/api/ipam/rirs/1/",
"name": "RFC1918",
"slug": "rfc1918"
},
"date_added": null,
"description": "",
"custom_fields": {}
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/ipam/available-ips-post.json 0000644 0001751 0001751 00000000273 15136437134 023404 0 ustar 00runner runner {
"id": 1,
"address": "10.1.1.1/32",
"vrf": null,
"tenant": null,
"status": 1,
"role": null,
"interface": null,
"description": "",
"nat_inside": null
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/ipam/available-ips.json 0000644 0001751 0001751 00000000412 15136437134 022414 0 ustar 00runner runner [
{
"family": 4,
"address": "10.1.1.2/27",
"vrf": null
},
{
"family": 4,
"address": "10.1.1.3/27",
"vrf": null
},
{
"family": 4,
"address": "10.1.1.7/27",
"vrf": null
}
] ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/ipam/available-prefixes-post.json 0000644 0001751 0001751 00000000371 15136437134 024435 0 ustar 00runner runner [
{
"id": 4,
"prefix": "10.1.1.0/30",
"site": null,
"vrf": null,
"tenant": null,
"vlan": null,
"status": 1,
"role": null,
"is_pool": false,
"description": ""
}
] ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/ipam/available-prefixes.json 0000644 0001751 0001751 00000000131 15136437134 023444 0 ustar 00runner runner [
{
"family": 4,
"prefix": "10.1.1.0/24",
"vrf": null
}
] ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/ipam/ip_address.json 0000644 0001751 0001751 00000001422 15136437134 022022 0 ustar 00runner runner {
"id": 1,
"family": 4,
"address": "10.0.255.1/32",
"vrf": null,
"tenant": null,
"status": {
"value": 1,
"label": "Active"
},
"interface": {
"id": 3,
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "test1-edge1",
"display_name": "test1-edge1"
},
"name": "lo0",
"form_factor": {
"value": 0,
"label": "Virtual"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
"description": "",
"nat_inside": null,
"nat_outside": null,
"custom_fields": {}
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/ipam/ip_addresses.json 0000644 0001751 0001751 00000070036 15136437134 022361 0 ustar 00runner runner {
"count": 18,
"next": null,
"previous": null,
"results": [
{
"id": 5,
"family": 4,
"address": "10.0.254.1/24",
"vrf": null,
"tenant": null,
"status": {
"value": 1,
"label": "Active"
},
"interface": {
"id": 12,
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "lo0",
"form_factor": {
"value": 0,
"label": "Virtual"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
"description": "",
"nat_inside": null,
"nat_outside": null,
"custom_fields": {}
},
{
"id": 19,
"family": 4,
"address": "10.0.254.2/32",
"vrf": null,
"tenant": null,
"status": {
"value": 1,
"label": "Active"
},
"interface": {
"id": 188,
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "lo0",
"form_factor": {
"value": 0,
"label": "Virtual"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
"description": "",
"nat_inside": null,
"nat_outside": null,
"custom_fields": {}
},
{
"id": 1,
"family": 4,
"address": "10.0.255.1/32",
"vrf": null,
"tenant": null,
"status": {
"value": 1,
"label": "Active"
},
"interface": {
"id": 3,
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "test1-edge1",
"display_name": "test1-edge1"
},
"name": "lo0",
"form_factor": {
"value": 0,
"label": "Virtual"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
"description": "",
"nat_inside": null,
"nat_outside": null,
"custom_fields": {}
},
{
"id": 3,
"family": 4,
"address": "10.0.255.2/32",
"vrf": null,
"tenant": null,
"status": {
"value": 1,
"label": "Active"
},
"interface": {
"id": 185,
"device": {
"id": 7,
"url": "http://localhost:8000/api/dcim/devices/7/",
"name": "test1-edge2",
"display_name": "test1-edge2"
},
"name": "lo0",
"form_factor": {
"value": 0,
"label": "Virtual"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
"description": "",
"nat_inside": null,
"nat_outside": null,
"custom_fields": {}
},
{
"id": 11,
"family": 4,
"address": "10.15.20.1/31",
"vrf": null,
"tenant": null,
"status": {
"value": 1,
"label": "Active"
},
"interface": {
"id": 7,
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "test1-edge1",
"display_name": "test1-edge1"
},
"name": "xe-0/0/3",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": {
"id": 24,
"url": "http://localhost:8000/api/dcim/interface-connections/24/",
"connection_status": true
},
"connected_interface": {
"id": 212,
"url": "http://localhost:8000/api/dcim/interfaces/212/",
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "xe-0/0/5",
"form_factor": 1200,
"mac_address": null,
"mgmt_only": false,
"description": ""
}
},
"description": "",
"nat_inside": null,
"nat_outside": null,
"custom_fields": {}
},
{
"id": 8,
"family": 4,
"address": "10.15.21.1/31",
"vrf": null,
"tenant": null,
"status": {
"value": 1,
"label": "Active"
},
"interface": {
"id": 218,
"device": {
"id": 7,
"url": "http://localhost:8000/api/dcim/devices/7/",
"name": "test1-edge2",
"display_name": "test1-edge2"
},
"name": "xe-0/0/5",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": {
"id": 22,
"url": "http://localhost:8000/api/dcim/interface-connections/22/",
"connection_status": true
},
"connected_interface": {
"id": 9,
"url": "http://localhost:8000/api/dcim/interfaces/9/",
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "test1-edge1",
"display_name": "test1-edge1"
},
"name": "xe-0/0/5",
"form_factor": 1200,
"mac_address": null,
"mgmt_only": false,
"description": ""
}
},
"description": "",
"nat_inside": null,
"nat_outside": null,
"custom_fields": {}
},
{
"id": 9,
"family": 4,
"address": "10.15.21.2/31",
"vrf": null,
"tenant": null,
"status": {
"value": 1,
"label": "Active"
},
"interface": {
"id": 9,
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "test1-edge1",
"display_name": "test1-edge1"
},
"name": "xe-0/0/5",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": {
"id": 22,
"url": "http://localhost:8000/api/dcim/interface-connections/22/",
"connection_status": true
},
"connected_interface": {
"id": 218,
"url": "http://localhost:8000/api/dcim/interfaces/218/",
"device": {
"id": 7,
"url": "http://localhost:8000/api/dcim/devices/7/",
"name": "test1-edge2",
"display_name": "test1-edge2"
},
"name": "xe-0/0/5",
"form_factor": 1200,
"mac_address": null,
"mgmt_only": false,
"description": ""
}
},
"description": "",
"nat_inside": null,
"nat_outside": null,
"custom_fields": {}
},
{
"id": 10,
"family": 4,
"address": "10.15.22.1/31",
"vrf": null,
"tenant": null,
"status": {
"value": 1,
"label": "Active"
},
"interface": {
"id": 8,
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "test1-edge1",
"display_name": "test1-edge1"
},
"name": "xe-0/0/4",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": {
"id": 23,
"url": "http://localhost:8000/api/dcim/interface-connections/23/",
"connection_status": true
},
"connected_interface": {
"id": 206,
"url": "http://localhost:8000/api/dcim/interfaces/206/",
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "xe-0/0/5",
"form_factor": 1200,
"mac_address": null,
"mgmt_only": false,
"description": ""
}
},
"description": "",
"nat_inside": null,
"nat_outside": null,
"custom_fields": {}
},
{
"id": 13,
"family": 4,
"address": "10.15.22.2/31",
"vrf": null,
"tenant": null,
"status": {
"value": 1,
"label": "Active"
},
"interface": {
"id": 206,
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "xe-0/0/5",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": {
"id": 23,
"url": "http://localhost:8000/api/dcim/interface-connections/23/",
"connection_status": true
},
"connected_interface": {
"id": 8,
"url": "http://localhost:8000/api/dcim/interfaces/8/",
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "test1-edge1",
"display_name": "test1-edge1"
},
"name": "xe-0/0/4",
"form_factor": 1200,
"mac_address": null,
"mgmt_only": false,
"description": ""
}
},
"description": "",
"nat_inside": null,
"nat_outside": null,
"custom_fields": {}
},
{
"id": 17,
"family": 4,
"address": "10.15.22.2/31",
"vrf": null,
"tenant": null,
"status": {
"value": 1,
"label": "Active"
},
"interface": {
"id": 212,
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "xe-0/0/5",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": {
"id": 24,
"url": "http://localhost:8000/api/dcim/interface-connections/24/",
"connection_status": true
},
"connected_interface": {
"id": 7,
"url": "http://localhost:8000/api/dcim/interfaces/7/",
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "test1-edge1",
"display_name": "test1-edge1"
},
"name": "xe-0/0/3",
"form_factor": 1200,
"mac_address": null,
"mgmt_only": false,
"description": ""
}
},
"description": "",
"nat_inside": null,
"nat_outside": null,
"custom_fields": {}
},
{
"id": 12,
"family": 4,
"address": "10.16.20.1/31",
"vrf": null,
"tenant": null,
"status": {
"value": 1,
"label": "Active"
},
"interface": {
"id": 216,
"device": {
"id": 7,
"url": "http://localhost:8000/api/dcim/devices/7/",
"name": "test1-edge2",
"display_name": "test1-edge2"
},
"name": "xe-0/0/3",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": {
"id": 26,
"url": "http://localhost:8000/api/dcim/interface-connections/26/",
"connection_status": true
},
"connected_interface": {
"id": 211,
"url": "http://localhost:8000/api/dcim/interfaces/211/",
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "xe-0/0/4",
"form_factor": 1200,
"mac_address": null,
"mgmt_only": false,
"description": ""
}
},
"description": "",
"nat_inside": null,
"nat_outside": null,
"custom_fields": {}
},
{
"id": 16,
"family": 4,
"address": "10.16.20.2/31",
"vrf": null,
"tenant": null,
"status": {
"value": 1,
"label": "Active"
},
"interface": {
"id": 211,
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "xe-0/0/4",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": {
"id": 26,
"url": "http://localhost:8000/api/dcim/interface-connections/26/",
"connection_status": true
},
"connected_interface": {
"id": 216,
"url": "http://localhost:8000/api/dcim/interfaces/216/",
"device": {
"id": 7,
"url": "http://localhost:8000/api/dcim/devices/7/",
"name": "test1-edge2",
"display_name": "test1-edge2"
},
"name": "xe-0/0/3",
"form_factor": 1200,
"mac_address": null,
"mgmt_only": false,
"description": ""
}
},
"description": "",
"nat_inside": null,
"nat_outside": null,
"custom_fields": {}
},
{
"id": 14,
"family": 4,
"address": "10.16.22.1/31",
"vrf": null,
"tenant": null,
"status": {
"value": 1,
"label": "Active"
},
"interface": {
"id": 217,
"device": {
"id": 7,
"url": "http://localhost:8000/api/dcim/devices/7/",
"name": "test1-edge2",
"display_name": "test1-edge2"
},
"name": "xe-0/0/4",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": {
"id": 25,
"url": "http://localhost:8000/api/dcim/interface-connections/25/",
"connection_status": true
},
"connected_interface": {
"id": 205,
"url": "http://localhost:8000/api/dcim/interfaces/205/",
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "xe-0/0/4",
"form_factor": 1200,
"mac_address": null,
"mgmt_only": false,
"description": ""
}
},
"description": "",
"nat_inside": null,
"nat_outside": null,
"custom_fields": {}
},
{
"id": 15,
"family": 4,
"address": "10.16.22.2/31",
"vrf": null,
"tenant": null,
"status": {
"value": 1,
"label": "Active"
},
"interface": {
"id": 205,
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "xe-0/0/4",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": {
"id": 25,
"url": "http://localhost:8000/api/dcim/interface-connections/25/",
"connection_status": true
},
"connected_interface": {
"id": 217,
"url": "http://localhost:8000/api/dcim/interfaces/217/",
"device": {
"id": 7,
"url": "http://localhost:8000/api/dcim/devices/7/",
"name": "test1-edge2",
"display_name": "test1-edge2"
},
"name": "xe-0/0/4",
"form_factor": 1200,
"mac_address": null,
"mgmt_only": false,
"description": ""
}
},
"description": "",
"nat_inside": null,
"nat_outside": null,
"custom_fields": {}
},
{
"id": 4,
"family": 4,
"address": "169.254.1.1/31",
"vrf": null,
"tenant": null,
"status": {
"value": 1,
"label": "Active"
},
"interface": {
"id": 213,
"device": {
"id": 7,
"url": "http://localhost:8000/api/dcim/devices/7/",
"name": "test1-edge2",
"display_name": "test1-edge2"
},
"name": "xe-0/0/0",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": null,
"connected_interface": null
},
"description": "",
"nat_inside": null,
"nat_outside": null,
"custom_fields": {}
},
{
"id": 20,
"family": 4,
"address": "169.254.1.1/31",
"vrf": null,
"tenant": null,
"status": {
"value": 1,
"label": "Active"
},
"interface": {
"id": 200,
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "et-0/1/2",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": {
"id": 21,
"url": "http://localhost:8000/api/dcim/interface-connections/21/",
"connection_status": true
},
"connected_interface": {
"id": 194,
"url": "http://localhost:8000/api/dcim/interfaces/194/",
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "et-0/1/2",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
}
},
"description": "",
"nat_inside": null,
"nat_outside": null,
"custom_fields": {}
},
{
"id": 21,
"family": 4,
"address": "169.254.1.2/31",
"vrf": null,
"tenant": null,
"status": {
"value": 1,
"label": "Active"
},
"interface": {
"id": 194,
"device": {
"id": 2,
"url": "http://localhost:8000/api/dcim/devices/2/",
"name": "test1-core1",
"display_name": "test1-core1"
},
"name": "et-0/1/2",
"form_factor": {
"value": 1400,
"label": "QSFP+ (40GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "",
"connection": {
"id": 21,
"url": "http://localhost:8000/api/dcim/interface-connections/21/",
"connection_status": true
},
"connected_interface": {
"id": 200,
"url": "http://localhost:8000/api/dcim/interfaces/200/",
"device": {
"id": 8,
"url": "http://localhost:8000/api/dcim/devices/8/",
"name": "test1-core2",
"display_name": "test1-core2"
},
"name": "et-0/1/2",
"form_factor": 1400,
"mac_address": null,
"mgmt_only": false,
"description": ""
}
},
"description": "",
"nat_inside": null,
"nat_outside": null,
"custom_fields": {}
},
{
"id": 2,
"family": 4,
"address": "169.254.254.1/31",
"vrf": null,
"tenant": null,
"status": {
"value": 1,
"label": "Active"
},
"interface": {
"id": 4,
"device": {
"id": 1,
"url": "http://localhost:8000/api/dcim/devices/1/",
"name": "test1-edge1",
"display_name": "test1-edge1"
},
"name": "xe-0/0/0",
"form_factor": {
"value": 1200,
"label": "SFP+ (10GE)"
},
"lag": null,
"mac_address": null,
"mgmt_only": false,
"description": "TEST",
"connection": null,
"connected_interface": null
},
"description": "",
"nat_inside": null,
"nat_outside": null,
"custom_fields": {}
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/ipam/prefix.json 0000644 0001751 0001751 00000001055 15136437134 021204 0 ustar 00runner runner {
"id": 1,
"family": 4,
"prefix": "10.1.1.0/24",
"site": {
"id": 1,
"url": "http://localhost:8000/api/dcim/sites/1/",
"name": "TEST1",
"slug": "test1"
},
"vrf": null,
"tenant": null,
"vlan": null,
"status": {
"value": 1,
"label": "Active"
},
"role": {
"id": 1,
"url": "http://localhost:8000/api/ipam/roles/1/",
"name": "Lab Network",
"slug": "lab-network"
},
"is_pool": false,
"description": "",
"custom_fields": {}
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/ipam/prefixes.json 0000644 0001751 0001751 00000003141 15136437134 021532 0 ustar 00runner runner {
"count": 2,
"next": null,
"previous": null,
"results": [
{
"id": 2,
"family": 4,
"prefix": "10.0.255.0/24",
"site": {
"id": 1,
"url": "http://localhost:8000/api/dcim/sites/1/",
"name": "TEST1",
"slug": "test1"
},
"vrf": null,
"tenant": null,
"vlan": null,
"status": {
"value": 1,
"label": "Active"
},
"role": {
"id": 1,
"url": "http://localhost:8000/api/ipam/roles/1/",
"name": "Lab Network",
"slug": "lab-network"
},
"is_pool": false,
"description": "",
"custom_fields": {}
},
{
"id": 1,
"family": 4,
"prefix": "10.1.1.0/24",
"site": {
"id": 1,
"url": "http://localhost:8000/api/dcim/sites/1/",
"name": "TEST1",
"slug": "test1"
},
"vrf": null,
"tenant": null,
"vlan": null,
"status": {
"value": 1,
"label": "Active"
},
"role": {
"id": 1,
"url": "http://localhost:8000/api/ipam/roles/1/",
"name": "Lab Network",
"slug": "lab-network"
},
"is_pool": false,
"description": "",
"custom_fields": {}
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/ipam/rir.json 0000644 0001751 0001751 00000000126 15136437134 020501 0 ustar 00runner runner {
"id": 1,
"name": "RFC1918",
"slug": "rfc1918",
"is_private": false
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/ipam/rirs.json 0000644 0001751 0001751 00000000331 15136437134 020662 0 ustar 00runner runner {
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"name": "RFC1918",
"slug": "rfc1918",
"is_private": false
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/ipam/role.json 0000644 0001751 0001751 00000000131 15136437134 020642 0 ustar 00runner runner {
"id": 1,
"name": "Lab Network",
"slug": "lab-network",
"weight": 1000
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/ipam/roles.json 0000644 0001751 0001751 00000000334 15136437134 021032 0 ustar 00runner runner {
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"name": "Lab Network",
"slug": "lab-network",
"weight": 1000
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/ipam/vlan.json 0000644 0001751 0001751 00000001043 15136437134 020644 0 ustar 00runner runner {
"id": 3,
"site": {
"id": 1,
"url": "http://localhost:8000/api/dcim/sites/1/",
"name": "TEST1",
"slug": "test1"
},
"group": null,
"vid": 1210,
"name": "v1210",
"tenant": null,
"status": {
"value": 1,
"label": "Active"
},
"role": {
"id": 1,
"url": "http://localhost:8000/api/ipam/roles/1/",
"name": "Lab Network",
"slug": "lab-network"
},
"description": "",
"display_name": "1210 (v1210)",
"custom_fields": {}
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/ipam/vlan_group.json 0000644 0001751 0001751 00000000310 15136437134 022054 0 ustar 00runner runner {
"id": 1,
"name": "TEST",
"slug": "test",
"site": {
"id": 1,
"url": "http://localhost:8000/api/dcim/sites/1/",
"name": "TEST1",
"slug": "test1"
}
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/ipam/vlan_groups.json 0000644 0001751 0001751 00000000563 15136437134 022251 0 ustar 00runner runner {
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"name": "TEST",
"slug": "test",
"site": {
"id": 1,
"url": "http://localhost:8000/api/dcim/sites/1/",
"name": "TEST1",
"slug": "test1"
}
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/ipam/vlans.json 0000644 0001751 0001751 00000004454 15136437134 021040 0 ustar 00runner runner {
"count": 3,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"site": {
"id": 1,
"url": "http://localhost:8000/api/dcim/sites/1/",
"name": "TEST1",
"slug": "test1"
},
"group": null,
"vid": 999,
"name": "TEST",
"tenant": null,
"status": {
"value": 1,
"label": "Active"
},
"role": {
"id": 1,
"url": "http://localhost:8000/api/ipam/roles/1/",
"name": "Lab Network",
"slug": "lab-network"
},
"description": "",
"display_name": "999 (TEST)",
"custom_fields": {}
},
{
"id": 2,
"site": {
"id": 1,
"url": "http://localhost:8000/api/dcim/sites/1/",
"name": "TEST1",
"slug": "test1"
},
"group": null,
"vid": 2069,
"name": "v2069",
"tenant": null,
"status": {
"value": 1,
"label": "Active"
},
"role": {
"id": 1,
"url": "http://localhost:8000/api/ipam/roles/1/",
"name": "Lab Network",
"slug": "lab-network"
},
"description": "",
"display_name": "2069 (v2069)",
"custom_fields": {}
},
{
"id": 3,
"site": {
"id": 1,
"url": "http://localhost:8000/api/dcim/sites/1/",
"name": "TEST1",
"slug": "test1"
},
"group": null,
"vid": 1210,
"name": "v1210",
"tenant": null,
"status": {
"value": 1,
"label": "Active"
},
"role": {
"id": 1,
"url": "http://localhost:8000/api/ipam/roles/1/",
"name": "Lab Network",
"slug": "lab-network"
},
"description": "",
"display_name": "1210 (v1210)",
"custom_fields": {}
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/ipam/vrf.json 0000644 0001751 0001751 00000000230 15136437134 020476 0 ustar 00runner runner {
"id": 1,
"name": "TEST",
"rd": "65535:1",
"tenant": null,
"enforce_unique": true,
"description": "",
"custom_fields": {}
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/ipam/vrfs.json 0000644 0001751 0001751 00000000463 15136437134 020671 0 ustar 00runner runner {
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"name": "TEST",
"rd": "65535:1",
"tenant": null,
"enforce_unique": true,
"description": "",
"custom_fields": {}
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1769619043.8173304
pynetbox-7.6.1/tests/fixtures/tenancy/ 0000755 0001751 0001751 00000000000 15136437144 017527 5 ustar 00runner runner ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/tenancy/tenant.json 0000644 0001751 0001751 00000000464 15136437134 021716 0 ustar 00runner runner {
"id": 1,
"name": "TEST Tenant 1",
"slug": "test-tenant-1",
"group": {
"id": 1,
"url": "http://localhost:8000/api/tenancy/tenant-groups/1/",
"name": "TEST Group",
"slug": "test-group"
},
"description": "",
"comments": "",
"custom_fields": {}
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/tenancy/tenant_group.json 0000644 0001751 0001751 00000000103 15136437134 023120 0 ustar 00runner runner {
"id": 1,
"name": "TEST Group",
"slug": "test-group"
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/tenancy/tenant_groups.json 0000644 0001751 0001751 00000000276 15136437134 023316 0 ustar 00runner runner {
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"name": "TEST Group",
"slug": "test-group"
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/tenancy/tenants.json 0000644 0001751 0001751 00000001635 15136437134 022102 0 ustar 00runner runner {
"count": 2,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"name": "TEST Tenant 1",
"slug": "test-tenant-1",
"group": {
"id": 1,
"url": "http://localhost:8000/api/tenancy/tenant-groups/1/",
"name": "TEST Group",
"slug": "test-group"
},
"description": "",
"comments": "",
"custom_fields": {}
},
{
"id": 2,
"name": "TEST Tenant 2",
"slug": "test-tenant-2",
"group": {
"id": 1,
"url": "http://localhost:8000/api/tenancy/tenant-groups/1/",
"name": "TEST Group",
"slug": "test-group"
},
"description": "",
"comments": "",
"custom_fields": {}
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1769619043.8183303
pynetbox-7.6.1/tests/fixtures/users/ 0000755 0001751 0001751 00000000000 15136437144 017227 5 ustar 00runner runner ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/users/group.json 0000644 0001751 0001751 00000000052 15136437134 021252 0 ustar 00runner runner {
"id": 1,
"name": "usergroup1"
}
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/users/groups.json 0000644 0001751 0001751 00000000350 15136437134 021436 0 ustar 00runner runner {
"count": 2,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"name": "usergroup1"
},
{
"id": 2,
"name": "usergroup2"
}
]
}
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/users/permission.json 0000644 0001751 0001751 00000000376 15136437134 022317 0 ustar 00runner runner {
"id": 1,
"name": "permission1",
"users": [
{
"username": "user1"
}
],
"constraints": [
{
"status": "active"
},
{
"region__name": "Europe"
}
]
}
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/users/permissions.json 0000644 0001751 0001751 00000000352 15136437134 022474 0 ustar 00runner runner {
"count": 2,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"name": "permission1"
},
{
"id": 2,
"name": "permission2"
}
]
}
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/users/unknown_model.json 0000644 0001751 0001751 00000000061 15136437134 022775 0 ustar 00runner runner {
"id": 1,
"display": "Unknown object"
}
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/users/user.json 0000644 0001751 0001751 00000000051 15136437134 021073 0 ustar 00runner runner {
"id": 1,
"username": "user1"
}
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/users/users.json 0000644 0001751 0001751 00000000346 15136437134 021265 0 ustar 00runner runner {
"count": 2,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"username": "user1"
},
{
"id": 2,
"username": "user2"
}
]
}
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1769619043.8193305
pynetbox-7.6.1/tests/fixtures/virtualization/ 0000755 0001751 0001751 00000000000 15136437144 021152 5 ustar 00runner runner ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/virtualization/cluster.json 0000644 0001751 0001751 00000001122 15136437134 023521 0 ustar 00runner runner {
"id": 1,
"name": "vm-test-cluster",
"type": {
"id": 1,
"url": "http://localhost:8000/api/virtualization/cluster-types/1/",
"name": "vm-test-type",
"slug": "vm-test-type"
},
"group": {
"id": 1,
"url": "http://localhost:8000/api/virtualization/cluster-groups/1/",
"name": "vm-test-group",
"slug": "vm-test-group"
},
"site": {
"id": 1,
"url": "http://localhost:8000/api/dcim/sites/1/",
"name": "TEST1",
"slug": "test1"
},
"comments": "",
"custom_fields": {}
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/virtualization/cluster_group.json 0000644 0001751 0001751 00000000111 15136437134 024732 0 ustar 00runner runner {
"id": 1,
"name": "vm-test-group",
"slug": "vm-test-group"
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/virtualization/cluster_groups.json 0000644 0001751 0001751 00000000304 15136437134 025121 0 ustar 00runner runner {
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"name": "vm-test-group",
"slug": "vm-test-group"
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/virtualization/cluster_type.json 0000644 0001751 0001751 00000000107 15136437134 024564 0 ustar 00runner runner {
"id": 1,
"name": "vm-test-type",
"slug": "vm-test-type"
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/virtualization/cluster_types.json 0000644 0001751 0001751 00000000302 15136437134 024744 0 ustar 00runner runner {
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"name": "vm-test-type",
"slug": "vm-test-type"
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/virtualization/clusters.json 0000644 0001751 0001751 00000001545 15136437134 023715 0 ustar 00runner runner {
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"name": "vm-test-cluster",
"type": {
"id": 1,
"url": "http://localhost:8000/api/virtualization/cluster-types/1/",
"name": "vm-test-type",
"slug": "vm-test-type"
},
"group": {
"id": 1,
"url": "http://localhost:8000/api/virtualization/cluster-groups/1/",
"name": "vm-test-group",
"slug": "vm-test-group"
},
"site": {
"id": 1,
"url": "http://localhost:8000/api/dcim/sites/1/",
"name": "TEST1",
"slug": "test1"
},
"comments": "",
"custom_fields": {}
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/virtualization/interface.json 0000644 0001751 0001751 00000000427 15136437134 024007 0 ustar 00runner runner {
"id": 223,
"name": "eth0",
"virtual_machine": {
"id": 1,
"url": "http://localhost:8000/api/virtualization/virtual-machines/1/",
"name": "vm-test01"
},
"enabled": true,
"mac_address": null,
"mtu": null,
"description": ""
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/virtualization/interfaces.json 0000644 0001751 0001751 00000001523 15136437134 024170 0 ustar 00runner runner {
"count": 2,
"next": null,
"previous": null,
"results": [
{
"id": 223,
"name": "eth0",
"virtual_machine": {
"id": 1,
"url": "http://localhost:8000/api/virtualization/virtual-machines/1/",
"name": "vm-test01"
},
"enabled": true,
"mac_address": null,
"mtu": null,
"description": ""
},
{
"id": 224,
"name": "eth1",
"virtual_machine": {
"id": 1,
"url": "http://localhost:8000/api/virtualization/virtual-machines/1/",
"name": "vm-test01"
},
"enabled": true,
"mac_address": null,
"mtu": null,
"description": ""
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/virtualization/virtual_machine.json 0000644 0001751 0001751 00000000720 15136437134 025215 0 ustar 00runner runner {
"id": 1,
"name": "vm-test01",
"status": {
"value": 1,
"label": "Active"
},
"cluster": {
"id": 1,
"url": "http://localhost:8000/api/virtualization/clusters/1/",
"name": "vm-test-cluster"
},
"role": null,
"tenant": null,
"platform": null,
"primary_ip4": null,
"primary_ip6": null,
"vcpus": 2,
"memory": 1024,
"disk": 500,
"comments": "",
"custom_fields": {}
}
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/virtualization/virtual_machines.json 0000644 0001751 0001751 00000001332 15136437134 025400 0 ustar 00runner runner {
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"name": "vm-test01",
"status": {
"value": 1,
"label": "Active"
},
"cluster": {
"id": 1,
"url": "http://localhost:8000/api/virtualization/clusters/1/",
"name": "vm-test-cluster"
},
"role": null,
"tenant": null,
"platform": null,
"primary_ip4": null,
"primary_ip6": null,
"vcpus": 2,
"memory": 1024,
"disk": 500,
"comments": "",
"custom_fields": {}
}
]
} ././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1769619043.8203304
pynetbox-7.6.1/tests/fixtures/wireless/ 0000755 0001751 0001751 00000000000 15136437144 017723 5 ustar 00runner runner ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/wireless/wireless_lan.json 0000644 0001751 0001751 00000000046 15136437134 023304 0 ustar 00runner runner {
"id": 1,
"ssid": "SSID 1"
}
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/fixtures/wireless/wireless_lans.json 0000644 0001751 0001751 00000000340 15136437134 023464 0 ustar 00runner runner {
"count": 2,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"ssid": "SSID 1"
},
{
"id": 2,
"ssid": "SSID 2"
}
]
}
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1769619043.8203304
pynetbox-7.6.1/tests/integration/ 0000755 0001751 0001751 00000000000 15136437144 016540 5 ustar 00runner runner ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/integration/conftest.py 0000644 0001751 0001751 00000045612 15136437134 020746 0 ustar 00runner runner import atexit
import os
import subprocess as subp
import time
from http.client import RemoteDisconnected
import pytest
import requests
import yaml
import pynetbox
DOCKER_PROJECT_PREFIX = "pytest_pynetbox"
def get_netbox_docker_version_tag(netbox_version):
"""Get the repo tag to build netbox-docker in from the requested netbox version.
Args:
netbox_version (version.Version): The version of netbox we want to build
Returns:
str: The release tag for the netbox-docker repo that should be able to build
the requested version of netbox.
"""
major, minor = netbox_version.major, netbox_version.minor
if (major, minor) == (4, 2):
tag = "3.2.1"
elif (major, minor) == (4, 3):
tag = "3.3.0"
elif (major, minor) == (4, 4):
tag = "3.4.2"
else:
raise NotImplementedError(
"Version %s is not currently supported" % netbox_version
)
return tag
@pytest.fixture(scope="session")
def git_toplevel():
"""Get the top level of the current git repo.
Returns:
str: The path of the top level directory of the current git repo.
"""
try:
subp.check_call(["which", "git"])
except subp.CalledProcessError:
pytest.skip(reason="git executable was not found on the host")
return (
subp.check_output(["git", "rev-parse", "--show-toplevel"])
.decode("utf-8")
.splitlines()[0]
)
@pytest.fixture(scope="session")
def netbox_docker_repo_dirpaths(pytestconfig, git_toplevel):
"""Get the path to the netbox-docker repos we will use.
Returns:
dict: A map of the repo dir paths to the versions of netbox that should be run
from that repo as:
{
: [
,
...,
]
}
"""
try:
subp.check_call(["which", "docker"])
except subp.CalledProcessError:
pytest.skip(reason="docker executable was not found on the host")
netbox_versions_by_repo_dirpaths = {}
for netbox_version in pytestconfig.option.netbox_versions:
repo_version_tag = get_netbox_docker_version_tag(netbox_version=netbox_version)
print("top: ", git_toplevel)
repo_fpath = os.path.join(
git_toplevel, ".netbox-docker-%s" % str(repo_version_tag)
)
if os.path.isdir(repo_fpath):
subp.check_call(
["git", "fetch"], cwd=repo_fpath, stdout=subp.PIPE, stderr=subp.PIPE
)
subp.check_call(
["git", "reset", "--hard"],
cwd=repo_fpath,
stdout=subp.PIPE,
stderr=subp.PIPE,
)
subp.check_call(
["git", "pull", "origin", "release"],
cwd=repo_fpath,
stdout=subp.PIPE,
stderr=subp.PIPE,
)
else:
subp.check_call(
[
"git",
"clone",
"https://github.com/netbox-community/netbox-docker",
repo_fpath,
],
cwd=git_toplevel,
stdout=subp.PIPE,
stderr=subp.PIPE,
)
subp.check_call(
["git", "checkout", repo_version_tag],
cwd=repo_fpath,
stdout=subp.PIPE,
stderr=subp.PIPE,
)
try:
netbox_versions_by_repo_dirpaths[repo_fpath].append(netbox_version)
except KeyError:
netbox_versions_by_repo_dirpaths[repo_fpath] = [netbox_version]
return netbox_versions_by_repo_dirpaths
@pytest.fixture(scope="session")
def docker_compose_project_name(pytestconfig):
"""Get the project name to use for docker containers.
This will return a consistently generated project name so we can kill stale
containers after the test run is finished.
"""
return "%s_%s" % (DOCKER_PROJECT_PREFIX, int(time.time()))
def clean_netbox_docker_tmpfiles():
"""Clean up any temporary files created in the netbox-docker repo."""
dirpath, dirnames, filenames = next(os.walk("./"))
for filename in filenames:
if filename.startswith("docker-compose-v"):
os.remove(filename)
def clean_docker_objects():
"""Clean up any docker objects created via these tests."""
# clean up any containers
for line in subp.check_output(["docker", "ps", "-a"]).decode("utf-8").splitlines():
words = line.split()
if not words:
continue
if words[-1].startswith(DOCKER_PROJECT_PREFIX):
subp.check_call(
["docker", "rm", "-f", words[0]], stdout=subp.PIPE, stderr=subp.PIPE
)
# clean up any volumes
for line in (
subp.check_output(["docker", "volume", "list"]).decode("utf-8").splitlines()
):
words = line.split()
if not words:
continue
if words[-1].startswith(DOCKER_PROJECT_PREFIX):
subp.check_call(
["docker", "volume", "rm", "-f", words[-1]],
stdout=subp.PIPE,
stderr=subp.PIPE,
)
# clean up any networks
for line in (
subp.check_output(["docker", "network", "list"]).decode("utf-8").splitlines()
):
words = line.split()
if not words:
continue
if words[1].startswith(DOCKER_PROJECT_PREFIX):
subp.check_call(
["docker", "network", "rm", words[1]],
stdout=subp.PIPE,
stderr=subp.PIPE,
)
# TODO: this function could be split up
@pytest.fixture(scope="session")
def docker_compose_file(pytestconfig, netbox_docker_repo_dirpaths):
"""Return paths to the compose files needed to create test containers.
We can create container sets for multiple versions of netbox here by returning a
list of paths to multiple compose files.
"""
clean_netbox_docker_tmpfiles()
clean_docker_objects()
compose_files = []
for (
netbox_docker_repo_dirpath,
netbox_versions,
) in netbox_docker_repo_dirpaths.items():
compose_source_fpath = os.path.join(
netbox_docker_repo_dirpath, "docker-compose.yml"
)
for netbox_version in netbox_versions:
# check for updates to the local netbox images
subp.check_call(
["docker", "pull", "netboxcommunity/netbox:v%s" % (netbox_version)],
stdout=subp.PIPE,
stderr=subp.PIPE,
)
docker_netbox_version = str(netbox_version).replace(".", "_")
# load the compose file yaml
compose_data = yaml.safe_load(open(compose_source_fpath, "r").read())
# add the custom network for this version
docker_network_name = "%s_v%s" % (
DOCKER_PROJECT_PREFIX,
docker_netbox_version,
)
compose_data["networks"] = {docker_network_name: {}}
# https://docs.docker.com/compose/compose-file/compose-file-v3/#network-configuration-reference
if "version" not in compose_data or compose_data["version"] >= "3.5":
compose_data["networks"][docker_network_name][
"name"
] = docker_network_name
# prepend the netbox version to each of the service names and anything else
# needed to make the continers unique to the netbox version
new_services = {}
for service_name in compose_data["services"].keys():
new_service_name = "netbox_v%s_%s" % (
docker_netbox_version,
service_name,
)
new_services[new_service_name] = compose_data["services"][service_name]
if service_name in ["netbox", "netbox-worker"]:
# set the netbox image version
new_services[new_service_name]["image"] = (
"netboxcommunity/netbox:v%s" % netbox_version
)
new_services[new_service_name]["environment"] = {
"SKIP_SUPERUSER": "false",
"SUPERUSER_API_TOKEN": "0123456789abcdef0123456789abcdef01234567",
"SUPERUSER_EMAIL": "admin@example.com",
"SUPERUSER_NAME": "admin",
"SUPERUSER_PASSWORD": "admin",
}
if service_name == "netbox":
# ensure the netbox container listens on a random port
new_services[new_service_name]["ports"] = ["8080"]
# Increase health check timeouts for GitHub Actions runners
# which may have more resource constraints
new_services[new_service_name]["healthcheck"] = {
"test": "curl -f http://localhost:8080/login/ || exit 1",
"start_period": "180s", # Increased from 90s
"timeout": "10s", # Increased from 3s
"interval": "15s",
"retries": 5,
}
# set the network and an alias to the proper short name of the container
# within that network
new_services[new_service_name]["networks"] = {
docker_network_name: {"aliases": [service_name]}
}
# fix the naming of any dependencies
if "depends_on" in new_services[new_service_name]:
new_service_dependencies = []
for dependent_service_name in new_services[new_service_name][
"depends_on"
]:
new_service_dependencies.append(
"netbox_v%s_%s"
% (
docker_netbox_version,
dependent_service_name,
)
)
new_services[new_service_name][
"depends_on"
] = new_service_dependencies
# make any internal named volumes unique to the netbox version
if "volumes" in new_services[new_service_name]:
new_volumes = []
for volume_config in new_services[new_service_name]["volumes"]:
source = volume_config.split(":")[0]
if "/" in source:
if volume_config.startswith("./"):
# Set the full path to the volume source. Without this
# some of the containers would be spun up from the
# wrong source directories.
volume_source, volume_dest = volume_config.split(
":", maxsplit=1
)
volume_source = os.path.join(
netbox_docker_repo_dirpath, volume_source[2::]
)
new_volumes.append(
":".join([volume_source, volume_dest])
)
else:
new_volumes.append(volume_config)
else:
new_volumes.append(
"%s_v%s_%s"
% (
DOCKER_PROJECT_PREFIX,
docker_netbox_version,
volume_config,
)
)
new_services[new_service_name]["volumes"] = new_volumes
# replace the services config with the renamed versions
compose_data["services"] = new_services
# prepend local volume names
new_volumes = {}
for volume_name, volume_config in compose_data["volumes"].items():
new_volumes[
"%s_v%s_%s"
% (
DOCKER_PROJECT_PREFIX,
docker_netbox_version,
volume_name,
)
] = volume_config
compose_data["volumes"] = new_volumes
compose_output_fpath = os.path.join(
netbox_docker_repo_dirpath,
"docker-compose-v%s.yml" % netbox_version,
)
with open(compose_output_fpath, "w") as fdesc:
fdesc.write(yaml.dump(compose_data))
compose_files.append(compose_output_fpath)
# set post=run cleanup hooks if requested
if pytestconfig.option.cleanup:
atexit.register(clean_docker_objects)
atexit.register(clean_netbox_docker_tmpfiles)
return compose_files
def netbox_is_responsive(url):
"""Check if the HTTP service is up and responsive."""
try:
response = requests.get(url)
if response.status_code == 200:
return True
except (
ConnectionError,
ConnectionResetError,
requests.exceptions.ConnectionError,
RemoteDisconnected,
):
return False
def id_netbox_service(fixture_value):
"""Create and ID representation for a netbox service fixture param.
Returns:
str: Identifiable representation of the service, as best we can
"""
return "netbox v%s" % fixture_value
@pytest.fixture(scope="session")
def docker_netbox_service(
pytestconfig,
docker_ip,
docker_services,
request,
):
"""Get the netbox service to test against.
This function waits until the netbox container is fully up and running then does an
initial data population with a few object types to be used in testing. Then the
service is returned as a fixture to be called from tests.
"""
netbox_integration_version = request.param
netbox_service_name = "netbox_v%s_netbox" % str(netbox_integration_version).replace(
".", "_"
)
netbox_service_port = 8080
try:
# `port_for` takes a container port and returns the corresponding host port
port = docker_services.port_for(netbox_service_name, netbox_service_port)
except Exception as err:
docker_ps_stdout = subp.check_output(["docker", "ps", "-a"]).decode("utf-8")
exited_container_logs = []
for line in docker_ps_stdout.splitlines():
if "Exited" in line:
container_id = line.split()[0]
exited_container_logs.append(
"\nContainer %s logs:\n%s"
% (
container_id,
subp.check_output(["docker", "logs", container_id]).decode(
"utf-8"
),
)
)
raise KeyError(
"Unable to find a docker service matching the name %s on port %s. Running"
" containers: %s. Original error: %s. Logs:\n%s"
% (
netbox_service_name,
netbox_service_port,
docker_ps_stdout,
err,
exited_container_logs,
)
)
url = "http://{}:{}".format(docker_ip, port)
docker_services.wait_until_responsive(
timeout=300.0, pause=1, check=lambda: netbox_is_responsive(url)
)
return {
"url": url,
"netbox_version": netbox_integration_version,
}
@pytest.fixture(scope="session")
def api(docker_netbox_service):
return pynetbox.api(
docker_netbox_service["url"], token="0123456789abcdef0123456789abcdef01234567"
)
@pytest.fixture(scope="session")
def nb_version(docker_netbox_service):
return docker_netbox_service["netbox_version"]
@pytest.fixture(scope="session")
def site(api):
site = api.dcim.sites.create(name="test", slug="test")
yield site
site.delete()
@pytest.fixture(scope="session")
def manufacturer(api):
manufacturer = api.dcim.manufacturers.create(
name="test-manufacturer", slug="test-manufacturer"
)
yield manufacturer
manufacturer.delete()
@pytest.fixture(scope="session")
def device_type(api, manufacturer):
device_type = api.dcim.device_types.create(
manufacturer=manufacturer.id,
model="test-device-type",
slug="test-device-type",
height=1,
)
yield device_type
device_type.delete()
@pytest.fixture(scope="session")
def role(api):
role = api.dcim.device_roles.create(
name="test-device-role",
slug="test-device-role",
color="000000",
)
yield role
role.delete()
def create_device(api, site, device_type, role, name):
"""Helper function to create a device with proper version handling.
Args:
api: The API instance
site: Site object
device_type: DeviceType object
role: DeviceRole object
name: Device name
Returns:
Created device object
"""
from packaging import version
if version.parse(api.version) >= version.parse("3.6"):
return api.dcim.devices.create(
name=name,
role=role.id,
device_type=device_type.id,
site=site.id,
)
else:
return api.dcim.devices.create(
name=name,
device_role=role.id,
device_type=device_type.id,
site=site.id,
)
def pytest_generate_tests(metafunc):
"""Dynamically parametrize some functions based on args from the cli parser."""
if "docker_netbox_service" in metafunc.fixturenames:
# parametrize the requested versions of netbox to the docker_netbox_services fixture
# so that it will return a fixture for each of the versions requested
# individually rather than one fixture with multiple versions within it
metafunc.parametrize(
"docker_netbox_service",
metafunc.config.getoption("netbox_versions"),
ids=id_netbox_service,
indirect=True,
)
@pytest.fixture(scope="session")
def docker_cleanup(pytestconfig):
"""Override the docker cleanup command for the containsers used in testing."""
# pytest-docker does not always clean up after itself properly, and sometimes it
# will fail during cleanup because there is still a connection to one of the
# running containers. Here we will disable the builtin cleanup of containers via the
# pytest-docker module and implement our own instead.
# This is only relevant until https://github.com/avast/pytest-docker/pull/33 gets
# resolved.
# There is not a great way to skip the shutdown step, so in this case to skip
# it we will just pass the "version" arg so the containers are left alone
command_args = "version"
return command_args
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/integration/test_circuits.py 0000644 0001751 0001751 00000017752 15136437134 022011 0 ustar 00runner runner import pytest
@pytest.fixture(scope="module")
def provider(api):
provider = api.circuits.providers.create(name="test-provider", slug="test-provider")
yield provider
provider.delete()
@pytest.fixture(scope="module")
def circuit_type(api):
circuit_type = api.circuits.circuit_types.create(
name="test-circuit-type", slug="test-circuit-type"
)
yield circuit_type
circuit_type.delete()
@pytest.fixture(scope="module")
def circuit(api, provider, circuit_type):
circuit = api.circuits.circuits.create(
cid="TEST-CIRCUIT-001", provider=provider.id, type=circuit_type.id
)
yield circuit
circuit.delete()
@pytest.fixture(scope="module")
def provider_network(api, provider):
provider_network = api.circuits.provider_networks.create(
name="test-provider-network", provider=provider.id
)
yield provider_network
provider_network.delete()
@pytest.fixture(scope="module")
def virtual_circuit_type(api):
virtual_circuit_type = api.circuits.virtual_circuit_types.create(
name="test-virtual-circuit-type", slug="test-virtual-circuit-type"
)
yield virtual_circuit_type
virtual_circuit_type.delete()
@pytest.fixture(scope="module")
def virtual_circuit(api, provider_network, virtual_circuit_type):
virtual_circuit = api.circuits.virtual_circuits.create(
cid="TEST-VCIRCUIT-001",
provider_network=provider_network.id,
type=virtual_circuit_type.id,
)
yield virtual_circuit
virtual_circuit.delete()
@pytest.mark.usefixtures("init")
class BaseTest:
app = "circuits"
def _init_helper(
self,
request,
fixture,
update_field=None,
filter_kwargs=None,
endpoint=None,
str_repr=None,
):
request.cls.endpoint = endpoint
request.cls.fixture = fixture
request.cls.update_field = update_field
request.cls.filter_kwargs = filter_kwargs
request.cls.str_repr = str_repr
def test_create(self):
assert self.fixture
def test_str(self):
if self.str_repr:
test = str(self.fixture)
assert test == self.str_repr
def test_update_fixture(self):
if self.update_field:
setattr(self.fixture, self.update_field, "Test Value")
assert self.fixture.save()
def test_get_fixture_by_id(self, api):
test = getattr(getattr(api, self.app), self.endpoint).get(self.fixture.id)
assert test
if self.update_field:
assert getattr(test, self.update_field) == "Test Value"
def test_get_fixture_by_kwarg(self, api):
test = getattr(getattr(api, self.app), self.endpoint).get(**self.filter_kwargs)
assert test
if self.update_field:
assert getattr(test, self.update_field) == "Test Value"
def test_filter_fixture(self, api):
test = list(
getattr(getattr(api, self.app), self.endpoint).filter(**self.filter_kwargs)
)[0]
assert test
if self.update_field:
assert getattr(test, self.update_field) == "Test Value"
class TestCircuit(BaseTest):
@pytest.fixture(scope="class")
def init(self, request, circuit):
self._init_helper(
request,
circuit,
filter_kwargs={"cid": circuit.cid},
update_field="description",
endpoint="circuits",
str_repr=circuit.cid,
)
class TestCircuitTermination(BaseTest):
@pytest.fixture(scope="class")
def site_b(self, api):
site_b = api.dcim.sites.create(name="test-site-b", slug="test-site-b")
yield site_b
site_b.delete()
@pytest.fixture(scope="class")
def circuit_termination_a(self, api, circuit, site):
ret = api.circuits.circuit_terminations.create(
circuit=circuit.id,
site=site.id,
term_side="A",
termination_type="dcim.site",
termination_id=site.id,
)
yield ret
@pytest.fixture(scope="class")
def circuit_termination_b(self, api, circuit, site_b):
ret = api.circuits.circuit_terminations.create(
circuit=circuit.id,
site=site_b.id,
term_side="Z",
termination_type="dcim.site",
termination_id=site_b.id,
)
yield ret
@pytest.fixture(scope="class")
def init(
self,
request,
circuit_termination_a,
):
self._init_helper(
request,
circuit_termination_a,
filter_kwargs={"circuit_id": circuit_termination_a.circuit.id},
endpoint="circuit_terminations",
str_repr=circuit_termination_a.circuit.cid,
)
def test_circuit_termination_paths(self, circuit_termination_a):
paths_result = circuit_termination_a.paths()
assert isinstance(paths_result, list)
# Circuit terminations may have paths if connected through patch panels
# For this test, we just verify the method works and returns correct structure
if paths_result:
for path in paths_result:
assert "origin" in path
assert "destination" in path
assert "path" in path
assert isinstance(path["path"], list)
class TestVirtualCircuit(BaseTest):
@pytest.fixture(scope="class")
def init(self, request, virtual_circuit):
self._init_helper(
request,
virtual_circuit,
filter_kwargs={"cid": virtual_circuit.cid},
update_field="description",
endpoint="virtual_circuits",
str_repr=virtual_circuit.cid,
)
class TestVirtualCircuitTermination(BaseTest):
@pytest.fixture(scope="class")
def device(self, api, site, device_type, role):
from tests.integration.conftest import create_device
device = create_device(api, site, device_type, role, "test-vcircuit-device")
yield device
device.delete()
@pytest.fixture(scope="class")
def interface_a(self, api, device):
ret = api.dcim.interfaces.create(
name="vlan100", type="virtual", device=device.id
)
yield ret
@pytest.fixture(scope="class")
def interface_b(self, api, device):
ret = api.dcim.interfaces.create(
name="vlan200", type="virtual", device=device.id
)
yield ret
@pytest.fixture(scope="class")
def virtual_circuit_termination_a(self, api, virtual_circuit, interface_a):
ret = api.circuits.virtual_circuit_terminations.create(
virtual_circuit=virtual_circuit.id, role="hub", interface=interface_a.id
)
yield ret
@pytest.fixture(scope="class")
def virtual_circuit_termination_b(self, api, virtual_circuit, interface_b):
ret = api.circuits.virtual_circuit_terminations.create(
virtual_circuit=virtual_circuit.id, role="spoke", interface=interface_b.id
)
yield ret
@pytest.fixture(scope="class")
def init(
self,
request,
virtual_circuit_termination_a,
):
self._init_helper(
request,
virtual_circuit_termination_a,
filter_kwargs={
"virtual_circuit_id": virtual_circuit_termination_a.virtual_circuit.id
},
endpoint="virtual_circuit_terminations",
str_repr=virtual_circuit_termination_a.virtual_circuit.cid,
)
def test_virtual_circuit_termination_paths(self, virtual_circuit_termination_a):
paths_result = virtual_circuit_termination_a.paths()
assert isinstance(paths_result, list)
# Virtual circuit terminations may have paths if they traverse physical infrastructure
# For this test, we just verify the method works and returns correct structure
if paths_result:
for path in paths_result:
assert "origin" in path
assert "destination" in path
assert "path" in path
assert isinstance(path["path"], list)
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/integration/test_dcim.py 0000644 0001751 0001751 00000032565 15136437134 021077 0 ustar 00runner runner import pytest
from packaging import version
import pynetbox
@pytest.fixture(scope="module")
def rack(api, site):
rack = api.dcim.racks.create(site=site.id, name="test-rack")
yield rack
rack.delete()
@pytest.fixture(scope="module")
def device(api, site, device_type, role):
from tests.integration.conftest import create_device
device = create_device(api, site, device_type, role, "test-device")
yield device
device.delete()
@pytest.mark.usefixtures("init")
class BaseTest:
app = "dcim"
def _init_helper(
self,
request,
fixture,
update_field=None,
filter_kwargs=None,
endpoint=None,
str_repr=None,
):
request.cls.endpoint = endpoint
request.cls.fixture = fixture
request.cls.update_field = update_field
request.cls.filter_kwargs = filter_kwargs
request.cls.str_repr = str_repr
def test_create(self):
assert self.fixture
def test_str(self):
if self.str_repr:
test = str(self.fixture)
assert test == self.str_repr
def test_update_fixture(self):
if self.update_field:
setattr(self.fixture, self.update_field, "Test Value")
assert self.fixture.save()
def test_get_fixture_by_id(self, api):
test = getattr(getattr(api, self.app), self.endpoint).get(self.fixture.id)
assert test
if self.update_field:
assert getattr(test, self.update_field) == "Test Value"
def test_get_fixture_by_kwarg(self, api):
test = getattr(getattr(api, self.app), self.endpoint).get(**self.filter_kwargs)
assert test
if self.update_field:
assert getattr(test, self.update_field) == "Test Value"
def test_filter_fixture(self, api):
test = list(
getattr(getattr(api, self.app), self.endpoint).filter(**self.filter_kwargs)
)[0]
assert test
if self.update_field:
assert getattr(test, self.update_field) == "Test Value"
class TestSite(BaseTest):
@pytest.fixture(scope="class")
def init(self, request, site):
self._init_helper(
request,
site,
filter_kwargs={"name": "test"},
update_field="description",
endpoint="sites",
)
@pytest.fixture(scope="class")
def add_sites(self, api):
sites = api.dcim.sites.create(
[
{"name": "test{}".format(i), "slug": "test{}".format(i)}
for i in range(2, 20)
]
)
yield
for i in sites:
i.delete()
def test_threading_duplicates(self, docker_netbox_service, add_sites):
api = pynetbox.api(
docker_netbox_service["url"],
token="0123456789abcdef0123456789abcdef01234567",
threading=True,
)
test = api.dcim.sites.all(limit=5)
test_list = list(test)
test_set = set(test_list)
assert len(test_list) == len(test_set)
class TestRack(BaseTest):
@pytest.fixture(scope="class")
def init(self, request, rack):
self._init_helper(
request,
rack,
filter_kwargs={"name": rack.name},
update_field="comments",
endpoint="racks",
)
def test_get_elevation(self):
test = self.fixture.elevation.list()
assert test
assert isinstance(test, list)
class TestManufacturer(BaseTest):
@pytest.fixture(scope="class")
def init(self, request, manufacturer, nb_version):
self._init_helper(
request,
manufacturer,
filter_kwargs={"name": manufacturer.name},
update_field="description" if version.parse("2.10") < nb_version else None,
endpoint="manufacturers",
)
class TestDeviceType(BaseTest):
@pytest.fixture(scope="class")
def init(self, request, device_type):
self._init_helper(
request,
device_type,
filter_kwargs={"model": device_type.model},
update_field="comments",
endpoint="device_types",
str_repr=device_type.model,
)
class TestDevice(BaseTest):
@pytest.fixture(scope="class")
def init(self, request, device):
self._init_helper(
request,
device,
filter_kwargs={"name": device.name},
update_field="comments",
endpoint="devices",
)
class TestInterface(BaseTest):
@pytest.fixture(scope="class")
def interface(self, api, device):
ret = api.dcim.interfaces.create(
name="test-interface", type="1000base-t", device=device.id
)
yield ret
ret.delete()
@pytest.fixture(scope="class")
def init(self, request, interface):
self._init_helper(
request,
interface,
filter_kwargs={"name": interface.name},
update_field="description",
endpoint="interfaces",
)
class TestPowerCable(BaseTest):
@pytest.fixture(scope="class")
def power_outlet(self, api, device_type, role, site):
from tests.integration.conftest import create_device
pdu = create_device(api, site, device_type, role, "test-pdu")
outlet = api.dcim.power_outlets.create(name="outlet", device=pdu.id)
yield outlet
pdu.delete()
@pytest.fixture(scope="class")
def power_port(self, api, device):
ret = api.dcim.power_ports.create(name="PSU1", device=device.id)
yield ret
@pytest.fixture(scope="class")
def power_cable(self, api, power_outlet, power_port):
cable = api.dcim.cables.create(
a_terminations=[
{"object_type": "dcim.powerport", "object_id": power_port.id},
],
b_terminations=[
{"object_type": "dcim.poweroutlet", "object_id": power_outlet.id},
],
)
yield cable
cable.delete()
@pytest.fixture(scope="class")
def init(self, request, power_cable):
self._init_helper(
request,
power_cable,
filter_kwargs={"id": power_cable.id},
endpoint="cables",
str_repr="PSU1 <> outlet",
)
class TestConsoleCable(BaseTest):
@pytest.fixture(scope="class")
def console_server_port(self, api, device_type, role, site):
from tests.integration.conftest import create_device
device = create_device(api, site, device_type, role, "test-console-server")
ret = api.dcim.console_server_ports.create(name="Port 1", device=device.id)
yield ret
device.delete()
@pytest.fixture(scope="class")
def console_port(self, api, device):
ret = api.dcim.console_ports.create(name="Console", device=device.id)
yield ret
@pytest.fixture(scope="class")
def console_cable(self, api, console_port, console_server_port):
ret = api.dcim.cables.create(
a_terminations=[
{"object_type": "dcim.consoleport", "object_id": console_port.id},
],
b_terminations=[
{
"object_type": "dcim.consoleserverport",
"object_id": console_server_port.id,
},
],
)
yield ret
ret.delete()
@pytest.fixture(scope="class")
def init(self, request, console_cable):
self._init_helper(
request,
console_cable,
filter_kwargs={"id": console_cable.id},
endpoint="cables",
str_repr="Console <> Port 1",
)
class TestInterfaceCable(BaseTest):
@pytest.fixture(scope="class")
def interface_b(self, api, device_type, role, site):
from tests.integration.conftest import create_device
device = create_device(api, site, device_type, role, "test-device-2")
ret = api.dcim.interfaces.create(
name="Ethernet1", type="1000base-t", device=device.id
)
yield ret
device.delete()
@pytest.fixture(scope="class")
def interface_a(self, api, device):
ret = api.dcim.interfaces.create(
name="Ethernet1", type="1000base-t", device=device.id
)
yield ret
@pytest.fixture(scope="class")
def interface_cable(self, api, interface_a, interface_b):
ret = api.dcim.cables.create(
a_terminations=[
{"object_type": "dcim.interface", "object_id": interface_a.id},
],
b_terminations=[
{"object_type": "dcim.interface", "object_id": interface_b.id},
],
)
yield ret
ret.delete()
@pytest.fixture(scope="class")
def init(self, request, interface_cable):
self._init_helper(
request,
interface_cable,
filter_kwargs={"id": interface_cable.id},
endpoint="cables",
str_repr="Ethernet1 <> Ethernet1",
)
def test_trace(self, interface_a):
test = interface_a.trace()
assert test
assert test[0][0].name == "Ethernet1"
assert test[2][0].name == "Ethernet1"
class TestPassThroughPorts(BaseTest):
@pytest.fixture(scope="class")
def device_a(self, api, device_type, role, site):
from tests.integration.conftest import create_device
device = create_device(api, site, device_type, role, "test-device-a")
yield device
device.delete()
@pytest.fixture(scope="class")
def device_b(self, api, device_type, role, site):
from tests.integration.conftest import create_device
device = create_device(api, site, device_type, role, "test-device-b")
yield device
device.delete()
@pytest.fixture(scope="class")
def front_port_a(self, api, device_a, rear_port_a):
ret = api.dcim.front_ports.create(
name="FrontPort1",
device=device_a.id,
type="8p8c",
rear_port=rear_port_a.id,
rear_port_position=1,
)
yield ret
@pytest.fixture(scope="class")
def rear_port_a(self, api, device_a):
ret = api.dcim.rear_ports.create(
name="RearPort1", device=device_a.id, type="8p8c", positions=1
)
yield ret
@pytest.fixture(scope="class")
def front_port_b(self, api, device_b, rear_port_b):
ret = api.dcim.front_ports.create(
name="FrontPort2",
device=device_b.id,
type="8p8c",
rear_port=rear_port_b.id,
rear_port_position=1,
)
yield ret
@pytest.fixture(scope="class")
def rear_port_b(self, api, device_b):
ret = api.dcim.rear_ports.create(
name="RearPort2", device=device_b.id, type="8p8c", positions=1
)
yield ret
@pytest.fixture(scope="class")
def interface_a(self, api, device_a):
ret = api.dcim.interfaces.create(
name="eth0", type="1000base-t", device=device_a.id
)
yield ret
@pytest.fixture(scope="class")
def interface_b(self, api, device_b):
ret = api.dcim.interfaces.create(
name="eth0", type="1000base-t", device=device_b.id
)
yield ret
@pytest.fixture(scope="class")
def cable_front(self, api, front_port_a, front_port_b):
ret = api.dcim.cables.create(
a_terminations=[
{"object_type": "dcim.frontport", "object_id": front_port_a.id},
],
b_terminations=[
{"object_type": "dcim.frontport", "object_id": front_port_b.id},
],
)
yield ret
ret.delete()
@pytest.fixture(scope="class")
def cable_rear_a(self, api, rear_port_a, interface_a):
ret = api.dcim.cables.create(
a_terminations=[
{"object_type": "dcim.rearport", "object_id": rear_port_a.id},
],
b_terminations=[
{"object_type": "dcim.interface", "object_id": interface_a.id},
],
)
yield ret
ret.delete()
@pytest.fixture(scope="class")
def cable_rear_b(self, api, rear_port_b, interface_b):
ret = api.dcim.cables.create(
a_terminations=[
{"object_type": "dcim.rearport", "object_id": rear_port_b.id},
],
b_terminations=[
{"object_type": "dcim.interface", "object_id": interface_b.id},
],
)
yield ret
ret.delete()
@pytest.fixture(scope="class")
def init(
self,
request,
front_port_a,
cable_front,
cable_rear_a,
cable_rear_b,
):
self._init_helper(
request,
front_port_a,
filter_kwargs={"name": front_port_a.name},
endpoint="front_ports",
)
def test_front_port_paths(self, front_port_a):
paths_result = front_port_a.paths()
assert paths_result
assert isinstance(paths_result, list)
assert len(paths_result) > 0
# Each path should have origin, destination, and path keys
for path in paths_result:
assert "origin" in path
assert "destination" in path
assert "path" in path
assert isinstance(path["path"], list)
def test_rear_port_paths(self, rear_port_a):
paths_result = rear_port_a.paths()
assert paths_result
assert isinstance(paths_result, list)
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/integration/test_ipam.py 0000644 0001751 0001751 00000011636 15136437134 021105 0 ustar 00runner runner import pytest
from packaging import version
@pytest.mark.usefixtures("init")
class BaseTest:
app = "ipam"
def _init_helper(
self,
request,
fixture,
update_field=None,
filter_kwargs=None,
endpoint=None,
str_repr=None,
):
request.cls.endpoint = endpoint
request.cls.fixture = fixture
request.cls.update_field = update_field
request.cls.filter_kwargs = filter_kwargs
request.cls.str_repr = str_repr
def test_create(self):
assert self.fixture
def test_str(self):
if self.str_repr:
test = str(self.fixture)
assert test == self.str_repr
def test_update_fixture(self):
if self.update_field:
setattr(self.fixture, self.update_field, "Test Value")
assert self.fixture.save()
def test_get_fixture_by_id(self, api):
test = getattr(getattr(api, self.app), self.endpoint).get(self.fixture.id)
assert test
if self.update_field:
assert getattr(test, self.update_field) == "Test Value"
def test_get_fixture_by_kwarg(self, api):
test = getattr(getattr(api, self.app), self.endpoint).get(**self.filter_kwargs)
assert test
if self.update_field:
assert getattr(test, self.update_field) == "Test Value"
def test_filter_fixture(self, api):
test = list(
getattr(getattr(api, self.app), self.endpoint).filter(**self.filter_kwargs)
)[0]
assert test
if self.update_field:
assert getattr(test, self.update_field) == "Test Value"
@pytest.fixture(scope="module")
def rir(api, site):
ret = api.ipam.rirs.create(
name="ministry-of-silly-walks", slug="ministry-of-silly-walks"
)
yield ret
ret.delete()
class TestRIR(BaseTest):
@pytest.fixture(scope="class")
def init(self, request, rir, nb_version):
self._init_helper(
request,
rir,
filter_kwargs={"name": "ministry-of-silly-walks"},
update_field="description" if nb_version >= version.parse("2.8") else None,
endpoint="rirs",
)
class TestAggregate(BaseTest):
@pytest.fixture(scope="class")
def aggregate(self, api, rir):
ret = api.ipam.aggregates.create(prefix="192.0.2.0/24", rir=rir.id)
yield ret
ret.delete()
@pytest.fixture(scope="class")
def init(self, request, aggregate):
self._init_helper(
request,
aggregate,
filter_kwargs={"prefix": "192.0.2.0/24"},
update_field="description",
endpoint="aggregates",
)
class TestPrefix(BaseTest):
@pytest.fixture(scope="class")
def prefix(self, api):
ret = api.ipam.prefixes.create(prefix="192.0.2.0/24")
yield ret
ret.delete()
@pytest.fixture(scope="class")
def init(self, request, prefix):
self._init_helper(
request,
prefix,
filter_kwargs={"prefix": "192.0.2.0/24"},
update_field="description",
endpoint="prefixes",
)
class TestIpAddress(BaseTest):
@pytest.fixture(scope="class")
def ip(self, api):
ret = api.ipam.ip_addresses.create(address="192.0.2.1/24")
yield ret
ret.delete()
@pytest.fixture(scope="class")
def init(self, request, ip):
self._init_helper(
request,
ip,
filter_kwargs={"q": "192.0.2.1/24"},
update_field="description",
endpoint="ip_addresses",
)
class TestRole(BaseTest):
@pytest.fixture(scope="class")
def role(self, api):
ret = api.ipam.roles.create(name="test-role", slug="test-role")
yield ret
ret.delete()
@pytest.fixture(scope="class")
def init(self, request, role):
self._init_helper(
request,
role,
filter_kwargs={"name": "test-role"},
update_field="description",
endpoint="roles",
)
class TestVlan(BaseTest):
@pytest.fixture(scope="class")
def vlan(self, api):
ret = api.ipam.vlans.create(vid=123, name="test-vlan")
yield ret
ret.delete()
@pytest.fixture(scope="class")
def init(self, request, vlan):
self._init_helper(
request,
vlan,
filter_kwargs={"name": "test-vlan"},
update_field="description",
endpoint="vlans",
)
class TestVRF(BaseTest):
@pytest.fixture(scope="class")
def vrf(self, api):
ret = api.ipam.vrfs.create(name="test-vrf", rd="192.0.2.1:1234")
yield ret
ret.delete()
@pytest.fixture(scope="class")
def init(self, request, vrf):
self._init_helper(
request,
vrf,
filter_kwargs={"name": "test-vrf"},
update_field="description",
endpoint="vrfs",
)
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/test_api.py 0000644 0001751 0001751 00000005321 15136437134 016377 0 ustar 00runner runner import unittest
from unittest.mock import patch
import pynetbox
from .util import Response
host = "http://localhost:8000"
def_kwargs = {
"token": "abc123",
}
# Keys are app names, values are arbitrarily selected endpoints
# We use dcim and ipam since they have unique app classes
# and circuits because it does not. We don't add other apps/endpoints
# beyond 'circuits' as they all use the same code as each other
endpoints = {
"dcim": "devices",
"ipam": "prefixes",
"circuits": "circuits",
}
class ApiTestCase(unittest.TestCase):
@patch(
"requests.sessions.Session.post",
return_value=Response(),
)
def test_get(self, *_):
api = pynetbox.api(host, **def_kwargs)
self.assertTrue(api)
@patch(
"requests.sessions.Session.post",
return_value=Response(),
)
def test_sanitize_url(self, *_):
api = pynetbox.api("http://localhost:8000/", **def_kwargs)
self.assertTrue(api)
self.assertEqual(api.base_url, "http://localhost:8000/api")
class ApiVersionTestCase(unittest.TestCase):
class ResponseHeadersWithVersion:
headers = {"API-Version": "1.999"}
ok = True
@patch(
"requests.sessions.Session.get",
return_value=ResponseHeadersWithVersion(),
)
def test_api_version(self, *_):
api = pynetbox.api(
host,
)
self.assertEqual(api.version, "1.999")
class ResponseHeadersWithoutVersion:
headers = {}
ok = True
@patch(
"requests.sessions.Session.get",
return_value=ResponseHeadersWithoutVersion(),
)
def test_api_version_not_found(self, *_):
api = pynetbox.api(
host,
)
self.assertEqual(api.version, "")
class ApiStatusTestCase(unittest.TestCase):
class ResponseWithStatus:
ok = True
def json(self):
return {
"netbox-version": "0.9.9",
}
@patch(
"requests.sessions.Session.get",
return_value=ResponseWithStatus(),
)
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")
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/test_app.py 0000644 0001751 0001751 00000003054 15136437134 016407 0 ustar 00runner runner import unittest
from unittest.mock import patch
import pynetbox
host = "http://localhost:8000"
def_kwargs = {
"token": "abc123",
}
class AppConfigTestCase(unittest.TestCase):
@patch(
"pynetbox.core.query.Request.get",
return_value={
"tables": {
"DeviceTable": {
"columns": [
"name",
"status",
"tenant",
"tags",
],
},
},
},
)
def test_config(self, *_):
api = pynetbox.api(host, **def_kwargs)
config = api.users.config()
self.assertEqual(sorted(config.keys()), ["tables"])
self.assertEqual(
sorted(config["tables"]["DeviceTable"]["columns"]),
["name", "status", "tags", "tenant"],
)
class PluginAppTestCase(unittest.TestCase):
@patch(
"pynetbox.core.query.Request.get",
return_value=[
{
"name": "test_plugin",
"package": "netbox_test_plugin",
}
],
)
def test_installed_plugins(self, *_):
api = pynetbox.api(host, **def_kwargs)
plugins = api.plugins.installed_plugins()
self.assertEqual(len(plugins), 1)
self.assertEqual(plugins[0]["name"], "test_plugin")
def test_plugin_app_name(self, *_):
api = pynetbox.api(host, **def_kwargs)
test_plugin = api.plugins.test_plugin
self.assertEqual(test_plugin.name, "plugins/test-plugin")
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/test_circuits.py 0000644 0001751 0001751 00000006250 15136437134 017455 0 ustar 00runner runner import unittest
from unittest.mock import patch
import pynetbox
from .util import Response
api = pynetbox.api(
"http://localhost:8000",
)
nb = api.circuits
HEADERS = {"accept": "application/json"}
class Generic:
class Tests(unittest.TestCase):
name = ""
ret = pynetbox.core.response.Record
app = "circuits"
def test_get_all(self):
with patch(
"requests.sessions.Session.get",
return_value=Response(fixture="{}/{}.json".format(self.app, self.name)),
) as mock:
ret = list(getattr(nb, self.name).all())
self.assertTrue(ret)
self.assertTrue(isinstance(ret[0], self.ret))
mock.assert_called_with(
"http://localhost:8000/api/{}/{}/".format(
self.app, self.name.replace("_", "-")
),
params={"limit": 0},
json=None,
headers=HEADERS,
)
def test_filter(self):
with patch(
"requests.sessions.Session.get",
return_value=Response(fixture="{}/{}.json".format(self.app, self.name)),
) as mock:
ret = list(getattr(nb, self.name).filter(name="test"))
self.assertTrue(ret)
self.assertTrue(isinstance(ret[0], self.ret))
mock.assert_called_with(
"http://localhost:8000/api/{}/{}/".format(
self.app, self.name.replace("_", "-")
),
params={"name": "test", "limit": 0},
json=None,
headers=HEADERS,
)
def test_get(self):
with patch(
"requests.sessions.Session.get",
return_value=Response(
fixture="{}/{}.json".format(self.app, self.name[:-1])
),
) as mock:
ret = getattr(nb, self.name).get(1)
self.assertTrue(ret)
self.assertTrue(isinstance(ret, self.ret))
mock.assert_called_with(
"http://localhost:8000/api/{}/{}/1/".format(
self.app, self.name.replace("_", "-")
),
params={},
json=None,
headers=HEADERS,
)
class CircuitsTestCase(Generic.Tests):
name = "circuits"
@patch(
"requests.sessions.Session.get",
return_value=Response(fixture="circuits/circuit.json"),
)
def test_repr(self, _):
test = nb.circuits.get(1)
self.assertEqual(str(test), "123456")
class ProviderTestCase(Generic.Tests):
name = "providers"
class CircuitTypeTestCase(Generic.Tests):
name = "circuit_types"
class CircuitTerminationsTestCase(Generic.Tests):
name = "circuit_terminations"
@patch(
"requests.sessions.Session.get",
return_value=Response(fixture="circuits/circuit_termination.json"),
)
def test_repr(self, _):
test = nb.circuit_terminations.get(1)
self.assertEqual(str(test), "123456")
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/test_tenancy.py 0000644 0001751 0001751 00000005047 15136437134 017274 0 ustar 00runner runner import unittest
from unittest.mock import patch
import pynetbox
from .util import Response
api = pynetbox.api(
"http://localhost:8000",
)
nb = api.tenancy
HEADERS = {"accept": "application/json"}
class Generic:
class Tests(unittest.TestCase):
name = ""
ret = pynetbox.core.response.Record
app = "tenancy"
def test_get_all(self):
with patch(
"requests.sessions.Session.get",
return_value=Response(fixture="{}/{}.json".format(self.app, self.name)),
) as mock:
ret = list(getattr(nb, self.name).all())
self.assertTrue(ret)
self.assertTrue(isinstance(ret[0], self.ret))
mock.assert_called_with(
"http://localhost:8000/api/{}/{}/".format(
self.app, self.name.replace("_", "-")
),
params={"limit": 0},
json=None,
headers=HEADERS,
)
def test_filter(self):
with patch(
"requests.sessions.Session.get",
return_value=Response(fixture="{}/{}.json".format(self.app, self.name)),
) as mock:
ret = list(getattr(nb, self.name).filter(name="test"))
self.assertTrue(ret)
self.assertTrue(isinstance(ret[0], self.ret))
mock.assert_called_with(
"http://localhost:8000/api/{}/{}/".format(
self.app, self.name.replace("_", "-")
),
params={"name": "test", "limit": 0},
json=None,
headers=HEADERS,
)
def test_get(self):
with patch(
"requests.sessions.Session.get",
return_value=Response(
fixture="{}/{}.json".format(self.app, self.name[:-1])
),
) as mock:
ret = getattr(nb, self.name).get(1)
self.assertTrue(ret)
self.assertTrue(isinstance(ret, self.ret))
mock.assert_called_with(
"http://localhost:8000/api/{}/{}/1/".format(
self.app, self.name.replace("_", "-")
),
params={},
json=None,
headers=HEADERS,
)
class TenantsTestCase(Generic.Tests):
name = "tenants"
class TenantGroupsTestCase(Generic.Tests):
name = "tenant_groups"
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/test_users.py 0000644 0001751 0001751 00000010161 15136437134 016765 0 ustar 00runner runner import unittest
from unittest.mock import patch
import pynetbox
from .util import Response
api = pynetbox.api(
"http://localhost:8000",
)
nb = api.users
HEADERS = {"accept": "application/json"}
class Generic:
class Tests(unittest.TestCase):
name = ""
ret = pynetbox.core.response.Record
app = "users"
def test_get_all(self):
with patch(
"requests.sessions.Session.get",
return_value=Response(fixture="{}/{}.json".format(self.app, self.name)),
) as mock:
ret = list(getattr(nb, self.name).all())
self.assertTrue(ret)
self.assertTrue(isinstance(ret[0], self.ret))
mock.assert_called_with(
"http://localhost:8000/api/{}/{}/".format(
self.app, self.name.replace("_", "-")
),
params={"limit": 0},
json=None,
headers=HEADERS,
)
def test_filter(self):
with patch(
"requests.sessions.Session.get",
return_value=Response(fixture="{}/{}.json".format(self.app, self.name)),
) as mock:
ret = list(getattr(nb, self.name).filter(name="test"))
self.assertTrue(ret)
self.assertTrue(isinstance(ret[0], self.ret))
mock.assert_called_with(
"http://localhost:8000/api/{}/{}/".format(
self.app, self.name.replace("_", "-")
),
params={"name": "test", "limit": 0},
json=None,
headers=HEADERS,
)
def test_get(self):
with patch(
"requests.sessions.Session.get",
return_value=Response(
fixture="{}/{}.json".format(self.app, self.name[:-1])
),
) as mock:
ret = getattr(nb, self.name).get(1)
self.assertTrue(ret)
self.assertTrue(isinstance(ret, self.ret))
mock.assert_called_with(
"http://localhost:8000/api/{}/{}/1/".format(
self.app, self.name.replace("_", "-")
),
params={},
json=None,
headers=HEADERS,
)
class UsersTestCase(Generic.Tests):
name = "users"
@patch(
"requests.sessions.Session.get",
return_value=Response(fixture="users/user.json"),
)
def test_repr(self, _):
test = nb.users.get(1)
self.assertEqual(type(test), pynetbox.models.users.Users)
self.assertEqual(str(test), "user1")
class GroupsTestCase(Generic.Tests):
name = "groups"
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")
@patch(
"requests.sessions.Session.get",
return_value=Response(fixture="users/permission.json"),
)
def test_constraints(self, _):
permission = nb.permissions.get(1)
self.assertIsInstance(permission.constraints, list)
self.assertIsInstance(permission.constraints[0], dict)
class UnknownModelTestCase(unittest.TestCase):
"""This test validates that an unknown model is returned as Record object
and that the __str__() method correctly uses the 'display' field of the
object (introduced as a standard field in NetBox 2.11.0).
"""
@patch(
"requests.sessions.Session.get",
return_value=Response(fixture="users/unknown_model.json"),
)
def test_unknown_model(self, _):
unknown_obj = nb.unknown_model.get(1)
self.assertEqual(type(unknown_obj), pynetbox.core.response.Record)
self.assertEqual(str(unknown_obj), "Unknown object")
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/test_virtualization.py 0000644 0001751 0001751 00000005422 15136437134 020714 0 ustar 00runner runner import unittest
from unittest.mock import patch
import pynetbox
from .util import Response
api = pynetbox.api(
"http://localhost:8000",
)
nb = api.virtualization
HEADERS = {"accept": "application/json"}
class Generic:
class Tests(unittest.TestCase):
name = ""
ret = pynetbox.core.response.Record
app = "virtualization"
def test_get_all(self):
with patch(
"requests.sessions.Session.get",
return_value=Response(fixture="{}/{}.json".format(self.app, self.name)),
) as mock:
ret = list(getattr(nb, self.name).all())
self.assertTrue(ret)
self.assertTrue(isinstance(ret[0], self.ret))
mock.assert_called_with(
"http://localhost:8000/api/{}/{}/".format(
self.app, self.name.replace("_", "-")
),
params={"limit": 0},
json=None,
headers=HEADERS,
)
def test_filter(self):
with patch(
"requests.sessions.Session.get",
return_value=Response(fixture="{}/{}.json".format(self.app, self.name)),
) as mock:
ret = list(getattr(nb, self.name).filter(name="test"))
self.assertTrue(ret)
self.assertTrue(isinstance(ret[0], self.ret))
mock.assert_called_with(
"http://localhost:8000/api/{}/{}/".format(
self.app, self.name.replace("_", "-")
),
params={"name": "test", "limit": 0},
json=None,
headers=HEADERS,
)
def test_get(self):
with patch(
"requests.sessions.Session.get",
return_value=Response(
fixture="{}/{}.json".format(self.app, self.name[:-1])
),
) as mock:
ret = getattr(nb, self.name).get(1)
self.assertTrue(ret)
self.assertTrue(isinstance(ret, self.ret))
mock.assert_called_with(
"http://localhost:8000/api/{}/{}/1/".format(
self.app, self.name.replace("_", "-")
),
params={},
json=None,
headers=HEADERS,
)
class ClusterTypesTestCase(Generic.Tests):
name = "cluster_types"
class ClusterGroupsTestCase(Generic.Tests):
name = "cluster_groups"
class ClustersTestCase(Generic.Tests):
name = "clusters"
class VirtualMachinesTestCase(Generic.Tests):
name = "virtual_machines"
class InterfacesTestCase(Generic.Tests):
name = "interfaces"
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/test_wireless.py 0000644 0001751 0001751 00000005533 15136437134 017470 0 ustar 00runner runner import unittest
from unittest.mock import patch
import pynetbox
from .util import Response
api = pynetbox.api("http://localhost:8000")
nb_app = api.wireless
HEADERS = {"accept": "application/json"}
class Generic:
class Tests(unittest.TestCase):
name = ""
ret = pynetbox.core.response.Record
app = "wireless"
def test_get_all(self):
with patch(
"requests.sessions.Session.get",
return_value=Response(fixture="{}/{}.json".format(self.app, self.name)),
) as mock:
ret = list(getattr(nb_app, self.name).all())
self.assertTrue(ret)
self.assertTrue(isinstance(ret[0], self.ret))
mock.assert_called_with(
"http://localhost:8000/api/{}/{}/".format(
self.app, self.name.replace("_", "-")
),
params={"limit": 0},
json=None,
headers=HEADERS,
)
def test_filter(self):
with patch(
"requests.sessions.Session.get",
return_value=Response(fixture="{}/{}.json".format(self.app, self.name)),
) as mock:
ret = list(getattr(nb_app, self.name).filter(name="test"))
self.assertTrue(ret)
self.assertTrue(isinstance(ret[0], self.ret))
mock.assert_called_with(
"http://localhost:8000/api/{}/{}/".format(
self.app, self.name.replace("_", "-")
),
params={"name": "test", "limit": 0},
json=None,
headers=HEADERS,
)
def test_get(self):
with patch(
"requests.sessions.Session.get",
return_value=Response(
fixture="{}/{}.json".format(self.app, self.name[:-1])
),
) as mock:
ret = getattr(nb_app, self.name).get(1)
self.assertTrue(ret)
self.assertTrue(isinstance(ret, self.ret))
mock.assert_called_with(
"http://localhost:8000/api/{}/{}/1/".format(
self.app, self.name.replace("_", "-")
),
params={},
json=None,
headers=HEADERS,
)
class WirelessLansTestCase(Generic.Tests):
name = "wireless_lans"
@patch(
"requests.sessions.Session.get",
return_value=Response(fixture="wireless/wireless_lan.json"),
)
def test_repr(self, _):
wireless_lan_obj = nb_app.wireless_lans.get(1)
self.assertEqual(type(wireless_lan_obj), pynetbox.models.wireless.WirelessLans)
self.assertEqual(str(wireless_lan_obj), "SSID 1")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1769619043.8223305
pynetbox-7.6.1/tests/unit/ 0000755 0001751 0001751 00000000000 15136437144 015174 5 ustar 00runner runner ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/unit/__init__.py 0000644 0001751 0001751 00000000000 15136437134 017272 0 ustar 00runner runner ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/unit/test_detailendpoint.py 0000644 0001751 0001751 00000005053 15136437134 021612 0 ustar 00runner runner import unittest
from unittest.mock import patch
import pynetbox
nb = pynetbox.api("http://localhost:8000")
class DetailEndpointTestCase(unittest.TestCase):
def test_detail_endpoint_create_single(self):
# Prefixes
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")
# IP Ranges
with patch(
"pynetbox.core.query.Request._make_call",
return_value={"id": 321, "display": "1.2.4.1-254/24"},
):
ip_range_obj = nb.ipam.ip_ranges.get(321)
self.assertEqual(ip_range_obj.display, "1.2.4.1-254/24")
with patch(
"pynetbox.core.query.Request._make_call",
return_value={"address": "1.2.4.2/24"},
):
ip_obj = ip_range_obj.available_ips.create()
self.assertEqual(ip_obj.address, "1.2.4.2/24")
def test_detail_endpoint_create_list(self):
# Prefixes
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)
# IP Ranges
with patch(
"pynetbox.core.query.Request._make_call",
return_value={"id": 321, "display": "1.2.4.1-254/24"},
):
ip_range_obj = nb.ipam.ip_ranges.get(321)
self.assertEqual(ip_range_obj.display, "1.2.4.1-254/24")
with patch(
"pynetbox.core.query.Request._make_call",
return_value=[{"address": "1.2.4.2/24"}, {"address": "1.2.4.3/24"}],
):
ip_list = ip_range_obj.available_ips.create([{} for _ in range(2)])
self.assertTrue(isinstance(ip_list, list))
self.assertEqual(len(ip_list), 2)
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/unit/test_endpoint.py 0000644 0001751 0001751 00000022676 15136437134 020441 0 ustar 00runner runner import unittest
from unittest.mock import Mock, patch
from pynetbox.core.endpoint import Endpoint
class EndPointTestCase(unittest.TestCase):
def test_filter(self):
with patch(
"pynetbox.core.query.Request._make_call", return_value=Mock()
) as mock:
api = Mock(base_url="http://localhost:8000/api", strict_filters=False)
app = Mock(name="test")
mock.return_value = [{"id": 123}, {"id": 321}]
test_obj = Endpoint(api, app, "test")
test = test_obj.filter(test="test")
self.assertEqual(len(test), 2)
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(offset=1)
def test_filter_replace_none_with_null(self):
api = Mock(base_url="http://localhost:8000/api", strict_filters=False)
app = Mock(name="test")
test_obj = Endpoint(api, app, "test")
test = test_obj.filter(name=None, id=0)
self.assertEqual(test.request.filters, {"name": "null", "id": 0})
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.all(offset=1)
def test_choices(self):
with patch("pynetbox.core.query.Request.options", return_value=Mock()) as mock:
api = Mock(base_url="http://localhost:8000/api")
app = Mock(name="test")
mock.return_value = {
"actions": {
"POST": {
"letter": {
"choices": [
{"display_name": "A", "value": 1},
{"display_name": "B", "value": 2},
{"display_name": "C", "value": 3},
]
}
}
}
}
test_obj = Endpoint(api, app, "test")
choices = test_obj.choices()
self.assertEqual(choices["letter"][1]["display_name"], "B")
self.assertEqual(choices["letter"][1]["value"], 2)
def test_choices_put(self):
with patch("pynetbox.core.query.Request.options", return_value=Mock()) as mock:
api = Mock(base_url="http://localhost:8000/api")
app = Mock(name="test")
mock.return_value = {
"actions": {
"PUT": {
"letter": {
"choices": [
{"display_name": "A", "value": 1},
{"display_name": "B", "value": 2},
{"display_name": "C", "value": 3},
]
}
}
}
}
test_obj = Endpoint(api, app, "test")
choices = test_obj.choices()
self.assertEqual(choices["letter"][0]["display_name"], "A")
self.assertEqual(choices["letter"][0]["value"], 1)
def test_choices_precedence(self):
with patch("pynetbox.core.query.Request.options", return_value=Mock()) as mock:
api = Mock(base_url="http://localhost:8000/api")
app = Mock(name="test")
mock.return_value = {
"actions": {
"POST": {
"letter": {
"choices": [
{"display_name": "A", "value": 1},
{"display_name": "B", "value": 2},
{"display_name": "C", "value": 3},
]
}
},
"PUT": {
"letter": {
"choices": [
{"display_name": "D", "value": 4},
{"display_name": "E", "value": 5},
{"display_name": "F", "value": 6},
]
}
},
}
}
test_obj = Endpoint(api, app, "test")
choices = test_obj.choices()
self.assertEqual(choices["letter"][2]["display_name"], "C")
self.assertEqual(choices["letter"][2]["value"], 3)
def test_get_with_filter(self):
with patch(
"pynetbox.core.query.Request._make_call", return_value=Mock()
) as mock:
mock.return_value = [{"id": 123}]
api = Mock(base_url="http://localhost:8000/api", strict_filters=False)
app = Mock(name="test")
test_obj = Endpoint(api, app, "test")
test = test_obj.get(name="test")
self.assertEqual(test.id, 123)
def test_delete_with_ids(self):
with patch(
"pynetbox.core.query.Request._make_call", return_value=Mock()
) as mock:
ids = [1, 3, 5]
mock.return_value = True
api = Mock(base_url="http://localhost:8000/api")
app = Mock(name="test")
test_obj = Endpoint(api, app, "test")
test = test_obj.delete(ids)
mock.assert_called_with(verb="delete", data=[{"id": i} for i in ids])
self.assertTrue(test)
def test_delete_with_objects(self):
with patch(
"pynetbox.core.query.Request._make_call", return_value=Mock()
) as mock:
from pynetbox.core.response import Record
ids = [1, 3, 5]
mock.return_value = True
api = Mock(base_url="http://localhost:8000/api")
app = Mock(name="test")
test_obj = Endpoint(api, app, "test")
objects = [
Record({"id": i, "name": "dummy" + str(i)}, api, test_obj) for i in ids
]
test = test_obj.delete(objects)
mock.assert_called_with(verb="delete", data=[{"id": i} for i in ids])
self.assertTrue(test)
def test_delete_with_recordset(self):
with patch(
"pynetbox.core.query.Request._make_call", return_value=Mock()
) as mock:
from pynetbox.core.response import RecordSet
ids = [1, 3, 5]
class FakeRequest:
def get(self):
return iter([{"id": i, "name": "dummy" + str(i)} for i in ids])
mock.return_value = True
api = Mock(base_url="http://localhost:8000/api")
app = Mock(name="test")
test_obj = Endpoint(api, app, "test")
recordset = RecordSet(test_obj, FakeRequest())
test = test_obj.delete(recordset)
mock.assert_called_with(verb="delete", data=[{"id": i} for i in ids])
self.assertTrue(test)
def test_get_greater_than_one(self):
with patch(
"pynetbox.core.query.Request._make_call", return_value=Mock()
) as mock:
mock.return_value = [{"id": 123}, {"id": 321}]
api = Mock(base_url="http://localhost:8000/api", strict_filters=False)
app = Mock(name="test")
test_obj = Endpoint(api, app, "test")
with self.assertRaises(ValueError) as _:
test_obj.get(name="test")
def test_get_no_results(self):
with patch(
"pynetbox.core.query.Request._make_call", return_value=Mock()
) as mock:
mock.return_value = []
api = Mock(base_url="http://localhost:8000/api", strict_filters=False)
app = Mock(name="test")
test_obj = Endpoint(api, app, "test")
test = test_obj.get(name="test")
self.assertIsNone(test)
def test_bulk_update_records(self):
with patch(
"pynetbox.core.query.Request._make_call", return_value=Mock()
) as mock:
from pynetbox.core.response import Record
ids = [1, 3, 5]
mock.return_value = True
api = Mock(base_url="http://localhost:8000/api")
app = Mock(name="test")
test_obj = Endpoint(api, app, "test")
objects = [
Record(
{"id": i, "name": "dummy" + str(i), "unchanged": "yes"},
api,
test_obj,
)
for i in ids
]
for o in objects:
o.name = "fluffy" + str(o.id)
mock.return_value = [o.serialize() for o in objects]
test = test_obj.update(objects)
mock.assert_called_with(
verb="patch", data=[{"id": i, "name": "fluffy" + str(i)} for i in ids]
)
self.assertTrue(test)
def test_bulk_update_json(self):
with patch(
"pynetbox.core.query.Request._make_call", return_value=Mock()
) as mock:
ids = [1, 3, 5]
changes = [{"id": i, "name": "puffy" + str(i)} for i in ids]
mock.return_value = True
api = Mock(base_url="http://localhost:8000/api")
app = Mock(name="test")
mock.return_value = changes
test_obj = Endpoint(api, app, "test")
test = test_obj.update(changes)
mock.assert_called_with(verb="patch", data=changes)
self.assertTrue(test)
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/unit/test_endpoint_strict_filter.py 0000644 0001751 0001751 00000003705 15136437134 023366 0 ustar 00runner runner import unittest
from unittest.mock import Mock
from tests.util import openapi_mock
from pynetbox.core.endpoint import Endpoint
from pynetbox import ParameterValidationError
class StrictFilterTestCase(unittest.TestCase):
def test_filter_strict_valid_kwargs(self):
api = Mock(
base_url="http://localhost:8000/api",
strict_filters=True,
openapi=openapi_mock,
)
app = Mock(name="test")
app.name = "test"
test_obj = Endpoint(api, app, "test")
test_obj.filter(test="test")
def test_filter_strict_invalid_kwarg(self):
api = Mock(
base_url="http://localhost:8000/api",
strict_filters=True,
openapi=openapi_mock,
)
app = Mock(name="test")
app.name = "test"
test_obj = Endpoint(api, app, "test")
with self.assertRaises(ParameterValidationError):
test_obj.filter(very_invalid_kwarg="test")
def test_filter_strict_per_request_disable_invalid_kwarg(self):
api = Mock(
base_url="http://localhost:8000/api",
strict_filters=True, # Enable globally
openapi=openapi_mock,
)
app = Mock(name="test")
app.name = "test"
test_obj = Endpoint(api, app, "test")
# Disable strict_filters only for this specific request
test_obj.filter(very_invalid_kwarg="test", strict_filters=False)
def test_filter_strict_per_request_enable_invalid_kwarg(self):
api = Mock(
base_url="http://localhost:8000/api",
strict_filters=False, # Disable globally
openapi=openapi_mock,
)
app = Mock(name="test")
app.name = "test"
test_obj = Endpoint(api, app, "test")
with self.assertRaises(ParameterValidationError):
# Enable strict_filters only for this specific request
test_obj.filter(very_invalid_kwarg="test", strict_filters=True)
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/unit/test_extras.py 0000644 0001751 0001751 00000002354 15136437134 020116 0 ustar 00runner runner import unittest
from pynetbox.models.extras import ConfigContexts
class ExtrasTestCase(unittest.TestCase):
def test_config_contexts(self):
test_values = {
"data": {
"test_int": 123,
"test_str": "testing",
"test_list": [1, 2, 3],
}
}
test = ConfigContexts(test_values, None, None)
self.assertTrue(test)
def test_config_contexts_diff_str(self):
test_values = {
"data": {
"test_int": 123,
"test_str": "testing",
"test_list": [1, 2, 3],
"test_dict": {"foo": "bar"},
}
}
test = ConfigContexts(test_values, None, None)
test.data["test_str"] = "bar"
self.assertEqual(test._diff(), {"data"})
def test_config_contexts_diff_dict(self):
test_values = {
"data": {
"test_int": 123,
"test_str": "testing",
"test_list": [1, 2, 3],
"test_dict": {"foo": "bar"},
}
}
test = ConfigContexts(test_values, None, None)
test.data["test_dict"].update({"bar": "foo"})
self.assertEqual(test._diff(), {"data"})
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/unit/test_file_upload.py 0000644 0001751 0001751 00000021037 15136437134 021072 0 ustar 00runner runner """Tests for file upload/multipart support."""
import io
import unittest
from unittest.mock import Mock, patch
from pynetbox.core.query import Request, _extract_files, _is_file_like
from pynetbox.core.endpoint import Endpoint
class TestIsFileLike(unittest.TestCase):
"""Tests for _is_file_like helper function."""
def test_file_object(self):
"""File objects should be detected as file-like."""
f = io.BytesIO(b"test content")
self.assertTrue(_is_file_like(f))
def test_string_io(self):
"""StringIO objects should be detected as file-like."""
f = io.StringIO("test content")
self.assertTrue(_is_file_like(f))
def test_string(self):
"""Strings should not be detected as file-like."""
self.assertFalse(_is_file_like("test"))
def test_bytes(self):
"""Bytes should not be detected as file-like."""
self.assertFalse(_is_file_like(b"test"))
def test_dict(self):
"""Dicts should not be detected as file-like."""
self.assertFalse(_is_file_like({"key": "value"}))
def test_none(self):
"""None should not be detected as file-like."""
self.assertFalse(_is_file_like(None))
def test_non_callable_read_attribute(self):
"""Objects with non-callable read attribute should not be file-like."""
class FakeFile:
read = "not a method"
self.assertFalse(_is_file_like(FakeFile()))
class TestExtractFiles(unittest.TestCase):
"""Tests for _extract_files helper function."""
def test_no_files(self):
"""Data without files should return unchanged."""
data = {"name": "test", "device": 1}
clean_data, files = _extract_files(data)
self.assertEqual(clean_data, {"name": "test", "device": 1})
self.assertIsNone(files)
def test_extract_file_object(self):
"""File objects should be extracted from data."""
file_obj = io.BytesIO(b"test content")
data = {"name": "test", "image": file_obj}
clean_data, files = _extract_files(data)
self.assertEqual(clean_data, {"name": "test"})
self.assertIn("image", files)
self.assertEqual(files["image"][0], "image") # filename defaults to key
self.assertEqual(files["image"][1], file_obj)
def test_extract_file_with_name_attribute(self):
"""File objects with name attribute should use that as filename."""
file_obj = io.BytesIO(b"test content")
file_obj.name = "/path/to/image.png"
data = {"name": "test", "image": file_obj}
clean_data, files = _extract_files(data)
self.assertEqual(files["image"][0], "image.png") # basename extracted
def test_tuple_format(self):
"""Files passed as tuples should be preserved."""
file_obj = io.BytesIO(b"test content")
data = {"name": "test", "image": ("custom_name.png", file_obj, "image/png")}
clean_data, files = _extract_files(data)
self.assertEqual(clean_data, {"name": "test"})
self.assertEqual(files["image"], ("custom_name.png", file_obj, "image/png"))
def test_non_dict_data(self):
"""Non-dict data should be returned unchanged."""
data = [{"id": 1}, {"id": 2}]
result_data, files = _extract_files(data)
self.assertEqual(result_data, data)
self.assertIsNone(files)
class TestRequestWithFiles(unittest.TestCase):
"""Tests for Request._make_call with file uploads."""
def test_post_with_files_uses_multipart(self):
"""POST with files should use multipart/form-data."""
mock_session = Mock()
mock_session.post.return_value.ok = True
mock_session.post.return_value.status_code = 201
mock_session.post.return_value.json.return_value = {"id": 1, "name": "test"}
file_obj = io.BytesIO(b"test content")
req = Request(
base="http://localhost:8000/api/extras/image-attachments",
http_session=mock_session,
token="testtoken",
)
req._make_call(
verb="post",
data={"object_type": "dcim.device", "object_id": 1, "image": file_obj},
)
# Verify multipart was used (data= instead of json=)
mock_session.post.assert_called_once()
call_kwargs = mock_session.post.call_args
self.assertIn("data", call_kwargs.kwargs)
self.assertIn("files", call_kwargs.kwargs)
self.assertNotIn("json", call_kwargs.kwargs)
# Verify Content-Type was not set (requests handles it for multipart)
headers = call_kwargs.kwargs["headers"]
self.assertNotIn("Content-Type", headers)
self.assertEqual(headers["accept"], "application/json")
self.assertEqual(headers["authorization"], "Token testtoken")
def test_post_without_files_uses_json(self):
"""POST without files should use JSON."""
mock_session = Mock()
mock_session.post.return_value.ok = True
mock_session.post.return_value.status_code = 201
mock_session.post.return_value.json.return_value = {"id": 1, "name": "test"}
req = Request(
base="http://localhost:8000/api/dcim/devices",
http_session=mock_session,
token="testtoken",
)
req._make_call(verb="post", data={"name": "test-device", "site": 1})
mock_session.post.assert_called_once()
call_kwargs = mock_session.post.call_args
self.assertIn("json", call_kwargs.kwargs)
self.assertNotIn("files", call_kwargs.kwargs)
self.assertEqual(
call_kwargs.kwargs["headers"]["Content-Type"], "application/json"
)
def test_patch_with_files_uses_multipart(self):
"""PATCH with files should use multipart/form-data."""
mock_session = Mock()
mock_session.patch.return_value.ok = True
mock_session.patch.return_value.status_code = 200
mock_session.patch.return_value.json.return_value = {"id": 1, "name": "test"}
file_obj = io.BytesIO(b"new content")
req = Request(
base="http://localhost:8000/api/extras/image-attachments",
http_session=mock_session,
token="testtoken",
key=1,
)
req._make_call(verb="patch", data={"image": file_obj})
mock_session.patch.assert_called_once()
call_kwargs = mock_session.patch.call_args
self.assertIn("data", call_kwargs.kwargs)
self.assertIn("files", call_kwargs.kwargs)
def test_patch_without_files_uses_json(self):
"""PATCH without files should use JSON and set Content-Type."""
mock_session = Mock()
mock_session.patch.return_value.ok = True
mock_session.patch.return_value.status_code = 200
mock_session.patch.return_value.json.return_value = {"id": 1, "name": "updated"}
req = Request(
base="http://localhost:8000/api/dcim/devices",
http_session=mock_session,
token="testtoken",
key=1,
)
req._make_call(verb="patch", data={"name": "updated-device"})
mock_session.patch.assert_called_once()
call_kwargs = mock_session.patch.call_args
self.assertIn("json", call_kwargs.kwargs)
self.assertNotIn("files", call_kwargs.kwargs)
self.assertEqual(
call_kwargs.kwargs["headers"]["Content-Type"], "application/json"
)
class TestEndpointCreateWithFiles(unittest.TestCase):
"""Tests for Endpoint.create() with file uploads."""
def test_create_image_attachment(self):
"""Creating image attachment should work with file objects."""
with patch("pynetbox.core.query.Request._make_call") as mock_call:
mock_call.return_value = {
"id": 1,
"object_type": "dcim.device",
"object_id": 1,
"image": "/media/image-attachments/test.png",
"name": "test.png",
}
api = Mock(base_url="http://localhost:8000/api")
app = Mock(name="extras")
endpoint = Endpoint(api, app, "image_attachments")
file_obj = io.BytesIO(b"fake image content")
endpoint.create(
object_type="dcim.device", object_id=1, image=file_obj, name="test.png"
)
mock_call.assert_called_once()
call_kwargs = mock_call.call_args
self.assertEqual(call_kwargs.kwargs["verb"], "post")
data = call_kwargs.kwargs["data"]
self.assertEqual(data["object_type"], "dcim.device")
self.assertEqual(data["object_id"], 1)
self.assertEqual(data["image"], file_obj)
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 010213 x ustar 00 22 mtime=1769619036.0
pynetbox-7.6.1/tests/unit/test_multiformat_endpoint.py 0000644 0001751 0001751 00000012107 15136437134 023050 0 ustar 00runner runner """Tests for ROMultiFormatDetailEndpoint."""
import unittest
from unittest.mock import patch
import pynetbox
class ROMultiFormatDetailEndpointTestCase(unittest.TestCase):
"""Test cases for ROMultiFormatDetailEndpoint class."""
def setUp(self):
"""Set up test fixtures."""
self.nb = pynetbox.api("http://localhost:8000", token="test-token")
def test_list_returns_json_by_default(self):
"""list() without render parameter returns JSON data."""
with patch(
"pynetbox.core.query.Request._make_call",
return_value={"id": 123, "name": "Test Rack"},
):
rack = self.nb.dcim.racks.get(123)
with patch(
"pynetbox.core.query.Request._make_call",
return_value=[
{"id": 1, "name": "U1"},
{"id": 2, "name": "U2"},
],
):
result = rack.elevation.list()
# Should return generator that yields dict items
result_list = list(result)
self.assertEqual(len(result_list), 2)
# Verify custom_return was applied (RUs objects)
self.assertTrue(hasattr(result_list[0], "id"))
def test_list_with_render_svg_returns_raw_string(self):
"""list(render='svg') returns raw SVG string."""
with patch(
"pynetbox.core.query.Request._make_call",
return_value={"id": 123, "name": "Test Rack"},
):
rack = self.nb.dcim.racks.get(123)
svg_content = ''
with patch(
"pynetbox.core.query.Request._make_call",
return_value=svg_content,
):
result = rack.elevation.list(render="svg")
# Should return raw string, not wrapped in list
self.assertIsInstance(result, str)
self.assertEqual(result, svg_content)
self.assertIn("