diff --git a/.cookiecutter.json b/.cookiecutter.json
index 00920d54..35a512b4 100644
--- a/.cookiecutter.json
+++ b/.cookiecutter.json
@@ -13,7 +13,7 @@
"min_nautobot_version": "2.0.0",
"max_nautobot_version": "2.9999",
"camel_name": "NautobotCircuitMaintenance",
- "project_short_description": "Nautobot app to automatically handle Circuit Maintenances Notifications",
+ "project_short_description": "Nautobot App that automatically manages network circuit maintenance notifications. Dynamically reads email inboxes (or APIs) and updates Nautobot mapping circuit maintenances to devices",
"model_class_name": "None",
"open_source_license": "Apache-2.0",
"docs_base_url": "https://docs.nautobot.com",
@@ -21,7 +21,7 @@
"_drift_manager": {
"template": "https://github.com/nautobot/cookiecutter-nautobot-app.git",
"template_dir": "nautobot-app",
- "template_ref": "refs/tags/nautobot-app-v2.2.0",
+ "template_ref": "refs/tags/nautobot-app-v2.3.2",
"cookie_dir": "",
"branch_prefix": "drift-manager",
"pull_request_strategy": "create",
@@ -29,7 +29,7 @@
"black"
],
"draft": true,
- "baked_commit_ref": "5d47e90f9673571d6ec5aedd45f97497a114e23e"
+ "baked_commit_ref": "a05eb77056d979eb079934d35bda706b247b18e6"
}
}
}
diff --git a/.dockerignore b/.dockerignore
index c8c9a47d..a0bf06f4 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -18,8 +18,7 @@ docs/_build
FAQ.md
.git/
.gitignore
-.github/
-tasks.py
+.github
LICENSE
**/*.log
**/.vscode/
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index c3d46652..fcc6db95 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -13,10 +13,10 @@ on: # yamllint disable-line rule:truthy rule:comments
pull_request: ~
env:
- APP_NAME: "nautobot-app-circuit-maintenance"
+ APP_NAME: "nautobot-circuit-maintenance"
jobs:
- black:
+ ruff-format:
runs-on: "ubuntu-22.04"
env:
INVOKE_NAUTOBOT_CIRCUIT_MAINTENANCE_LOCAL: "True"
@@ -25,20 +25,9 @@ jobs:
uses: "actions/checkout@v4"
- name: "Setup environment"
uses: "networktocode/gh-action-setup-poetry-environment@v6"
- - name: "Linting: black"
- run: "poetry run invoke black"
- bandit:
- runs-on: "ubuntu-22.04"
- env:
- INVOKE_NAUTOBOT_CIRCUIT_MAINTENANCE_LOCAL: "True"
- steps:
- - name: "Check out repository code"
- uses: "actions/checkout@v4"
- - name: "Setup environment"
- uses: "networktocode/gh-action-setup-poetry-environment@v6"
- - name: "Linting: bandit"
- run: "poetry run invoke bandit"
- ruff:
+ - name: "Linting: ruff format"
+ run: "poetry run invoke ruff --action format"
+ ruff-lint:
runs-on: "ubuntu-22.04"
env:
INVOKE_NAUTOBOT_CIRCUIT_MAINTENANCE_LOCAL: "True"
@@ -60,17 +49,6 @@ jobs:
uses: "networktocode/gh-action-setup-poetry-environment@v6"
- name: "Check Docs Build"
run: "poetry run invoke build-and-check-docs"
- flake8:
- runs-on: "ubuntu-22.04"
- env:
- INVOKE_NAUTOBOT_CIRCUIT_MAINTENANCE_LOCAL: "True"
- steps:
- - name: "Check out repository code"
- uses: "actions/checkout@v4"
- - name: "Setup environment"
- uses: "networktocode/gh-action-setup-poetry-environment@v6"
- - name: "Linting: flake8"
- run: "poetry run invoke flake8"
poetry:
runs-on: "ubuntu-22.04"
env:
@@ -95,12 +73,10 @@ jobs:
run: "poetry run invoke yamllint"
check-in-docker:
needs:
- - "bandit"
- - "ruff"
- - "flake8"
+ - "ruff-format"
+ - "ruff-lint"
- "poetry"
- "yamllint"
- - "black"
runs-on: "ubuntu-22.04"
strategy:
fail-fast: true
@@ -115,6 +91,10 @@ jobs:
uses: "actions/checkout@v4"
- name: "Setup environment"
uses: "networktocode/gh-action-setup-poetry-environment@v6"
+ - name: "Constrain Nautobot version and regenerate lock file"
+ env:
+ INVOKE_NAUTOBOT_CIRCUIT_MAINTENANCE_LOCAL: "true"
+ run: "poetry run invoke lock --constrain-nautobot-ver --constrain-python-ver"
- name: "Set up Docker Buildx"
id: "buildx"
uses: "docker/setup-buildx-action@v3"
@@ -132,6 +112,7 @@ jobs:
build-args: |
NAUTOBOT_VER=${{ matrix.nautobot-version }}
PYTHON_VER=${{ matrix.python-version }}
+ CI=true
- name: "Copy credentials"
run: "cp development/creds.example.env development/creds.env"
- name: "Linting: pylint"
@@ -146,14 +127,14 @@ jobs:
strategy:
fail-fast: true
matrix:
- python-version: ["3.8", "3.11"]
+ python-version: ["3.8", "3.12"]
db-backend: ["postgresql"]
nautobot-version: ["stable"]
include:
- python-version: "3.11"
db-backend: "postgresql"
nautobot-version: "2.0.0"
- - python-version: "3.11"
+ - python-version: "3.12"
db-backend: "mysql"
nautobot-version: "stable"
runs-on: "ubuntu-22.04"
@@ -182,6 +163,7 @@ jobs:
build-args: |
NAUTOBOT_VER=${{ matrix.nautobot-version }}
PYTHON_VER=${{ matrix.python-version }}
+ CI=true
- name: "Copy credentials"
run: "cp development/creds.example.env development/creds.env"
- name: "Use Mysql invoke settings when needed"
@@ -220,7 +202,7 @@ jobs:
- name: "Set up Python"
uses: "actions/setup-python@v5"
with:
- python-version: "3.11"
+ python-version: "3.12"
- name: "Install Python Packages"
run: "pip install poetry"
- name: "Set env"
@@ -255,7 +237,7 @@ jobs:
- name: "Set up Python"
uses: "actions/setup-python@v5"
with:
- python-version: "3.11"
+ python-version: "3.12"
- name: "Install Python Packages"
run: "pip install poetry"
- name: "Set env"
diff --git a/README.md b/README.md
index e74da226..90e3a3d5 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@
- An App for Nautobot.
+ An App for Nautobot.
## Overview
diff --git a/development/Dockerfile b/development/Dockerfile
index 37d8d962..6c4214fa 100644
--- a/development/Dockerfile
+++ b/development/Dockerfile
@@ -57,34 +57,18 @@ RUN --mount=type=cache,target=/var/lib/apt/lists,sharing=locked \
WORKDIR /source
COPY . /source
-# Get container's installed Nautobot version as a forced constraint
-# NAUTOBOT_VER may be a branch name and not a published release therefor we need to get the installed version
-# so pip can use it to recognize local constraints.
-RUN pip show nautobot | grep "^Version: " | sed -e 's/Version: /nautobot==/' > constraints.txt
-
-# Use Poetry to grab dev dependencies from the lock file
-# Can be improved in Poetry 1.2 which allows `poetry install --only dev`
-#
-# We can't use the entire freeze as it takes forever to resolve with rigidly fixed non-direct dependencies,
-# especially those that are only direct to Nautobot but the container included versions slightly mismatch
-RUN poetry export -f requirements.txt --without-hashes --extras all --output poetry_freeze_base.txt
-RUN poetry export -f requirements.txt --without-hashes --extras all --with dev --output poetry_freeze_all.txt
-RUN sort poetry_freeze_base.txt poetry_freeze_all.txt | uniq -u > poetry_freeze_dev.txt
-
-# TBD: Verify following instruction
-# Install wheel to avoid deprecation warnings related to https://github.com/pypa/pip/issues/8559
-RUN --mount=type=cache,target=/root/.cache/pip pip install \
- wheel==0.41.1
-
-# Install all local project as editable, constrained on Nautobot version, to get any additional
-# direct dependencies of the app
-RUN --mount=type=cache,target="/root/.cache/pip",sharing=locked \
- pip install -c constraints.txt -e .[all]
-
-# Install any dev dependencies frozen from Poetry
-# Can be improved in Poetry 1.2 which allows `poetry install --only dev`
-RUN --mount=type=cache,target="/root/.cache/pip",sharing=locked \
- pip install -c constraints.txt -r poetry_freeze_dev.txt
+# Build args must be declared in each stage
+ARG PYTHON_VER
+
+# Constrain the Nautobot version to NAUTOBOT_VER
+# In CI, this should be done outside of the Dockerfile to prevent cross-compile build failures
+ARG CI
+RUN if [ -z "${CI+x}" ]; then \
+ INSTALLED_NAUTOBOT_VER=$(pip show nautobot | grep "^Version" | sed "s/Version: //"); \
+ poetry add --lock nautobot@${INSTALLED_NAUTOBOT_VER} --python ${PYTHON_VER}; fi
+
+# Install the app
+RUN poetry install --extras all --with dev
COPY development/nautobot_config.py ${NAUTOBOT_ROOT}/nautobot_config.py
diff --git a/development/nautobot_config.py b/development/nautobot_config.py
index d24c065c..e04abd38 100644
--- a/development/nautobot_config.py
+++ b/development/nautobot_config.py
@@ -11,7 +11,7 @@
# Debug
#
-DEBUG = is_truthy(os.getenv("NAUTOBOT_DEBUG", False))
+DEBUG = is_truthy(os.getenv("NAUTOBOT_DEBUG", "false"))
_TESTING = len(sys.argv) > 1 and sys.argv[1] == "test"
if DEBUG and not _TESTING:
@@ -60,9 +60,10 @@
"PASSWORD": os.getenv("NAUTOBOT_DB_PASSWORD", ""), # Database password
"HOST": os.getenv("NAUTOBOT_DB_HOST", "localhost"), # Database server
"PORT": os.getenv(
- "NAUTOBOT_DB_PORT", default_db_settings[nautobot_db_engine]["NAUTOBOT_DB_PORT"]
+ "NAUTOBOT_DB_PORT",
+ default_db_settings[nautobot_db_engine]["NAUTOBOT_DB_PORT"],
), # Database port, default to postgres
- "CONN_MAX_AGE": int(os.getenv("NAUTOBOT_DB_TIMEOUT", 300)), # Database timeout
+ "CONN_MAX_AGE": int(os.getenv("NAUTOBOT_DB_TIMEOUT", "300")), # Database timeout
"ENGINE": nautobot_db_engine,
}
}
diff --git a/docs/admin/compatibility_matrix.md b/docs/admin/compatibility_matrix.md
index d4e1f47b..02377fe5 100644
--- a/docs/admin/compatibility_matrix.md
+++ b/docs/admin/compatibility_matrix.md
@@ -4,8 +4,9 @@
| ------------- | -------------------- | ------------- |
| 0.1.1-0.6.2 | 1.0.0 | 1.99.99 |
| 1.0.0 | 1.4.0 | 1.5.99 |
-| 2.0.0-2.2.3 | 2.0.0 | 2.2.99 |
+| 2.0.0-2.2.3 | 2.0.0 | 2.2.99 |
| 2.2.4 | 2.0.0 | 2.99.99 |
+| 2.3.x | 2.0.0 | 2.99.99 |
!!! note
MySQL support added in v0.5.0
diff --git a/docs/admin/release_notes/version_2.3.md b/docs/admin/release_notes/version_2.3.md
new file mode 100644
index 00000000..a1dc04ac
--- /dev/null
+++ b/docs/admin/release_notes/version_2.3.md
@@ -0,0 +1,14 @@
+# v2.3 Release Notes
+
+
+
+## [v2.3.0 (2024-09-12)](https://github.com/nautobot/nautobot-app-circuit-maintenance/releases/tag/v2.3.0)
+
+### Added
+
+- [#319](https://github.com/nautobot/nautobot-app-circuit-maintenance/issues/319) - Added Python 3.12 support.
+
+### Housekeeping
+
+- [#317](https://github.com/nautobot/nautobot-app-circuit-maintenance/issues/317) - Rebake with 2.3 Cookiecutter.
+- [#319](https://github.com/nautobot/nautobot-app-circuit-maintenance/issues/319) - Rebake with nautobot-app-v2.3.2 Cookiecutter.
diff --git a/docs/assets/extra.css b/docs/assets/extra.css
index 1eff1192..3f3931a0 100644
--- a/docs/assets/extra.css
+++ b/docs/assets/extra.css
@@ -96,7 +96,7 @@ a.autorefs-external:hover::after {
}
-/* Customization for mkdocs-version-annotations */
+/* Customization for markdown-version-annotations */
:root {
/* Icon for "version-added" admonition: Material Design Icons "plus-box-outline" */
--md-admonition-icon--version-added: url('data:image/svg+xml;charset=utf-8,');
diff --git a/docs/dev/contributing.md b/docs/dev/contributing.md
index 97002f63..43a56288 100644
--- a/docs/dev/contributing.md
+++ b/docs/dev/contributing.md
@@ -4,7 +4,7 @@ The project is packaged with a light [development environment](dev_environment.m
The project is following Network to Code software development guidelines and is leveraging the following:
-- Python linting and formatting: `black`, `pylint`, `bandit`, `flake8`, and `ruff`.
+- Python linting and formatting: `pylint` and `ruff`.
- YAML linting is done with `yamllint`.
- Django unit test to ensure the app is working properly.
@@ -47,7 +47,7 @@ The branching policy includes the following tenets:
- PRs intended to add new features should be sourced from the `develop` branch.
- PRs intended to fix issues in the Nautobot LTM compatible release should be sourced from the latest `ltm-` branch instead of `develop`.
-Circuit Maintenance will observe semantic versioning, as of 1.0. This may result in a quick turnaround in minor versions to keep pace with an ever growing feature set.
+Circuit Maintenance will observe semantic versioning, as of 1.0. This may result in a quick turnaround in minor versions to keep pace with an ever-growing feature set.
## Release Policy
@@ -56,17 +56,17 @@ Circuit Maintenance has currently no intended scheduled release schedule, and wi
When a new release, from `develop` to `main`, is created the following should happen.
- A release PR is created from `develop` with:
- - Update the release notes in `docs/admin/release_notes/version_..md` file to reflect the changes.
- - Change the version from `..-beta` to `..` in `pyproject.toml`.
- - Set the PR to the `main` branch.
+ - Update the release notes in `docs/admin/release_notes/version_..md` file to reflect the changes.
+ - Change the version from `..-beta` to `..` in `pyproject.toml`.
+ - Set the PR to the `main` branch.
- Ensure the tests for the PR pass.
- Merge the PR.
- Create a new tag:
- - The tag should be in the form of `v..`.
- - The title should be in the form of `v..`.
- - The description should be the changes that were added to the `version_..md` document.
+ - The tag should be in the form of `v..`.
+ - The title should be in the form of `v..`.
+ - The description should be the changes that were added to the `version_..md` document.
- If merged into `main`, then push from `main` to `develop`, in order to retain the merge commit created when the PR was merged
- A post release PR is created with:
- - Change the version from `..` to `..-beta` in both `pyproject.toml` and `nautobot.__init__.__version__`.
- - Set the PR to the proper branch, `develop`.
- - Once tests pass, merge.
+ - Change the version from `..` to `..-beta` in both `pyproject.toml` and `nautobot.__init__.__version__`.
+ - Set the PR to the proper branch, `develop`.
+ - Once tests pass, merge.
diff --git a/docs/dev/dev_environment.md b/docs/dev/dev_environment.md
index 87c06cc0..2e5ee602 100644
--- a/docs/dev/dev_environment.md
+++ b/docs/dev/dev_environment.md
@@ -123,10 +123,7 @@ Each command can be executed with `invoke `. All commands support the a
#### Testing
```
- bandit Run bandit to validate basic static code security analysis.
- black Run black to check that Python files adhere to its style standards.
- flake8 Run flake8 to check that Python files adhere to its style standards.
- ruff Run ruff to validate docstring formatting adheres to NTC defined standards.
+ ruff Run ruff to perform code formatting and/or linting.
pylint Run pylint code analysis.
tests Run all tests for this app.
unittest Run Django unit tests for the app.
@@ -454,7 +451,7 @@ This is the same as running:
### Tests
-To run tests against your code, you can run all of the tests that TravisCI runs against any new PR with:
+To run tests against your code, you can run all of the tests that the CI runs against any new PR with:
```bash
➜ invoke tests
@@ -464,9 +461,6 @@ To run an individual test, you can run any or all of the following:
```bash
➜ invoke unittest
-➜ invoke bandit
-➜ invoke black
-➜ invoke flake8
➜ invoke ruff
➜ invoke pylint
```
diff --git a/docs/requirements.txt b/docs/requirements.txt
index d168c88f..bf10c13b 100644
--- a/docs/requirements.txt
+++ b/docs/requirements.txt
@@ -1,5 +1,6 @@
-mkdocs==1.5.2
-mkdocs-material==9.1.15
-mkdocs-version-annotations==1.0.0
-mkdocstrings-python==1.5.2
-mkdocstrings==0.22.0
+mkdocs==1.6.0
+mkdocs-material==9.5.32
+markdown-version-annotations==1.0.1
+griffe==1.1.1
+mkdocstrings-python==1.10.8
+mkdocstrings==0.25.2
diff --git a/invoke.example.yml b/invoke.example.yml
index eee8abf7..86a32102 100644
--- a/invoke.example.yml
+++ b/invoke.example.yml
@@ -1,12 +1,15 @@
---
nautobot_circuit_maintenance:
- project_name: "nautobot-circuit-maintenance"
nautobot_ver: "2.0.0"
- local: false
python_ver: "3.11"
- compose_dir: "development"
- compose_files:
- - "docker-compose.base.yml"
- - "docker-compose.redis.yml"
- - "docker-compose.postgres.yml"
- - "docker-compose.dev.yml"
+ # local: false
+ # compose_dir: "/full/path/to/nautobot-app-circuit-maintenance/development"
+
+# The following is an example of using MySQL as the database backend
+# ---
+# nautobot_circuit_maintenance:
+# compose_files:
+# - "docker-compose.base.yml"
+# - "docker-compose.redis.yml"
+# - "docker-compose.mysql.yml"
+# - "docker-compose.dev.yml"
diff --git a/mkdocs.yml b/mkdocs.yml
index 31af25d6..51c8d194 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -1,6 +1,6 @@
---
dev_addr: "127.0.0.1:8001"
-edit_uri: "edit/main/nautobot-app-circuit-maintenance/docs"
+edit_uri: "edit/main/docs"
site_dir: "nautobot_circuit_maintenance/static/nautobot_circuit_maintenance/docs"
site_name: "Circuit Maintenance Documentation"
site_url: "https://docs.nautobot.com/projects/circuit-maintenance/en/latest/"
@@ -72,6 +72,8 @@ extra:
link: "https://twitter.com/networktocode"
name: "Network to Code Twitter"
markdown_extensions:
+ - "markdown_version_annotations":
+ admonition_tag: "???"
- "admonition"
- "toc":
permalink: true
@@ -89,7 +91,6 @@ markdown_extensions:
- "footnotes"
plugins:
- "search"
- - "mkdocs-version-annotations"
- "mkdocstrings":
default_handler: "python"
handlers:
@@ -115,6 +116,7 @@ nav:
- Compatibility Matrix: "admin/compatibility_matrix.md"
- Release Notes:
- "admin/release_notes/index.md"
+ - v2.3: "admin/release_notes/version_2.3.md"
- v2.2: "admin/release_notes/version_2.2.md"
- v2.1: "admin/release_notes/version_2.1.md"
- v2.0: "admin/release_notes/version_2.0.md"
diff --git a/nautobot_circuit_maintenance/__init__.py b/nautobot_circuit_maintenance/__init__.py
index 9677794f..3bdd8644 100644
--- a/nautobot_circuit_maintenance/__init__.py
+++ b/nautobot_circuit_maintenance/__init__.py
@@ -1,5 +1,6 @@
-"""Init for Circuit Maintenance app."""
+"""App declaration for nautobot_circuit_maintenance."""
+# Metadata is inherited from Nautobot. If not including Nautobot in the environment, this should be added
from importlib import metadata
from django.apps import apps as global_apps
@@ -75,7 +76,6 @@ class CircuitMaintenanceConfig(NautobotAppConfig):
verbose_name = "Circuit Maintenance Management"
version = __version__
author = "Network to Code, LLC"
- author_email = "opensource@networktocode.com"
description = "Nautobot App that automatically manages network circuit maintenance notifications. Dynamically reads email inboxes (or APIs) and updates Nautobot mapping circuit maintenances to devices."
base_url = "circuit-maintenance"
min_version = "2.0.0"
@@ -101,6 +101,7 @@ def ready(self):
if settings.PLUGINS_CONFIG.get("nautobot_circuit_maintenance", {}).get("metrics", {}).get("enable", False):
# pylint: disable=import-outside-toplevel
from nautobot_capacity_metrics import register_metric_func
+
from .metrics_app import metric_circuit_operational
register_metric_func(metric_circuit_operational)
diff --git a/nautobot_circuit_maintenance/admin.py b/nautobot_circuit_maintenance/admin.py
index f98a12ea..1c58b147 100644
--- a/nautobot_circuit_maintenance/admin.py
+++ b/nautobot_circuit_maintenance/admin.py
@@ -1,6 +1,7 @@
"""Admin management content for this app."""
from django.contrib import admin
+
from .models import NotificationSource
diff --git a/nautobot_circuit_maintenance/api/serializers.py b/nautobot_circuit_maintenance/api/serializers.py
index b4f4d4cd..c340ff91 100644
--- a/nautobot_circuit_maintenance/api/serializers.py
+++ b/nautobot_circuit_maintenance/api/serializers.py
@@ -1,6 +1,7 @@
"""Serializer for Circuit Maintenance API."""
from nautobot.core.api.serializers import NautobotModelSerializer
+
from nautobot_circuit_maintenance.models import (
CircuitImpact,
CircuitMaintenance,
diff --git a/nautobot_circuit_maintenance/api/views.py b/nautobot_circuit_maintenance/api/views.py
index 8c0f5832..0596f1a7 100644
--- a/nautobot_circuit_maintenance/api/views.py
+++ b/nautobot_circuit_maintenance/api/views.py
@@ -1,26 +1,26 @@
"""Views for API."""
from django.contrib.contenttypes.models import ContentType
+from nautobot.apps.api import CustomFieldModelViewSet
from rest_framework import viewsets
-from nautobot.apps.api import CustomFieldModelViewSet
+from nautobot_circuit_maintenance import filters
from nautobot_circuit_maintenance.models import (
CircuitImpact,
CircuitMaintenance,
Note,
NotificationSource,
- RawNotification,
ParsedNotification,
+ RawNotification,
)
-from nautobot_circuit_maintenance import filters
from .serializers import (
+ CircuitImpactSerializer,
+ CircuitMaintenanceSerializer,
NoteSerializer,
NotificationSourceSerializer,
ParsedNotificationSerializer,
RawNotificationSerializer,
- CircuitMaintenanceSerializer,
- CircuitImpactSerializer,
)
diff --git a/nautobot_circuit_maintenance/custom_validators.py b/nautobot_circuit_maintenance/custom_validators.py
index fc444c85..105c3748 100644
--- a/nautobot_circuit_maintenance/custom_validators.py
+++ b/nautobot_circuit_maintenance/custom_validators.py
@@ -1,10 +1,9 @@
"""Custom Validators definition."""
+from circuit_maintenance_parser import SUPPORTED_PROVIDER_NAMES
from nautobot.circuits.models import Provider
-from nautobot.extras.plugins import PluginCustomValidator
from nautobot.extras.models import CustomField
-
-from circuit_maintenance_parser import SUPPORTED_PROVIDER_NAMES
+from nautobot.extras.plugins import PluginCustomValidator
class ProviderEmailValidator(PluginCustomValidator):
diff --git a/nautobot_circuit_maintenance/filters.py b/nautobot_circuit_maintenance/filters.py
index cbffa151..53d78776 100644
--- a/nautobot_circuit_maintenance/filters.py
+++ b/nautobot_circuit_maintenance/filters.py
@@ -4,17 +4,11 @@
import django_filters
from django.db.models import Q
-from nautobot.circuits.models import Circuit
-from nautobot.circuits.models import Provider
+from nautobot.circuits.models import Circuit, Provider
from nautobot.core.filters import NaturalKeyOrPKMultipleChoiceFilter
from nautobot.extras.filters import NautobotFilterSet
-from .models import CircuitImpact
-from .models import CircuitMaintenance
-from .models import Note
-from .models import NotificationSource
-from .models import ParsedNotification
-from .models import RawNotification
+from .models import CircuitImpact, CircuitMaintenance, Note, NotificationSource, ParsedNotification, RawNotification
logger = logging.getLogger(__name__)
@@ -47,9 +41,9 @@ class Meta:
"""Meta class attributes for CircuitMaintenanceFilterSet."""
model = CircuitMaintenance
- fields = ["id", "name", "status", "ack"]
+ fields = '__all__'
- def search(self, queryset, name, value): # pylint: disable=unused-argument, no-self-use
+ def search(self, queryset, name, value): # pylint: disable=unused-argument
"""Perform the filtered search."""
if not value.strip():
return queryset
@@ -77,7 +71,7 @@ class Meta:
"""Meta class attributes for CircuitImpactFilterSet."""
model = CircuitImpact
- fields = ["id", "maintenance", "circuit", "impact"]
+ fields = '__all__'
class NoteFilterSet(NautobotFilterSet):
@@ -94,9 +88,9 @@ class Meta:
"""Meta class attributes for NoteFilterSet."""
model = Note
- fields = ["id", "maintenance", "title"]
+ fields = '__all__'
- def search(self, queryset, name, value): # pylint: disable=unused-argument, no-self-use
+ def search(self, queryset, name, value): # pylint: disable=unused-argument
"""Perform the filtered search."""
if not value.strip():
return queryset
@@ -130,16 +124,9 @@ class RawNotificationFilterSet(NautobotFilterSet):
class Meta: # noqa: D106 "Missing docstring in public nested class"
model = RawNotification
- fields = [
- "subject",
- "provider",
- "sender",
- "source",
- "parsed",
- "stamp",
- ]
-
- def search(self, queryset, name, value): # pylint: disable=unused-argument, no-self-use
+ exclude = ["raw"]
+
+ def search(self, queryset, name, value): # pylint: disable=unused-argument
"""Perform the filtered search."""
if not value.strip():
return queryset
@@ -166,9 +153,9 @@ class Meta:
"""Meta class attributes for ParsedNotificationFilterSet."""
model = ParsedNotification
- fields = ["maintenance", "raw_notification", "json"]
+ fields = '__all__'
- def search(self, queryset, name, value): # pylint: disable=unused-argument, no-self-use
+ def search(self, queryset, name, value): # pylint: disable=unused-argument
"""Perform the filtered search."""
if not value.strip():
return queryset
@@ -188,9 +175,9 @@ class Meta:
"""Meta class attributes for NotificationSourceFilterSet."""
model = NotificationSource
- fields = ["name", "attach_all_providers"]
+ exclude = ["_token"]
- def search(self, queryset, name, value): # pylint: disable=unused-argument, no-self-use
+ def search(self, queryset, name, value): # pylint: disable=unused-argument
"""Perform the filtered search."""
if not value.strip():
return queryset
diff --git a/nautobot_circuit_maintenance/forms.py b/nautobot_circuit_maintenance/forms.py
index 456e59fb..023b0ca5 100644
--- a/nautobot_circuit_maintenance/forms.py
+++ b/nautobot_circuit_maintenance/forms.py
@@ -3,8 +3,16 @@
# pylint: disable=nb-incorrect-base-class
"""Forms for Circuit Maintenance."""
+
from django import forms
from django_filters.widgets import BooleanWidget
+from nautobot.apps.forms import (
+ BootstrapMixin,
+ CustomFieldModelBulkEditFormMixin,
+ CustomFieldModelFilterFormMixin,
+ CustomFieldModelFormMixin,
+ RelationshipModelFormMixin,
+)
from nautobot.circuits.models import Circuit, Provider
from nautobot.core.forms import (
DateTimePicker,
@@ -14,13 +22,6 @@
)
from nautobot.core.forms.constants import BOOLEAN_WITH_BLANK_CHOICES
from nautobot.extras.forms import AddRemoveTagsForm
-from nautobot.apps.forms import (
- BootstrapMixin,
- CustomFieldModelBulkEditFormMixin,
- CustomFieldModelFilterFormMixin,
- CustomFieldModelFormMixin,
- RelationshipModelFormMixin,
-)
from .choices import CircuitMaintenanceStatusChoices
from .models import (
@@ -31,7 +32,6 @@
RawNotification,
)
-
BLANK_CHOICE = (("", "---------"),)
diff --git a/nautobot_circuit_maintenance/handle_notifications/handler.py b/nautobot_circuit_maintenance/handle_notifications/handler.py
index 20b0f954..95066cf7 100644
--- a/nautobot_circuit_maintenance/handle_notifications/handler.py
+++ b/nautobot_circuit_maintenance/handle_notifications/handler.py
@@ -1,38 +1,34 @@
# pylint: disable=logging-fstring-interpolation
"""Notifications jobs."""
+
import datetime
import uuid
-from typing import List
-from typing import Optional
+from typing import List, Optional
-from circuit_maintenance_parser import Maintenance
-from circuit_maintenance_parser import NotificationData
-from circuit_maintenance_parser import ProviderError
-from circuit_maintenance_parser import init_provider
+from circuit_maintenance_parser import Maintenance, NotificationData, ProviderError, init_provider
from dateutil import parser
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from django.db import transaction
-from nautobot.circuits.models import Circuit
-from nautobot.circuits.models import Provider
-from nautobot.extras.jobs import Job
-from nautobot.extras.jobs import DryRunVar
+from nautobot.circuits.models import Circuit, Provider
+from nautobot.extras.jobs import DryRunVar, Job
from nautobot_circuit_maintenance.choices import CircuitMaintenanceStatusChoices
from nautobot_circuit_maintenance.enum import MessageProcessingStatus
-from nautobot_circuit_maintenance.models import MAX_MAINTENANCE_NAME_LENGTH
-from nautobot_circuit_maintenance.models import MAX_NOTE_TITLE_LENGTH
-from nautobot_circuit_maintenance.models import MAX_NOTIFICATION_SENDER_LENGTH
-from nautobot_circuit_maintenance.models import MAX_NOTIFICATION_SUBJECT_LENGTH
-from nautobot_circuit_maintenance.models import CircuitImpact
-from nautobot_circuit_maintenance.models import CircuitMaintenance
-from nautobot_circuit_maintenance.models import Note
-from nautobot_circuit_maintenance.models import NotificationSource
-from nautobot_circuit_maintenance.models import ParsedNotification
-from nautobot_circuit_maintenance.models import RawNotification
-
-from .sources import MaintenanceNotification
-from .sources import get_notifications
+from nautobot_circuit_maintenance.models import (
+ MAX_MAINTENANCE_NAME_LENGTH,
+ MAX_NOTE_TITLE_LENGTH,
+ MAX_NOTIFICATION_SENDER_LENGTH,
+ MAX_NOTIFICATION_SUBJECT_LENGTH,
+ CircuitImpact,
+ CircuitMaintenance,
+ Note,
+ NotificationSource,
+ ParsedNotification,
+ RawNotification,
+)
+
+from .sources import MaintenanceNotification, get_notifications
name = "Circuit Maintenance" # pylint: disable=invalid-name
diff --git a/nautobot_circuit_maintenance/handle_notifications/sources.py b/nautobot_circuit_maintenance/handle_notifications/sources.py
index f434a978..07493bad 100644
--- a/nautobot_circuit_maintenance/handle_notifications/sources.py
+++ b/nautobot_circuit_maintenance/handle_notifications/sources.py
@@ -8,14 +8,7 @@
import logging
import os
import re
-from typing import Dict
-from typing import Iterable
-from typing import List
-from typing import Optional
-from typing import Tuple
-from typing import Type
-from typing import TypeVar
-from typing import Union
+from typing import Dict, Iterable, List, Optional, Tuple, Type, TypeVar, Union
from urllib.parse import urlparse
try:
@@ -29,8 +22,7 @@
from google.auth.transport.requests import Request
from google.oauth2 import service_account
from google.oauth2.credentials import Credentials
-from googleapiclient.discovery import Resource
-from googleapiclient.discovery import build
+from googleapiclient.discovery import Resource, build
from googleapiclient.errors import HttpError
from nautobot.circuits.models import Provider
from nautobot.extras.jobs import Job
diff --git a/nautobot_circuit_maintenance/jobs/__init__.py b/nautobot_circuit_maintenance/jobs/__init__.py
index 799a1aec..6273621f 100644
--- a/nautobot_circuit_maintenance/jobs/__init__.py
+++ b/nautobot_circuit_maintenance/jobs/__init__.py
@@ -5,7 +5,6 @@
from nautobot_circuit_maintenance.handle_notifications.handler import HandleCircuitMaintenanceNotifications
from nautobot_circuit_maintenance.jobs.location_search import FindLocationsWithMaintenanceOverlap
-
jobs = [FindLocationsWithMaintenanceOverlap, HandleCircuitMaintenanceNotifications]
register_jobs(*jobs)
diff --git a/nautobot_circuit_maintenance/jobs/location_search.py b/nautobot_circuit_maintenance/jobs/location_search.py
index f0729233..9ad21aa4 100644
--- a/nautobot_circuit_maintenance/jobs/location_search.py
+++ b/nautobot_circuit_maintenance/jobs/location_search.py
@@ -1,12 +1,12 @@
# pylint: disable=logging-fstring-interpolation
"""Location searching Job definition."""
+
import collections
from datetime import date
from django.conf import settings
-
-from nautobot.extras.jobs import Job
from nautobot.circuits.models import Circuit
+from nautobot.extras.jobs import Job
from nautobot_circuit_maintenance.models import CircuitMaintenance
diff --git a/nautobot_circuit_maintenance/metrics_app.py b/nautobot_circuit_maintenance/metrics_app.py
index 86b3d0cb..f437dfd0 100644
--- a/nautobot_circuit_maintenance/metrics_app.py
+++ b/nautobot_circuit_maintenance/metrics_app.py
@@ -1,11 +1,12 @@
"""Nautobot Circuit Maintenance app application level metrics exposed through nautobot_capacity_metrics."""
-from collections import OrderedDict
import functools
+from collections import OrderedDict
from datetime import datetime, timezone
-from prometheus_client.core import GaugeMetricFamily
-from nautobot.circuits.models import CircuitTermination
+
from django.conf import settings
+from nautobot.circuits.models import CircuitTermination
+from prometheus_client.core import GaugeMetricFamily
from .models import CircuitImpact, CircuitMaintenance
diff --git a/nautobot_circuit_maintenance/migrations/0001_initial.py b/nautobot_circuit_maintenance/migrations/0001_initial.py
index 7c2f7778..a46791c8 100644
--- a/nautobot_circuit_maintenance/migrations/0001_initial.py
+++ b/nautobot_circuit_maintenance/migrations/0001_initial.py
@@ -1,12 +1,13 @@
# Generated by Django 3.1.10 on 2021-05-07 08:37
+import uuid
+
import django.core.serializers.json
-from django.db import migrations, models, connection
import django.db.models.deletion
import django.utils.timezone
import django_cryptography.fields
import taggit.managers
-import uuid
+from django.db import connection, migrations, models
class Migration(migrations.Migration):
diff --git a/nautobot_circuit_maintenance/migrations/0003_improve_rawnotification.py b/nautobot_circuit_maintenance/migrations/0003_improve_rawnotification.py
index a12bfa96..ac26dab6 100644
--- a/nautobot_circuit_maintenance/migrations/0003_improve_rawnotification.py
+++ b/nautobot_circuit_maintenance/migrations/0003_improve_rawnotification.py
@@ -1,7 +1,7 @@
# Generated by Django 3.1.10 on 2021-06-10 09:15
-from django.db import migrations, models
import django.db.models.deletion
+from django.db import migrations, models
def migrate_source(apps, schema_editor):
diff --git a/nautobot_circuit_maintenance/migrations/0004_raw_md5.py b/nautobot_circuit_maintenance/migrations/0004_raw_md5.py
index 5f357955..ff78d6c7 100644
--- a/nautobot_circuit_maintenance/migrations/0004_raw_md5.py
+++ b/nautobot_circuit_maintenance/migrations/0004_raw_md5.py
@@ -1,15 +1,16 @@
# Generated by Django 3.1.10 on 2021-06-22 16:27
-from django.db import migrations, models, connection
import hashlib
+from django.db import connection, migrations, models
+
def gen_raw_md5(apps, schema_editor):
"""Custom update of _raw_md5 hash."""
RawNotificationModel = apps.get_model("nautobot_circuit_maintenance", "RawNotification")
for raw_notification in RawNotificationModel.objects.all():
- raw_notification._raw_md5 = hashlib.md5(raw_notification.raw.encode("utf-8")).hexdigest() # nosec
+ raw_notification._raw_md5 = hashlib.md5(raw_notification.raw.encode("utf-8")).hexdigest() # noqa: S324
raw_notification.save(update_fields=["_raw_md5"])
diff --git a/nautobot_circuit_maintenance/migrations/0012_auto_20230810_1245.py b/nautobot_circuit_maintenance/migrations/0012_auto_20230810_1245.py
index 58621443..f10bc778 100644
--- a/nautobot_circuit_maintenance/migrations/0012_auto_20230810_1245.py
+++ b/nautobot_circuit_maintenance/migrations/0012_auto_20230810_1245.py
@@ -1,7 +1,7 @@
# Generated by Django 3.2.20 on 2023-08-10 12:45
-from django.db import migrations, models
import nautobot.core.models.fields
+from django.db import migrations, models
class Migration(migrations.Migration):
diff --git a/nautobot_circuit_maintenance/models.py b/nautobot_circuit_maintenance/models.py
index a265f73e..ba76679c 100644
--- a/nautobot_circuit_maintenance/models.py
+++ b/nautobot_circuit_maintenance/models.py
@@ -3,16 +3,16 @@
import logging
import pickle # nosec
from datetime import datetime, timezone
+
from django.conf import settings
from django.core.exceptions import ValidationError
from django.db import models
-from django.urls import reverse
from django.db.models.signals import post_save
from django.dispatch import receiver
-
-from nautobot.extras.utils import extras_features
+from django.urls import reverse
from nautobot.circuits.models import Circuit, Provider
-from nautobot.core.models.generics import PrimaryModel, OrganizationalModel
+from nautobot.core.models.generics import OrganizationalModel, PrimaryModel
+from nautobot.extras.utils import extras_features
from .choices import CircuitImpactChoices, CircuitMaintenanceStatusChoices, NoteLevelChoices
@@ -193,10 +193,11 @@ def get_absolute_url(self, api=False):
"""Returns reverse loop up URL."""
return reverse("plugins:nautobot_circuit_maintenance:notificationsource", args=[self.pk])
+ # TODO: Look if we can replace token with Nautobot Secrets.
@property
def token(self):
"""Getter for _token."""
- return pickle.loads(self._token) # nosec
+ return pickle.loads(self._token) # noqa: S301
@token.setter
def token(self, value):
diff --git a/nautobot_circuit_maintenance/navigation.py b/nautobot_circuit_maintenance/navigation.py
index 0ffe5cc0..b0e1495c 100644
--- a/nautobot_circuit_maintenance/navigation.py
+++ b/nautobot_circuit_maintenance/navigation.py
@@ -1,10 +1,10 @@
"""Navigation for Circuit Maintenance."""
-from nautobot.core.choices import ButtonColorChoices
+from nautobot.apps.ui import NavMenuAddButton, NavMenuGroup, NavMenuItem, NavMenuTab
# TODO: NavMenuButton is not part of the new 2.0 UI, this should be replaced
from nautobot.core.apps import NavMenuButton
-from nautobot.apps.ui import NavMenuTab, NavMenuGroup, NavMenuItem, NavMenuAddButton
+from nautobot.core.choices import ButtonColorChoices
menu_items = (
NavMenuTab(
diff --git a/nautobot_circuit_maintenance/tables.py b/nautobot_circuit_maintenance/tables.py
index a7c585dd..5f7939f6 100644
--- a/nautobot_circuit_maintenance/tables.py
+++ b/nautobot_circuit_maintenance/tables.py
@@ -1,10 +1,9 @@
"""Tables for Circuit Maintenance."""
import django_tables2 as tables
-
from nautobot.core.tables import BaseTable, ToggleColumn
-from .models import CircuitMaintenance, RawNotification, CircuitImpact, NotificationSource, Note
+from .models import CircuitImpact, CircuitMaintenance, Note, NotificationSource, RawNotification
class CircuitMaintenanceTable(BaseTable):
diff --git a/nautobot_circuit_maintenance/template_content.py b/nautobot_circuit_maintenance/template_content.py
index 162dc1c6..c50b439c 100644
--- a/nautobot_circuit_maintenance/template_content.py
+++ b/nautobot_circuit_maintenance/template_content.py
@@ -1,6 +1,7 @@
"""Additions to existing Nautobot page content."""
from nautobot.extras.plugins import PluginTemplateExtension
+
from .models import CircuitImpact
diff --git a/nautobot_circuit_maintenance/tests/test_api.py b/nautobot_circuit_maintenance/tests/test_api.py
index 8a57c905..ed344bb1 100644
--- a/nautobot_circuit_maintenance/tests/test_api.py
+++ b/nautobot_circuit_maintenance/tests/test_api.py
@@ -1,18 +1,13 @@
-"""Test for Circuit Maintenace API."""
+"""Unit tests for nautobot_circuit_maintenance."""
-from datetime import datetime
-from datetime import timedelta
-from datetime import timezone
+from datetime import datetime, timedelta, timezone
from django.urls import reverse
-from nautobot.circuits.models import Circuit
-from nautobot.circuits.models import CircuitType
-from nautobot.circuits.models import Provider
+from nautobot.circuits.models import Circuit, CircuitType, Provider
from nautobot.core.testing import APIViewTestCases
from nautobot.extras.models import Status
-from nautobot_circuit_maintenance.models import CircuitImpact
-from nautobot_circuit_maintenance.models import CircuitMaintenance
+from nautobot_circuit_maintenance.models import CircuitImpact, CircuitMaintenance
class CircuitMaintenanceTest(APIViewTestCases.CreateObjectViewTestCase):
@@ -46,7 +41,6 @@ def setUpTestData(cls):
}
]
- # pylint: disable-next=no-self-use
def get_deletable_object(self):
"""Return an object that can be deleted via the API."""
return CircuitMaintenance.objects.get_or_create(
@@ -115,7 +109,6 @@ def setUpTestData(cls):
{"maintenance": maintenances[1].id, "circuit": circuits[1].id},
]
- # pylint: disable-next=no-self-use
def get_deletable_object(self):
"""Return an object that can be deleted via the API."""
return CircuitImpact.objects.get_or_create(
diff --git a/nautobot_circuit_maintenance/tests/test_app_metrics.py b/nautobot_circuit_maintenance/tests/test_app_metrics.py
index f52a34b3..466180d6 100644
--- a/nautobot_circuit_maintenance/tests/test_app_metrics.py
+++ b/nautobot_circuit_maintenance/tests/test_app_metrics.py
@@ -1,21 +1,14 @@
"""Test cases for application metrics endpoint views."""
-from datetime import datetime
-from datetime import timedelta
-from datetime import timezone
+from datetime import datetime, timedelta, timezone
from django.test import TestCase
-from nautobot.circuits.models import Circuit
-from nautobot.circuits.models import CircuitTermination
-from nautobot.circuits.models import CircuitType
-from nautobot.circuits.models import Provider
-from nautobot.dcim.models import Location
-from nautobot.dcim.models import LocationType
+from nautobot.circuits.models import Circuit, CircuitTermination, CircuitType, Provider
+from nautobot.dcim.models import Location, LocationType
from nautobot.extras.models import Status
from nautobot_circuit_maintenance.metrics_app import metric_circuit_operational
-from nautobot_circuit_maintenance.models import CircuitImpact
-from nautobot_circuit_maintenance.models import CircuitMaintenance
+from nautobot_circuit_maintenance.models import CircuitImpact, CircuitMaintenance
class AppMetricTests(TestCase):
diff --git a/nautobot_circuit_maintenance/tests/test_basic.py b/nautobot_circuit_maintenance/tests/test_basic.py
index 30fc318e..d72f2d02 100644
--- a/nautobot_circuit_maintenance/tests/test_basic.py
+++ b/nautobot_circuit_maintenance/tests/test_basic.py
@@ -1,7 +1,8 @@
"""Basic tests that do not require Django."""
-import unittest
import os
+import unittest
+
import toml
@@ -16,8 +17,9 @@ def test_version(self):
with open(f"{parent_path}/docs/requirements.txt", "r", encoding="utf-8") as file:
requirements = [line for line in file.read().splitlines() if (len(line) > 0 and not line.startswith("#"))]
for pkg in requirements:
- if len(pkg.split("==")) == 2:
- pkg, version = pkg.split("==")
+ package_name = pkg
+ if len(pkg.split("==")) == 2: # noqa: PLR2004
+ package_name, version = pkg.split("==")
else:
version = "*"
- self.assertEqual(poetry_details[pkg], version)
+ self.assertEqual(poetry_details[package_name], version)
diff --git a/nautobot_circuit_maintenance/tests/test_basics.py b/nautobot_circuit_maintenance/tests/test_basics.py
index 859aa2ac..a09f7667 100644
--- a/nautobot_circuit_maintenance/tests/test_basics.py
+++ b/nautobot_circuit_maintenance/tests/test_basics.py
@@ -1,7 +1,8 @@
"""Basic tests that do not require Django."""
-import unittest
import os
+import unittest
+
import toml
from nautobot_circuit_maintenance import __version__ as project_version
diff --git a/nautobot_circuit_maintenance/tests/test_graphql.py b/nautobot_circuit_maintenance/tests/test_graphql.py
index 82f2fe94..a3002b4f 100644
--- a/nautobot_circuit_maintenance/tests/test_graphql.py
+++ b/nautobot_circuit_maintenance/tests/test_graphql.py
@@ -1,17 +1,13 @@
"""GraphQL tests."""
from django.contrib.auth import get_user_model
-from django.test import TestCase
-from django.test import override_settings
-from nautobot.circuits.models import Circuit
-from nautobot.circuits.models import CircuitType
-from nautobot.circuits.models import Provider
+from django.test import TestCase, override_settings
+from nautobot.circuits.models import Circuit, CircuitType, Provider
from nautobot.core.graphql import execute_query
from nautobot.core.testing.utils import create_test_user
from nautobot.extras.models import Status
-from nautobot_circuit_maintenance.models import CircuitImpact
-from nautobot_circuit_maintenance.models import CircuitMaintenance
+from nautobot_circuit_maintenance.models import CircuitImpact, CircuitMaintenance
# Use the proper swappable User model
User = get_user_model()
diff --git a/nautobot_circuit_maintenance/tests/test_handler.py b/nautobot_circuit_maintenance/tests/test_handler.py
index 6eb51974..3ac4e709 100644
--- a/nautobot_circuit_maintenance/tests/test_handler.py
+++ b/nautobot_circuit_maintenance/tests/test_handler.py
@@ -1,37 +1,37 @@
"""Tests for Handle Notifications methods."""
import uuid
-from unittest.mock import Mock, patch, ANY
from datetime import datetime, timezone
from email.message import EmailMessage
from email.utils import format_datetime
+from unittest.mock import ANY, Mock, patch
+
+from circuit_maintenance_parser import NotificationData, init_provider
+from circuit_maintenance_parser.errors import ProviderError
from django.test import TestCase
from jinja2 import Template
from nautobot.circuits.models import Circuit, Provider
-from circuit_maintenance_parser import init_provider, NotificationData
-from circuit_maintenance_parser.errors import ProviderError
from nautobot_circuit_maintenance.handle_notifications.handler import (
+ HandleCircuitMaintenanceNotifications,
create_circuit_maintenance,
get_maintenances_from_notification,
get_since_reference,
- HandleCircuitMaintenanceNotifications,
process_raw_notification,
update_circuit_maintenance,
)
-
+from nautobot_circuit_maintenance.handle_notifications.sources import MaintenanceNotification, Source
from nautobot_circuit_maintenance.models import (
- CircuitMaintenance,
- CircuitImpact,
MAX_MAINTENANCE_NAME_LENGTH,
MAX_NOTIFICATION_SENDER_LENGTH,
MAX_NOTIFICATION_SUBJECT_LENGTH,
- NotificationSource,
+ CircuitImpact,
+ CircuitMaintenance,
Note,
- RawNotification,
+ NotificationSource,
ParsedNotification,
+ RawNotification,
)
-from nautobot_circuit_maintenance.handle_notifications.sources import MaintenanceNotification, Source
from .utils import MockedLogger
diff --git a/nautobot_circuit_maintenance/tests/test_models.py b/nautobot_circuit_maintenance/tests/test_models.py
index bddb5e46..902e96c1 100644
--- a/nautobot_circuit_maintenance/tests/test_models.py
+++ b/nautobot_circuit_maintenance/tests/test_models.py
@@ -3,16 +3,11 @@
import datetime
from django.test import TestCase
-from nautobot.circuits.models import Circuit
-from nautobot.circuits.models import CircuitType
-from nautobot.circuits.models import Provider
+from nautobot.circuits.models import Circuit, CircuitType, Provider
from nautobot.extras.models import Status
from nautobot_circuit_maintenance.choices import CircuitImpactChoices
-from nautobot_circuit_maintenance.models import CircuitImpact
-from nautobot_circuit_maintenance.models import CircuitMaintenance
-from nautobot_circuit_maintenance.models import NotificationSource
-from nautobot_circuit_maintenance.models import RawNotification
+from nautobot_circuit_maintenance.models import CircuitImpact, CircuitMaintenance, NotificationSource, RawNotification
class CircuitMaintenanceModelTestCase(TestCase):
diff --git a/nautobot_circuit_maintenance/tests/test_sources.py b/nautobot_circuit_maintenance/tests/test_sources.py
index 7e0234ba..d424ff67 100644
--- a/nautobot_circuit_maintenance/tests/test_sources.py
+++ b/nautobot_circuit_maintenance/tests/test_sources.py
@@ -5,9 +5,7 @@
import json
import os
from email.message import EmailMessage
-from unittest.mock import ANY
-from unittest.mock import patch
-from unittest.mock import MagicMock
+from unittest.mock import ANY, MagicMock, patch
import exchangelib
from django.conf import settings
@@ -16,19 +14,20 @@
from parameterized import parameterized
from pydantic import ValidationError
-from nautobot_circuit_maintenance.handle_notifications.sources import IMAP
-from nautobot_circuit_maintenance.handle_notifications.sources import EmailSource
-from nautobot_circuit_maintenance.handle_notifications.sources import ExchangeWebService
-from nautobot_circuit_maintenance.handle_notifications.sources import GmailAPI
-from nautobot_circuit_maintenance.handle_notifications.sources import GmailAPIOauth
-from nautobot_circuit_maintenance.handle_notifications.sources import GmailAPIServiceAccount
-from nautobot_circuit_maintenance.handle_notifications.sources import MaintenanceNotification
-from nautobot_circuit_maintenance.handle_notifications.sources import Source
-from nautobot_circuit_maintenance.handle_notifications.sources import get_notifications
+from nautobot_circuit_maintenance.handle_notifications.sources import (
+ IMAP,
+ EmailSource,
+ ExchangeWebService,
+ GmailAPI,
+ GmailAPIOauth,
+ GmailAPIServiceAccount,
+ MaintenanceNotification,
+ Source,
+ get_notifications,
+)
from nautobot_circuit_maintenance.models import NotificationSource
-from .test_handler import generate_email_notification
-from .test_handler import get_base_notification_data
+from .test_handler import generate_email_notification, get_base_notification_data
from .utils import MockedJob, assert_called_with_substring
SOURCE_IMAP = {
@@ -263,7 +262,6 @@ def test_get_notifications_without_notifications(self, mock_receive_notification
extra=ANY,
)
- # pylint: disable-next=no-self-use
def test_get_notifications_no_imap_account(self):
"""Test get_notifications without IMAP account."""
del settings.PLUGINS_CONFIG["nautobot_circuit_maintenance"]["notification_sources"][0]["account"]
diff --git a/nautobot_circuit_maintenance/tests/test_views.py b/nautobot_circuit_maintenance/tests/test_views.py
index df1db228..20b830be 100644
--- a/nautobot_circuit_maintenance/tests/test_views.py
+++ b/nautobot_circuit_maintenance/tests/test_views.py
@@ -1,28 +1,27 @@
# TBD: Review skipped tests
# pylint: disable=duplicate-code,too-many-public-methods
"""Test for Circuit Maintenace Views."""
-from datetime import datetime
-from datetime import timezone
+
+from datetime import datetime, timezone
from unittest import skip
from unittest.mock import patch
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.urls import reverse
-from nautobot.circuits.models import Circuit
-from nautobot.circuits.models import CircuitType
-from nautobot.circuits.models import Provider
-from nautobot.core.testing import ModelViewTestCase
-from nautobot.core.testing import ViewTestCases
+from nautobot.circuits.models import Circuit, CircuitType, Provider
+from nautobot.core.testing import ModelViewTestCase, ViewTestCases
from nautobot.extras.models import Status
from nautobot.users.models import ObjectPermission
-from nautobot_circuit_maintenance.models import CircuitImpact
-from nautobot_circuit_maintenance.models import CircuitMaintenance
-from nautobot_circuit_maintenance.models import Note
-from nautobot_circuit_maintenance.models import NotificationSource
-from nautobot_circuit_maintenance.models import ParsedNotification
-from nautobot_circuit_maintenance.models import RawNotification
+from nautobot_circuit_maintenance.models import (
+ CircuitImpact,
+ CircuitMaintenance,
+ Note,
+ NotificationSource,
+ ParsedNotification,
+ RawNotification,
+)
from nautobot_circuit_maintenance.views import CircuitMaintenanceOverview
diff --git a/nautobot_circuit_maintenance/tests/utils.py b/nautobot_circuit_maintenance/tests/utils.py
index 18ddeb89..aa396387 100644
--- a/nautobot_circuit_maintenance/tests/utils.py
+++ b/nautobot_circuit_maintenance/tests/utils.py
@@ -1,7 +1,8 @@
# pylint: disable=logging-fstring-interpolation
"""Test utilities."""
-from unittest.mock import Mock
+
import logging
+from unittest.mock import Mock
def _add(level):
diff --git a/nautobot_circuit_maintenance/urls.py b/nautobot_circuit_maintenance/urls.py
index 9ee4eae1..bd3e8c1e 100644
--- a/nautobot_circuit_maintenance/urls.py
+++ b/nautobot_circuit_maintenance/urls.py
@@ -1,16 +1,12 @@
"""URLS for Circuit Maintenance."""
-from django.urls import path
from django.templatetags.static import static
+from django.urls import path
from django.views.generic import RedirectView
-
from nautobot.extras.views import ObjectChangeLogView
from . import views
-from .models import CircuitImpact
-from .models import CircuitMaintenance
-from .models import Note
-from .models import NotificationSource
+from .models import CircuitImpact, CircuitMaintenance, Note, NotificationSource
urlpatterns = [
# Overview
diff --git a/nautobot_circuit_maintenance/views.py b/nautobot_circuit_maintenance/views.py
index b120bd78..17ccd22b 100644
--- a/nautobot_circuit_maintenance/views.py
+++ b/nautobot_circuit_maintenance/views.py
@@ -8,16 +8,11 @@
from django.shortcuts import redirect
from django.urls import reverse
from django.urls.exceptions import NoReverseMatch
-from nautobot.circuits.models import Circuit
-from nautobot.circuits.models import Provider
+from nautobot.circuits.models import Circuit, Provider
from nautobot.core.views import generic
-from nautobot_circuit_maintenance import filters
-from nautobot_circuit_maintenance import forms
-from nautobot_circuit_maintenance import models
-from nautobot_circuit_maintenance import tables
-from nautobot_circuit_maintenance.handle_notifications.sources import RedirectAuthorize
-from nautobot_circuit_maintenance.handle_notifications.sources import Source
+from nautobot_circuit_maintenance import filters, forms, models, tables
+from nautobot_circuit_maintenance.handle_notifications.sources import RedirectAuthorize, Source
from nautobot_circuit_maintenance.models import CircuitMaintenance
logger = logging.getLogger(__name__)
diff --git a/poetry.lock b/poetry.lock
index 8f52fc41..2244d1a2 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,4 +1,4 @@
-# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
+# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand.
[[package]]
name = "amqp"
@@ -69,17 +69,22 @@ tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"]
[[package]]
name = "astroid"
-version = "3.2.2"
+version = "2.15.8"
description = "An abstract syntax tree for Python with inference support."
optional = false
-python-versions = ">=3.8.0"
+python-versions = ">=3.7.2"
files = [
- {file = "astroid-3.2.2-py3-none-any.whl", hash = "sha256:e8a0083b4bb28fcffb6207a3bfc9e5d0a68be951dd7e336d5dcf639c682388c0"},
- {file = "astroid-3.2.2.tar.gz", hash = "sha256:8ead48e31b92b2e217b6c9733a21afafe479d52d6e164dd25fb1a770c7c3cf94"},
+ {file = "astroid-2.15.8-py3-none-any.whl", hash = "sha256:1aa149fc5c6589e3d0ece885b4491acd80af4f087baafa3fb5203b113e68cd3c"},
+ {file = "astroid-2.15.8.tar.gz", hash = "sha256:6c107453dffee9055899705de3c9ead36e74119cee151e5a9aaf7f0b0e020a6a"},
]
[package.dependencies]
+lazy-object-proxy = ">=1.4.0"
typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""}
+wrapt = [
+ {version = ">=1.11,<2", markers = "python_version < \"3.11\""},
+ {version = ">=1.14,<2", markers = "python_version >= \"3.11\""},
+]
[[package]]
name = "asttokens"
@@ -159,6 +164,23 @@ files = [
pycodestyle = ">=2.9.1"
tomli = "*"
+[[package]]
+name = "babel"
+version = "2.16.0"
+description = "Internationalization utilities"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b"},
+ {file = "babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316"},
+]
+
+[package.dependencies]
+pytz = {version = ">=2015.7", markers = "python_version < \"3.9\""}
+
+[package.extras]
+dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"]
+
[[package]]
name = "backcall"
version = "0.2.0"
@@ -212,30 +234,6 @@ tzdata = {version = "*", optional = true, markers = "extra == \"tzdata\""}
[package.extras]
tzdata = ["tzdata"]
-[[package]]
-name = "bandit"
-version = "1.7.8"
-description = "Security oriented static analyser for python code."
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "bandit-1.7.8-py3-none-any.whl", hash = "sha256:509f7af645bc0cd8fd4587abc1a038fc795636671ee8204d502b933aee44f381"},
- {file = "bandit-1.7.8.tar.gz", hash = "sha256:36de50f720856ab24a24dbaa5fee2c66050ed97c1477e0a1159deab1775eab6b"},
-]
-
-[package.dependencies]
-colorama = {version = ">=0.3.9", markers = "platform_system == \"Windows\""}
-PyYAML = ">=5.3.1"
-rich = "*"
-stevedore = ">=1.20.0"
-
-[package.extras]
-baseline = ["GitPython (>=3.1.30)"]
-sarif = ["jschema-to-python (>=1.2.3)", "sarif-om (>=1.0.4)"]
-test = ["beautifulsoup4 (>=4.8.0)", "coverage (>=4.5.4)", "fixtures (>=3.0.0)", "flake8 (>=4.0.0)", "pylint (==1.9.4)", "stestr (>=2.5.0)", "testscenarios (>=0.5.0)", "testtools (>=2.3.0)"]
-toml = ["tomli (>=1.1.0)"]
-yaml = ["PyYAML"]
-
[[package]]
name = "beautifulsoup4"
version = "4.12.3"
@@ -268,52 +266,6 @@ files = [
{file = "billiard-4.2.0.tar.gz", hash = "sha256:9a3c3184cb275aa17a732f93f65b20c525d3d9f253722d26a82194803ade5a2c"},
]
-[[package]]
-name = "black"
-version = "24.4.2"
-description = "The uncompromising code formatter."
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "black-24.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dd1b5a14e417189db4c7b64a6540f31730713d173f0b63e55fabd52d61d8fdce"},
- {file = "black-24.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e537d281831ad0e71007dcdcbe50a71470b978c453fa41ce77186bbe0ed6021"},
- {file = "black-24.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaea3008c281f1038edb473c1aa8ed8143a5535ff18f978a318f10302b254063"},
- {file = "black-24.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:7768a0dbf16a39aa5e9a3ded568bb545c8c2727396d063bbaf847df05b08cd96"},
- {file = "black-24.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:257d724c2c9b1660f353b36c802ccece186a30accc7742c176d29c146df6e474"},
- {file = "black-24.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bdde6f877a18f24844e381d45e9947a49e97933573ac9d4345399be37621e26c"},
- {file = "black-24.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e151054aa00bad1f4e1f04919542885f89f5f7d086b8a59e5000e6c616896ffb"},
- {file = "black-24.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:7e122b1c4fb252fd85df3ca93578732b4749d9be076593076ef4d07a0233c3e1"},
- {file = "black-24.4.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:accf49e151c8ed2c0cdc528691838afd217c50412534e876a19270fea1e28e2d"},
- {file = "black-24.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:88c57dc656038f1ab9f92b3eb5335ee9b021412feaa46330d5eba4e51fe49b04"},
- {file = "black-24.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be8bef99eb46d5021bf053114442914baeb3649a89dc5f3a555c88737e5e98fc"},
- {file = "black-24.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:415e686e87dbbe6f4cd5ef0fbf764af7b89f9057b97c908742b6008cc554b9c0"},
- {file = "black-24.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bf10f7310db693bb62692609b397e8d67257c55f949abde4c67f9cc574492cc7"},
- {file = "black-24.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:98e123f1d5cfd42f886624d84464f7756f60ff6eab89ae845210631714f6db94"},
- {file = "black-24.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48a85f2cb5e6799a9ef05347b476cce6c182d6c71ee36925a6c194d074336ef8"},
- {file = "black-24.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:b1530ae42e9d6d5b670a34db49a94115a64596bc77710b1d05e9801e62ca0a7c"},
- {file = "black-24.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:37aae07b029fa0174d39daf02748b379399b909652a806e5708199bd93899da1"},
- {file = "black-24.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da33a1a5e49c4122ccdfd56cd021ff1ebc4a1ec4e2d01594fef9b6f267a9e741"},
- {file = "black-24.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef703f83fc32e131e9bcc0a5094cfe85599e7109f896fe8bc96cc402f3eb4b6e"},
- {file = "black-24.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:b9176b9832e84308818a99a561e90aa479e73c523b3f77afd07913380ae2eab7"},
- {file = "black-24.4.2-py3-none-any.whl", hash = "sha256:d36ed1124bb81b32f8614555b34cc4259c3fbc7eec17870e8ff8ded335b58d8c"},
- {file = "black-24.4.2.tar.gz", hash = "sha256:c872b53057f000085da66a19c55d68f6f8ddcac2642392ad3a355878406fbd4d"},
-]
-
-[package.dependencies]
-click = ">=8.0.0"
-mypy-extensions = ">=0.4.3"
-packaging = ">=22.0"
-pathspec = ">=0.9.0"
-platformdirs = ">=2"
-tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
-typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""}
-
-[package.extras]
-colorama = ["colorama (>=0.4.3)"]
-d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"]
-jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
-uvloop = ["uvloop (>=0.15.2)"]
-
[[package]]
name = "bs4"
version = "0.0.2"
@@ -878,19 +830,20 @@ profile = ["gprof2dot (>=2022.7.29)"]
[[package]]
name = "django"
-version = "3.2.25"
-description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design."
+version = "4.2.16"
+description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design."
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.8"
files = [
- {file = "Django-3.2.25-py3-none-any.whl", hash = "sha256:a52ea7fcf280b16f7b739cec38fa6d3f8953a5456986944c3ca97e79882b4e38"},
- {file = "Django-3.2.25.tar.gz", hash = "sha256:7ca38a78654aee72378594d63e51636c04b8e28574f5505dff630895b5472777"},
+ {file = "Django-4.2.16-py3-none-any.whl", hash = "sha256:1ddc333a16fc139fd253035a1606bb24261951bbc3a6ca256717fa06cc41a898"},
+ {file = "Django-4.2.16.tar.gz", hash = "sha256:6f1616c2786c408ce86ab7e10f792b8f15742f7b7b7460243929cb371e7f1dad"},
]
[package.dependencies]
-asgiref = ">=3.3.2,<4"
-pytz = "*"
-sqlparse = ">=0.2.2"
+asgiref = ">=3.6.0,<4"
+"backports.zoneinfo" = {version = "*", markers = "python_version < \"3.9\""}
+sqlparse = ">=0.3.1"
+tzdata = {version = "*", markers = "sys_platform == \"win32\""}
[package.extras]
argon2 = ["argon2-cffi (>=19.1.0)"]
@@ -957,36 +910,35 @@ Django = ">=3.2.18"
[[package]]
name = "django-constance"
-version = "2.9.1"
+version = "3.1.0"
description = "Django live settings with pluggable backends, including Redis."
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
files = [
- {file = "django-constance-2.9.1.tar.gz", hash = "sha256:4c6a96a5f2cbce1bc3fa41aa20566b6ee26fbd896c9f91f996518a3a0904f6c8"},
- {file = "django_constance-2.9.1-py3-none-any.whl", hash = "sha256:bf0b392efa18a1f3f464eddb7eb36ac5c02598354a5e31d0d4ce4fc8b535694b"},
+ {file = "django-constance-3.1.0.tar.gz", hash = "sha256:2b96e51de63751ef63f8f92f74e0f6aea30fb6453f3a736c21e1f8b3f6cf0b4f"},
+ {file = "django_constance-3.1.0-py3-none-any.whl", hash = "sha256:6242486a346e396d765a9333d17f3101c8613cabc92e0b98dcb70c2a391bc53b"},
]
[package.dependencies]
-django-picklefield = {version = "*", optional = true, markers = "extra == \"database\""}
+django-picklefield = "*"
[package.extras]
-database = ["django-picklefield"]
redis = ["redis"]
[[package]]
name = "django-cors-headers"
-version = "4.3.1"
+version = "4.4.0"
description = "django-cors-headers is a Django application for handling the server headers required for Cross-Origin Resource Sharing (CORS)."
optional = false
python-versions = ">=3.8"
files = [
- {file = "django-cors-headers-4.3.1.tar.gz", hash = "sha256:0bf65ef45e606aff1994d35503e6b677c0b26cafff6506f8fd7187f3be840207"},
- {file = "django_cors_headers-4.3.1-py3-none-any.whl", hash = "sha256:0b1fd19297e37417fc9f835d39e45c8c642938ddba1acce0c1753d3edef04f36"},
+ {file = "django_cors_headers-4.4.0-py3-none-any.whl", hash = "sha256:5c6e3b7fe870876a1efdfeb4f433782c3524078fa0dc9e0195f6706ce7a242f6"},
+ {file = "django_cors_headers-4.4.0.tar.gz", hash = "sha256:92cf4633e22af67a230a1456cb1b7a02bb213d6536d2dcb2a4a24092ea9cebc2"},
]
[package.dependencies]
asgiref = ">=3.6"
-Django = ">=3.2"
+django = ">=3.2"
[[package]]
name = "django-cryptography"
@@ -1048,27 +1000,27 @@ Django = ">=3.2"
[[package]]
name = "django-filter"
-version = "23.5"
+version = "24.2"
description = "Django-filter is a reusable Django application for allowing users to filter querysets dynamically."
optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
files = [
- {file = "django-filter-23.5.tar.gz", hash = "sha256:67583aa43b91fe8c49f74a832d95f4d8442be628fd4c6d65e9f811f5153a4e5c"},
- {file = "django_filter-23.5-py3-none-any.whl", hash = "sha256:99122a201d83860aef4fe77758b69dda913e874cc5e0eaa50a86b0b18d708400"},
+ {file = "django-filter-24.2.tar.gz", hash = "sha256:48e5fc1da3ccd6ca0d5f9bb550973518ce977a4edde9d2a8a154a7f4f0b9f96e"},
+ {file = "django_filter-24.2-py3-none-any.whl", hash = "sha256:df2ee9857e18d38bed203c8745f62a803fa0f31688c9fe6f8e868120b1848e48"},
]
[package.dependencies]
-Django = ">=3.2"
+Django = ">=4.2"
[[package]]
name = "django-health-check"
-version = "3.18.2"
+version = "3.18.3"
description = "Run checks on services like databases, queue servers, celery processes, etc."
optional = false
python-versions = ">=3.8"
files = [
- {file = "django_health_check-3.18.2-py2.py3-none-any.whl", hash = "sha256:16f9c9186236cbc2858fa0d0ecc3566ba2ad2b72683e5678d0d58eb9e8bbba1a"},
- {file = "django_health_check-3.18.2.tar.gz", hash = "sha256:21235120f8d756fa75ba430d0b0dbb04620fbd7bfac92ed6a0b911915ba38918"},
+ {file = "django_health_check-3.18.3-py2.py3-none-any.whl", hash = "sha256:f5f58762b80bdf7b12fad724761993d6e83540f97e2c95c42978f187e452fa07"},
+ {file = "django_health_check-3.18.3.tar.gz", hash = "sha256:18b75daca4551c69a43f804f9e41e23f5f5fb9efd06cf6a313b3d5031bb87bd0"},
]
[package.dependencies]
@@ -1078,6 +1030,20 @@ django = ">=2.2"
docs = ["sphinx"]
test = ["boto3", "celery", "django-storages", "pytest", "pytest-cov", "pytest-django", "redis"]
+[[package]]
+name = "django-ipware"
+version = "7.0.1"
+description = "A Django application to retrieve user's IP address"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "django-ipware-7.0.1.tar.gz", hash = "sha256:d9ec43d2bf7cdf216fed8d494a084deb5761a54860a53b2e74346a4f384cff47"},
+ {file = "django_ipware-7.0.1-py2.py3-none-any.whl", hash = "sha256:db16bbee920f661ae7f678e4270460c85850f03c6761a4eaeb489bdc91f64709"},
+]
+
+[package.dependencies]
+python-ipware = ">=2.0.3"
+
[[package]]
name = "django-jinja"
version = "2.11.0"
@@ -1159,6 +1125,27 @@ Django = ">=3.2"
gprof2dot = ">=2017.09.19"
sqlparse = "*"
+[[package]]
+name = "django-structlog"
+version = "8.1.0"
+description = "Structured Logging for Django"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "django_structlog-8.1.0-py3-none-any.whl", hash = "sha256:1072564bd6f36e8d3ba9893e7b31c1c46e94301189fedaecc0fb8a46525a3214"},
+ {file = "django_structlog-8.1.0.tar.gz", hash = "sha256:0229b9a2efbd24a4e3500169788e53915c2429521e34e41dd58ccc56039bef3f"},
+]
+
+[package.dependencies]
+asgiref = ">=3.6.0"
+django = ">=4.2"
+django-ipware = ">=6.0.2"
+structlog = ">=21.4.0"
+
+[package.extras]
+celery = ["celery (>=5.1)"]
+commands = ["django-extensions (>=1.4.9)"]
+
[[package]]
name = "django-tables2"
version = "2.7.0"
@@ -1178,43 +1165,42 @@ tablib = ["tablib"]
[[package]]
name = "django-taggit"
-version = "4.0.0"
+version = "5.0.1"
description = "django-taggit is a reusable Django application for simple tagging."
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.8"
files = [
- {file = "django-taggit-4.0.0.tar.gz", hash = "sha256:4d52de9d37245a9b9f98c0ec71fdccf1d2283e38e8866d40a7ae6a3b6787a161"},
- {file = "django_taggit-4.0.0-py3-none-any.whl", hash = "sha256:eb800dabef5f0a4e047ab0751f82cf805bc4a9e972037ef12bf519f52cd92480"},
+ {file = "django-taggit-5.0.1.tar.gz", hash = "sha256:edcd7db1e0f35c304e082a2f631ddac2e16ef5296029524eb792af7430cab4cc"},
+ {file = "django_taggit-5.0.1-py3-none-any.whl", hash = "sha256:a0ca8a28b03c4b26c2630fd762cb76ec39b5e41abf727a7b66f897a625c5e647"},
]
[package.dependencies]
-Django = ">=3.2"
+Django = ">=4.1"
[[package]]
name = "django-timezone-field"
-version = "5.1"
+version = "7.0"
description = "A Django app providing DB, form, and REST framework fields for zoneinfo and pytz timezone objects."
optional = false
-python-versions = ">=3.7,<4.0"
+python-versions = "<4.0,>=3.8"
files = [
- {file = "django_timezone_field-5.1-py3-none-any.whl", hash = "sha256:16ca9955a4e16064e32168b1a0d1cdb2839679c6cb56856c1f49f506e2ca4281"},
- {file = "django_timezone_field-5.1.tar.gz", hash = "sha256:73fc49519273cd5da1c7f16abc04a4bcad87b00cc02968d0d384c0fecf9a8a86"},
+ {file = "django_timezone_field-7.0-py3-none-any.whl", hash = "sha256:3232e7ecde66ba4464abb6f9e6b8cc739b914efb9b29dc2cf2eee451f7cc2acb"},
+ {file = "django_timezone_field-7.0.tar.gz", hash = "sha256:aa6f4965838484317b7f08d22c0d91a53d64e7bbbd34264468ae83d4023898a7"},
]
[package.dependencies]
"backports.zoneinfo" = {version = ">=0.2.1,<0.3.0", markers = "python_version < \"3.9\""}
-Django = ">=2.2,<3.0.dev0 || >=3.2.dev0,<5.0"
-pytz = "*"
+Django = ">=3.2,<6.0"
[[package]]
name = "django-tree-queries"
-version = "0.17.0"
+version = "0.19.0"
description = "Tree queries with explicit opt-in, without configurability"
optional = false
python-versions = ">=3.8"
files = [
- {file = "django_tree_queries-0.17.0-py3-none-any.whl", hash = "sha256:df62cc7daa7a766483a8ae11618ff7649d74425b5d245e9644526f2dd2f51af0"},
- {file = "django_tree_queries-0.17.0.tar.gz", hash = "sha256:f115cf6756c55fde56bb876d5b5aa1b2bd33ae3d6e2949c3176ef0b4fb64c532"},
+ {file = "django_tree_queries-0.19.0-py3-none-any.whl", hash = "sha256:05b9e3158e31612528f136b4704a8d807e14edc0b4a607a45377e6132517ba2c"},
+ {file = "django_tree_queries-0.19.0.tar.gz", hash = "sha256:d1325e75f96e90b86c4316a3d63498101ec05703f4e629786b561e8aaab0e4a7"},
]
[package.extras]
@@ -1243,18 +1229,18 @@ waitress = ["waitress"]
[[package]]
name = "djangorestframework"
-version = "3.15.1"
+version = "3.15.2"
description = "Web APIs for Django, made easy."
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.8"
files = [
- {file = "djangorestframework-3.15.1-py3-none-any.whl", hash = "sha256:3ccc0475bce968608cf30d07fb17d8e52d1d7fc8bfe779c905463200750cbca6"},
- {file = "djangorestframework-3.15.1.tar.gz", hash = "sha256:f88fad74183dfc7144b2756d0d2ac716ea5b4c7c9840995ac3bfd8ec034333c1"},
+ {file = "djangorestframework-3.15.2-py3-none-any.whl", hash = "sha256:2b8871b062ba1aefc2de01f773875441a961fefbf79f5eed1e32b2f096944b20"},
+ {file = "djangorestframework-3.15.2.tar.gz", hash = "sha256:36fe88cd2d6c6bec23dca9804bab2ba5517a8bb9d8f47ebc68981b56840107ad"},
]
[package.dependencies]
"backports.zoneinfo" = {version = "*", markers = "python_version < \"3.9\""}
-django = ">=3.0"
+django = ">=4.2"
[[package]]
name = "dnspython"
@@ -1292,13 +1278,13 @@ djangorestframework = ">=3.12.0,<4.0.0"
[[package]]
name = "drf-spectacular"
-version = "0.26.5"
+version = "0.27.2"
description = "Sane and flexible OpenAPI 3 schema generation for Django REST framework"
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
files = [
- {file = "drf-spectacular-0.26.5.tar.gz", hash = "sha256:aee55330a774ba8a9cbdb125714d1c9ee05a8aafd3ce3be8bfd26527649aeb44"},
- {file = "drf_spectacular-0.26.5-py3-none-any.whl", hash = "sha256:c0002a820b11771fdbf37853deb371947caf0159d1afeeffe7598e964bc1db94"},
+ {file = "drf-spectacular-0.27.2.tar.gz", hash = "sha256:a199492f2163c4101055075ebdbb037d59c6e0030692fc83a1a8c0fc65929981"},
+ {file = "drf_spectacular-0.27.2-py3-none-any.whl", hash = "sha256:b1c04bf8b2fbbeaf6f59414b4ea448c8787aba4d32f76055c3b13335cf7ec37b"},
]
[package.dependencies]
@@ -1308,6 +1294,7 @@ drf-spectacular-sidecar = {version = "*", optional = true, markers = "extra == \
inflection = ">=0.3.1"
jsonschema = ">=2.6.0"
PyYAML = ">=5.1"
+typing-extensions = {version = "*", markers = "python_version < \"3.10\""}
uritemplate = ">=2.0.0"
[package.extras]
@@ -1330,17 +1317,20 @@ Django = ">=2.2"
[[package]]
name = "emoji"
-version = "2.11.1"
+version = "2.12.1"
description = "Emoji for Python"
optional = false
-python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
+python-versions = ">=3.7"
files = [
- {file = "emoji-2.11.1-py2.py3-none-any.whl", hash = "sha256:b7ba25299bbf520cc8727848ae66b986da32aee27dc2887eaea2bff07226ce49"},
- {file = "emoji-2.11.1.tar.gz", hash = "sha256:062ff0b3154b6219143f8b9f4b3e5c64c35bc2b146e6e2349ab5f29e218ce1ee"},
+ {file = "emoji-2.12.1-py3-none-any.whl", hash = "sha256:a00d62173bdadc2510967a381810101624a2f0986145b8da0cffa42e29430235"},
+ {file = "emoji-2.12.1.tar.gz", hash = "sha256:4aa0488817691aa58d83764b6c209f8a27c0b3ab3f89d1b8dceca1a62e4973eb"},
]
+[package.dependencies]
+typing-extensions = ">=4.7.0"
+
[package.extras]
-dev = ["coverage", "coveralls", "pytest"]
+dev = ["coverage", "pytest (>=7.4.4)"]
[[package]]
name = "exchangelib"
@@ -1388,22 +1378,6 @@ files = [
[package.extras]
tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"]
-[[package]]
-name = "flake8"
-version = "5.0.4"
-description = "the modular source code checker: pep8 pyflakes and co"
-optional = false
-python-versions = ">=3.6.1"
-files = [
- {file = "flake8-5.0.4-py2.py3-none-any.whl", hash = "sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248"},
- {file = "flake8-5.0.4.tar.gz", hash = "sha256:6fbe320aad8d6b95cec8b8e47bc933004678dc63095be98528b7bdd2a9f510db"},
-]
-
-[package.dependencies]
-mccabe = ">=0.7.0,<0.8.0"
-pycodestyle = ">=2.9.0,<2.10.0"
-pyflakes = ">=2.5.0,<2.6.0"
-
[[package]]
name = "geographiclib"
version = "2.0"
@@ -1706,13 +1680,13 @@ six = ">=1.12"
[[package]]
name = "griffe"
-version = "0.45.2"
+version = "1.1.1"
description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API."
optional = false
python-versions = ">=3.8"
files = [
- {file = "griffe-0.45.2-py3-none-any.whl", hash = "sha256:297ec8530d0c68e5b98ff86fb588ebc3aa3559bb5dc21f3caea8d9542a350133"},
- {file = "griffe-0.45.2.tar.gz", hash = "sha256:83ce7dcaafd8cb7f43cbf1a455155015a1eb624b1ffd93249e5e1c4a22b2fdb2"},
+ {file = "griffe-1.1.1-py3-none-any.whl", hash = "sha256:0c469411e8d671a545725f5c0851a746da8bd99d354a79fdc4abd45219252efb"},
+ {file = "griffe-1.1.1.tar.gz", hash = "sha256:faeb78764c0b2bd010719d6e015d07709b0f260258b5d4dd6c88343d9702aa30"},
]
[package.dependencies]
@@ -2063,6 +2037,52 @@ sqs = ["boto3 (>=1.26.143)", "pycurl (>=7.43.0.5)", "urllib3 (>=1.26.16)"]
yaml = ["PyYAML (>=3.10)"]
zookeeper = ["kazoo (>=2.8.0)"]
+[[package]]
+name = "lazy-object-proxy"
+version = "1.10.0"
+description = "A fast and thorough lazy object proxy."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "lazy-object-proxy-1.10.0.tar.gz", hash = "sha256:78247b6d45f43a52ef35c25b5581459e85117225408a4128a3daf8bf9648ac69"},
+ {file = "lazy_object_proxy-1.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:855e068b0358ab916454464a884779c7ffa312b8925c6f7401e952dcf3b89977"},
+ {file = "lazy_object_proxy-1.10.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab7004cf2e59f7c2e4345604a3e6ea0d92ac44e1c2375527d56492014e690c3"},
+ {file = "lazy_object_proxy-1.10.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc0d2fc424e54c70c4bc06787e4072c4f3b1aa2f897dfdc34ce1013cf3ceef05"},
+ {file = "lazy_object_proxy-1.10.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e2adb09778797da09d2b5ebdbceebf7dd32e2c96f79da9052b2e87b6ea495895"},
+ {file = "lazy_object_proxy-1.10.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b1f711e2c6dcd4edd372cf5dec5c5a30d23bba06ee012093267b3376c079ec83"},
+ {file = "lazy_object_proxy-1.10.0-cp310-cp310-win32.whl", hash = "sha256:76a095cfe6045c7d0ca77db9934e8f7b71b14645f0094ffcd842349ada5c5fb9"},
+ {file = "lazy_object_proxy-1.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:b4f87d4ed9064b2628da63830986c3d2dca7501e6018347798313fcf028e2fd4"},
+ {file = "lazy_object_proxy-1.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fec03caabbc6b59ea4a638bee5fce7117be8e99a4103d9d5ad77f15d6f81020c"},
+ {file = "lazy_object_proxy-1.10.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02c83f957782cbbe8136bee26416686a6ae998c7b6191711a04da776dc9e47d4"},
+ {file = "lazy_object_proxy-1.10.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:009e6bb1f1935a62889ddc8541514b6a9e1fcf302667dcb049a0be5c8f613e56"},
+ {file = "lazy_object_proxy-1.10.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:75fc59fc450050b1b3c203c35020bc41bd2695ed692a392924c6ce180c6f1dc9"},
+ {file = "lazy_object_proxy-1.10.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:782e2c9b2aab1708ffb07d4bf377d12901d7a1d99e5e410d648d892f8967ab1f"},
+ {file = "lazy_object_proxy-1.10.0-cp311-cp311-win32.whl", hash = "sha256:edb45bb8278574710e68a6b021599a10ce730d156e5b254941754a9cc0b17d03"},
+ {file = "lazy_object_proxy-1.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:e271058822765ad5e3bca7f05f2ace0de58a3f4e62045a8c90a0dfd2f8ad8cc6"},
+ {file = "lazy_object_proxy-1.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e98c8af98d5707dcdecc9ab0863c0ea6e88545d42ca7c3feffb6b4d1e370c7ba"},
+ {file = "lazy_object_proxy-1.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:952c81d415b9b80ea261d2372d2a4a2332a3890c2b83e0535f263ddfe43f0d43"},
+ {file = "lazy_object_proxy-1.10.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80b39d3a151309efc8cc48675918891b865bdf742a8616a337cb0090791a0de9"},
+ {file = "lazy_object_proxy-1.10.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e221060b701e2aa2ea991542900dd13907a5c90fa80e199dbf5a03359019e7a3"},
+ {file = "lazy_object_proxy-1.10.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:92f09ff65ecff3108e56526f9e2481b8116c0b9e1425325e13245abfd79bdb1b"},
+ {file = "lazy_object_proxy-1.10.0-cp312-cp312-win32.whl", hash = "sha256:3ad54b9ddbe20ae9f7c1b29e52f123120772b06dbb18ec6be9101369d63a4074"},
+ {file = "lazy_object_proxy-1.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:127a789c75151db6af398b8972178afe6bda7d6f68730c057fbbc2e96b08d282"},
+ {file = "lazy_object_proxy-1.10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9e4ed0518a14dd26092614412936920ad081a424bdcb54cc13349a8e2c6d106a"},
+ {file = "lazy_object_proxy-1.10.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ad9e6ed739285919aa9661a5bbed0aaf410aa60231373c5579c6b4801bd883c"},
+ {file = "lazy_object_proxy-1.10.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fc0a92c02fa1ca1e84fc60fa258458e5bf89d90a1ddaeb8ed9cc3147f417255"},
+ {file = "lazy_object_proxy-1.10.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0aefc7591920bbd360d57ea03c995cebc204b424524a5bd78406f6e1b8b2a5d8"},
+ {file = "lazy_object_proxy-1.10.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5faf03a7d8942bb4476e3b62fd0f4cf94eaf4618e304a19865abf89a35c0bbee"},
+ {file = "lazy_object_proxy-1.10.0-cp38-cp38-win32.whl", hash = "sha256:e333e2324307a7b5d86adfa835bb500ee70bfcd1447384a822e96495796b0ca4"},
+ {file = "lazy_object_proxy-1.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:cb73507defd385b7705c599a94474b1d5222a508e502553ef94114a143ec6696"},
+ {file = "lazy_object_proxy-1.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:366c32fe5355ef5fc8a232c5436f4cc66e9d3e8967c01fb2e6302fd6627e3d94"},
+ {file = "lazy_object_proxy-1.10.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2297f08f08a2bb0d32a4265e98a006643cd7233fb7983032bd61ac7a02956b3b"},
+ {file = "lazy_object_proxy-1.10.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18dd842b49456aaa9a7cf535b04ca4571a302ff72ed8740d06b5adcd41fe0757"},
+ {file = "lazy_object_proxy-1.10.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:217138197c170a2a74ca0e05bddcd5f1796c735c37d0eee33e43259b192aa424"},
+ {file = "lazy_object_proxy-1.10.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9a3a87cf1e133e5b1994144c12ca4aa3d9698517fe1e2ca82977781b16955658"},
+ {file = "lazy_object_proxy-1.10.0-cp39-cp39-win32.whl", hash = "sha256:30b339b2a743c5288405aa79a69e706a06e02958eab31859f7f3c04980853b70"},
+ {file = "lazy_object_proxy-1.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:a899b10e17743683b293a729d3a11f2f399e8a90c73b089e29f5d0fe3509f0dd"},
+ {file = "lazy_object_proxy-1.10.0-pp310.pp311.pp312.pp38.pp39-none-any.whl", hash = "sha256:80fa48bd89c8f2f456fc0765c11c23bf5af827febacd2f523ca5bc1893fcc09d"},
+]
+
[[package]]
name = "lxml"
version = "4.9.4"
@@ -2173,13 +2193,13 @@ source = ["Cython (==0.29.37)"]
[[package]]
name = "markdown"
-version = "3.5.2"
+version = "3.6"
description = "Python implementation of John Gruber's Markdown."
optional = false
python-versions = ">=3.8"
files = [
- {file = "Markdown-3.5.2-py3-none-any.whl", hash = "sha256:d43323865d89fc0cb9b20c75fc8ad313af307cc087e84b657d9eec768eddeadd"},
- {file = "Markdown-3.5.2.tar.gz", hash = "sha256:e1ac7b3dc550ee80e602e71c1d168002f062e49f1b11e26a36264dafd4df2ef8"},
+ {file = "Markdown-3.6-py3-none-any.whl", hash = "sha256:48f276f4d8cfb8ce6527c8f79e2ee29708508bf4d40aa410fbc3b4ee832c850f"},
+ {file = "Markdown-3.6.tar.gz", hash = "sha256:ed4f41f6daecbeeb96e576ce414c41d2d876daa9a16cb35fa8ed8c2ddfad0224"},
]
[package.dependencies]
@@ -2190,28 +2210,18 @@ docs = ["mdx-gh-links (>=0.2)", "mkdocs (>=1.5)", "mkdocs-gen-files", "mkdocs-li
testing = ["coverage", "pyyaml"]
[[package]]
-name = "markdown-it-py"
-version = "3.0.0"
-description = "Python port of markdown-it. Markdown parsing, done right!"
+name = "markdown-version-annotations"
+version = "1.0.1"
+description = "Markdown plugin to add custom admonitions for documenting version differences"
optional = false
-python-versions = ">=3.8"
+python-versions = "<4.0,>=3.7"
files = [
- {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"},
- {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"},
+ {file = "markdown_version_annotations-1.0.1-py3-none-any.whl", hash = "sha256:6df0b2ac08bab906c8baa425f59fc0fe342fbe8b3917c144fb75914266b33200"},
+ {file = "markdown_version_annotations-1.0.1.tar.gz", hash = "sha256:620aade507ef175ccfb2059db152a34c6a1d2add28c2be16ea4de38d742e6132"},
]
[package.dependencies]
-mdurl = ">=0.1,<1.0"
-
-[package.extras]
-benchmarking = ["psutil", "pytest", "pytest-benchmark"]
-code-style = ["pre-commit (>=3.0,<4.0)"]
-compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"]
-linkify = ["linkify-it-py (>=1,<3)"]
-plugins = ["mdit-py-plugins"]
-profiling = ["gprof2dot"]
-rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"]
-testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"]
+markdown = ">=3.3.7,<4.0.0"
[[package]]
name = "markupsafe"
@@ -2307,17 +2317,6 @@ files = [
{file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"},
]
-[[package]]
-name = "mdurl"
-version = "0.1.2"
-description = "Markdown URL utilities"
-optional = false
-python-versions = ">=3.7"
-files = [
- {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"},
- {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
-]
-
[[package]]
name = "mergedeep"
version = "1.3.4"
@@ -2331,34 +2330,34 @@ files = [
[[package]]
name = "mkdocs"
-version = "1.5.2"
+version = "1.6.0"
description = "Project documentation with Markdown."
optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
files = [
- {file = "mkdocs-1.5.2-py3-none-any.whl", hash = "sha256:60a62538519c2e96fe8426654a67ee177350451616118a41596ae7c876bb7eac"},
- {file = "mkdocs-1.5.2.tar.gz", hash = "sha256:70d0da09c26cff288852471be03c23f0f521fc15cf16ac89c7a3bfb9ae8d24f9"},
+ {file = "mkdocs-1.6.0-py3-none-any.whl", hash = "sha256:1eb5cb7676b7d89323e62b56235010216319217d4af5ddc543a91beb8d125ea7"},
+ {file = "mkdocs-1.6.0.tar.gz", hash = "sha256:a73f735824ef83a4f3bcb7a231dcab23f5a838f88b7efc54a0eef5fbdbc3c512"},
]
[package.dependencies]
click = ">=7.0"
colorama = {version = ">=0.4", markers = "platform_system == \"Windows\""}
ghp-import = ">=1.0"
-importlib-metadata = {version = ">=4.3", markers = "python_version < \"3.10\""}
+importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""}
jinja2 = ">=2.11.1"
-markdown = ">=3.2.1"
+markdown = ">=3.3.6"
markupsafe = ">=2.0.1"
mergedeep = ">=1.3.4"
+mkdocs-get-deps = ">=0.2.0"
packaging = ">=20.5"
pathspec = ">=0.11.1"
-platformdirs = ">=2.2.0"
pyyaml = ">=5.1"
pyyaml-env-tag = ">=0.1"
watchdog = ">=2.0"
[package.extras]
i18n = ["babel (>=2.9.0)"]
-min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4)", "ghp-import (==1.0)", "importlib-metadata (==4.3)", "jinja2 (==2.11.1)", "markdown (==3.2.1)", "markupsafe (==2.0.1)", "mergedeep (==1.3.4)", "packaging (==20.5)", "pathspec (==0.11.1)", "platformdirs (==2.2.0)", "pyyaml (==5.1)", "pyyaml-env-tag (==0.1)", "typing-extensions (==3.10)", "watchdog (==2.0)"]
+min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4)", "ghp-import (==1.0)", "importlib-metadata (==4.4)", "jinja2 (==2.11.1)", "markdown (==3.3.6)", "markupsafe (==2.0.1)", "mergedeep (==1.3.4)", "mkdocs-get-deps (==0.2.0)", "packaging (==20.5)", "pathspec (==0.11.1)", "pyyaml (==5.1)", "pyyaml-env-tag (==0.1)", "watchdog (==2.0)"]
[[package]]
name = "mkdocs-autorefs"
@@ -2376,27 +2375,51 @@ Markdown = ">=3.3"
markupsafe = ">=2.0.1"
mkdocs = ">=1.1"
+[[package]]
+name = "mkdocs-get-deps"
+version = "0.2.0"
+description = "MkDocs extension that lists all dependencies according to a mkdocs.yml file"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134"},
+ {file = "mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c"},
+]
+
+[package.dependencies]
+importlib-metadata = {version = ">=4.3", markers = "python_version < \"3.10\""}
+mergedeep = ">=1.3.4"
+platformdirs = ">=2.2.0"
+pyyaml = ">=5.1"
+
[[package]]
name = "mkdocs-material"
-version = "9.1.15"
+version = "9.5.32"
description = "Documentation that simply works"
optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
files = [
- {file = "mkdocs_material-9.1.15-py3-none-any.whl", hash = "sha256:b49e12869ab464558e2dd3c5792da5b748a7e0c48ee83b4d05715f98125a7a39"},
- {file = "mkdocs_material-9.1.15.tar.gz", hash = "sha256:8513ab847c9a541ed3d11a3a7eed556caf72991ee786c31c5aac6691a121088a"},
+ {file = "mkdocs_material-9.5.32-py3-none-any.whl", hash = "sha256:f3704f46b63d31b3cd35c0055a72280bed825786eccaf19c655b44e0cd2c6b3f"},
+ {file = "mkdocs_material-9.5.32.tar.gz", hash = "sha256:38ed66e6d6768dde4edde022554553e48b2db0d26d1320b19e2e2b9da0be1120"},
]
[package.dependencies]
-colorama = ">=0.4"
-jinja2 = ">=3.0"
-markdown = ">=3.2"
-mkdocs = ">=1.4.2"
-mkdocs-material-extensions = ">=1.1"
-pygments = ">=2.14"
-pymdown-extensions = ">=9.9.1"
-regex = ">=2022.4.24"
-requests = ">=2.26"
+babel = ">=2.10,<3.0"
+colorama = ">=0.4,<1.0"
+jinja2 = ">=3.0,<4.0"
+markdown = ">=3.2,<4.0"
+mkdocs = ">=1.6,<2.0"
+mkdocs-material-extensions = ">=1.3,<2.0"
+paginate = ">=0.5,<1.0"
+pygments = ">=2.16,<3.0"
+pymdown-extensions = ">=10.2,<11.0"
+regex = ">=2022.4"
+requests = ">=2.26,<3.0"
+
+[package.extras]
+git = ["mkdocs-git-committers-plugin-2 (>=1.1,<2.0)", "mkdocs-git-revision-date-localized-plugin (>=1.2.4,<2.0)"]
+imaging = ["cairosvg (>=2.6,<3.0)", "pillow (>=10.2,<11.0)"]
+recommended = ["mkdocs-minify-plugin (>=0.7,<1.0)", "mkdocs-redirects (>=1.2,<2.0)", "mkdocs-rss-plugin (>=1.6,<2.0)"]
[[package]]
name = "mkdocs-material-extensions"
@@ -2409,35 +2432,26 @@ files = [
{file = "mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443"},
]
-[[package]]
-name = "mkdocs-version-annotations"
-version = "1.0.0"
-description = "MkDocs plugin to add custom admonitions for documenting version differences"
-optional = false
-python-versions = ">=3.7,<4.0"
-files = [
- {file = "mkdocs-version-annotations-1.0.0.tar.gz", hash = "sha256:6786024b37d27b330fda240b76ebec8e7ce48bd5a9d7a66e99804559d088dffa"},
- {file = "mkdocs_version_annotations-1.0.0-py3-none-any.whl", hash = "sha256:385004eb4a7530dd87a227e08cd907ce7a8fe21fdf297720a4149c511bcf05f5"},
-]
-
[[package]]
name = "mkdocstrings"
-version = "0.22.0"
+version = "0.25.2"
description = "Automatic documentation from sources, for MkDocs."
optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
files = [
- {file = "mkdocstrings-0.22.0-py3-none-any.whl", hash = "sha256:2d4095d461554ff6a778fdabdca3c00c468c2f1459d469f7a7f622a2b23212ba"},
- {file = "mkdocstrings-0.22.0.tar.gz", hash = "sha256:82a33b94150ebb3d4b5c73bab4598c3e21468c79ec072eff6931c8f3bfc38256"},
+ {file = "mkdocstrings-0.25.2-py3-none-any.whl", hash = "sha256:9e2cda5e2e12db8bb98d21e3410f3f27f8faab685a24b03b06ba7daa5b92abfc"},
+ {file = "mkdocstrings-0.25.2.tar.gz", hash = "sha256:5cf57ad7f61e8be3111a2458b4e49c2029c9cb35525393b179f9c916ca8042dc"},
]
[package.dependencies]
+click = ">=7.0"
importlib-metadata = {version = ">=4.6", markers = "python_version < \"3.10\""}
Jinja2 = ">=2.11.1"
Markdown = ">=3.3"
MarkupSafe = ">=1.1"
-mkdocs = ">=1.2"
+mkdocs = ">=1.4"
mkdocs-autorefs = ">=0.3.1"
+platformdirs = ">=2.2.0"
pymdown-extensions = ">=6.3"
typing-extensions = {version = ">=4.1", markers = "python_version < \"3.10\""}
@@ -2448,74 +2462,64 @@ python-legacy = ["mkdocstrings-python-legacy (>=0.2.1)"]
[[package]]
name = "mkdocstrings-python"
-version = "1.5.2"
+version = "1.10.8"
description = "A Python handler for mkdocstrings."
optional = false
python-versions = ">=3.8"
files = [
- {file = "mkdocstrings_python-1.5.2-py3-none-any.whl", hash = "sha256:ed37ca6d216986e2ac3530c19c3e7be381d1e3d09ea414e4ff467d6fd2cbd9c1"},
- {file = "mkdocstrings_python-1.5.2.tar.gz", hash = "sha256:81eb4a93bc454a253daf247d1a11397c435d641c64fa165324c17c06170b1dfb"},
+ {file = "mkdocstrings_python-1.10.8-py3-none-any.whl", hash = "sha256:bb12e76c8b071686617f824029cb1dfe0e9afe89f27fb3ad9a27f95f054dcd89"},
+ {file = "mkdocstrings_python-1.10.8.tar.gz", hash = "sha256:5856a59cbebbb8deb133224a540de1ff60bded25e54d8beacc375bb133d39016"},
]
[package.dependencies]
-griffe = ">=0.35"
-mkdocstrings = ">=0.20"
-
-[[package]]
-name = "mypy-extensions"
-version = "1.0.0"
-description = "Type system extensions for programs checked with the mypy type checker."
-optional = false
-python-versions = ">=3.5"
-files = [
- {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"},
- {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
-]
+griffe = ">=0.49"
+mkdocstrings = ">=0.25"
[[package]]
name = "nautobot"
-version = "2.2.5"
+version = "2.3.1"
description = "Source of truth and network automation platform."
optional = false
-python-versions = "<3.12,>=3.8"
+python-versions = "<3.13,>=3.8"
files = [
- {file = "nautobot-2.2.5-py3-none-any.whl", hash = "sha256:8b4256cb5f76b13d56c754b8a04e2869bc78d6a6593b2e7aae8094073320cb49"},
- {file = "nautobot-2.2.5.tar.gz", hash = "sha256:0b0ac6aae922092dad271feccfef3efe1e1482284b23d0acbdb0c61f78227b57"},
+ {file = "nautobot-2.3.1-py3-none-any.whl", hash = "sha256:28c02e229dcc87d69dba0e75d36c3bd219fefa9328ac996471e9b39f3ec74bb3"},
+ {file = "nautobot-2.3.1.tar.gz", hash = "sha256:96a3f0ee9cf73b404abca34bd2ed53a6d4494fcf85338734baa10dcd977f27f7"},
]
[package.dependencies]
-celery = ">=5.3.1,<5.4.0"
-Django = ">=3.2.25,<3.3.0"
+celery = ">=5.3.6,<5.4.0"
+Django = ">=4.2.15,<4.3.0"
django-ajax-tables = ">=1.1.1,<1.2.0"
django-celery-beat = ">=2.6.0,<2.7.0"
django-celery-results = ">=2.5.1,<2.6.0"
-django-constance = {version = ">=2.9.1,<2.10.0", extras = ["database"]}
-django-cors-headers = ">=4.3.1,<4.4.0"
-django-db-file-storage = ">=0.5.5,<0.6.0"
+django-constance = ">=3.1.0,<3.2.0"
+django-cors-headers = ">=4.4.0,<4.5.0"
+django-db-file-storage = ">=0.5.6.1,<0.6.0.0"
django-extensions = ">=3.2.3,<3.3.0"
-django-filter = ">=23.5,<23.6"
-django-health-check = ">=3.18.1,<3.19.0"
+django-filter = ">=24.2,<24.3"
+django-health-check = ">=3.18.3,<3.19.0"
django-jinja = ">=2.11.0,<2.12.0"
django-prometheus = ">=2.3.1,<2.4.0"
django-redis = ">=5.4.0,<5.5.0"
django-silk = ">=5.1.0,<5.2.0"
+django-structlog = {version = ">=8.1.0,<9.0.0", extras = ["all"]}
django-tables2 = ">=2.7.0,<2.8.0"
-django-taggit = ">=4.0.0,<4.1.0"
-django-timezone-field = ">=5.1,<5.2"
-django-tree-queries = ">=0.17.0,<0.18.0"
+django-taggit = ">=5.0.0,<5.1.0"
+django-timezone-field = ">=7.0,<7.1"
+django-tree-queries = ">=0.19.0,<0.20.0"
django-webserver = ">=1.2.0,<1.3.0"
-djangorestframework = ">=3.15.1,<3.16.0"
+djangorestframework = ">=3.15.2,<3.16.0"
drf-react-template-framework = ">=0.0.17,<0.0.18"
-drf-spectacular = {version = ">=0.26.5,<0.27.0", extras = ["sidecar"]}
-emoji = ">=2.11.0,<2.12.0"
+drf-spectacular = {version = ">=0.27.2,<0.28.0", extras = ["sidecar"]}
+emoji = ">=2.12.1,<2.13.0"
GitPython = ">=3.1.43,<3.2.0"
graphene-django = ">=2.16.0,<2.17.0"
graphene-django-optimizer = ">=0.8.0,<0.9.0"
Jinja2 = ">=3.1.4,<3.2.0"
jsonschema = ">=4.7.0,<5.0.0"
-Markdown = ">=3.5.2,<3.6.0"
+Markdown = ">=3.6,<3.7"
MarkupSafe = ">=2.1.5,<2.2.0"
-netaddr = ">=0.10.1,<0.11.0"
+netaddr = ">=1.3.0,<1.4.0"
netutils = ">=1.6.0,<2.0.0"
nh3 = ">=0.2.15,<0.3.0"
packaging = ">=23.1"
@@ -2525,26 +2529,26 @@ psycopg2-binary = ">=2.9.9,<2.10.0"
python-slugify = ">=8.0.3,<8.1.0"
pyuwsgi = ">=2.0.23,<2.1.0"
PyYAML = ">=6.0,<6.1"
-social-auth-app-django = ">=5.4.1,<5.5.0"
+social-auth-app-django = ">=5.4.2,<5.5.0"
svgwrite = ">=1.4.2,<1.5.0"
[package.extras]
-all = ["django-auth-ldap (>=4.7.0,<4.8.0)", "django-storages (>=1.14.2,<1.15.0)", "mysqlclient (>=2.2.3,<2.3.0)", "napalm (>=4.1.0,<4.2.0)", "social-auth-core[saml] (>=4.5.3,<4.6.0)"]
-ldap = ["django-auth-ldap (>=4.7.0,<4.8.0)"]
+all = ["django-auth-ldap (>=4.8.0,<4.9.0)", "django-storages (==1.14.3)", "mysqlclient (>=2.2.3,<2.3.0)", "napalm (>=4.1.0,<6.0.0)", "social-auth-core[saml] (>=4.5.3,<4.6.0)"]
+ldap = ["django-auth-ldap (>=4.8.0,<4.9.0)"]
mysql = ["mysqlclient (>=2.2.3,<2.3.0)"]
-napalm = ["napalm (>=4.1.0,<4.2.0)"]
-remote-storage = ["django-storages (>=1.14.2,<1.15.0)"]
+napalm = ["napalm (>=4.1.0,<6.0.0)"]
+remote-storage = ["django-storages (==1.14.3)"]
sso = ["social-auth-core[saml] (>=4.5.3,<4.6.0)"]
[[package]]
name = "nautobot-capacity-metrics"
-version = "3.0.1"
-description = "Plugin to improve the instrumentation of Nautobot and expose additional metrics (Application Metrics, RQ Worker)."
+version = "3.1.1"
+description = "App to improve the instrumentation of Nautobot and expose additional metrics (Application Metrics, RQ Worker)."
optional = true
-python-versions = ">=3.8,<3.12"
+python-versions = "<3.13,>=3.8"
files = [
- {file = "nautobot_capacity_metrics-3.0.1-py3-none-any.whl", hash = "sha256:066ad2a76c31f58d235cff3de770141013370d86d31fcfa1ae4110de47a1eb12"},
- {file = "nautobot_capacity_metrics-3.0.1.tar.gz", hash = "sha256:a9f0731fc3956d706ec5540795dabd83290f3616d9079bbd2fbc4d8f730dc086"},
+ {file = "nautobot_capacity_metrics-3.1.1-py3-none-any.whl", hash = "sha256:cba7108fc32473dd57e67e49e4c9de353837d0db63212e3dc9bed78ea6df57e6"},
+ {file = "nautobot_capacity_metrics-3.1.1.tar.gz", hash = "sha256:3f54cbaca846fd89bd215829305e28877b596a4de081e785d22afd91f2ae90c2"},
]
[package.dependencies]
@@ -2552,15 +2556,18 @@ nautobot = ">=2.0.0,<3.0.0"
[[package]]
name = "netaddr"
-version = "0.10.1"
+version = "1.3.0"
description = "A network address manipulation library for Python"
optional = false
-python-versions = "*"
+python-versions = ">=3.7"
files = [
- {file = "netaddr-0.10.1-py2.py3-none-any.whl", hash = "sha256:9822305b42ea1020d54fee322d43cee5622b044c07a1f0130b459bb467efcf88"},
- {file = "netaddr-0.10.1.tar.gz", hash = "sha256:f4da4222ca8c3f43c8e18a8263e5426c750a3a837fdfeccf74c68d0408eaa3bf"},
+ {file = "netaddr-1.3.0-py3-none-any.whl", hash = "sha256:c2c6a8ebe5554ce33b7d5b3a306b71bbb373e000bbbf2350dd5213cc56e3dbbe"},
+ {file = "netaddr-1.3.0.tar.gz", hash = "sha256:5c3c3d9895b551b763779ba7db7a03487dc1f8e3b385af819af341ae9ef6e48a"},
]
+[package.extras]
+nicer-shell = ["ipython"]
+
[[package]]
name = "netutils"
version = "1.8.1"
@@ -2709,6 +2716,21 @@ files = [
{file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"},
]
+[[package]]
+name = "paginate"
+version = "0.5.7"
+description = "Divides large result sets into pages for easier browsing"
+optional = false
+python-versions = "*"
+files = [
+ {file = "paginate-0.5.7-py2.py3-none-any.whl", hash = "sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591"},
+ {file = "paginate-0.5.7.tar.gz", hash = "sha256:22bd083ab41e1a8b4f3690544afb2c60c25e5c9a63a30fa2f483f6c60c8e5945"},
+]
+
+[package.extras]
+dev = ["pytest", "tox"]
+lint = ["black"]
+
[[package]]
name = "parameterized"
version = "0.9.0"
@@ -2749,17 +2771,6 @@ files = [
{file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"},
]
-[[package]]
-name = "pbr"
-version = "6.0.0"
-description = "Python Build Reasonableness"
-optional = false
-python-versions = ">=2.6"
-files = [
- {file = "pbr-6.0.0-py2.py3-none-any.whl", hash = "sha256:4a7317d5e3b17a3dccb6a8cfe67dab65b20551404c52c8ed41279fa4f0cb4cda"},
- {file = "pbr-6.0.0.tar.gz", hash = "sha256:d1377122a5a00e2f940ee482999518efe16d745d423a670c27773dfbc3c9a7d9"},
-]
-
[[package]]
name = "pexpect"
version = "4.9.0"
@@ -3242,17 +3253,6 @@ files = [
[package.dependencies]
typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
-[[package]]
-name = "pyflakes"
-version = "2.5.0"
-description = "passive checker of Python programs"
-optional = false
-python-versions = ">=3.6"
-files = [
- {file = "pyflakes-2.5.0-py2.py3-none-any.whl", hash = "sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2"},
- {file = "pyflakes-2.5.0.tar.gz", hash = "sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3"},
-]
-
[[package]]
name = "pygments"
version = "2.18.0"
@@ -3286,23 +3286,23 @@ tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"]
[[package]]
name = "pylint"
-version = "3.2.2"
+version = "2.17.7"
description = "python code static checker"
optional = false
-python-versions = ">=3.8.0"
+python-versions = ">=3.7.2"
files = [
- {file = "pylint-3.2.2-py3-none-any.whl", hash = "sha256:3f8788ab20bb8383e06dd2233e50f8e08949cfd9574804564803441a4946eab4"},
- {file = "pylint-3.2.2.tar.gz", hash = "sha256:d068ca1dfd735fb92a07d33cb8f288adc0f6bc1287a139ca2425366f7cbe38f8"},
+ {file = "pylint-2.17.7-py3-none-any.whl", hash = "sha256:27a8d4c7ddc8c2f8c18aa0050148f89ffc09838142193fdbe98f172781a3ff87"},
+ {file = "pylint-2.17.7.tar.gz", hash = "sha256:f4fcac7ae74cfe36bc8451e931d8438e4a476c20314b1101c458ad0f05191fad"},
]
[package.dependencies]
-astroid = ">=3.2.2,<=3.3.0-dev0"
+astroid = ">=2.15.8,<=2.17.0-dev0"
colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""}
dill = [
{version = ">=0.2", markers = "python_version < \"3.11\""},
{version = ">=0.3.6", markers = "python_version >= \"3.11\""},
]
-isort = ">=4.2.5,<5.13.0 || >5.13.0,<6"
+isort = ">=4.2.5,<6"
mccabe = ">=0.6,<0.8"
platformdirs = ">=2.2.0"
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
@@ -3333,18 +3333,18 @@ with-django = ["Django (>=2.2)"]
[[package]]
name = "pylint-nautobot"
-version = "0.3.0"
+version = "0.3.1"
description = "Custom Pylint Rules for Nautobot"
optional = false
-python-versions = ">=3.8,<3.12"
+python-versions = "<4.0,>=3.8"
files = [
- {file = "pylint_nautobot-0.3.0-py3-none-any.whl", hash = "sha256:91fed48d9a9f565c6aa46c679b930d64b06d014061f6e7e802e6de8b6b8e3f87"},
- {file = "pylint_nautobot-0.3.0.tar.gz", hash = "sha256:387a1d73b49186a7b325b6c1a3634e2c57ec0f2350e93494304c47073400099b"},
+ {file = "pylint_nautobot-0.3.1-py3-none-any.whl", hash = "sha256:097bb85405aabe766395a9d09dc474e39c8d9d23700d0e64e21f3855b4188466"},
+ {file = "pylint_nautobot-0.3.1.tar.gz", hash = "sha256:3a637f03dccf29db47d6fdfa348f6fbcd97e9471ade5c8eca7efd0921740dd94"},
]
[package.dependencies]
importlib-resources = ">=5.12.0"
-pylint = ">=2.17.5"
+pylint = ">=2.17,<3.0"
pyyaml = ">=6.0.1"
toml = ">=0.10.2"
@@ -3444,6 +3444,20 @@ files = [
[package.dependencies]
six = ">=1.5"
+[[package]]
+name = "python-ipware"
+version = "3.0.0"
+description = "A Python package to retrieve user's IP address"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "python_ipware-3.0.0-py3-none-any.whl", hash = "sha256:fc936e6e7ec9fcc107f9315df40658f468ac72f739482a707181742882e36b60"},
+ {file = "python_ipware-3.0.0.tar.gz", hash = "sha256:9117b1c4dddcb5d5ca49e6a9617de2fc66aec2ef35394563ac4eecabdf58c062"},
+]
+
+[package.extras]
+dev = ["coverage[toml]", "coveralls (>=3.3,<4.0)", "ruff", "twine"]
+
[[package]]
name = "python-slugify"
version = "8.0.4"
@@ -3792,25 +3806,6 @@ requests = ">=2.0.0"
[package.extras]
rsa = ["oauthlib[signedtoken] (>=3.0.0)"]
-[[package]]
-name = "rich"
-version = "13.7.1"
-description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
-optional = false
-python-versions = ">=3.7.0"
-files = [
- {file = "rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222"},
- {file = "rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"},
-]
-
-[package.dependencies]
-markdown-it-py = ">=2.2.0"
-pygments = ">=2.13.0,<3.0.0"
-typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.9\""}
-
-[package.extras]
-jupyter = ["ipywidgets (>=7.5.1,<9)"]
-
[[package]]
name = "rpds-py"
version = "0.18.1"
@@ -3935,28 +3930,29 @@ pyasn1 = ">=0.1.3"
[[package]]
name = "ruff"
-version = "0.4.6"
+version = "0.5.5"
description = "An extremely fast Python linter and code formatter, written in Rust."
optional = false
python-versions = ">=3.7"
files = [
- {file = "ruff-0.4.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ef995583a038cd4a7edf1422c9e19118e2511b8ba0b015861b4abd26ec5367c5"},
- {file = "ruff-0.4.6-py3-none-macosx_11_0_arm64.whl", hash = "sha256:602ebd7ad909eab6e7da65d3c091547781bb06f5f826974a53dbe563d357e53c"},
- {file = "ruff-0.4.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f9ced5cbb7510fd7525448eeb204e0a22cabb6e99a3cb160272262817d49786"},
- {file = "ruff-0.4.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:04a80acfc862e0e1630c8b738e70dcca03f350bad9e106968a8108379e12b31f"},
- {file = "ruff-0.4.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:be47700ecb004dfa3fd4dcdddf7322d4e632de3c06cd05329d69c45c0280e618"},
- {file = "ruff-0.4.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:1ff930d6e05f444090a0139e4e13e1e2e1f02bd51bb4547734823c760c621e79"},
- {file = "ruff-0.4.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f13410aabd3b5776f9c5699f42b37a3a348d65498c4310589bc6e5c548dc8a2f"},
- {file = "ruff-0.4.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0cf5cc02d3ae52dfb0c8a946eb7a1d6ffe4d91846ffc8ce388baa8f627e3bd50"},
- {file = "ruff-0.4.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea3424793c29906407e3cf417f28fc33f689dacbbadfb52b7e9a809dd535dcef"},
- {file = "ruff-0.4.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:1fa8561489fadf483ffbb091ea94b9c39a00ed63efacd426aae2f197a45e67fc"},
- {file = "ruff-0.4.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:4d5b914818d8047270308fe3e85d9d7f4a31ec86c6475c9f418fbd1624d198e0"},
- {file = "ruff-0.4.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:4f02284335c766678778475e7698b7ab83abaf2f9ff0554a07b6f28df3b5c259"},
- {file = "ruff-0.4.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:3a6a0a4f4b5f54fff7c860010ab3dd81425445e37d35701a965c0248819dde7a"},
- {file = "ruff-0.4.6-py3-none-win32.whl", hash = "sha256:9018bf59b3aa8ad4fba2b1dc0299a6e4e60a4c3bc62bbeaea222679865453062"},
- {file = "ruff-0.4.6-py3-none-win_amd64.whl", hash = "sha256:a769ae07ac74ff1a019d6bd529426427c3e30d75bdf1e08bb3d46ac8f417326a"},
- {file = "ruff-0.4.6-py3-none-win_arm64.whl", hash = "sha256:735a16407a1a8f58e4c5b913ad6102722e80b562dd17acb88887685ff6f20cf6"},
- {file = "ruff-0.4.6.tar.gz", hash = "sha256:a797a87da50603f71e6d0765282098245aca6e3b94b7c17473115167d8dfb0b7"},
+ {file = "ruff-0.5.5-py3-none-linux_armv6l.whl", hash = "sha256:605d589ec35d1da9213a9d4d7e7a9c761d90bba78fc8790d1c5e65026c1b9eaf"},
+ {file = "ruff-0.5.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:00817603822a3e42b80f7c3298c8269e09f889ee94640cd1fc7f9329788d7bf8"},
+ {file = "ruff-0.5.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:187a60f555e9f865a2ff2c6984b9afeffa7158ba6e1eab56cb830404c942b0f3"},
+ {file = "ruff-0.5.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe26fc46fa8c6e0ae3f47ddccfbb136253c831c3289bba044befe68f467bfb16"},
+ {file = "ruff-0.5.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4ad25dd9c5faac95c8e9efb13e15803cd8bbf7f4600645a60ffe17c73f60779b"},
+ {file = "ruff-0.5.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f70737c157d7edf749bcb952d13854e8f745cec695a01bdc6e29c29c288fc36e"},
+ {file = "ruff-0.5.5-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:cfd7de17cef6ab559e9f5ab859f0d3296393bc78f69030967ca4d87a541b97a0"},
+ {file = "ruff-0.5.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a09b43e02f76ac0145f86a08e045e2ea452066f7ba064fd6b0cdccb486f7c3e7"},
+ {file = "ruff-0.5.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d0b856cb19c60cd40198be5d8d4b556228e3dcd545b4f423d1ad812bfdca5884"},
+ {file = "ruff-0.5.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3687d002f911e8a5faf977e619a034d159a8373514a587249cc00f211c67a091"},
+ {file = "ruff-0.5.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ac9dc814e510436e30d0ba535f435a7f3dc97f895f844f5b3f347ec8c228a523"},
+ {file = "ruff-0.5.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:af9bdf6c389b5add40d89b201425b531e0a5cceb3cfdcc69f04d3d531c6be74f"},
+ {file = "ruff-0.5.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d40a8533ed545390ef8315b8e25c4bb85739b90bd0f3fe1280a29ae364cc55d8"},
+ {file = "ruff-0.5.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:cab904683bf9e2ecbbe9ff235bfe056f0eba754d0168ad5407832928d579e7ab"},
+ {file = "ruff-0.5.5-py3-none-win32.whl", hash = "sha256:696f18463b47a94575db635ebb4c178188645636f05e934fdf361b74edf1bb2d"},
+ {file = "ruff-0.5.5-py3-none-win_amd64.whl", hash = "sha256:50f36d77f52d4c9c2f1361ccbfbd09099a1b2ea5d2b2222c586ab08885cf3445"},
+ {file = "ruff-0.5.5-py3-none-win_arm64.whl", hash = "sha256:3191317d967af701f1b73a31ed5788795936e423b7acce82a2b63e26eb3e89d6"},
+ {file = "ruff-0.5.5.tar.gz", hash = "sha256:cc5516bdb4858d972fbc31d246bdb390eab8df1a26e2353be2dbc0c2d7f5421a"},
]
[[package]]
@@ -4023,13 +4019,13 @@ files = [
[[package]]
name = "social-auth-app-django"
-version = "5.4.1"
+version = "5.4.2"
description = "Python Social Authentication, Django integration."
optional = false
python-versions = ">=3.8"
files = [
- {file = "social-auth-app-django-5.4.1.tar.gz", hash = "sha256:2a43cde559dd34fdc7132417b6c52c780fa99ec2332dee9f405b4763f371c367"},
- {file = "social_auth_app_django-5.4.1-py3-none-any.whl", hash = "sha256:7519f186c63c50f2d364457b236f051338d194bcface55e318a6a705c5213477"},
+ {file = "social-auth-app-django-5.4.2.tar.gz", hash = "sha256:c8832c6cf13da6ad76f5613bcda2647d89ae7cfbc5217fadd13477a3406feaa8"},
+ {file = "social_auth_app_django-5.4.2-py3-none-any.whl", hash = "sha256:0c041a31707921aef9a930f143183c65d8c7b364381364a50f3f7c6fcc9d62f6"},
]
[package.dependencies]
@@ -4147,18 +4143,21 @@ pure-eval = "*"
tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"]
[[package]]
-name = "stevedore"
-version = "5.2.0"
-description = "Manage dynamic plugins for Python applications"
+name = "structlog"
+version = "24.4.0"
+description = "Structured Logging for Python"
optional = false
python-versions = ">=3.8"
files = [
- {file = "stevedore-5.2.0-py3-none-any.whl", hash = "sha256:1c15d95766ca0569cad14cb6272d4d31dae66b011a929d7c18219c176ea1b5c9"},
- {file = "stevedore-5.2.0.tar.gz", hash = "sha256:46b93ca40e1114cea93d738a6c1e365396981bb6bb78c27045b7587c9473544d"},
+ {file = "structlog-24.4.0-py3-none-any.whl", hash = "sha256:597f61e80a91cc0749a9fd2a098ed76715a1c8a01f73e336b746504d1aad7610"},
+ {file = "structlog-24.4.0.tar.gz", hash = "sha256:b27bfecede327a6d2da5fbc96bd859f114ecc398a6389d664f62085ee7ae6fc4"},
]
-[package.dependencies]
-pbr = ">=2.0.0,<2.1.0 || >2.1.0"
+[package.extras]
+dev = ["freezegun (>=0.2.8)", "mypy (>=1.4)", "pretend", "pytest (>=6.0)", "pytest-asyncio (>=0.17)", "rich", "simplejson", "twisted"]
+docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-mermaid", "sphinxext-opengraph", "twisted"]
+tests = ["freezegun (>=0.2.8)", "pretend", "pytest (>=6.0)", "pytest-asyncio (>=0.17)", "simplejson"]
+typing = ["mypy (>=1.4)", "rich", "twisted"]
[[package]]
name = "svgwrite"
@@ -4438,6 +4437,85 @@ files = [
[package.extras]
test = ["pytest (>=6.0.0)", "setuptools (>=65)"]
+[[package]]
+name = "wrapt"
+version = "1.16.0"
+description = "Module for decorators, wrappers and monkey patching."
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "wrapt-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4"},
+ {file = "wrapt-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020"},
+ {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440"},
+ {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487"},
+ {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf"},
+ {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72"},
+ {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0"},
+ {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136"},
+ {file = "wrapt-1.16.0-cp310-cp310-win32.whl", hash = "sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d"},
+ {file = "wrapt-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2"},
+ {file = "wrapt-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09"},
+ {file = "wrapt-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d"},
+ {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389"},
+ {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060"},
+ {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1"},
+ {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3"},
+ {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956"},
+ {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d"},
+ {file = "wrapt-1.16.0-cp311-cp311-win32.whl", hash = "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362"},
+ {file = "wrapt-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89"},
+ {file = "wrapt-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b"},
+ {file = "wrapt-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36"},
+ {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73"},
+ {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809"},
+ {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b"},
+ {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81"},
+ {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9"},
+ {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c"},
+ {file = "wrapt-1.16.0-cp312-cp312-win32.whl", hash = "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc"},
+ {file = "wrapt-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8"},
+ {file = "wrapt-1.16.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8"},
+ {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39"},
+ {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c"},
+ {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40"},
+ {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc"},
+ {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e"},
+ {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465"},
+ {file = "wrapt-1.16.0-cp36-cp36m-win32.whl", hash = "sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e"},
+ {file = "wrapt-1.16.0-cp36-cp36m-win_amd64.whl", hash = "sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966"},
+ {file = "wrapt-1.16.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593"},
+ {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292"},
+ {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5"},
+ {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf"},
+ {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228"},
+ {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f"},
+ {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c"},
+ {file = "wrapt-1.16.0-cp37-cp37m-win32.whl", hash = "sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c"},
+ {file = "wrapt-1.16.0-cp37-cp37m-win_amd64.whl", hash = "sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00"},
+ {file = "wrapt-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0"},
+ {file = "wrapt-1.16.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202"},
+ {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0"},
+ {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e"},
+ {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f"},
+ {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267"},
+ {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca"},
+ {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6"},
+ {file = "wrapt-1.16.0-cp38-cp38-win32.whl", hash = "sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b"},
+ {file = "wrapt-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41"},
+ {file = "wrapt-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2"},
+ {file = "wrapt-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb"},
+ {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8"},
+ {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c"},
+ {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a"},
+ {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664"},
+ {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f"},
+ {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537"},
+ {file = "wrapt-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3"},
+ {file = "wrapt-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35"},
+ {file = "wrapt-1.16.0-py3-none-any.whl", hash = "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1"},
+ {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"},
+]
+
[[package]]
name = "yamllint"
version = "1.35.1"
@@ -4472,10 +4550,11 @@ doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linke
test = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"]
[extras]
-all = ["exchangelib"]
+all = ["exchangelib", "nautobot-capacity-metrics"]
+capacity-metrics = ["nautobot-capacity-metrics"]
ews = ["exchangelib"]
[metadata]
lock-version = "2.0"
-python-versions = ">=3.8, <3.12"
-content-hash = "03f52269a19b6c0752100b9739a41c2bce2f5fd4190f87b224a6aea26c429728"
+python-versions = ">=3.8,<3.13"
+content-hash = "5d5b85698959a5407347a16a6311e9cf52fa15836198fa12e227e9b0d5bbfb30"
diff --git a/pyproject.toml b/pyproject.toml
index 6ffe2ea2..92a18351 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "nautobot-circuit-maintenance"
-version = "2.2.4"
+version = "2.3.0"
description = "Nautobot app to automatically handle Circuit Maintenances Notifications"
authors = ["Network to Code, LLC "]
license = "Apache-2.0"
@@ -17,6 +17,7 @@ classifiers = [
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
+ "Programming Language :: Python :: 3.12",
]
packages = [
{ include = "nautobot_circuit_maintenance" },
@@ -27,6 +28,9 @@ include = [
]
[tool.poetry.dependencies]
+python = ">=3.8,<3.13"
+# Used for local development
+nautobot = "^2.0.0"
circuit-maintenance-parser = "^2.0.0"
django-cryptography = "^1.1"
exchangelib = { version = ">=5.1.0", optional = true }
@@ -35,35 +39,31 @@ google-api-python-client = "^2.9.0"
google-auth-httplib2 = "^0.1.0"
google-auth-oauthlib = "^0.5.0"
markdown = "!=3.3.5" # Added due an issue with Markdown 3.3.5
-nautobot = "^2.0.0" # Used for local development
nautobot-capacity-metrics = {version = ">=3.0.0", optional = true }
-python = ">=3.8, <3.12"
pydantic = ">=1.10.4,<3"
[tool.poetry.group.dev.dependencies]
-Markdown = "*"
-bandit = "*"
-black = "*"
coverage = "*"
django-debug-toolbar = "*"
-flake8 = "*"
invoke = "*"
ipython = "*"
pylint = "*"
pylint-django = "*"
pylint-nautobot = "*"
-ruff = "*"
+ruff = "0.5.5"
yamllint = "*"
toml = "*"
+Markdown = "*"
+# Render custom markdown for version added/changed/remove notes
+markdown-version-annotations = "1.0.1"
# Rendering docs to HTML
-mkdocs = "1.5.2"
+mkdocs = "1.6.0"
# Material for MkDocs theme
-mkdocs-material = "9.1.15"
-# Render custom markdown for version added/changed/remove notes
-mkdocs-version-annotations = "1.0.0"
+mkdocs-material = "9.5.32"
# Automatic documentation from sources, for MkDocs
-mkdocstrings = "0.22.0"
-mkdocstrings-python = "1.5.2"
+mkdocstrings = "0.25.2"
+mkdocstrings-python = "1.10.8"
+griffe = "1.1.1"
parameterized = "*"
towncrier = "~23.6.0"
to-json-schema = "*"
@@ -73,58 +73,31 @@ jsonschema = "*"
ews = [
"exchangelib",
]
+capacity_metrics = [
+ "nautobot-capacity-metrics",
+]
all = [
"exchangelib",
+ "nautobot-capacity-metrics",
]
-[tool.black]
-line-length = 120
-target-version = ['py38', 'py39', 'py310', 'py311']
-include = '\.pyi?$'
-exclude = '''
-(
- /(
- \.eggs # exclude a few common directories in the
- | \.git # root of the project
- | \.hg
- | \.mypy_cache
- | \.tox
- | \.venv
- | _build
- | buck-out
- | build
- | dist
- )/
- | settings.py # This is where you define files that should not be stylized by black
- # the root of the project
-)
-'''
-
[tool.pylint.master]
# Include the pylint_django plugin to avoid spurious warnings about Django patterns
-load-plugins="pylint_django, pylint_nautobot"
-
-# Ignore migrations and tests
-ignore = ".venv,.*/tests/*,.*/migrations/*"
-
-# Don't raise alarms if args/kwargs has an issue, as may be required, just as a decorator
-ignored-argument-names="args|kwargs"
+load-plugins = "pylint_django, pylint_nautobot"
+ignore = ".venv"
[tool.pylint.basic]
# No docstrings required for private methods (Pylint default), or for test_ functions, or for inner Meta classes.
-no-docstring-rgx="^(_|test_|Meta$)"
+no-docstring-rgx = "^(_|test_|Meta$)"
[tool.pylint.messages_control]
-# Line length is enforced by Black, so pylint doesn't need to check it.
-# Pylint and Black disagree about how to format multi-line arrays; Black wins.
disable = """,
+ duplicate-code,
line-too-long,
too-few-public-methods,
- duplicate-code,
- too-many-ancestors,
- useless-option-value,
- """
+ too-many-ancestors
+"""
[tool.pylint.miscellaneous]
# Don't flag TODO as a failure, let us commit with things that still need to be done in the code
@@ -145,34 +118,39 @@ target-version = "py38"
[tool.ruff.lint]
select = [
"D", # pydocstyle
+ "F", "E", "W", # flake8
+ "S", # bandit
+ "I", # isort
]
ignore = [
# warning: `one-blank-line-before-class` (D203) and `no-blank-line-before-class` (D211) are incompatible.
- "D203", # 1 blank line required before class docstring
+ "D203", # 1 blank line required before class docstring
# D212 is enabled by default in google convention, and complains if we have a docstring like:
# """
# My docstring is on the line after the opening quotes instead of on the same line as them.
# """
# We've discussed and concluded that we consider this to be a valid style choice.
- "D212", # Multi-line docstring summary should start at the first line
- "D213", # Multi-line docstring summary should start at the second line
+ "D212", # Multi-line docstring summary should start at the first line
+ "D213", # Multi-line docstring summary should start at the second line
# Produces a lot of issues in the current codebase.
- "D401", # First line of docstring should be in imperative mood
- "D407", # Missing dashed underline after section
- "D416", # Section name ends in colon
+ "D401", # First line of docstring should be in imperative mood
+ "D407", # Missing dashed underline after section
+ "D416", # Section name ends in colon
+ "E501", # Line too long
]
[tool.ruff.lint.pydocstyle]
convention = "google"
-[tool.ruff.per-file-ignores]
+[tool.ruff.lint.per-file-ignores]
"nautobot_circuit_maintenance/migrations/*" = [
- "D", # pydocstyle
+ "D",
]
"nautobot_circuit_maintenance/tests/*" = [
- "D", # pydocstyle
+ "D",
+ "S"
]
[build-system]
diff --git a/tasks.py b/tasks.py
index d5c46993..7bc439e4 100644
--- a/tasks.py
+++ b/tasks.py
@@ -13,10 +13,12 @@
"""
import os
+import re
from pathlib import Path
from time import sleep
from invoke.collection import Collection
+from invoke.exceptions import Exit
from invoke.tasks import task as invoke_task
@@ -48,7 +50,7 @@ def is_truthy(arg):
namespace.configure(
{
"nautobot_circuit_maintenance": {
- "nautobot_ver": "2.0.0",
+ "nautobot_ver": "2.3.1",
"project_name": "nautobot-circuit-maintenance",
"python_ver": "3.11",
"local": False,
@@ -159,17 +161,17 @@ def run_command(context, command, **kwargs):
# Check if nautobot is running, no need to start another nautobot container to run a command
docker_compose_status = "ps --services --filter status=running"
results = docker_compose(context, docker_compose_status, hide="out")
- if "nautobot" in results.stdout:
- compose_command = "exec"
- else:
- compose_command = "run --rm --entrypoint=''"
+ command_env_args = ""
if "command_env" in kwargs:
command_env = kwargs.pop("command_env")
for key, value in command_env.items():
- compose_command += f' --env="{key}={value}"'
+ command_env_args += f' --env="{key}={value}"'
- compose_command += f" -- nautobot {command}"
+ if "nautobot" in results.stdout:
+ compose_command = f"exec{command_env_args} nautobot {command}"
+ else:
+ compose_command = f"run{command_env_args} --rm --entrypoint='{command}' nautobot"
pty = kwargs.pop("pty", True)
@@ -205,17 +207,51 @@ def generate_packages(context):
run_command(context, command)
+def _get_docker_nautobot_version(context, nautobot_ver=None, python_ver=None):
+ """Extract Nautobot version from base docker image."""
+ if nautobot_ver is None:
+ nautobot_ver = context.nautobot_circuit_maintenance.nautobot_ver
+ if python_ver is None:
+ python_ver = context.nautobot_circuit_maintenance.python_ver
+ dockerfile_path = os.path.join(context.nautobot_circuit_maintenance.compose_dir, "Dockerfile")
+ base_image = context.run(f"grep --max-count=1 '^FROM ' {dockerfile_path}", hide=True).stdout.strip().split(" ")[1]
+ base_image = base_image.replace(r"${NAUTOBOT_VER}", nautobot_ver).replace(r"${PYTHON_VER}", python_ver)
+ pip_nautobot_ver = context.run(f"docker run --rm --entrypoint '' {base_image} pip show nautobot", hide=True)
+ match_version = re.search(r"^Version: (.+)$", pip_nautobot_ver.stdout.strip(), flags=re.MULTILINE)
+ if match_version:
+ return match_version.group(1)
+ else:
+ raise Exit(f"Nautobot version not found in Docker base image {base_image}.")
+
+
@task(
help={
"check": (
"If enabled, check for outdated dependencies in the poetry.lock file, "
"instead of generating a new one. (default: disabled)"
- )
+ ),
+ "constrain_nautobot_ver": (
+ "Run 'poetry add nautobot@[version] --lock' to generate the lockfile, "
+ "where [version] is the version installed in the Dockerfile's base image. "
+ "Generally intended to be used in CI and not for local development. (default: disabled)"
+ ),
+ "constrain_python_ver": (
+ "When using `constrain_nautobot_ver`, further constrain the nautobot version "
+ "to python_ver so that poetry doesn't complain about python version incompatibilities. "
+ "Generally intended to be used in CI and not for local development. (default: disabled)"
+ ),
}
)
-def lock(context, check=False):
- """Generate poetry.lock inside the Nautobot container."""
- run_command(context, f"poetry {'check' if check else 'lock --no-update'}")
+def lock(context, check=False, constrain_nautobot_ver=False, constrain_python_ver=False):
+ """Generate poetry.lock file."""
+ if constrain_nautobot_ver:
+ docker_nautobot_version = _get_docker_nautobot_version(context)
+ command = f"poetry add --lock nautobot@{docker_nautobot_version}"
+ if constrain_python_ver:
+ command += f" --python {context.nautobot_circuit_maintenance.python_ver}"
+ else:
+ command = f"poetry {'check' if check else 'lock --no-update'}"
+ run_command(context, command)
# ------------------------------------------------------------------------------
@@ -496,7 +532,12 @@ def dbshell(context, db_name="", input_file="", output_file="", query=""):
f"> '{output_file}'" if output_file else "",
]
- docker_compose(context, " ".join(command), env=env, pty=not (input_file or output_file or query))
+ docker_compose(
+ context,
+ " ".join(command),
+ env=env,
+ pty=not (input_file or output_file or query),
+ )
@task(
@@ -651,28 +692,6 @@ def generate_release_notes(context, version=""):
# ------------------------------------------------------------------------------
# TESTS
# ------------------------------------------------------------------------------
-@task(
- help={
- "autoformat": "Apply formatting recommendations automatically, rather than failing if formatting is incorrect.",
- }
-)
-def black(context, autoformat=False):
- """Check Python code style with Black."""
- if autoformat:
- black_command = "black"
- else:
- black_command = "black --check --diff"
-
- command = f"{black_command} ."
-
- run_command(context, command)
-
-
-@task
-def flake8(context):
- """Check for PEP8 compliance and other style issues."""
- command = "flake8 . --config .flake8"
- run_command(context, command)
@task
@@ -694,38 +713,39 @@ def pylint(context):
@task(aliases=("a",))
def autoformat(context):
"""Run code autoformatting."""
- black(context, autoformat=True)
- ruff(context, fix=True)
+ ruff(context, action=["format"], fix=True)
@task(
help={
- "action": "One of 'lint', 'format', or 'both'",
- "fix": "Automatically fix selected action. May not be able to fix all.",
- "output_format": "see https://docs.astral.sh/ruff/settings/#output-format",
+ "action": "Available values are `['lint', 'format']`. Can be used multiple times. (default: `['lint', 'format']`)",
+ "target": "File or directory to inspect, repeatable (default: all files in the project will be inspected)",
+ "fix": "Automatically fix selected actions. May not be able to fix all issues found. (default: False)",
+ "output_format": "See https://docs.astral.sh/ruff/settings/#output-format for details. (default: `concise`)",
},
+ iterable=["action", "target"],
)
-def ruff(context, action="lint", fix=False, output_format="text"):
+def ruff(context, action=None, target=None, fix=False, output_format="concise"):
"""Run ruff to perform code formatting and/or linting."""
- if action != "lint":
- command = "ruff format"
- if not fix:
- command += " --check"
- command += " ."
- run_command(context, command)
- if action != "format":
- command = "ruff check"
- if fix:
- command += " --fix"
- command += f" --output-format {output_format} ."
- run_command(context, command)
+ if not action:
+ action = ["lint", "format"]
+ if not target:
+ target = ["."]
+ if "format" in action:
+ command = "ruff format "
+ if not fix:
+ command += "--check "
+ command += " ".join(target)
+ run_command(context, command, warn=True)
-@task
-def bandit(context):
- """Run bandit to validate basic static code security analysis."""
- command = "bandit --recursive . --configfile .bandit.yml"
- run_command(context, command)
+ if "lint" in action:
+ command = "ruff check "
+ if fix:
+ command += "--fix "
+ command += f"--output-format {output_format} "
+ command += " ".join(target)
+ run_command(context, command, warn=True)
@task
@@ -757,7 +777,7 @@ def check_migrations(context):
"verbose": "Enable verbose test output.",
}
)
-def unittest(
+def unittest( # noqa: PLR0913
context,
keepdb=False,
label="nautobot_circuit_maintenance",
@@ -805,14 +825,8 @@ def tests(context, failfast=False, keepdb=False, lint_only=False):
print("Starting Docker Containers...")
start(context)
# Sorted loosely from fastest to slowest
- print("Running black...")
- black(context)
print("Running ruff...")
ruff(context)
- print("Running flake8...")
- flake8(context)
- print("Running bandit...")
- bandit(context)
print("Running yamllint...")
yamllint(context)
print("Running poetry check...")
@@ -845,11 +859,20 @@ def generate_app_config_schema(context):
- `NautobotAppConfig.required_settings`
"""
start(context, service="nautobot")
- nbshell(context, file="development/app_config_schema.py", env={"APP_CONFIG_SCHEMA_COMMAND": "generate"})
+ nbshell(
+ context,
+ file="development/app_config_schema.py",
+ env={"APP_CONFIG_SCHEMA_COMMAND": "generate"},
+ )
@task
def validate_app_config(context):
"""Validate the app config based on the app config schema."""
start(context, service="nautobot")
- nbshell(context, plain=True, file="development/app_config_schema.py", env={"APP_CONFIG_SCHEMA_COMMAND": "validate"})
+ nbshell(
+ context,
+ plain=True,
+ file="development/app_config_schema.py",
+ env={"APP_CONFIG_SCHEMA_COMMAND": "validate"},
+ )