diff --git a/.bandit.yml b/.bandit.yml deleted file mode 100644 index f080f8bfe..000000000 --- a/.bandit.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -skips: ["B113"] -# No need to check for security issues in the test scripts! -exclude_dirs: - - "./tests/" - - "./.venv/" diff --git a/.cookiecutter.json b/.cookiecutter.json index e4e713c11..02ef3f20f 100644 --- a/.cookiecutter.json +++ b/.cookiecutter.json @@ -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.1", + "template_ref": "refs/tags/nautobot-app-v2.3.0", "cookie_dir": "", "branch_prefix": "drift-manager", "pull_request_strategy": "create", @@ -29,7 +29,7 @@ "black" ], "draft": true, - "baked_commit_ref": "88cb0d71afd4889658b76c64cfb86d5b347e7565" + "baked_commit_ref": "edf831ea98364f9a475ef147f13c1fb2f17b825f" } } } diff --git a/.dockerignore b/.dockerignore index 2270f4962..a0bf06f41 100644 --- a/.dockerignore +++ b/.dockerignore @@ -19,7 +19,6 @@ FAQ.md .git/ .gitignore .github -tasks.py LICENSE **/*.log **/.vscode/ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9c8a11bbc..445bf4ea1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ env: APP_NAME: "nautobot-app-ssot" jobs: - black: + ruff-format: runs-on: "ubuntu-22.04" env: INVOKE_NAUTOBOT_SSOT_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_SSOT_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_SSOT_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_SSOT_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 diff --git a/README.md b/README.md index beefec5da..61bae8cdd 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@
- An App for Nautobot. + An App for Nautobot.

diff --git a/changes/562.housekeeping b/changes/562.housekeeping new file mode 100644 index 000000000..6026d5a3b --- /dev/null +++ b/changes/562.housekeeping @@ -0,0 +1 @@ +Cut release 3.0.1. \ No newline at end of file diff --git a/development/nautobot_config.py b/development/nautobot_config.py index 5a0829c13..123ad7ec2 100644 --- a/development/nautobot_config.py +++ b/development/nautobot_config.py @@ -10,7 +10,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: @@ -48,9 +48,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/development/run_example_job.py b/development/run_example_job.py index ebbeabb6b..fe2d2501d 100644 --- a/development/run_example_job.py +++ b/development/run_example_job.py @@ -18,13 +18,8 @@ from django.core.management import call_command from nautobot.core.settings_funcs import is_truthy -from nautobot.extras.choices import SecretsGroupAccessTypeChoices -from nautobot.extras.choices import SecretsGroupSecretTypeChoices -from nautobot.extras.models import ExternalIntegration -from nautobot.extras.models import Job -from nautobot.extras.models import Secret -from nautobot.extras.models import SecretsGroup -from nautobot.extras.models import SecretsGroupAssociation +from nautobot.extras.choices import SecretsGroupAccessTypeChoices, SecretsGroupSecretTypeChoices +from nautobot.extras.models import ExternalIntegration, Job, Secret, SecretsGroup, SecretsGroupAssociation _TOKEN = 40 * "a" os.environ["NAUTOBOT_DEMO_TOKEN"] = _TOKEN diff --git a/docs/admin/compatibility_matrix.md b/docs/admin/compatibility_matrix.md index 7e1c604c5..013b73751 100644 --- a/docs/admin/compatibility_matrix.md +++ b/docs/admin/compatibility_matrix.md @@ -26,3 +26,4 @@ While that last supported version will not be strictly enforced--via the max_ver | 2.7.0 | 2.1.0 | 2.99.09 | | 2.8.0 | 2.1.0 | 2.99.09 | | 3.0.0 | 2.1.0 | 2.99.09 | +| 3.0.1 | 2.1.0 | 2.99.09 | diff --git a/docs/admin/release_notes/version_3.0.md b/docs/admin/release_notes/version_3.0.md index cd800262f..05742fd99 100644 --- a/docs/admin/release_notes/version_3.0.md +++ b/docs/admin/release_notes/version_3.0.md @@ -29,3 +29,21 @@ Updating DiffSync required changes to imports and many files changed `from diffs ### Housekeeping - [#433](https://github.com/nautobot/nautobot-app-ssot/issues/433) - Black 24.4.0 includes new formatting which was applied to all python files. + +## [v3.0.1 (2024-08-23)](https://github.com/nautobot/nautobot-app-ssot/releases/tag/v3.0.1) + +### Fixed + +- [#507](https://github.com/nautobot/nautobot-app-ssot/issues/507) - Fixed DataTarget example Job to include run() function for using ExternalIntegration or supplied URL and token. + +### Dependencies + +- [#516](https://github.com/nautobot/nautobot-app-ssot/issues/516) - Fix the dependencies for mkdocstrings and mkdocstrings-python to fix RTD build. + +### Documentation + +- [#518](https://github.com/nautobot/nautobot-app-ssot/issues/518) - Minor doc updates on upgrade to 3.0. + +### Housekeeping + +- [#515](https://github.com/nautobot/nautobot-app-ssot/issues/515) - Rebaked from the cookie `nautobot-app-v2.3.0`. diff --git a/docs/assets/extra.css b/docs/assets/extra.css index 1eff1192e..3f3931a0e 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 448835d93..a77574e79 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. diff --git a/docs/dev/dev_environment.md b/docs/dev/dev_environment.md index 7783ec795..3be133e9a 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/dev/upgrade.md b/docs/dev/upgrade.md index 46de17510..fc18dd789 100644 --- a/docs/dev/upgrade.md +++ b/docs/dev/upgrade.md @@ -24,7 +24,7 @@ class NautobotAdapter(Adapter) ## Set defaults for Optional -One of the changes with pydantic v2 is that any variables that are Optional must have a default of None defined. This needs to be done on your class attributes like below: +One of the changes with Pydantic v2 is that any variables that are Optional must have a default of None defined. This needs to be done on your class attributes like below: ```python class DeviceModel(NautobotModel): @@ -46,11 +46,11 @@ class DeviceModel(NautobotModel): name: str location__name: str location__location_type__name: str - location__parent__name: Optional[str] - location__parent__location_type__name: Optional[str] + location__parent__name: Optional[str] # Pydantic v1, replace + location__parent__location_type__name: Optional[str] # Pydantic v1, replace device_type__manufacturer__name: str device_type__model: str - platform__name: Optional[str] + platform__name: Optional[str] # Pydantic v1, replace role__name: str serial: str status__name: str @@ -78,11 +78,11 @@ class DeviceModel(NautobotModel): name: str location__name: str location__location_type__name: str - location__parent__name: Optional[str] = None - location__parent__location_type__name: Optional[str] = None + location__parent__name: Optional[str] = None # Pydantic v2 compatibile + location__parent__location_type__name: Optional[str] = None # Pydantic v2 compatibile device_type__manufacturer__name: str device_type__model: str - platform__name: Optional[str] = None + platform__name: Optional[str] = None # Pydantic v2 compatibile role__name: str serial: str status__name: str @@ -96,6 +96,8 @@ Any instances where you're referring to the diffsync kwarg needs to be updated t self.diffsync.job.logger.warning("Example") ``` +is changed to the following: + ```python self.adapter.job.logger.warning("Example") ``` diff --git a/docs/requirements.txt b/docs/requirements.txt index a2c1e2a2d..777f1b50b 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==* -mkdocstrings==* +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 \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index b223523a2..992eac2f8 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -71,6 +71,8 @@ extra: link: "https://twitter.com/networktocode" name: "Network to Code Twitter" markdown_extensions: + - "markdown_version_annotations": + admonition_tag: "???" - "admonition" - "toc": permalink: true @@ -88,7 +90,6 @@ markdown_extensions: - "footnotes" plugins: - "search" - - "mkdocs-version-annotations" - "mkdocstrings": default_handler: "python" handlers: diff --git a/nautobot_ssot/contrib/__init__.py b/nautobot_ssot/contrib/__init__.py index 6e7f6b275..1ace601c8 100644 --- a/nautobot_ssot/contrib/__init__.py +++ b/nautobot_ssot/contrib/__init__.py @@ -3,9 +3,9 @@ from nautobot_ssot.contrib.adapter import NautobotAdapter from nautobot_ssot.contrib.model import NautobotModel from nautobot_ssot.contrib.types import ( - RelationshipSideEnum, CustomFieldAnnotation, CustomRelationshipAnnotation, + RelationshipSideEnum, ) __all__ = ( diff --git a/nautobot_ssot/contrib/adapter.py b/nautobot_ssot/contrib/adapter.py index 57a680c06..a55555092 100644 --- a/nautobot_ssot/contrib/adapter.py +++ b/nautobot_ssot/contrib/adapter.py @@ -4,17 +4,17 @@ # Diffsync relies on underscore-prefixed attributes quite heavily, which is why we disable this here. from collections import defaultdict - -from typing import FrozenSet, Tuple, Hashable, DefaultDict, Dict, Type, get_args +from typing import DefaultDict, Dict, FrozenSet, Hashable, Tuple, Type, get_args import pydantic from diffsync import Adapter from diffsync.exceptions import ObjectCrudException from django.contrib.contenttypes.models import ContentType from django.db.models import Model -from nautobot.extras.models import Relationship, RelationshipAssociation from nautobot.extras.choices import RelationshipTypeChoices +from nautobot.extras.models import Relationship, RelationshipAssociation from typing_extensions import get_type_hints + from nautobot_ssot.contrib.types import ( CustomFieldAnnotation, CustomRelationshipAnnotation, diff --git a/nautobot_ssot/contrib/model.py b/nautobot_ssot/contrib/model.py index 567fd3f84..12b6fcf60 100644 --- a/nautobot_ssot/contrib/model.py +++ b/nautobot_ssot/contrib/model.py @@ -4,19 +4,18 @@ # Diffsync relies on underscore-prefixed attributes quite heavily, which is why we disable this here. from collections import defaultdict -from uuid import UUID - from typing import ClassVar, Optional +from uuid import UUID from diffsync import DiffSyncModel -from diffsync.exceptions import ObjectCrudException, ObjectNotUpdated, ObjectNotDeleted, ObjectNotCreated +from diffsync.exceptions import ObjectCrudException, ObjectNotCreated, ObjectNotDeleted, ObjectNotUpdated from django.contrib.contenttypes.models import ContentType -from django.core.exceptions import ValidationError, MultipleObjectsReturned +from django.core.exceptions import MultipleObjectsReturned, ValidationError from django.db.models import Model, ProtectedError -from nautobot.extras.models import Relationship, RelationshipAssociation from nautobot.extras.choices import RelationshipTypeChoices - +from nautobot.extras.models import Relationship, RelationshipAssociation from typing_extensions import get_type_hints + from nautobot_ssot.contrib.types import ( CustomFieldAnnotation, CustomRelationshipAnnotation, @@ -110,9 +109,7 @@ def create(cls, adapter, ids, attrs): return super().create(adapter, ids, attrs) @classmethod - def _handle_single_field( - cls, field, obj, value, relationship_fields, adapter - ): # pylint: disable=too-many-arguments,too-many-locals, too-many-branches + def _handle_single_field(cls, field, obj, value, relationship_fields, adapter): # pylint: disable=too-many-arguments,too-many-locals, too-many-branches """Set a single field on a Django object to a given value, or, for relationship fields, prepare setting. :param field: The name of the field to set. @@ -152,9 +149,9 @@ def _handle_single_field( # Custom relationship foreign keys if custom_relationship_annotation: relationship_fields["custom_relationship_foreign_keys"][related_model][lookup] = value - relationship_fields["custom_relationship_foreign_keys"][related_model][ - "_annotation" - ] = custom_relationship_annotation + relationship_fields["custom_relationship_foreign_keys"][related_model]["_annotation"] = ( + custom_relationship_annotation + ) # Normal foreign keys else: django_field = cls._model._meta.get_field(related_model) diff --git a/nautobot_ssot/filters.py b/nautobot_ssot/filters.py index 8858c82a1..bbebc69ea 100644 --- a/nautobot_ssot/filters.py +++ b/nautobot_ssot/filters.py @@ -2,7 +2,6 @@ import django_filters from django.db.models import Q - from nautobot.apps.filters import BaseFilterSet from .models import Sync, SyncLogEntry diff --git a/nautobot_ssot/forms.py b/nautobot_ssot/forms.py index e28019338..f61d9a439 100644 --- a/nautobot_ssot/forms.py +++ b/nautobot_ssot/forms.py @@ -1,9 +1,8 @@ """Forms for working with Sync and SyncLogEntry models.""" from django import forms - from nautobot.apps.forms import add_blank_choice -from nautobot.core.forms import BootstrapMixin, BOOLEAN_WITH_BLANK_CHOICES +from nautobot.core.forms import BOOLEAN_WITH_BLANK_CHOICES, BootstrapMixin from .choices import SyncLogEntryActionChoices, SyncLogEntryStatusChoices from .models import Sync, SyncLogEntry diff --git a/nautobot_ssot/integrations/aci/diffsync/adapters/aci.py b/nautobot_ssot/integrations/aci/diffsync/adapters/aci.py index b6f1d6e8c..9ff461070 100644 --- a/nautobot_ssot/integrations/aci/diffsync/adapters/aci.py +++ b/nautobot_ssot/integrations/aci/diffsync/adapters/aci.py @@ -5,23 +5,26 @@ import logging import os import re -from typing import Optional from ipaddress import ip_network +from typing import Optional + from diffsync import Adapter from diffsync.exceptions import ObjectNotFound + from nautobot_ssot.integrations.aci.constant import PLUGIN_CFG -from nautobot_ssot.integrations.aci.diffsync.models import NautobotTenant -from nautobot_ssot.integrations.aci.diffsync.models import NautobotVrf -from nautobot_ssot.integrations.aci.diffsync.models import NautobotDeviceType -from nautobot_ssot.integrations.aci.diffsync.models import NautobotDeviceRole -from nautobot_ssot.integrations.aci.diffsync.models import NautobotDevice -from nautobot_ssot.integrations.aci.diffsync.models import NautobotInterfaceTemplate -from nautobot_ssot.integrations.aci.diffsync.models import NautobotInterface -from nautobot_ssot.integrations.aci.diffsync.models import NautobotIPAddress -from nautobot_ssot.integrations.aci.diffsync.models import NautobotPrefix +from nautobot_ssot.integrations.aci.diffsync.models import ( + NautobotDevice, + NautobotDeviceRole, + NautobotDeviceType, + NautobotInterface, + NautobotInterfaceTemplate, + NautobotIPAddress, + NautobotPrefix, + NautobotTenant, + NautobotVrf, +) from nautobot_ssot.integrations.aci.diffsync.utils import load_yamlfile - logger = logging.getLogger(__name__) @@ -73,7 +76,7 @@ def load_tenants(self): """Load tenants from ACI.""" tenant_list = self.conn.get_tenants() for _tenant in tenant_list: - if not _tenant["name"] in PLUGIN_CFG.get("ignore_tenants"): + if _tenant["name"] not in PLUGIN_CFG.get("ignore_tenants"): tenant_name = f"{self.tenant_prefix}:{_tenant['name']}" if ":mso" in _tenant.get("annotation").lower(): # pylint: disable=simplifiable-if-statement _msite_tag = True @@ -132,7 +135,7 @@ def load_ipaddresses(self): # Leaf/Spine management IP addresses mgmt_tenant = f"{self.tenant_prefix}:mgmt" for node in node_dict.values(): - if node.get("oob_ip"): # nosec + if node.get("oob_ip"): if node.get("subnet"): subnet = node["subnet"] else: @@ -171,7 +174,7 @@ def load_ipaddresses(self): controller_dict = self.conn.get_controllers() # Controller IP addresses for controller in controller_dict.values(): - if controller.get("oob_ip"): # nosec + if controller.get("oob_ip"): if controller.get("subnet"): subnet = controller["subnet"] else: diff --git a/nautobot_ssot/integrations/aci/diffsync/adapters/nautobot.py b/nautobot_ssot/integrations/aci/diffsync/adapters/nautobot.py index a390a29c6..c735651f5 100644 --- a/nautobot_ssot/integrations/aci/diffsync/adapters/nautobot.py +++ b/nautobot_ssot/integrations/aci/diffsync/adapters/nautobot.py @@ -4,25 +4,28 @@ import logging from collections import defaultdict + from diffsync import Adapter from diffsync.enum import DiffSyncModelFlags from django.contrib.contenttypes.models import ContentType from django.db.models import ProtectedError +from nautobot.dcim.models import Device, DeviceType, Interface, InterfaceTemplate +from nautobot.extras.models import Role, Tag +from nautobot.ipam.models import VRF, IPAddress, Prefix from nautobot.tenancy.models import Tenant -from nautobot.dcim.models import DeviceType, Device, InterfaceTemplate, Interface -from nautobot.extras.models import Role -from nautobot.ipam.models import IPAddress, Prefix, VRF -from nautobot.extras.models import Tag -from nautobot_ssot.integrations.aci.diffsync.models import NautobotTenant -from nautobot_ssot.integrations.aci.diffsync.models import NautobotVrf -from nautobot_ssot.integrations.aci.diffsync.models import NautobotDeviceType -from nautobot_ssot.integrations.aci.diffsync.models import NautobotDeviceRole -from nautobot_ssot.integrations.aci.diffsync.models import NautobotDevice -from nautobot_ssot.integrations.aci.diffsync.models import NautobotInterfaceTemplate -from nautobot_ssot.integrations.aci.diffsync.models import NautobotInterface -from nautobot_ssot.integrations.aci.diffsync.models import NautobotIPAddress -from nautobot_ssot.integrations.aci.diffsync.models import NautobotPrefix + from nautobot_ssot.integrations.aci.constant import PLUGIN_CFG +from nautobot_ssot.integrations.aci.diffsync.models import ( + NautobotDevice, + NautobotDeviceRole, + NautobotDeviceType, + NautobotInterface, + NautobotInterfaceTemplate, + NautobotIPAddress, + NautobotPrefix, + NautobotTenant, + NautobotVrf, +) logger = logging.getLogger(__name__) diff --git a/nautobot_ssot/integrations/aci/diffsync/client.py b/nautobot_ssot/integrations/aci/diffsync/client.py index 55e7f408b..c51b73440 100644 --- a/nautobot_ssot/integrations/aci/diffsync/client.py +++ b/nautobot_ssot/integrations/aci/diffsync/client.py @@ -415,10 +415,10 @@ def get_nodes(self) -> dict: resp = self._get('/api/class/topSystem.json?query-target-filter=ne(topSystem.role,"controller")') for node in resp.json()["imdata"]: - if node["topSystem"]["attributes"]["oobMgmtAddr"] != "0.0.0.0": # nosec: B104 + if node["topSystem"]["attributes"]["oobMgmtAddr"] != "0.0.0.0": # noqa: S104 mgmt_addr = f"{node['topSystem']['attributes']['oobMgmtAddr']}/{node['topSystem']['attributes']['oobMgmtAddrMask']}" elif ( - node["topSystem"]["attributes"]["address"] != "0.0.0.0" # nosec: B104 + node["topSystem"]["attributes"]["address"] != "0.0.0.0" # noqa: S104 and node["topSystem"]["attributes"]["tepPool"] ): mgmt_addr = f"{node['topSystem']['attributes']['address']}/{ip_network(node['topSystem']['attributes']['tepPool'], strict=False).prefixlen}" @@ -426,7 +426,7 @@ def get_nodes(self) -> dict: mgmt_addr = "" if mgmt_addr: subnet = ip_network(mgmt_addr, strict=False).with_prefixlen - elif node["topSystem"]["attributes"]["tepPool"] != "0.0.0.0": # nosec: B104 + elif node["topSystem"]["attributes"]["tepPool"] != "0.0.0.0": # noqa: S104 subnet = node["topSystem"]["attributes"]["tepPool"] else: subnet = "" @@ -468,10 +468,10 @@ def get_controllers(self) -> dict: node_dict[node_id]["site"] = self.site resp = self._get('/api/class/topSystem.json?query-target-filter=eq(topSystem.role,"controller")') for node in resp.json()["imdata"]: - if node["topSystem"]["attributes"]["oobMgmtAddr"] != "0.0.0.0": # nosec: B104 + if node["topSystem"]["attributes"]["oobMgmtAddr"] != "0.0.0.0": # noqa: S104 mgmt_addr = f"{node['topSystem']['attributes']['oobMgmtAddr']}/{node['topSystem']['attributes']['oobMgmtAddrMask']}" elif ( - node["topSystem"]["attributes"]["address"] != "0.0.0.0" # nosec: B104 + node["topSystem"]["attributes"]["address"] != "0.0.0.0" # noqa: S104 and node["topSystem"]["attributes"]["tepPool"] ): mgmt_addr = f"{node['topSystem']['attributes']['address']}/{ip_network(node['topSystem']['attributes']['tepPool'], strict=False).prefixlen}" @@ -479,7 +479,7 @@ def get_controllers(self) -> dict: mgmt_addr = "" if mgmt_addr: subnet = ip_network(mgmt_addr, strict=False).with_prefixlen - elif node["topSystem"]["attributes"]["tepPool"] != "0.0.0.0": # nosec: B104 + elif node["topSystem"]["attributes"]["tepPool"] != "0.0.0.0": # noqa: S104 subnet = node["topSystem"]["attributes"]["tepPool"] else: subnet = "" diff --git a/nautobot_ssot/integrations/aci/diffsync/models/__init__.py b/nautobot_ssot/integrations/aci/diffsync/models/__init__.py index f93410bf8..8816cb258 100644 --- a/nautobot_ssot/integrations/aci/diffsync/models/__init__.py +++ b/nautobot_ssot/integrations/aci/diffsync/models/__init__.py @@ -1,15 +1,15 @@ """Initialize models for Nautobot and ACI.""" from .nautobot import ( - NautobotTenant, - NautobotVrf, NautobotDevice, NautobotDeviceRole, NautobotDeviceType, - NautobotInterfaceTemplate, NautobotInterface, - NautobotPrefix, + NautobotInterfaceTemplate, NautobotIPAddress, + NautobotPrefix, + NautobotTenant, + NautobotVrf, ) __all__ = [ diff --git a/nautobot_ssot/integrations/aci/diffsync/models/base.py b/nautobot_ssot/integrations/aci/diffsync/models/base.py index 42b979ce8..0874f5fba 100644 --- a/nautobot_ssot/integrations/aci/diffsync/models/base.py +++ b/nautobot_ssot/integrations/aci/diffsync/models/base.py @@ -1,6 +1,7 @@ """Base Shared Models for Cisco ACI integration with SSoT app.""" from typing import List, Optional + from diffsync import DiffSyncModel diff --git a/nautobot_ssot/integrations/aci/diffsync/utils.py b/nautobot_ssot/integrations/aci/diffsync/utils.py index c9bf072d3..a8584af7f 100644 --- a/nautobot_ssot/integrations/aci/diffsync/utils.py +++ b/nautobot_ssot/integrations/aci/diffsync/utils.py @@ -3,6 +3,7 @@ # pylint: disable=invalid-name import logging import re + import yaml logger = logging.getLogger(__name__) diff --git a/nautobot_ssot/integrations/aci/signals.py b/nautobot_ssot/integrations/aci/signals.py index 036e311c4..7cbc46023 100644 --- a/nautobot_ssot/integrations/aci/signals.py +++ b/nautobot_ssot/integrations/aci/signals.py @@ -48,7 +48,7 @@ def aci_create_tag(apps, **kwargs): if ("SITE" in key or "STAGE" in key) and not tag.objects.filter(name=apics[key]).exists(): tag.objects.update_or_create( name=apics[key], - color="".join([random.choice("ABCDEF0123456789") for i in range(6)]), # nosec + color="".join([random.choice("ABCDEF0123456789") for i in range(6)]), # noqa: S311 ) diff --git a/nautobot_ssot/integrations/aristacv/diffsync/adapters/cloudvision.py b/nautobot_ssot/integrations/aristacv/diffsync/adapters/cloudvision.py index 04b4c30ff..a9cfb1543 100644 --- a/nautobot_ssot/integrations/aristacv/diffsync/adapters/cloudvision.py +++ b/nautobot_ssot/integrations/aristacv/diffsync/adapters/cloudvision.py @@ -11,11 +11,11 @@ from nautobot_ssot.integrations.aristacv.diffsync.models.cloudvision import ( CloudvisionCustomField, CloudvisionDevice, + CloudvisionIPAddress, + CloudvisionIPAssignment, CloudvisionNamespace, CloudvisionPort, CloudvisionPrefix, - CloudvisionIPAddress, - CloudvisionIPAssignment, ) from nautobot_ssot.integrations.aristacv.types import CloudVisionAppConfig from nautobot_ssot.integrations.aristacv.utils import cloudvision diff --git a/nautobot_ssot/integrations/aristacv/diffsync/adapters/nautobot.py b/nautobot_ssot/integrations/aristacv/diffsync/adapters/nautobot.py index 5e5c01d3a..f769c9501 100644 --- a/nautobot_ssot/integrations/aristacv/diffsync/adapters/nautobot.py +++ b/nautobot_ssot/integrations/aristacv/diffsync/adapters/nautobot.py @@ -1,6 +1,9 @@ """DiffSync adapter for Nautobot.""" from collections import defaultdict + +from diffsync import Adapter +from diffsync.exceptions import ObjectAlreadyExists, ObjectNotFound from django.contrib.contenttypes.models import ContentType from django.db.models import ProtectedError from nautobot.dcim.models import Device as OrmDevice @@ -9,17 +12,15 @@ from nautobot.extras.models import RelationshipAssociation as OrmRelationshipAssociation from nautobot.ipam.models import IPAddress as OrmIPAddress from nautobot.ipam.models import IPAddressToInterface -from diffsync import Adapter -from diffsync.exceptions import ObjectNotFound, ObjectAlreadyExists from nautobot_ssot.integrations.aristacv.diffsync.models.nautobot import ( - NautobotDevice, NautobotCustomField, - NautobotNamespace, - NautobotPrefix, + NautobotDevice, NautobotIPAddress, NautobotIPAssignment, + NautobotNamespace, NautobotPort, + NautobotPrefix, ) from nautobot_ssot.integrations.aristacv.types import CloudVisionAppConfig from nautobot_ssot.integrations.aristacv.utils import nautobot diff --git a/nautobot_ssot/integrations/aristacv/diffsync/models/base.py b/nautobot_ssot/integrations/aristacv/diffsync/models/base.py index c6af8e974..99026f077 100644 --- a/nautobot_ssot/integrations/aristacv/diffsync/models/base.py +++ b/nautobot_ssot/integrations/aristacv/diffsync/models/base.py @@ -1,8 +1,9 @@ """DiffSyncModel subclasses for Nautobot-to-AristaCV data sync.""" +from typing import List, Optional from uuid import UUID + from diffsync import DiffSyncModel -from typing import List, Optional class Device(DiffSyncModel): diff --git a/nautobot_ssot/integrations/aristacv/diffsync/models/cloudvision.py b/nautobot_ssot/integrations/aristacv/diffsync/models/cloudvision.py index 18394b613..f5d5ede41 100644 --- a/nautobot_ssot/integrations/aristacv/diffsync/models/cloudvision.py +++ b/nautobot_ssot/integrations/aristacv/diffsync/models/cloudvision.py @@ -1,13 +1,13 @@ """CloudVision DiffSync models for AristaCV SSoT.""" from nautobot_ssot.integrations.aristacv.diffsync.models.base import ( - Device, CustomField, - Namespace, - Prefix, + Device, IPAddress, IPAssignment, + Namespace, Port, + Prefix, ) from nautobot_ssot.integrations.aristacv.types import CloudVisionAppConfig from nautobot_ssot.integrations.aristacv.utils.cloudvision import CloudvisionApi diff --git a/nautobot_ssot/integrations/aristacv/diffsync/models/nautobot.py b/nautobot_ssot/integrations/aristacv/diffsync/models/nautobot.py index c917c37f1..b1f64ab80 100644 --- a/nautobot_ssot/integrations/aristacv/diffsync/models/nautobot.py +++ b/nautobot_ssot/integrations/aristacv/diffsync/models/nautobot.py @@ -1,6 +1,8 @@ """Nautobot DiffSync models for AristaCV SSoT.""" +import distutils import logging + from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ValidationError from nautobot.core.settings_funcs import is_truthy @@ -11,10 +13,9 @@ from nautobot.extras.models import RelationshipAssociation as OrmRelationshipAssociation from nautobot.extras.models import Status as OrmStatus from nautobot.ipam.models import IPAddress as OrmIPAddress -from nautobot.ipam.models import Prefix as OrmPrefix -from nautobot.ipam.models import Namespace as OrmNamespace from nautobot.ipam.models import IPAddressToInterface -import distutils +from nautobot.ipam.models import Namespace as OrmNamespace +from nautobot.ipam.models import Prefix as OrmPrefix from nautobot_ssot.integrations.aristacv.constants import ( ARISTA_PLATFORM, @@ -22,8 +23,8 @@ DEFAULT_DEVICE_ROLE_COLOR, ) from nautobot_ssot.integrations.aristacv.diffsync.models.base import ( - Device, CustomField, + Device, IPAddress, IPAssignment, Namespace, diff --git a/nautobot_ssot/integrations/aristacv/jobs.py b/nautobot_ssot/integrations/aristacv/jobs.py index efbb63018..735318059 100644 --- a/nautobot_ssot/integrations/aristacv/jobs.py +++ b/nautobot_ssot/integrations/aristacv/jobs.py @@ -5,15 +5,13 @@ from django.urls import reverse from nautobot.core.utils.lookup import get_route_for_model from nautobot.dcim.models import DeviceType -from nautobot.extras.jobs import BooleanVar -from nautobot.extras.jobs import Job +from nautobot.extras.jobs import BooleanVar, Job + from nautobot_ssot.integrations.aristacv.diffsync.adapters.cloudvision import CloudvisionAdapter from nautobot_ssot.integrations.aristacv.diffsync.adapters.nautobot import NautobotAdapter from nautobot_ssot.integrations.aristacv.utils.cloudvision import CloudvisionApi from nautobot_ssot.integrations.aristacv.utils.nautobot import get_config -from nautobot_ssot.jobs.base import DataMapping -from nautobot_ssot.jobs.base import DataSource -from nautobot_ssot.jobs.base import DataTarget +from nautobot_ssot.jobs.base import DataMapping, DataSource, DataTarget name = "SSoT - Arista CloudVision" # pylint: disable=invalid-name diff --git a/nautobot_ssot/integrations/aristacv/utils/cloudvision.py b/nautobot_ssot/integrations/aristacv/utils/cloudvision.py index bde720aa0..0477a7a85 100644 --- a/nautobot_ssot/integrations/aristacv/utils/cloudvision.py +++ b/nautobot_ssot/integrations/aristacv/utils/cloudvision.py @@ -6,24 +6,21 @@ from typing import Any, Iterable, List, Optional, Tuple, Union from urllib.parse import urlparse +import cloudvision.Connector.gen.notification_pb2 as ntf +import cloudvision.Connector.gen.router_pb2 as rtr +import cloudvision.Connector.gen.router_pb2_grpc as rtr_client import google.protobuf.timestamp_pb2 as pbts import grpc import requests from arista.inventory.v1 import models, services from arista.tag.v2 import models as tag_models from arista.tag.v2 import services as tag_services - -from google.protobuf.wrappers_pb2 import StringValue # pylint: disable=no-name-in-module - -from cvprac.cvp_client import CvpClient -from cvprac.cvp_client import CvpLoginError -import cloudvision.Connector.gen.notification_pb2 as ntf -import cloudvision.Connector.gen.router_pb2 as rtr -import cloudvision.Connector.gen.router_pb2_grpc as rtr_client from cloudvision.Connector import codec from cloudvision.Connector.codec import Wildcard from cloudvision.Connector.codec.custom_types import FrozenDict from cloudvision.Connector.grpc_client.grpcClient import create_query, to_pbts +from cvprac.cvp_client import CvpClient, CvpLoginError +from google.protobuf.wrappers_pb2 import StringValue # pylint: disable=no-name-in-module from nautobot_ssot.integrations.aristacv.constants import PORT_TYPE_MAP from nautobot_ssot.integrations.aristacv.types import CloudVisionAppConfig @@ -66,8 +63,8 @@ def __init__(self, config: CloudVisionAppConfig): ) if token: call_creds = grpc.access_token_call_credentials(token) - elif config.cvp_user != "" and config.cvp_password != "": # nosec - response = requests.post( # nosec + elif config.cvp_user != "" and config.cvp_password != "": + response = requests.post( f"{parsed_url.hostname}:{parsed_url.port}/cvpservice/login/authenticate.do", auth=(config.cvp_user, config.cvp_password), timeout=60, @@ -688,7 +685,7 @@ def get_cvp_version(config: CloudVisionAppConfig): client.connect( nodes=[config.url], username="", - password="", # nosec: B106 + password="", is_cvaas=True, api_token=config.token, ) diff --git a/nautobot_ssot/integrations/aristacv/utils/nautobot.py b/nautobot_ssot/integrations/aristacv/utils/nautobot.py index 8078aaafb..bbd709d1a 100644 --- a/nautobot_ssot/integrations/aristacv/utils/nautobot.py +++ b/nautobot_ssot/integrations/aristacv/utils/nautobot.py @@ -9,21 +9,18 @@ from django.contrib.contenttypes.models import ContentType from nautobot.core.models.utils import slugify from nautobot.core.settings_funcs import is_truthy -from nautobot.dcim.models import Device -from nautobot.dcim.models import DeviceType -from nautobot.dcim.models import Location -from nautobot.dcim.models import LocationType -from nautobot.dcim.models import Manufacturer -from nautobot.extras.choices import SecretsGroupAccessTypeChoices -from nautobot.extras.choices import SecretsGroupSecretTypeChoices -from nautobot.extras.models import ExternalIntegration -from nautobot.extras.models import Relationship -from nautobot.extras.models import Role -from nautobot.extras.models import Secret -from nautobot.extras.models import SecretsGroup -from nautobot.extras.models import SecretsGroupAssociation -from nautobot.extras.models import Status -from nautobot.extras.models import Tag +from nautobot.dcim.models import Device, DeviceType, Location, LocationType, Manufacturer +from nautobot.extras.choices import SecretsGroupAccessTypeChoices, SecretsGroupSecretTypeChoices +from nautobot.extras.models import ( + ExternalIntegration, + Relationship, + Role, + Secret, + SecretsGroup, + SecretsGroupAssociation, + Status, + Tag, +) from nautobot_ssot.integrations.aristacv import constants from nautobot_ssot.integrations.aristacv.types import CloudVisionAppConfig diff --git a/nautobot_ssot/integrations/device42/diffsync/adapters/device42.py b/nautobot_ssot/integrations/device42/diffsync/adapters/device42.py index 21cb817af..8b617b3d9 100644 --- a/nautobot_ssot/integrations/device42/diffsync/adapters/device42.py +++ b/nautobot_ssot/integrations/device42/diffsync/adapters/device42.py @@ -1,22 +1,24 @@ """DiffSync adapter for Device42.""" +import ipaddress import re from decimal import Decimal from typing import List -import ipaddress + from diffsync import Adapter from diffsync.exceptions import ObjectAlreadyExists, ObjectNotFound from nautobot.core.settings_funcs import is_truthy from netutils.bandwidth import name_to_bits from netutils.dns import fqdn_to_ip, is_fqdn_resolvable + from nautobot_ssot.integrations.device42.constant import PLUGIN_CFG from nautobot_ssot.integrations.device42.diffsync.models.base import assets, circuits, dcim, ipam from nautobot_ssot.integrations.device42.utils.device42 import ( + get_custom_field_dict, get_facility, - get_intf_type, get_intf_status, + get_intf_type, get_netmiko_platform, - get_custom_field_dict, load_vlan, ) from nautobot_ssot.integrations.device42.utils.nautobot import determine_vc_position diff --git a/nautobot_ssot/integrations/device42/diffsync/adapters/nautobot.py b/nautobot_ssot/integrations/device42/diffsync/adapters/nautobot.py index 77bf464b9..d4495787a 100644 --- a/nautobot_ssot/integrations/device42/diffsync/adapters/nautobot.py +++ b/nautobot_ssot/integrations/device42/diffsync/adapters/nautobot.py @@ -1,7 +1,8 @@ """DiffSync adapter class for Nautobot as source-of-truth.""" -from collections import defaultdict import logging +from collections import defaultdict + from diffsync import Adapter from diffsync.exceptions import ObjectAlreadyExists, ObjectNotFound from django.db.models import ProtectedError @@ -22,7 +23,7 @@ VirtualChassis, ) from nautobot.extras.models import Relationship, Role, Status -from nautobot.ipam.models import VLAN, VRF, IPAddress, IPAddressToInterface, Prefix, Namespace +from nautobot.ipam.models import VLAN, VRF, IPAddress, IPAddressToInterface, Namespace, Prefix from netutils.lib_mapper import ANSIBLE_LIB_MAPPER from nautobot_ssot.integrations.device42.constant import PLUGIN_CFG diff --git a/nautobot_ssot/integrations/device42/diffsync/models/nautobot/assets.py b/nautobot_ssot/integrations/device42/diffsync/models/nautobot/assets.py index dec64d7fb..f441f0362 100644 --- a/nautobot_ssot/integrations/device42/diffsync/models/nautobot/assets.py +++ b/nautobot_ssot/integrations/device42/diffsync/models/nautobot/assets.py @@ -1,13 +1,15 @@ """DiffSyncModel Asset subclasses for Nautobot Device42 data sync.""" from typing import Optional + from django.core.exceptions import ValidationError -from nautobot.dcim.models import Device, DeviceType, FrontPort, RearPort, Location +from nautobot.dcim.models import Device, DeviceType, FrontPort, Location, RearPort + from nautobot_ssot.integrations.device42.constant import PLUGIN_CFG from nautobot_ssot.integrations.device42.diffsync.models.base.assets import ( PatchPanel, - PatchPanelRearPort, PatchPanelFrontPort, + PatchPanelRearPort, ) from nautobot_ssot.integrations.device42.diffsync.models.nautobot.dcim import NautobotRack from nautobot_ssot.integrations.device42.utils import nautobot diff --git a/nautobot_ssot/integrations/device42/diffsync/models/nautobot/circuits.py b/nautobot_ssot/integrations/device42/diffsync/models/nautobot/circuits.py index 5660f34d1..d1a42caa5 100644 --- a/nautobot_ssot/integrations/device42/diffsync/models/nautobot/circuits.py +++ b/nautobot_ssot/integrations/device42/diffsync/models/nautobot/circuits.py @@ -6,6 +6,7 @@ from nautobot.circuits.models import CircuitTermination as OrmCT from nautobot.circuits.models import Provider as OrmProvider from nautobot.dcim.models import Cable as OrmCable + from nautobot_ssot.integrations.device42.constant import INTF_SPEED_MAP, PLUGIN_CFG from nautobot_ssot.integrations.device42.diffsync.models.base.circuits import Circuit, Provider from nautobot_ssot.integrations.device42.diffsync.models.nautobot.dcim import NautobotDevice diff --git a/nautobot_ssot/integrations/device42/diffsync/models/nautobot/dcim.py b/nautobot_ssot/integrations/device42/diffsync/models/nautobot/dcim.py index 4ebb4f80c..2ac93bb94 100644 --- a/nautobot_ssot/integrations/device42/diffsync/models/nautobot/dcim.py +++ b/nautobot_ssot/integrations/device42/diffsync/models/nautobot/dcim.py @@ -13,15 +13,15 @@ from nautobot.dcim.models import DeviceType as OrmDeviceType from nautobot.dcim.models import FrontPort as OrmFrontPort from nautobot.dcim.models import Interface as OrmInterface +from nautobot.dcim.models import Location as OrmSite +from nautobot.dcim.models import LocationType as OrmLocationType from nautobot.dcim.models import Manufacturer as OrmManufacturer from nautobot.dcim.models import Rack as OrmRack from nautobot.dcim.models import RackGroup as OrmRackGroup -from nautobot.dcim.models import Location as OrmSite -from nautobot.dcim.models import LocationType as OrmLocationType from nautobot.dcim.models import VirtualChassis as OrmVC from nautobot.extras.models import RelationshipAssociation from nautobot.extras.models import Status as OrmStatus -from nautobot_ssot.jobs.base import DataSource + from nautobot_ssot.integrations.device42.constant import DEFAULTS, INTF_SPEED_MAP, PLUGIN_CFG from nautobot_ssot.integrations.device42.diffsync.models.base.dcim import ( Building, @@ -35,6 +35,7 @@ Vendor, ) from nautobot_ssot.integrations.device42.utils import device42, nautobot +from nautobot_ssot.jobs.base import DataSource try: from nautobot_device_lifecycle_mgmt.models import SoftwareLCM diff --git a/nautobot_ssot/integrations/device42/jobs.py b/nautobot_ssot/integrations/device42/jobs.py index 25e0de267..3cf996049 100644 --- a/nautobot_ssot/integrations/device42/jobs.py +++ b/nautobot_ssot/integrations/device42/jobs.py @@ -3,16 +3,15 @@ from django.templatetags.static import static from django.urls import reverse -from nautobot.extras.models import ExternalIntegration from nautobot.extras.jobs import BooleanVar, ObjectVar -from nautobot_ssot.jobs.base import DataMapping, DataSource +from nautobot.extras.models import ExternalIntegration from nautobot_ssot.integrations.device42.diffsync.adapters.device42 import Device42Adapter from nautobot_ssot.integrations.device42.diffsync.adapters.nautobot import NautobotAdapter from nautobot_ssot.integrations.device42.utils.device42 import Device42API +from nautobot_ssot.jobs.base import DataMapping, DataSource from nautobot_ssot.utils import get_username_password_https_from_secretsgroup - name = "SSoT - Device42" # pylint: disable=invalid-name diff --git a/nautobot_ssot/integrations/device42/utils/nautobot.py b/nautobot_ssot/integrations/device42/utils/nautobot.py index d1bba046e..36e023c73 100644 --- a/nautobot_ssot/integrations/device42/utils/nautobot.py +++ b/nautobot_ssot/integrations/device42/utils/nautobot.py @@ -14,6 +14,7 @@ from nautobot.extras.models import CustomField, Relationship, Role, Tag from netutils.lib_mapper import ANSIBLE_LIB_MAPPER_REVERSE, NAPALM_LIB_MAPPER_REVERSE from taggit.managers import TaggableManager + from nautobot_ssot.integrations.device42.diffsync.models.base.dcim import Device as NautobotDevice logger = logging.getLogger(__name__) @@ -38,7 +39,7 @@ def get_random_color() -> str: Returns: str: Hex code value for a color with hash stripped. """ - return f"{random.randint(0, 0xFFFFFF):06x}" # nosec: B311 + return f"{random.randint(0, 0xFFFFFF):06x}" # noqa: S311 def verify_device_role(adapter, role_name: str, role_color: str = "") -> UUID: diff --git a/nautobot_ssot/integrations/dna_center/diffsync/adapters/nautobot.py b/nautobot_ssot/integrations/dna_center/diffsync/adapters/nautobot.py index 8da70dbca..973b8ec22 100644 --- a/nautobot_ssot/integrations/dna_center/diffsync/adapters/nautobot.py +++ b/nautobot_ssot/integrations/dna_center/diffsync/adapters/nautobot.py @@ -9,6 +9,7 @@ from collections import defaultdict from typing import Optional + from diffsync import Adapter from diffsync.enum import DiffSyncModelFlags from diffsync.exceptions import ObjectNotFound @@ -19,15 +20,15 @@ from nautobot.dcim.models import Interface as OrmInterface from nautobot.dcim.models import Location as OrmLocation from nautobot.dcim.models import LocationType as OrmLocationType -from nautobot.extras.models import Status as OrmStatus from nautobot.extras.models import Relationship as OrmRelationship from nautobot.extras.models import RelationshipAssociation as OrmRelationshipAssociation +from nautobot.extras.models import Status as OrmStatus from nautobot.ipam.models import IPAddress as OrmIPAddress from nautobot.ipam.models import IPAddressToInterface as OrmIPAddressToInterface from nautobot.ipam.models import Namespace from nautobot.ipam.models import Prefix as OrmPrefix from nautobot.tenancy.models import Tenant as OrmTenant -from nautobot_ssot.jobs.base import DataTarget + from nautobot_ssot.integrations.dna_center.constants import PLUGIN_CFG from nautobot_ssot.integrations.dna_center.diffsync.models.nautobot import ( NautobotArea, @@ -35,10 +36,11 @@ NautobotDevice, NautobotFloor, NautobotIPAddress, + NautobotIPAddressOnInterface, NautobotPort, NautobotPrefix, - NautobotIPAddressOnInterface, ) +from nautobot_ssot.jobs.base import DataTarget class NautobotAdapter(Adapter): diff --git a/nautobot_ssot/integrations/dna_center/diffsync/models/base.py b/nautobot_ssot/integrations/dna_center/diffsync/models/base.py index a105b0b7d..d2f3e70a2 100644 --- a/nautobot_ssot/integrations/dna_center/diffsync/models/base.py +++ b/nautobot_ssot/integrations/dna_center/diffsync/models/base.py @@ -1,7 +1,8 @@ """DiffSyncModel subclasses for Nautobot-to-DNA Center data sync.""" -from typing import Optional, List +from typing import List, Optional from uuid import UUID + from diffsync import DiffSyncModel diff --git a/nautobot_ssot/integrations/dna_center/diffsync/models/dna_center.py b/nautobot_ssot/integrations/dna_center/diffsync/models/dna_center.py index 1b61a0dcb..1984410e8 100644 --- a/nautobot_ssot/integrations/dna_center/diffsync/models/dna_center.py +++ b/nautobot_ssot/integrations/dna_center/diffsync/models/dna_center.py @@ -3,12 +3,12 @@ from nautobot_ssot.integrations.dna_center.diffsync.models.base import ( Area, Building, - Floor, Device, - Port, - Prefix, + Floor, IPAddress, IPAddressOnInterface, + Port, + Prefix, ) diff --git a/nautobot_ssot/integrations/dna_center/jobs.py b/nautobot_ssot/integrations/dna_center/jobs.py index 02812e8a1..e52af5189 100644 --- a/nautobot_ssot/integrations/dna_center/jobs.py +++ b/nautobot_ssot/integrations/dna_center/jobs.py @@ -1,16 +1,16 @@ """Jobs for DNA Center SSoT integration.""" -from django.urls import reverse from django.templatetags.static import static +from django.urls import reverse +from nautobot.core.celery import register_jobs from nautobot.dcim.models import Controller, ControllerManagedDeviceGroup from nautobot.extras.choices import SecretsGroupAccessTypeChoices, SecretsGroupSecretTypeChoices from nautobot.extras.jobs import BooleanVar, ObjectVar from nautobot.tenancy.models import Tenant -from nautobot.core.celery import register_jobs -from nautobot_ssot.jobs.base import DataSource, DataMapping + from nautobot_ssot.integrations.dna_center.diffsync.adapters import dna_center, nautobot from nautobot_ssot.integrations.dna_center.utils.dna_center import DnaCenterClient - +from nautobot_ssot.jobs.base import DataMapping, DataSource name = "DNA Center SSoT" # pylint: disable=invalid-name diff --git a/nautobot_ssot/integrations/dna_center/utils/dna_center.py b/nautobot_ssot/integrations/dna_center/utils/dna_center.py index 83b1f0768..c695e299d 100644 --- a/nautobot_ssot/integrations/dna_center/utils/dna_center.py +++ b/nautobot_ssot/integrations/dna_center/utils/dna_center.py @@ -16,9 +16,7 @@ class DnaCenterClient: """Client for handling all interactions with DNA Center.""" - def __init__( - self, url: str, username: str, password: str, port: int = 443, verify: bool = True - ): # pylint: disable=too-many-arguments + def __init__(self, url: str, username: str, password: str, port: int = 443, verify: bool = True): # pylint: disable=too-many-arguments """Initialize instance of client.""" self.url = url self.port = port diff --git a/nautobot_ssot/integrations/dna_center/utils/nautobot.py b/nautobot_ssot/integrations/dna_center/utils/nautobot.py index 0ddf39039..d140179cf 100644 --- a/nautobot_ssot/integrations/dna_center/utils/nautobot.py +++ b/nautobot_ssot/integrations/dna_center/utils/nautobot.py @@ -1,10 +1,11 @@ """Utility functions for working with Nautobot.""" from uuid import UUID + from django.contrib.contenttypes.models import ContentType -from netutils.lib_mapper import ANSIBLE_LIB_MAPPER_REVERSE, NAPALM_LIB_MAPPER_REVERSE from nautobot.dcim.models import Device, Platform from nautobot.extras.models import Relationship, RelationshipAssociation +from netutils.lib_mapper import ANSIBLE_LIB_MAPPER_REVERSE, NAPALM_LIB_MAPPER_REVERSE try: from nautobot_device_lifecycle_mgmt.models import SoftwareLCM diff --git a/nautobot_ssot/integrations/infoblox/api/views.py b/nautobot_ssot/integrations/infoblox/api/views.py index 65408758b..5328e81b6 100644 --- a/nautobot_ssot/integrations/infoblox/api/views.py +++ b/nautobot_ssot/integrations/infoblox/api/views.py @@ -4,6 +4,7 @@ from nautobot_ssot.integrations.infoblox.filters import SSOTInfobloxConfigFilterSet from nautobot_ssot.integrations.infoblox.models import SSOTInfobloxConfig + from .serializers import SSOTInfobloxConfigSerializer diff --git a/nautobot_ssot/integrations/infoblox/diffsync/adapters/nautobot.py b/nautobot_ssot/integrations/infoblox/diffsync/adapters/nautobot.py index e6d7c332e..e8fc97e44 100644 --- a/nautobot_ssot/integrations/infoblox/diffsync/adapters/nautobot.py +++ b/nautobot_ssot/integrations/infoblox/diffsync/adapters/nautobot.py @@ -296,9 +296,7 @@ def _load_all_ipaddresses_filtered(self, sync_filters: list, include_ipv4: bool, return all_ipaddresses - def load_ipaddresses( - self, include_ipv4: bool, include_ipv6: bool, sync_filters: list - ): # pylint: disable=too-many-branches + def load_ipaddresses(self, include_ipv4: bool, include_ipv6: bool, sync_filters: list): # pylint: disable=too-many-branches """Load IP Addresses from Nautobot. Args: diff --git a/nautobot_ssot/integrations/infoblox/diffsync/models/nautobot.py b/nautobot_ssot/integrations/infoblox/diffsync/models/nautobot.py index e2a09698c..b11ebf40c 100644 --- a/nautobot_ssot/integrations/infoblox/diffsync/models/nautobot.py +++ b/nautobot_ssot/integrations/infoblox/diffsync/models/nautobot.py @@ -320,7 +320,7 @@ def update(self, attrs): # pylint: disable=too-many-branches if self.adapter.config.fixed_address_type == FixedAddressTypeChoices.DONT_CREATE_RECORD: self.adapter.job.logger.warning( - f"Did not update Fixed Address {self.address}/{self.prefix_length}-{self.namespace}. " # nosec: B608 + f"Did not update Fixed Address {self.address}/{self.prefix_length}-{self.namespace}. " # noqa: S608 "It exists in Infoblox but Nautobot config has `fixed_address_type` set to `DONT_CREATE_RECORD`." ) return super().update(attrs) @@ -510,7 +510,7 @@ def create(cls, adapter, ids, attrs): DNSRecordTypeChoices.A_AND_PTR_RECORD, ): adapter.job.logger.warning( - f"Can't create/update A record data for IP Address: {addr_w_pfxl}-{ids['namespace']}. Nautobot config is not set for A record operations." # nosec: B608 + f"Can't create/update A record data for IP Address: {addr_w_pfxl}-{ids['namespace']}. Nautobot config is not set for A record operations." # noqa: S608 ) return super().create(ids=ids, adapter=adapter, attrs=attrs) @@ -554,7 +554,7 @@ def update(self, attrs): DNSRecordTypeChoices.A_AND_PTR_RECORD, ): self.adapter.job.logger.warning( - f"Can't update A record data for IP Address: {self.address}/{self.prefix_length}-{self.namespace}. Nautobot config is not set for A record operations." # nosec: B608 + f"Can't update A record data for IP Address: {self.address}/{self.prefix_length}-{self.namespace}. Nautobot config is not set for A record operations." # noqa: S608 ) return super().update(attrs) @@ -613,7 +613,7 @@ def create(cls, adapter, ids, attrs): if adapter.config.dns_record_type != DNSRecordTypeChoices.HOST_RECORD: adapter.job.logger.warning( - f"Can't create/update Host record data for IP Address: {addr_w_pfxl}-{ids['namespace']}. Nautobot config is not set for Host record operations." # nosec: B608 + f"Can't create/update Host record data for IP Address: {addr_w_pfxl}-{ids['namespace']}. Nautobot config is not set for Host record operations." # noqa: S608 ) return super().create(ids=ids, adapter=adapter, attrs=attrs) @@ -656,7 +656,7 @@ def update(self, attrs): """Update Host Record data on IPAddress object in Nautobot.""" if self.adapter.config.dns_record_type != DNSRecordTypeChoices.HOST_RECORD: self.adapter.job.logger.warning( - f"Can't update Host record data for IP Address: {self.address}/{self.prefix_length}-{self.namespace}. Nautobot config is not set for Host record operations." # nosec: B608 + f"Can't update Host record data for IP Address: {self.address}/{self.prefix_length}-{self.namespace}. Nautobot config is not set for Host record operations." # noqa: S608 ) return super().update(attrs) @@ -712,7 +712,7 @@ def create(cls, adapter, ids, attrs): if adapter.config.dns_record_type != DNSRecordTypeChoices.A_AND_PTR_RECORD: adapter.job.logger.warning( - f"Can't create/update PTR record data for IP Address: {addr_w_pfxl}-{ids['namespace']}. Nautobot config is not set for PTR record operations." # nosec: B608 + f"Can't create/update PTR record data for IP Address: {addr_w_pfxl}-{ids['namespace']}. Nautobot config is not set for PTR record operations." # noqa: S608 ) return super().create(ids=ids, adapter=adapter, attrs=attrs) @@ -743,7 +743,7 @@ def update(self, attrs): """Update PTR Record data on IPAddress object in Nautobot.""" if self.adapter.config.dns_record_type != DNSRecordTypeChoices.A_AND_PTR_RECORD: self.adapter.job.logger.warning( - f"Can't update PTR record data for IP Address: {self.address}/{self.prefix_length}-{self.namespace}. Nautobot config is not set for PTR record operations." # nosec: B608 + f"Can't update PTR record data for IP Address: {self.address}/{self.prefix_length}-{self.namespace}. Nautobot config is not set for PTR record operations." # noqa: S608 ) return super().update(attrs) diff --git a/nautobot_ssot/integrations/infoblox/filters.py b/nautobot_ssot/integrations/infoblox/filters.py index 122b4a8b9..da0fa3954 100644 --- a/nautobot_ssot/integrations/infoblox/filters.py +++ b/nautobot_ssot/integrations/infoblox/filters.py @@ -1,11 +1,9 @@ """Filtering implementation for SSOT Infoblox.""" import django_filters - from django.db.models import Q from nautobot.apps.filters import NautobotFilterSet - from .models import SSOTInfobloxConfig diff --git a/nautobot_ssot/integrations/infoblox/jobs.py b/nautobot_ssot/integrations/infoblox/jobs.py index 156dcf2f9..40781f995 100644 --- a/nautobot_ssot/integrations/infoblox/jobs.py +++ b/nautobot_ssot/integrations/infoblox/jobs.py @@ -3,16 +3,16 @@ from diffsync.enum import DiffSyncFlags from django.templatetags.static import static from django.urls import reverse +from nautobot.apps.jobs import ObjectVar from nautobot.extras.choices import SecretsGroupAccessTypeChoices, SecretsGroupSecretTypeChoices from nautobot.extras.jobs import BooleanVar -from nautobot.apps.jobs import ObjectVar + from nautobot_ssot.jobs.base import DataMapping, DataSource, DataTarget from nautobot_ssot.models import SSOTInfobloxConfig from .diffsync.adapters import infoblox, nautobot from .utils.client import InfobloxApi - name = "SSoT - Infoblox DDI" # pylint: disable=invalid-name diff --git a/nautobot_ssot/integrations/infoblox/signals.py b/nautobot_ssot/integrations/infoblox/signals.py index 9fedb522a..2c62b34aa 100644 --- a/nautobot_ssot/integrations/infoblox/signals.py +++ b/nautobot_ssot/integrations/infoblox/signals.py @@ -4,6 +4,7 @@ import ipaddress +from django.conf import settings from nautobot.core.signals import nautobot_database_ready from nautobot.extras.choices import ( CustomFieldTypeChoices, @@ -11,10 +12,9 @@ SecretsGroupAccessTypeChoices, SecretsGroupSecretTypeChoices, ) -from django.conf import settings -from nautobot_ssot.integrations.infoblox.constant import TAG_COLOR -from nautobot_ssot.integrations.infoblox.choices import DNSRecordTypeChoices, FixedAddressTypeChoices +from nautobot_ssot.integrations.infoblox.choices import DNSRecordTypeChoices, FixedAddressTypeChoices +from nautobot_ssot.integrations.infoblox.constant import TAG_COLOR config = settings.PLUGINS_CONFIG["nautobot_ssot"] @@ -24,9 +24,7 @@ def register_signals(sender): nautobot_database_ready.connect(nautobot_database_ready_callback, sender=sender) -def nautobot_database_ready_callback( - sender, *, apps, **kwargs -): # pylint: disable=unused-argument,too-many-locals,too-many-statements +def nautobot_database_ready_callback(sender, *, apps, **kwargs): # pylint: disable=unused-argument,too-many-locals,too-many-statements """Create Tag and CustomField to note System of Record for SSoT. Callback function triggered by the nautobot_database_ready signal when the Nautobot database is fully ready. diff --git a/nautobot_ssot/integrations/infoblox/tables.py b/nautobot_ssot/integrations/infoblox/tables.py index 58542c984..038563198 100644 --- a/nautobot_ssot/integrations/infoblox/tables.py +++ b/nautobot_ssot/integrations/infoblox/tables.py @@ -1,7 +1,6 @@ """Tables implementation for SSOT Infoblox.""" import django_tables2 as tables - from nautobot.apps.tables import BaseTable, BooleanColumn, ButtonsColumn from .models import SSOTInfobloxConfig diff --git a/nautobot_ssot/integrations/infoblox/urls.py b/nautobot_ssot/integrations/infoblox/urls.py index 0d3d67ea5..b6dc4459c 100644 --- a/nautobot_ssot/integrations/infoblox/urls.py +++ b/nautobot_ssot/integrations/infoblox/urls.py @@ -3,8 +3,7 @@ from django.urls import path from nautobot.apps.urls import NautobotUIViewSetRouter -from . import views -from . import models +from . import models, views router = NautobotUIViewSetRouter() router.register("config/infoblox", viewset=views.SSOTInfobloxConfigUIViewSet) diff --git a/nautobot_ssot/integrations/infoblox/utils/client.py b/nautobot_ssot/integrations/infoblox/utils/client.py index 9b6c5968a..6f43442f5 100644 --- a/nautobot_ssot/integrations/infoblox/utils/client.py +++ b/nautobot_ssot/integrations/infoblox/utils/client.py @@ -238,9 +238,7 @@ def _update(self, resource, **params): logger.error(response.text) return response.text - def _get_network_ref( - self, prefix, network_view: Optional[str] = None - ): # pylint: disable=inconsistent-return-statements + def _get_network_ref(self, prefix, network_view: Optional[str] = None): # pylint: disable=inconsistent-return-statements """Fetch the _ref of a prefix resource. Args: @@ -268,9 +266,7 @@ def _get_network_ref( return results[0].get("_ref") return None - def _get_network_container_ref( - self, prefix, network_view: Optional[str] = None - ): # pylint: disable=inconsistent-return-statements + def _get_network_container_ref(self, prefix, network_view: Optional[str] = None): # pylint: disable=inconsistent-return-statements """Fetch the _ref of a networkcontainer resource. Args: @@ -872,9 +868,7 @@ def get_ptr_record_by_ref(self, ref: str): logger.error(response.text) return response.text - def get_ptr_record_by_ip( - self, ip_address, network_view: Optional[str] = None - ): # pylint: disable=inconsistent-return-statements + def get_ptr_record_by_ip(self, ip_address, network_view: Optional[str] = None): # pylint: disable=inconsistent-return-statements """Get the PTR record by FQDN. Args: diff --git a/nautobot_ssot/integrations/infoblox/views.py b/nautobot_ssot/integrations/infoblox/views.py index 9ef9206e7..eb5a673b1 100644 --- a/nautobot_ssot/integrations/infoblox/views.py +++ b/nautobot_ssot/integrations/infoblox/views.py @@ -1,12 +1,12 @@ """Views implementation for SSOT Infoblox.""" -from nautobot.extras.views import ObjectChangeLogView, ObjectNotesView from nautobot.apps.views import ( ObjectDestroyViewMixin, ObjectDetailViewMixin, ObjectEditViewMixin, ObjectListViewMixin, ) +from nautobot.extras.views import ObjectChangeLogView, ObjectNotesView from .api.serializers import SSOTInfobloxConfigSerializer from .filters import SSOTInfobloxConfigFilterSet diff --git a/nautobot_ssot/integrations/ipfabric/diffsync/diffsync_models.py b/nautobot_ssot/integrations/ipfabric/diffsync/diffsync_models.py index 6d1824590..652d4e374 100644 --- a/nautobot_ssot/integrations/ipfabric/diffsync/diffsync_models.py +++ b/nautobot_ssot/integrations/ipfabric/diffsync/diffsync_models.py @@ -66,9 +66,7 @@ def safe_delete(self, nautobot_object: Any, safe_delete_status: Optional[str] = logger.warning(f"{nautobot_object} will be deleted as safe delete mode is not enabled.") # This allows private class naming of nautobot objects to be ordered for delete() # Example definition in adapter class var: _site = Location - self.adapter.objects_to_delete[f"_{nautobot_object.__class__.__name__.lower()}"].append( - nautobot_object - ) # pylint: disable=protected-access + self.adapter.objects_to_delete[f"_{nautobot_object.__class__.__name__.lower()}"].append(nautobot_object) # pylint: disable=protected-access super().delete() else: if safe_delete_status: diff --git a/nautobot_ssot/integrations/ipfabric/signals.py b/nautobot_ssot/integrations/ipfabric/signals.py index 281c3bd2e..b48394f83 100644 --- a/nautobot_ssot/integrations/ipfabric/signals.py +++ b/nautobot_ssot/integrations/ipfabric/signals.py @@ -3,9 +3,9 @@ from typing import List, Optional +from nautobot.core.choices import ColorChoices from nautobot.core.signals import nautobot_database_ready from nautobot.extras.choices import CustomFieldTypeChoices -from nautobot.core.choices import ColorChoices def register_signals(sender): diff --git a/nautobot_ssot/integrations/ipfabric/utilities/__init__.py b/nautobot_ssot/integrations/ipfabric/utilities/__init__.py index 4b1a3eeb9..1ba85edc7 100644 --- a/nautobot_ssot/integrations/ipfabric/utilities/__init__.py +++ b/nautobot_ssot/integrations/ipfabric/utilities/__init__.py @@ -1,15 +1,15 @@ """Utilities.""" from .nbutils import ( - get_or_create_device_role_object, create_device_type_object, create_interface, create_ip, - create_manufacturer, create_location, + create_manufacturer, create_platform_object, create_status, create_vlan, + get_or_create_device_role_object, ) from .test_utils import clean_slate, json_fixture diff --git a/nautobot_ssot/integrations/ipfabric/utilities/nbutils.py b/nautobot_ssot/integrations/ipfabric/utilities/nbutils.py index 39c2ba3aa..b732d70c9 100644 --- a/nautobot_ssot/integrations/ipfabric/utilities/nbutils.py +++ b/nautobot_ssot/integrations/ipfabric/utilities/nbutils.py @@ -6,27 +6,27 @@ from typing import Any, Optional from django.contrib.contenttypes.models import ContentType -from django.db import Error as DjangoBaseDBError from django.core.exceptions import ValidationError -from netutils.ip import netmask_to_cidr -from netutils.lib_mapper import NAPALM_LIB_MAPPER +from django.db import Error as DjangoBaseDBError from nautobot.core.choices import ColorChoices from nautobot.dcim.models import ( Device, DeviceType, Interface, - Manufacturer, Location, LocationType, + Manufacturer, Platform, ) from nautobot.extras.choices import CustomFieldTypeChoices from nautobot.extras.models import CustomField, Role, Tag from nautobot.extras.models.statuses import Status -from nautobot.ipam.models import IPAddress, IPAddressToInterface, Namespace, Prefix, VLAN from nautobot.ipam.choices import PrefixTypeChoices -from nautobot_ssot.integrations.ipfabric.constants import LAST_SYNCHRONIZED_CF_NAME +from nautobot.ipam.models import VLAN, IPAddress, IPAddressToInterface, Namespace, Prefix +from netutils.ip import netmask_to_cidr +from netutils.lib_mapper import NAPALM_LIB_MAPPER +from nautobot_ssot.integrations.ipfabric.constants import LAST_SYNCHRONIZED_CF_NAME # pylint: disable=too-many-branches @@ -344,7 +344,7 @@ def create_ip( except (DjangoBaseDBError, ValidationError): try: parent, _ = Prefix.objects.get_or_create( - network="0.0.0.0", # nosec B104 + network="0.0.0.0", # noqa: S104 prefix_length=0, type=PrefixTypeChoices.TYPE_NETWORK, status=Status.objects.get_for_model(Prefix).get(name="Active"), diff --git a/nautobot_ssot/integrations/ipfabric/utilities/utils.py b/nautobot_ssot/integrations/ipfabric/utilities/utils.py index 437129c0c..e8a24f2d3 100644 --- a/nautobot_ssot/integrations/ipfabric/utilities/utils.py +++ b/nautobot_ssot/integrations/ipfabric/utilities/utils.py @@ -4,7 +4,6 @@ from nautobot_ssot.integrations.ipfabric.constants import DEFAULT_INTERFACE_TYPE - VIRTUAL = "virtual" BRIDGE = "bridge" LAG = "lag" diff --git a/nautobot_ssot/integrations/itential/api/serializers.py b/nautobot_ssot/integrations/itential/api/serializers.py index c06fbaacc..938604abe 100644 --- a/nautobot_ssot/integrations/itential/api/serializers.py +++ b/nautobot_ssot/integrations/itential/api/serializers.py @@ -1,8 +1,7 @@ """Itential SSoT serializers.""" -from rest_framework import serializers - from nautobot.apps.api import NautobotModelSerializer +from rest_framework import serializers from nautobot_ssot.integrations.itential import models diff --git a/nautobot_ssot/integrations/itential/api/urls.py b/nautobot_ssot/integrations/itential/api/urls.py index 7859c6d5e..17367da15 100644 --- a/nautobot_ssot/integrations/itential/api/urls.py +++ b/nautobot_ssot/integrations/itential/api/urls.py @@ -1,8 +1,8 @@ """Itential SSoT API URL's.""" from nautobot.apps.api import OrderedDefaultRouter -from nautobot_ssot.integrations.itential.api import views +from nautobot_ssot.integrations.itential.api import views router = OrderedDefaultRouter() router.register("itential/automation-gateway", views.AutomationGatewayModelViewSet) diff --git a/nautobot_ssot/integrations/itential/api/views.py b/nautobot_ssot/integrations/itential/api/views.py index 4575158e8..2d6327ef1 100644 --- a/nautobot_ssot/integrations/itential/api/views.py +++ b/nautobot_ssot/integrations/itential/api/views.py @@ -2,7 +2,7 @@ from nautobot.apps.api import NautobotModelViewSet -from nautobot_ssot.integrations.itential import models, filters +from nautobot_ssot.integrations.itential import filters, models from nautobot_ssot.integrations.itential.api import serializers diff --git a/nautobot_ssot/integrations/itential/clients.py b/nautobot_ssot/integrations/itential/clients.py index 2c691e75f..ad06ca961 100644 --- a/nautobot_ssot/integrations/itential/clients.py +++ b/nautobot_ssot/integrations/itential/clients.py @@ -3,7 +3,6 @@ from typing import List, Optional, Union import requests - from retry import retry from nautobot_ssot.integrations.itential.constants import BACKOFF, DELAY, RETRIES diff --git a/nautobot_ssot/integrations/itential/diffsync/adapters/itential.py b/nautobot_ssot/integrations/itential/diffsync/adapters/itential.py index 4a886226f..91f8fc691 100644 --- a/nautobot_ssot/integrations/itential/diffsync/adapters/itential.py +++ b/nautobot_ssot/integrations/itential/diffsync/adapters/itential.py @@ -2,11 +2,11 @@ from diffsync import Adapter +from nautobot_ssot.integrations.itential.clients import AutomationGatewayClient from nautobot_ssot.integrations.itential.diffsync.models.itential import ( ItentialAnsibleDeviceModel, ItentialDefaultAnsibleGroupModel, ) -from nautobot_ssot.integrations.itential.clients import AutomationGatewayClient class ItentialAnsibleDeviceAdapter(Adapter): diff --git a/nautobot_ssot/integrations/itential/diffsync/adapters/nautobot.py b/nautobot_ssot/integrations/itential/diffsync/adapters/nautobot.py index d62668a61..a6ebcb5e7 100644 --- a/nautobot_ssot/integrations/itential/diffsync/adapters/nautobot.py +++ b/nautobot_ssot/integrations/itential/diffsync/adapters/nautobot.py @@ -4,17 +4,15 @@ import traceback from diffsync import Adapter - -from nautobot.extras.models import Status from nautobot.dcim.models import Device - from nautobot.extras.choices import SecretsGroupAccessTypeChoices, SecretsGroupSecretTypeChoices +from nautobot.extras.models import Status -from nautobot_ssot.integrations.itential.models import AutomationGatewayModel from nautobot_ssot.integrations.itential.diffsync.models.nautobot import ( NautobotAnsibleDeviceModel, NautobotDefaultAnsibleGroupModel, ) +from nautobot_ssot.integrations.itential.models import AutomationGatewayModel class NautobotAnsibleDeviceAdapter(Adapter): diff --git a/nautobot_ssot/integrations/itential/diffsync/models/base.py b/nautobot_ssot/integrations/itential/diffsync/models/base.py index 875378049..ab17cbaa3 100644 --- a/nautobot_ssot/integrations/itential/diffsync/models/base.py +++ b/nautobot_ssot/integrations/itential/diffsync/models/base.py @@ -1,6 +1,7 @@ """Itential SSoT shared diffsync models.""" from typing import Optional + from diffsync import DiffSyncModel diff --git a/nautobot_ssot/integrations/itential/forms.py b/nautobot_ssot/integrations/itential/forms.py index ce59ce0cb..9a07da7dd 100644 --- a/nautobot_ssot/integrations/itential/forms.py +++ b/nautobot_ssot/integrations/itential/forms.py @@ -1,7 +1,6 @@ """Itential SSoT Forms.""" from django import forms - from nautobot.apps.forms import BootstrapMixin, BulkEditForm, NautobotModelForm from nautobot_ssot.integrations.itential import models diff --git a/nautobot_ssot/integrations/itential/jobs.py b/nautobot_ssot/integrations/itential/jobs.py index 5b9199e31..97a403700 100644 --- a/nautobot_ssot/integrations/itential/jobs.py +++ b/nautobot_ssot/integrations/itential/jobs.py @@ -1,16 +1,14 @@ """Itential SSoT Jobs.""" -from nautobot.extras.models import Status -from nautobot.extras.jobs import ObjectVar - from nautobot.extras.choices import SecretsGroupAccessTypeChoices, SecretsGroupSecretTypeChoices -from nautobot_ssot.jobs.base import DataTarget +from nautobot.extras.jobs import ObjectVar +from nautobot.extras.models import Status -from nautobot_ssot.integrations.itential.models import AutomationGatewayModel from nautobot_ssot.integrations.itential.clients import AutomationGatewayClient from nautobot_ssot.integrations.itential.diffsync.adapters.itential import ItentialAnsibleDeviceAdapter from nautobot_ssot.integrations.itential.diffsync.adapters.nautobot import NautobotAnsibleDeviceAdapter - +from nautobot_ssot.integrations.itential.models import AutomationGatewayModel +from nautobot_ssot.jobs.base import DataTarget name = "SSoT - Itential" # pylint: disable=invalid-name diff --git a/nautobot_ssot/integrations/itential/navigation.py b/nautobot_ssot/integrations/itential/navigation.py index 68bf155fa..5310a571a 100644 --- a/nautobot_ssot/integrations/itential/navigation.py +++ b/nautobot_ssot/integrations/itential/navigation.py @@ -2,7 +2,6 @@ from nautobot.apps.ui import NavMenuItem - nav_items = [ NavMenuItem( link="plugins:nautobot_ssot:automationgatewaymodel_list", diff --git a/nautobot_ssot/integrations/itential/tables.py b/nautobot_ssot/integrations/itential/tables.py index a8c3f9ba2..26ed63abd 100644 --- a/nautobot_ssot/integrations/itential/tables.py +++ b/nautobot_ssot/integrations/itential/tables.py @@ -1,7 +1,6 @@ """Itential SSoT tables.""" import django_tables2 as tables - from nautobot.apps.tables import ( BaseTable, ButtonsColumn, diff --git a/nautobot_ssot/integrations/itential/views.py b/nautobot_ssot/integrations/itential/views.py index 30d9774c3..0cd71cbb3 100644 --- a/nautobot_ssot/integrations/itential/views.py +++ b/nautobot_ssot/integrations/itential/views.py @@ -1,7 +1,8 @@ """Itential SSoT Views.""" from nautobot.apps import views -from nautobot_ssot.integrations.itential import forms, filters, tables, models + +from nautobot_ssot.integrations.itential import filters, forms, models, tables from nautobot_ssot.integrations.itential.api import serializers diff --git a/nautobot_ssot/integrations/servicenow/diffsync/adapter_nautobot.py b/nautobot_ssot/integrations/servicenow/diffsync/adapter_nautobot.py index c9f043ce1..a31469f41 100644 --- a/nautobot_ssot/integrations/servicenow/diffsync/adapter_nautobot.py +++ b/nautobot_ssot/integrations/servicenow/diffsync/adapter_nautobot.py @@ -5,13 +5,11 @@ from diffsync import Adapter from diffsync.exceptions import ObjectNotFound - from django.contrib.contenttypes.models import ContentType - -from nautobot.dcim.models import Device, DeviceType, Interface, Manufacturer, Location +from nautobot.core.choices import ColorChoices +from nautobot.dcim.models import Device, DeviceType, Interface, Location, Manufacturer from nautobot.extras.choices import CustomFieldTypeChoices from nautobot.extras.models import CustomField, Tag -from nautobot.core.choices import ColorChoices from . import models diff --git a/nautobot_ssot/integrations/servicenow/diffsync/adapter_servicenow.py b/nautobot_ssot/integrations/servicenow/diffsync/adapter_servicenow.py index 8b558494b..3ba5f94c2 100644 --- a/nautobot_ssot/integrations/servicenow/diffsync/adapter_servicenow.py +++ b/nautobot_ssot/integrations/servicenow/diffsync/adapter_servicenow.py @@ -1,16 +1,16 @@ # pylint: disable=duplicate-code """DiffSync adapter for ServiceNow.""" -from base64 import b64encode import json import os - +from base64 import b64encode from collections import defaultdict + +import yaml from diffsync import Adapter from diffsync.enum import DiffSyncFlags from diffsync.exceptions import ObjectAlreadyExists, ObjectNotFound from jinja2 import Environment, FileSystemLoader -import yaml from . import models diff --git a/nautobot_ssot/integrations/servicenow/diffsync/models.py b/nautobot_ssot/integrations/servicenow/diffsync/models.py index f8daefe94..4b62694c2 100644 --- a/nautobot_ssot/integrations/servicenow/diffsync/models.py +++ b/nautobot_ssot/integrations/servicenow/diffsync/models.py @@ -1,7 +1,7 @@ """DiffSyncModel subclasses for Nautobot-to-ServiceNow data sync.""" -from typing import List, Optional, Union import uuid +from typing import List, Optional, Union from diffsync import DiffSyncModel from diffsync.enum import DiffSyncStatus diff --git a/nautobot_ssot/integrations/servicenow/forms.py b/nautobot_ssot/integrations/servicenow/forms.py index 81fa0f901..ce0d68711 100644 --- a/nautobot_ssot/integrations/servicenow/forms.py +++ b/nautobot_ssot/integrations/servicenow/forms.py @@ -1,9 +1,8 @@ """User-facing forms for nautobot-ssot-servicenow.""" from django import forms - -from nautobot.extras.models import SecretsGroup from nautobot.core.forms import DynamicModelChoiceField +from nautobot.extras.models import SecretsGroup from .models import SSOTServiceNowConfig diff --git a/nautobot_ssot/integrations/servicenow/jobs.py b/nautobot_ssot/integrations/servicenow/jobs.py index f0d9fe58b..f8bcdbf5f 100644 --- a/nautobot_ssot/integrations/servicenow/jobs.py +++ b/nautobot_ssot/integrations/servicenow/jobs.py @@ -3,9 +3,8 @@ from django.core.exceptions import ObjectDoesNotExist from django.templatetags.static import static from django.urls import reverse - -from nautobot.dcim.models import Device, DeviceType, Interface, Manufacturer, Location -from nautobot.extras.jobs import Job, BooleanVar, ObjectVar +from nautobot.dcim.models import Device, DeviceType, Interface, Location, Manufacturer +from nautobot.extras.jobs import BooleanVar, Job, ObjectVar from nautobot_ssot.jobs.base import DataMapping, DataTarget @@ -14,7 +13,6 @@ from .servicenow import ServiceNowClient from .utils import get_servicenow_parameters - name = "SSoT - ServiceNow" # pylint: disable=invalid-name diff --git a/nautobot_ssot/integrations/servicenow/models.py b/nautobot_ssot/integrations/servicenow/models.py index 152761f66..eb8fb9906 100644 --- a/nautobot_ssot/integrations/servicenow/models.py +++ b/nautobot_ssot/integrations/servicenow/models.py @@ -2,7 +2,6 @@ from django.db import models from django.shortcuts import reverse - from nautobot.core.models import BaseModel diff --git a/nautobot_ssot/integrations/servicenow/servicenow.py b/nautobot_ssot/integrations/servicenow/servicenow.py index ab3d8096f..886dd0240 100644 --- a/nautobot_ssot/integrations/servicenow/servicenow.py +++ b/nautobot_ssot/integrations/servicenow/servicenow.py @@ -2,13 +2,13 @@ import logging +import requests # pylint: disable=wrong-import-order + # from pysnow import Client from nautobot_ssot.integrations.servicenow.third_party.pysnow import Client # from pysnow.exceptions import MultipleResults from nautobot_ssot.integrations.servicenow.third_party.pysnow.exceptions import MultipleResults -import requests # pylint: disable=wrong-import-order - logger = logging.getLogger(__name__) diff --git a/nautobot_ssot/integrations/servicenow/signals.py b/nautobot_ssot/integrations/servicenow/signals.py index c9badf765..19471209a 100644 --- a/nautobot_ssot/integrations/servicenow/signals.py +++ b/nautobot_ssot/integrations/servicenow/signals.py @@ -1,9 +1,9 @@ # pylint: disable=duplicate-code """Signal handlers for ServiceNow integration.""" +from nautobot.core.choices import ColorChoices from nautobot.core.signals import nautobot_database_ready from nautobot.extras.choices import CustomFieldTypeChoices -from nautobot.core.choices import ColorChoices def register_signals(sender): diff --git a/nautobot_ssot/integrations/servicenow/third_party/pysnow/__init__.py b/nautobot_ssot/integrations/servicenow/third_party/pysnow/__init__.py index 33e767dc7..84858aed8 100644 --- a/nautobot_ssot/integrations/servicenow/third_party/pysnow/__init__.py +++ b/nautobot_ssot/integrations/servicenow/third_party/pysnow/__init__.py @@ -1,13 +1,13 @@ # -*- coding: utf-8 -*- +# Set default logging handler to avoid "No handler found" warnings. +import logging + from .client import Client from .oauth_client import OAuthClient +from .params_builder import ParamsBuilder from .query_builder import QueryBuilder from .resource import Resource -from .params_builder import ParamsBuilder - -# Set default logging handler to avoid "No handler found" warnings. -import logging try: # Python 2.7+ from logging import NullHandler @@ -19,3 +19,11 @@ def emit(self, record): logging.getLogger(__name__).addHandler(NullHandler()) + +__all__ = ( + "Client", + "OAuthClient", + "ParamsBuilder", + "QueryBuilder", + "Resource", +) diff --git a/nautobot_ssot/integrations/servicenow/third_party/pysnow/client.py b/nautobot_ssot/integrations/servicenow/third_party/pysnow/client.py index 084895cff..880951317 100644 --- a/nautobot_ssot/integrations/servicenow/third_party/pysnow/client.py +++ b/nautobot_ssot/integrations/servicenow/third_party/pysnow/client.py @@ -1,18 +1,19 @@ # -*- coding: utf-8 -*- -import logging import inspect +import logging import warnings import requests +from requests.auth import HTTPBasicAuth + from nautobot_ssot.integrations.servicenow.third_party import pysnow -from requests.auth import HTTPBasicAuth -from .legacy_request import LegacyRequest from .exceptions import InvalidUsage +from .legacy_request import LegacyRequest +from .params_builder import ParamsBuilder from .resource import Resource from .url_builder import URLBuilder -from .params_builder import ParamsBuilder logger = logging.getLogger("pysnow") diff --git a/nautobot_ssot/integrations/servicenow/third_party/pysnow/criterion.py b/nautobot_ssot/integrations/servicenow/third_party/pysnow/criterion.py index 2f6f2061d..0a728d0ec 100644 --- a/nautobot_ssot/integrations/servicenow/third_party/pysnow/criterion.py +++ b/nautobot_ssot/integrations/servicenow/third_party/pysnow/criterion.py @@ -1,12 +1,13 @@ import inspect -import six -import pytz from datetime import datetime +import pytz +import six + from .enums import ( Boolean, - Equality, DateTimeOn, + Equality, Order, ) from .exceptions import QueryTypeError @@ -25,12 +26,12 @@ def wrap_constant(value, types, list_type=False): else: caller = inspect.currentframe().f_back.f_code.co_name raise QueryTypeError("Invalid type passed to %s() , expected list or tuple" % (caller)) - elif isinstance(value, ValueWrapper) and (value.type_ in types or (value.type_ == list and list_type)): + elif isinstance(value, ValueWrapper) and (value.type_ in types or (value.type_ == list and list_type)): # noqa: E721 return value # allow other types than datetime, as long as they have strftime elif hasattr(value, "strftime") and datetime in types: return DateTimeValueWrapper(value) - elif not type(value) in types: + elif type(value) not in types: caller = inspect.currentframe().f_back.f_code.co_name raise QueryTypeError("Invalid type passed to %s() , expected: %s" % (caller, types)) elif isinstance(value, int): diff --git a/nautobot_ssot/integrations/servicenow/third_party/pysnow/legacy_request.py b/nautobot_ssot/integrations/servicenow/third_party/pysnow/legacy_request.py index 54bfd26ee..80716c393 100644 --- a/nautobot_ssot/integrations/servicenow/third_party/pysnow/legacy_request.py +++ b/nautobot_ssot/integrations/servicenow/third_party/pysnow/legacy_request.py @@ -2,21 +2,21 @@ import itertools import json -import os -import six import ntpath +import os import warnings -from .query_builder import QueryBuilder +import six from .legacy_exceptions import ( - NoRequestExecuted, + InvalidUsage, + MissingResult, MultipleResults, + NoRequestExecuted, NoResults, - InvalidUsage, UnexpectedResponse, - MissingResult, ) +from .query_builder import QueryBuilder class LegacyRequest(object): @@ -138,7 +138,7 @@ def get_one(self, fields=list()): ) content = self._get_content(response) - l = len(content) + l = len(content) # noqa: E741 if l > 1: raise MultipleResults("Multiple results for get_one()") diff --git a/nautobot_ssot/integrations/servicenow/third_party/pysnow/oauth_client.py b/nautobot_ssot/integrations/servicenow/third_party/pysnow/oauth_client.py index 87f4ae4fb..0a3be49fa 100644 --- a/nautobot_ssot/integrations/servicenow/third_party/pysnow/oauth_client.py +++ b/nautobot_ssot/integrations/servicenow/third_party/pysnow/oauth_client.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- -import warnings import logging +import warnings from oauthlib.oauth2 import LegacyApplicationClient from oauthlib.oauth2.rfc6749.errors import OAuth2Error diff --git a/nautobot_ssot/integrations/servicenow/third_party/pysnow/params_builder.py b/nautobot_ssot/integrations/servicenow/third_party/pysnow/params_builder.py index 4c6774cb2..63c78b2c5 100644 --- a/nautobot_ssot/integrations/servicenow/third_party/pysnow/params_builder.py +++ b/nautobot_ssot/integrations/servicenow/third_party/pysnow/params_builder.py @@ -3,9 +3,8 @@ import six from .criterion import Criterion -from .query_builder import QueryBuilder - from .exceptions import InvalidUsage +from .query_builder import QueryBuilder class ParamsBuilder(object): diff --git a/nautobot_ssot/integrations/servicenow/third_party/pysnow/query_builder.py b/nautobot_ssot/integrations/servicenow/third_party/pysnow/query_builder.py index 2d7e0a85b..4bc362542 100644 --- a/nautobot_ssot/integrations/servicenow/third_party/pysnow/query_builder.py +++ b/nautobot_ssot/integrations/servicenow/third_party/pysnow/query_builder.py @@ -1,8 +1,9 @@ # -*- coding: utf-8 -*- import inspect -import six + import pytz +import six from .exceptions import ( QueryEmpty, @@ -228,7 +229,7 @@ def _add_condition(self, operator, operand, types): if not self.current_field: raise QueryMissingField("Conditions requires a field()") - elif not type(operand) in types: + elif type(operand) not in types: caller = inspect.currentframe().f_back.f_code.co_name raise QueryTypeError("Invalid type passed to %s() , expected: %s" % (caller, types)) diff --git a/nautobot_ssot/integrations/servicenow/third_party/pysnow/request.py b/nautobot_ssot/integrations/servicenow/third_party/pysnow/request.py index b10178ee3..a1363c7a2 100644 --- a/nautobot_ssot/integrations/servicenow/third_party/pysnow/request.py +++ b/nautobot_ssot/integrations/servicenow/third_party/pysnow/request.py @@ -1,11 +1,12 @@ # -*- coding: utf-8 -*- -import logging import json +import logging + import six -from .response import Response from .exceptions import InvalidUsage +from .response import Response logger = logging.getLogger("pysnow") diff --git a/nautobot_ssot/integrations/servicenow/third_party/pysnow/resource.py b/nautobot_ssot/integrations/servicenow/third_party/pysnow/resource.py index aac5b607e..ff2567121 100644 --- a/nautobot_ssot/integrations/servicenow/third_party/pysnow/resource.py +++ b/nautobot_ssot/integrations/servicenow/third_party/pysnow/resource.py @@ -1,13 +1,12 @@ # -*- coding: utf-8 -*- import logging - from copy import copy, deepcopy -from .request import SnowRequest from .attachment import Attachment -from .url_builder import URLBuilder from .exceptions import InvalidUsage +from .request import SnowRequest +from .url_builder import URLBuilder logger = logging.getLogger("pysnow") diff --git a/nautobot_ssot/integrations/servicenow/third_party/pysnow/response.py b/nautobot_ssot/integrations/servicenow/third_party/pysnow/response.py index d66c9b698..453f0bd27 100644 --- a/nautobot_ssot/integrations/servicenow/third_party/pysnow/response.py +++ b/nautobot_ssot/integrations/servicenow/third_party/pysnow/response.py @@ -1,16 +1,17 @@ # -*- coding: utf-8 -*- -import ijson +from itertools import chain +import ijson from ijson.common import ObjectBuilder -from itertools import chain + from .exceptions import ( - ResponseError, - NoResults, - InvalidUsage, - MultipleResults, EmptyContent, + InvalidUsage, MissingResult, + MultipleResults, + NoResults, + ResponseError, ) diff --git a/nautobot_ssot/integrations/servicenow/third_party/pysnow/url_builder.py b/nautobot_ssot/integrations/servicenow/third_party/pysnow/url_builder.py index b7464b4db..02422fa3a 100644 --- a/nautobot_ssot/integrations/servicenow/third_party/pysnow/url_builder.py +++ b/nautobot_ssot/integrations/servicenow/third_party/pysnow/url_builder.py @@ -1,7 +1,9 @@ # -*- coding: utf-8 -*- import re + import six + from .exceptions import InvalidUsage diff --git a/nautobot_ssot/integrations/servicenow/utils.py b/nautobot_ssot/integrations/servicenow/utils.py index 24aeb52a9..b77192843 100644 --- a/nautobot_ssot/integrations/servicenow/utils.py +++ b/nautobot_ssot/integrations/servicenow/utils.py @@ -3,12 +3,10 @@ import logging from django.conf import settings - from nautobot.extras.choices import SecretsGroupAccessTypeChoices, SecretsGroupSecretTypeChoices from .models import SSOTServiceNowConfig - logger = logging.getLogger(__name__) diff --git a/nautobot_ssot/integrations/servicenow/views.py b/nautobot_ssot/integrations/servicenow/views.py index 1571ab21c..c24751e9e 100644 --- a/nautobot_ssot/integrations/servicenow/views.py +++ b/nautobot_ssot/integrations/servicenow/views.py @@ -2,7 +2,6 @@ from django.contrib import messages from django.views.generic import UpdateView - from nautobot.core.forms import restrict_form_fields from .forms import SSOTServiceNowConfigForm diff --git a/nautobot_ssot/integrations/utils.py b/nautobot_ssot/integrations/utils.py index e5307d174..4fd3560a7 100644 --- a/nautobot_ssot/integrations/utils.py +++ b/nautobot_ssot/integrations/utils.py @@ -1,7 +1,6 @@ """Utility functions for nautobot_ssot integrations.""" import logging - from importlib import import_module from pathlib import Path from types import ModuleType diff --git a/nautobot_ssot/jobs/__init__.py b/nautobot_ssot/jobs/__init__.py index d6765371e..2d2c50d58 100644 --- a/nautobot_ssot/jobs/__init__.py +++ b/nautobot_ssot/jobs/__init__.py @@ -1,10 +1,10 @@ """App provision of Nautobot Job subclasses.""" from django.conf import settings - from nautobot.core.celery import register_jobs from nautobot.core.settings_funcs import is_truthy from nautobot.extras.models import Job + from nautobot_ssot.integrations.utils import each_enabled_integration_module from nautobot_ssot.jobs.base import DataSource, DataTarget from nautobot_ssot.jobs.examples import ExampleDataSource, ExampleDataTarget diff --git a/nautobot_ssot/jobs/base.py b/nautobot_ssot/jobs/base.py index 607321046..efed52d34 100644 --- a/nautobot_ssot/jobs/base.py +++ b/nautobot_ssot/jobs/base.py @@ -1,27 +1,24 @@ """Base Job classes for sync workers.""" +import tracemalloc from collections import namedtuple from datetime import datetime -import tracemalloc from typing import Iterable, Optional -from django.db.utils import OperationalError -from django.templatetags.static import static -from django.utils import timezone -from django.utils.functional import classproperty +import structlog # pylint-django doesn't understand classproperty, and complains unnecessarily. We disable this specific warning: # pylint: disable=no-self-argument - from diffsync.enum import DiffSyncFlags -import structlog - -from nautobot.extras.jobs import DryRunVar, Job, BooleanVar +from django.db.utils import OperationalError +from django.templatetags.static import static +from django.utils import timezone +from django.utils.functional import classproperty +from nautobot.extras.jobs import BooleanVar, DryRunVar, Job from nautobot_ssot.choices import SyncLogEntryActionChoices from nautobot_ssot.models import BaseModel, Sync, SyncLogEntry - DataMapping = namedtuple("DataMapping", ["source_name", "source_url", "target_name", "target_url"]) """Entry in the list returned by a job's data_mappings() API. diff --git a/nautobot_ssot/jobs/examples.py b/nautobot_ssot/jobs/examples.py index 85728d806..6effaf311 100644 --- a/nautobot_ssot/jobs/examples.py +++ b/nautobot_ssot/jobs/examples.py @@ -2,17 +2,21 @@ # Skip colon check for multiple statements on one line. # flake8: noqa: E701 - +# pylint: disable=too-many-lines try: from typing_extensions import TypedDict # Python<3.9 except ImportError: from typing import TypedDict # Python>=3.9 -from typing import Optional, Mapping, List +from typing import List, Mapping, Optional + +import requests +from diffsync import Adapter +from diffsync.enum import DiffSyncFlags +from diffsync.exceptions import ObjectNotFound from django.contrib.contenttypes.models import ContentType from django.templatetags.static import static from django.urls import reverse - from nautobot.dcim.models import Device, DeviceType, Interface, Location, LocationType, Manufacturer, Platform from nautobot.extras.choices import SecretsGroupAccessTypeChoices, SecretsGroupSecretTypeChoices from nautobot.extras.jobs import ObjectVar, StringVar @@ -20,16 +24,9 @@ from nautobot.ipam.models import IPAddress, Namespace, Prefix from nautobot.tenancy.models import Tenant -from diffsync import Adapter -from diffsync.enum import DiffSyncFlags -from diffsync.exceptions import ObjectNotFound - -import requests - -from nautobot_ssot.contrib import NautobotModel, NautobotAdapter -from nautobot_ssot.tests.contrib_base_classes import ContentTypeDict +from nautobot_ssot.contrib import NautobotAdapter, NautobotModel from nautobot_ssot.jobs.base import DataMapping, DataSource, DataTarget - +from nautobot_ssot.tests.contrib_base_classes import ContentTypeDict # In a more complex Job, you would probably want to move the DiffSyncModel subclasses into a separate Python module(s). @@ -907,6 +904,13 @@ def lookup_object(self, model_name, unique_id): class ExampleDataTarget(DataTarget): """Sync Region and Site data from the local Nautobot instance to a remote Nautobot instance.""" + target = ObjectVar( + model=ExternalIntegration, + queryset=ExternalIntegration.objects.all(), + display_field="display", + label="Nautobot Target Instance", + required=False, + ) target_url = StringVar(description="Remote Nautobot instance to update", default="https://demo.nautobot.com") target_token = StringVar(description="REST API authentication token for remote Nautobot instance", default="a" * 40) @@ -943,6 +947,38 @@ def data_mappings(cls): DataMapping("Interface (local)", reverse("dcim:interface_list"), "Interface (remote)", None), ) + def run( # pylint: disable=too-many-arguments, arguments-differ + self, + dryrun, + memory_profiling, + target, + target_url, + target_token, + *args, + **kwargs, + ): + """Run sync.""" + self.dryrun = dryrun + self.memory_profiling = memory_profiling + try: + if target: + self.logger.info(f"Using external integration '{target}'") + self.target_url = target.remote_url + secrets_group = target.secrets_group + self.target_token = secrets_group.get_secret_value( + access_type=SecretsGroupAccessTypeChoices.TYPE_HTTP, + secret_type=SecretsGroupSecretTypeChoices.TYPE_TOKEN, + ) + else: + self.target_url = target_url + self.target_token = target_token + except Exception as error: + # TBD: Why are these exceptions swallowed? + self.logger.error("Error setting up job: %s", error) + raise + + super().run(dryrun, memory_profiling, *args, **kwargs) + def load_source_adapter(self): """Method to instantiate and load the SOURCE adapter into `self.source_adapter`.""" self.source_adapter = NautobotLocal(job=self, sync=self.sync) diff --git a/nautobot_ssot/management/commands/elongate_interface_names.py b/nautobot_ssot/management/commands/elongate_interface_names.py index 3b7141f14..e9453b06a 100644 --- a/nautobot_ssot/management/commands/elongate_interface_names.py +++ b/nautobot_ssot/management/commands/elongate_interface_names.py @@ -1,9 +1,7 @@ """Django Management command to update DCIM.Interface names.""" from django.core.management.base import BaseCommand - from nautobot.dcim.models import Device - from netutils.interface import canonical_interface_name diff --git a/nautobot_ssot/metrics.py b/nautobot_ssot/metrics.py index e345cadf8..7bc210adc 100644 --- a/nautobot_ssot/metrics.py +++ b/nautobot_ssot/metrics.py @@ -1,14 +1,14 @@ """Nautobot SSoT framework level metrics.""" from django.conf import settings -from prometheus_client.core import GaugeMetricFamily from nautobot.extras.choices import JobResultStatusChoices from nautobot.extras.models.jobs import Job +from prometheus_client.core import GaugeMetricFamily + from nautobot_ssot.jobs import get_data_jobs from nautobot_ssot.jobs.base import DataSource, DataTarget from nautobot_ssot.models import Sync - PLUGIN_SETTINGS = settings.PLUGINS_CONFIG.get("nautobot_ssot", {}) diff --git a/nautobot_ssot/migrations/0001_initial.py b/nautobot_ssot/migrations/0001_initial.py index 42f172832..721afb871 100644 --- a/nautobot_ssot/migrations/0001_initial.py +++ b/nautobot_ssot/migrations/0001_initial.py @@ -1,9 +1,10 @@ # Generated by Django 3.1.12 on 2021-06-28 20:03 -from django.db import migrations, models -import django.db.models.deletion import uuid +import django.db.models.deletion +from django.db import migrations, models + class Migration(migrations.Migration): initial = True diff --git a/nautobot_ssot/migrations/0006_ssotservicenowconfig.py b/nautobot_ssot/migrations/0006_ssotservicenowconfig.py index 7d45a4909..bb81d433e 100644 --- a/nautobot_ssot/migrations/0006_ssotservicenowconfig.py +++ b/nautobot_ssot/migrations/0006_ssotservicenowconfig.py @@ -1,13 +1,12 @@ # Generated by Django 3.2.16 on 2023-06-13 09:15 +import uuid + +import django.db.models.deletion from django.contrib.contenttypes.models import ContentType from django.db import migrations, models from django.db.migrations.recorder import MigrationRecorder -import django.db.models.deletion -import uuid - - _APP_LABEL = "nautobot_ssot" _OLD_APP_LABEL = "nautobot_plugin_servicenow" _MODEL_NAME = "SSOTServiceNowConfig" @@ -28,7 +27,7 @@ def _move_data(apps, schema_editor): with schema_editor.connection.cursor() as cursor: # Table names are from trusted source (this script) - cursor.execute(f"INSERT INTO {new_table_name} SELECT * FROM {old_table_name};") # nosec + cursor.execute(f"INSERT INTO {new_table_name} SELECT * FROM {old_table_name};") # noqa: S608 # Update the content type to point to the new model old_content_type = ContentType.objects.get(app_label=_OLD_APP_LABEL, model=_MODEL_NAME.lower()) diff --git a/nautobot_ssot/migrations/0007_replace_dashed_custom_fields.py b/nautobot_ssot/migrations/0007_replace_dashed_custom_fields.py index 4cffdad5e..9bcd73088 100644 --- a/nautobot_ssot/migrations/0007_replace_dashed_custom_fields.py +++ b/nautobot_ssot/migrations/0007_replace_dashed_custom_fields.py @@ -1,8 +1,7 @@ from django.db import migrations -from nautobot.dcim.models import Device, DeviceType, Interface, Manufacturer, Location +from nautobot.dcim.models import Device, DeviceType, Interface, Location, Manufacturer from nautobot.extras.models import Role -from nautobot.extras.utils import FeatureQuery -from nautobot.ipam.models import IPAddress, VLAN +from nautobot.ipam.models import VLAN, IPAddress CF_KEY_CHANGE_MAP = { "ssot_synced_to_servicenow": "ssot-synced-to-servicenow", diff --git a/nautobot_ssot/migrations/0008_auto_20240110_1019.py b/nautobot_ssot/migrations/0008_auto_20240110_1019.py index 96c6e3663..4c003669f 100644 --- a/nautobot_ssot/migrations/0008_auto_20240110_1019.py +++ b/nautobot_ssot/migrations/0008_auto_20240110_1019.py @@ -1,6 +1,7 @@ # Generated by Django 3.2.21 on 2024-01-10 10:19 from django.db import migrations, models + import nautobot_ssot.models diff --git a/nautobot_ssot/migrations/0009_ssotconfig_ssotinfobloxconfig.py b/nautobot_ssot/migrations/0009_ssotconfig_ssotinfobloxconfig.py index fbcd5689b..4b6fbdd7e 100644 --- a/nautobot_ssot/migrations/0009_ssotconfig_ssotinfobloxconfig.py +++ b/nautobot_ssot/migrations/0009_ssotconfig_ssotinfobloxconfig.py @@ -1,12 +1,14 @@ # Generated by Django 3.2.23 on 2024-06-17 14:33 +import uuid + import django.core.serializers.json -from django.db import migrations, models import django.db.models.deletion import nautobot.core.models.fields import nautobot.extras.models.mixins +from django.db import migrations, models + import nautobot_ssot.integrations.infoblox.models -import uuid class Migration(migrations.Migration): diff --git a/nautobot_ssot/migrations/0010_automationgatewaymodel.py b/nautobot_ssot/migrations/0010_automationgatewaymodel.py index 13e47cab7..5974e1cba 100644 --- a/nautobot_ssot/migrations/0010_automationgatewaymodel.py +++ b/nautobot_ssot/migrations/0010_automationgatewaymodel.py @@ -1,11 +1,12 @@ # Generated by Django 3.2.23 on 2024-06-26 19:01 +import uuid + import django.core.serializers.json -from django.db import migrations, models import django.db.models.deletion import nautobot.core.models.fields import nautobot.extras.models.mixins -import uuid +from django.db import migrations, models class Migration(migrations.Migration): diff --git a/nautobot_ssot/models.py b/nautobot_ssot/models.py index e4c7810dd..9f96e6a03 100644 --- a/nautobot_ssot/models.py +++ b/nautobot_ssot/models.py @@ -27,16 +27,14 @@ from django.urls import reverse from django.utils.formats import date_format from django.utils.timezone import now - - from nautobot.core.models import BaseModel from nautobot.extras.choices import JobResultStatusChoices from nautobot.extras.models import JobResult from nautobot.extras.utils import extras_features -from nautobot_ssot.integrations.servicenow.models import SSOTServiceNowConfig from nautobot_ssot.integrations.infoblox.models import SSOTInfobloxConfig from nautobot_ssot.integrations.itential.models import AutomationGatewayModel +from nautobot_ssot.integrations.servicenow.models import SSOTServiceNowConfig from .choices import SyncLogEntryActionChoices, SyncLogEntryStatusChoices diff --git a/nautobot_ssot/navigation.py b/nautobot_ssot/navigation.py index ac686903e..175149f52 100644 --- a/nautobot_ssot/navigation.py +++ b/nautobot_ssot/navigation.py @@ -1,8 +1,8 @@ """App additions to the Nautobot navigation menu.""" from nautobot.apps.ui import NavMenuGroup, NavMenuItem, NavMenuTab -from .integrations.utils import each_enabled_integration_module +from .integrations.utils import each_enabled_integration_module items = [ NavMenuItem( diff --git a/nautobot_ssot/tables.py b/nautobot_ssot/tables.py index 38cfde649..3d787dcdb 100644 --- a/nautobot_ssot/tables.py +++ b/nautobot_ssot/tables.py @@ -1,13 +1,11 @@ """Data tables for Single Source of Truth (SSOT) views.""" from django_tables2 import Column, DateTimeColumn, JSONColumn, LinkColumn, TemplateColumn - from nautobot.apps.tables import BaseTable, ToggleColumn from .choices import SyncLogEntryActionChoices, SyncLogEntryStatusChoices from .models import Sync, SyncLogEntry - ACTION_LOGS_LINK = """ diff --git a/nautobot_ssot/template_content.py b/nautobot_ssot/template_content.py index caba66cb9..6f3a4e317 100644 --- a/nautobot_ssot/template_content.py +++ b/nautobot_ssot/template_content.py @@ -1,7 +1,6 @@ """App template content extensions of base Nautobot views.""" from django.urls import reverse - from nautobot.extras.plugins import PluginTemplateExtension from nautobot_ssot.models import Sync diff --git a/nautobot_ssot/templatetags/dashboard_helpers.py b/nautobot_ssot/templatetags/dashboard_helpers.py index 56a8720b2..082d4c2bc 100644 --- a/nautobot_ssot/templatetags/dashboard_helpers.py +++ b/nautobot_ssot/templatetags/dashboard_helpers.py @@ -4,7 +4,6 @@ from django import template - logger = logging.getLogger(__name__) diff --git a/nautobot_ssot/templatetags/humanize_bytes.py b/nautobot_ssot/templatetags/humanize_bytes.py index 7e8e9897f..5ef4f80e3 100644 --- a/nautobot_ssot/templatetags/humanize_bytes.py +++ b/nautobot_ssot/templatetags/humanize_bytes.py @@ -2,7 +2,6 @@ from django import template - register = template.Library() diff --git a/nautobot_ssot/templatetags/render_diff.py b/nautobot_ssot/templatetags/render_diff.py index 258adf576..549b13586 100644 --- a/nautobot_ssot/templatetags/render_diff.py +++ b/nautobot_ssot/templatetags/render_diff.py @@ -1,9 +1,8 @@ """Template tag for rendering a DiffSync diff dictionary in a more human-readable form.""" from django import template -from django.utils.safestring import mark_safe from django.utils.html import format_html - +from django.utils.safestring import mark_safe register = template.Library() @@ -55,7 +54,7 @@ def render_diff_recursive(diff): child_result += render_diff_recursive(child_diffs) child_result += "" - result += format_html("
  • {}
      {}
  • ", record_type, mark_safe(child_result)) # nosec + result += format_html("
  • {}
      {}
  • ", record_type, mark_safe(child_result)) # noqa: S308 return result @@ -63,4 +62,4 @@ def render_diff_recursive(diff): def render_diff(diff): """Render a DiffSync diff dict to HTML.""" html_text = render_diff_recursive(diff) - return format_html("", mark_safe(html_text)) # nosec + return format_html("", mark_safe(html_text)) # noqa: S308 diff --git a/nautobot_ssot/templatetags/shorter_timedelta.py b/nautobot_ssot/templatetags/shorter_timedelta.py index 2b0be7aa1..b3b575798 100644 --- a/nautobot_ssot/templatetags/shorter_timedelta.py +++ b/nautobot_ssot/templatetags/shorter_timedelta.py @@ -3,7 +3,6 @@ from django import template from django.utils.html import format_html - register = template.Library() diff --git a/nautobot_ssot/tests/aristacv/test_nautobot_adapter.py b/nautobot_ssot/tests/aristacv/test_nautobot_adapter.py index 868d24785..9faaa1e89 100644 --- a/nautobot_ssot/tests/aristacv/test_nautobot_adapter.py +++ b/nautobot_ssot/tests/aristacv/test_nautobot_adapter.py @@ -2,9 +2,10 @@ from unittest.mock import MagicMock, patch +from nautobot.core.testing import TransactionTestCase from nautobot.dcim.models import Device, DeviceType, Location, LocationType, Manufacturer from nautobot.extras.models import JobResult, Role, Status -from nautobot.core.testing import TransactionTestCase + from nautobot_ssot.integrations.aristacv.diffsync.adapters.nautobot import NautobotAdapter from nautobot_ssot.integrations.aristacv.jobs import CloudVisionDataSource diff --git a/nautobot_ssot/tests/aristacv/test_utils_cloudvision.py b/nautobot_ssot/tests/aristacv/test_utils_cloudvision.py index fe325032f..dabef2a20 100644 --- a/nautobot_ssot/tests/aristacv/test_utils_cloudvision.py +++ b/nautobot_ssot/tests/aristacv/test_utils_cloudvision.py @@ -1,7 +1,6 @@ """Tests of CloudVision utility methods.""" -from unittest.mock import MagicMock -from unittest.mock import patch +from unittest.mock import MagicMock, patch from cloudvision.Connector.codec.custom_types import FrozenDict from django.test import override_settings diff --git a/nautobot_ssot/tests/contrib_base_classes.py b/nautobot_ssot/tests/contrib_base_classes.py index 4ecdb7386..be9af316d 100644 --- a/nautobot_ssot/tests/contrib_base_classes.py +++ b/nautobot_ssot/tests/contrib_base_classes.py @@ -1,24 +1,25 @@ """Base classes for contrib testing.""" -from typing import Optional, List +from typing import List, Optional from unittest import skip from unittest.mock import MagicMock -from diffsync.exceptions import ObjectNotCreated, ObjectNotUpdated, ObjectNotDeleted -from django.contrib.contenttypes.models import ContentType + import nautobot.circuits.models as circuits_models -from nautobot.dcim.choices import InterfaceTypeChoices -import nautobot.extras.models as extras_models import nautobot.dcim.models as dcim_models +import nautobot.extras.models as extras_models import nautobot.ipam.models as ipam_models import nautobot.tenancy.models as tenancy_models +from diffsync.exceptions import ObjectNotCreated, ObjectNotDeleted, ObjectNotUpdated +from django.contrib.contenttypes.models import ContentType from nautobot.core.testing import TestCase -from typing_extensions import TypedDict, Annotated +from nautobot.dcim.choices import InterfaceTypeChoices +from typing_extensions import Annotated, TypedDict from nautobot_ssot.contrib import ( - NautobotModel, - NautobotAdapter, CustomFieldAnnotation, CustomRelationshipAnnotation, + NautobotAdapter, + NautobotModel, RelationshipSideEnum, ) diff --git a/nautobot_ssot/tests/device42/unit/test_device42_adapter.py b/nautobot_ssot/tests/device42/unit/test_device42_adapter.py index df51669f9..4f6129708 100644 --- a/nautobot_ssot/tests/device42/unit/test_device42_adapter.py +++ b/nautobot_ssot/tests/device42/unit/test_device42_adapter.py @@ -2,14 +2,16 @@ import json from unittest.mock import MagicMock, patch + from diffsync.exceptions import ObjectAlreadyExists, ObjectNotFound from nautobot.core.testing import TransactionTestCase from nautobot.extras.models import JobResult from parameterized import parameterized + from nautobot_ssot.integrations.device42.diffsync.adapters.device42 import ( Device42Adapter, - get_dns_a_record, get_circuit_status, + get_dns_a_record, get_site_from_mapping, ) from nautobot_ssot.integrations.device42.jobs import Device42DataSource diff --git a/nautobot_ssot/tests/device42/unit/test_utils_device42.py b/nautobot_ssot/tests/device42/unit/test_utils_device42.py index 1bdd6476c..80c8f3da1 100644 --- a/nautobot_ssot/tests/device42/unit/test_utils_device42.py +++ b/nautobot_ssot/tests/device42/unit/test_utils_device42.py @@ -6,6 +6,7 @@ import responses from nautobot.core.testing import TestCase from parameterized import parameterized + from nautobot_ssot.integrations.device42.jobs import Device42DataSource from nautobot_ssot.integrations.device42.utils import device42 @@ -218,7 +219,7 @@ def setUp(self): """Setup Device42API instance.""" self.uri = "https://device42.testexample.com" self.username = "testuser" - self.password = "testpassword" # nosec B105 + self.password = "testpassword" # noqa: S105 self.verify = False self.dev42 = device42.Device42API(self.uri, self.username, self.password, self.verify) diff --git a/nautobot_ssot/tests/device42/unit/test_utils_nautobot.py b/nautobot_ssot/tests/device42/unit/test_utils_nautobot.py index 3035893c5..605c770a7 100644 --- a/nautobot_ssot/tests/device42/unit/test_utils_nautobot.py +++ b/nautobot_ssot/tests/device42/unit/test_utils_nautobot.py @@ -1,20 +1,22 @@ """Tests of Nautobot utility methods.""" -from uuid import UUID from unittest.mock import MagicMock, patch +from uuid import UUID + from diffsync.exceptions import ObjectNotFound from django.contrib.contenttypes.models import ContentType from nautobot.core.testing import TransactionTestCase -from nautobot.dcim.models import Manufacturer, Location, LocationType, Device, DeviceType, Interface +from nautobot.dcim.models import Device, DeviceType, Interface, Location, LocationType, Manufacturer from nautobot.extras.choices import CustomFieldTypeChoices from nautobot.extras.models import CustomField, Role, Status from nautobot.ipam.models import VLAN + from nautobot_ssot.integrations.device42.diffsync.models.nautobot.dcim import NautobotDevice from nautobot_ssot.integrations.device42.utils.nautobot import ( - verify_platform, + apply_vlans_to_port, determine_vc_position, update_custom_fields, - apply_vlans_to_port, + verify_platform, ) @@ -91,6 +93,7 @@ def test_lifecycle_mgmt_available(self): from nautobot_device_lifecycle_mgmt.models import ( # noqa: F401 # pylint: disable=import-outside-toplevel, unused-import SoftwareLCM, ) + from nautobot_ssot.integrations.device42.utils.nautobot import ( # noqa: F401 # pylint: disable=import-outside-toplevel, unused-import LIFECYCLE_MGMT, ) diff --git a/nautobot_ssot/tests/dna_center/test_adapters_dna_center.py b/nautobot_ssot/tests/dna_center/test_adapters_dna_center.py index a9f9e9ec8..ee3e6cfaf 100644 --- a/nautobot_ssot/tests/dna_center/test_adapters_dna_center.py +++ b/nautobot_ssot/tests/dna_center/test_adapters_dna_center.py @@ -38,9 +38,7 @@ @override_settings(PLUGINS_CONFIG={"nautobot_ssot": {"dna_center_import_global": True}}) -class TestDnaCenterAdapterTestCase( - TransactionTestCase -): # pylint: disable=too-many-public-methods, too-many-instance-attributes +class TestDnaCenterAdapterTestCase(TransactionTestCase): # pylint: disable=too-many-public-methods, too-many-instance-attributes """Test NautobotSsotDnaCenterAdapter class.""" databases = ("default", "job_logs") diff --git a/nautobot_ssot/tests/dna_center/test_adapters_nautobot.py b/nautobot_ssot/tests/dna_center/test_adapters_nautobot.py index e9f2ba8b0..51a1eda5a 100644 --- a/nautobot_ssot/tests/dna_center/test_adapters_nautobot.py +++ b/nautobot_ssot/tests/dna_center/test_adapters_nautobot.py @@ -2,22 +2,24 @@ import uuid from unittest.mock import MagicMock, patch + from diffsync.exceptions import ObjectNotFound from django.contrib.contenttypes.models import ContentType +from nautobot.core.testing import TransactionTestCase from nautobot.dcim.models import ( - Manufacturer, - Location, - LocationType, Device, DeviceType, - Platform, Interface, + Location, + LocationType, + Manufacturer, + Platform, ) -from nautobot.extras.models import Status, JobResult, Role -from nautobot.ipam.models import IPAddress, Namespace, Prefix, IPAddressToInterface -from nautobot.core.testing import TransactionTestCase -from nautobot_ssot.integrations.dna_center.jobs import DnaCenterDataSource +from nautobot.extras.models import JobResult, Role, Status +from nautobot.ipam.models import IPAddress, IPAddressToInterface, Namespace, Prefix + from nautobot_ssot.integrations.dna_center.diffsync.adapters.nautobot import NautobotAdapter +from nautobot_ssot.integrations.dna_center.jobs import DnaCenterDataSource class NautobotDiffSyncTestCase(TransactionTestCase): # pylint: disable=too-many-instance-attributes diff --git a/nautobot_ssot/tests/dna_center/test_models_nautobot.py b/nautobot_ssot/tests/dna_center/test_models_nautobot.py index 170669cdb..12d5afa6a 100644 --- a/nautobot_ssot/tests/dna_center/test_models_nautobot.py +++ b/nautobot_ssot/tests/dna_center/test_models_nautobot.py @@ -1,24 +1,26 @@ """Test the DiffSync models for Nautobot.""" from unittest.mock import MagicMock, patch -from django.test import override_settings + from diffsync import Adapter +from django.test import override_settings +from nautobot.core.testing import TransactionTestCase from nautobot.dcim.models import ( Controller, ControllerManagedDeviceGroup, + DeviceType, Location, LocationType, - DeviceType, Manufacturer, ) -from nautobot.extras.models import Status, Role +from nautobot.extras.models import Role, Status from nautobot.tenancy.models import Tenant -from nautobot.core.testing import TransactionTestCase + from nautobot_ssot.integrations.dna_center.diffsync.models.nautobot import ( NautobotArea, NautobotBuilding, - NautobotFloor, NautobotDevice, + NautobotFloor, ) diff --git a/nautobot_ssot/tests/dna_center/test_utils_dna_center.py b/nautobot_ssot/tests/dna_center/test_utils_dna_center.py index 7cd657f71..9fe2a8e2e 100644 --- a/nautobot_ssot/tests/dna_center/test_utils_dna_center.py +++ b/nautobot_ssot/tests/dna_center/test_utils_dna_center.py @@ -1,10 +1,13 @@ """Tests of DNA Center utility methods.""" -from unittest.mock import MagicMock, patch, create_autospec -from requests import Response -from parameterized import parameterized -from nautobot.core.testing import TestCase +from unittest.mock import MagicMock, create_autospec, patch + from dnacentersdk.exceptions import dnacentersdkException +from nautobot.core.testing import TestCase +from parameterized import parameterized +from requests import Response + +from nautobot_ssot.integrations.dna_center.utils.dna_center import DnaCenterClient from nautobot_ssot.tests.dna_center.fixtures import ( DEVICE_DETAIL_FIXTURE, DEVICE_FIXTURE, @@ -15,7 +18,6 @@ RECV_LOCATION_FIXTURE, RECV_PORT_FIXTURE, ) -from nautobot_ssot.integrations.dna_center.utils.dna_center import DnaCenterClient class TestDnaCenterClient(TestCase): # pylint: disable=too-many-public-methods @@ -27,7 +29,7 @@ def setUp(self): """Setup DNAC instance.""" self.url = "https://dnac.testexample.com" self.username = "testuser" - self.password = "testpassword" # nosec B105 + self.password = "testpassword" # noqa: S105 self.verify = False self.dnac = DnaCenterClient(self.url, self.username, self.password, verify=self.verify) self.dnac.conn = MagicMock() @@ -46,7 +48,7 @@ def setUp(self): @patch("nautobot_ssot.integrations.dna_center.utils.dna_center.api.DNACenterAPI") def test_connect_success(self, mock_api): self.dnac.connect() - mock_api.assert_called_once_with( # nosec B106 + mock_api.assert_called_once_with( # noqa: S106 base_url="https://dnac.testexample.com:443", username="testuser", password="testpassword", verify=False ) self.assertIsNotNone(self.dnac.conn) @@ -57,7 +59,7 @@ def test_connect_error(self, mock_api): mock_api.side_effect = dnacentersdkException(self.mock_response) with self.assertRaises(dnacentersdkException): self.dnac.connect() - mock_api.assert_called_once_with( # nosec B106 + mock_api.assert_called_once_with( # noqa: S106 base_url="https://dnac.testexample.com:443", password="testpassword", username="testuser", verify=False ) self.assertIsNone(self.dnac.conn) diff --git a/nautobot_ssot/tests/ipfabric/test_nautobot_adapter.py b/nautobot_ssot/tests/ipfabric/test_nautobot_adapter.py index 7443dc701..13684e7d9 100644 --- a/nautobot_ssot/tests/ipfabric/test_nautobot_adapter.py +++ b/nautobot_ssot/tests/ipfabric/test_nautobot_adapter.py @@ -4,7 +4,6 @@ from django.contrib.contenttypes.models import ContentType from django.test import TestCase - from nautobot.dcim.models import ( Device, DeviceType, diff --git a/nautobot_ssot/tests/itential/fixtures/clients.py b/nautobot_ssot/tests/itential/fixtures/clients.py index 9698590b5..11ee2f3ba 100644 --- a/nautobot_ssot/tests/itential/fixtures/clients.py +++ b/nautobot_ssot/tests/itential/fixtures/clients.py @@ -4,8 +4,8 @@ from nautobot.extras.choices import SecretsGroupAccessTypeChoices, SecretsGroupSecretTypeChoices -from nautobot_ssot.integrations.itential.models import AutomationGatewayModel from nautobot_ssot.integrations.itential.clients import AutomationGatewayClient +from nautobot_ssot.integrations.itential.models import AutomationGatewayModel def api_client(device_obj: AutomationGatewayModel, job: object = unittest.mock.MagicMock()) -> AutomationGatewayClient: diff --git a/nautobot_ssot/tests/itential/fixtures/gateways.py b/nautobot_ssot/tests/itential/fixtures/gateways.py index 78926179c..943257563 100644 --- a/nautobot_ssot/tests/itential/fixtures/gateways.py +++ b/nautobot_ssot/tests/itential/fixtures/gateways.py @@ -1,8 +1,8 @@ """Itential Automation Gateway Fixtures.""" -from nautobot.extras.models import Secret, SecretsGroup, SecretsGroupAssociation, ExternalIntegration, Status +from nautobot.dcim.models import Location, LocationType from nautobot.extras.choices import SecretsGroupAccessTypeChoices, SecretsGroupSecretTypeChoices -from nautobot.dcim.models import LocationType, Location +from nautobot.extras.models import ExternalIntegration, Secret, SecretsGroup, SecretsGroupAssociation, Status from nautobot_ssot.integrations.itential.models import AutomationGatewayModel diff --git a/nautobot_ssot/tests/itential/fixtures/urls.py b/nautobot_ssot/tests/itential/fixtures/urls.py index 968d51a1b..0505624bd 100644 --- a/nautobot_ssot/tests/itential/fixtures/urls.py +++ b/nautobot_ssot/tests/itential/fixtures/urls.py @@ -2,7 +2,6 @@ from nautobot_ssot.tests.itential.fixtures import gateways - data = [ { "method": "POST", diff --git a/nautobot_ssot/tests/itential/test_clients.py b/nautobot_ssot/tests/itential/test_clients.py index e496b7036..69a9ea3bb 100644 --- a/nautobot_ssot/tests/itential/test_clients.py +++ b/nautobot_ssot/tests/itential/test_clients.py @@ -1,7 +1,7 @@ """Itential SSoT API Client Tests.""" -from nautobot_ssot.tests.itential.fixtures.base import ItentialSSoTBaseTestCase from nautobot_ssot.tests.itential.fixtures import gateways +from nautobot_ssot.tests.itential.fixtures.base import ItentialSSoTBaseTestCase class AutomationGatewayClientTestCase(ItentialSSoTBaseTestCase): diff --git a/nautobot_ssot/tests/itential/test_jobs.py b/nautobot_ssot/tests/itential/test_jobs.py index 9ede55df1..4da5f4505 100644 --- a/nautobot_ssot/tests/itential/test_jobs.py +++ b/nautobot_ssot/tests/itential/test_jobs.py @@ -1,12 +1,11 @@ """Itential SSoT Jobs Test Cases.""" from django.test import override_settings -from nautobot.extras.models import Job, JobLogEntry from nautobot.apps.testing import run_job_for_testing - -from nautobot_ssot.tests.itential.fixtures import base +from nautobot.extras.models import Job, JobLogEntry from nautobot_ssot.integrations.itential.models import AutomationGatewayModel +from nautobot_ssot.tests.itential.fixtures import base @override_settings( diff --git a/nautobot_ssot/tests/jobs/__init__.py b/nautobot_ssot/tests/jobs/__init__.py index 45ab3fc73..dff380bba 100644 --- a/nautobot_ssot/tests/jobs/__init__.py +++ b/nautobot_ssot/tests/jobs/__init__.py @@ -1,7 +1,9 @@ """Override of classes.""" from nautobot.extras.jobs import Job -from nautobot_ssot.jobs import DataSource as _DataSource, DataTarget as _DataTarget + +from nautobot_ssot.jobs import DataSource as _DataSource +from nautobot_ssot.jobs import DataTarget as _DataTarget from nautobot_ssot.jobs.base import DataSyncBaseJob as _DataSyncBaseJob diff --git a/nautobot_ssot/tests/servicenow/test_adapter_nautobot.py b/nautobot_ssot/tests/servicenow/test_adapter_nautobot.py index 63f699a23..0ef304967 100644 --- a/nautobot_ssot/tests/servicenow/test_adapter_nautobot.py +++ b/nautobot_ssot/tests/servicenow/test_adapter_nautobot.py @@ -1,11 +1,11 @@ """Unit tests for the Nautobot DiffSync adapter.""" -from nautobot.dcim.models import Device, DeviceType, Interface, Manufacturer, Location, LocationType -from nautobot.extras.models import JobResult, Role, Status from nautobot.core.testing import TransactionTestCase +from nautobot.dcim.models import Device, DeviceType, Interface, Location, LocationType, Manufacturer +from nautobot.extras.models import JobResult, Role, Status -from nautobot_ssot.integrations.servicenow.jobs import ServiceNowDataTarget from nautobot_ssot.integrations.servicenow.diffsync.adapter_nautobot import NautobotDiffSync +from nautobot_ssot.integrations.servicenow.jobs import ServiceNowDataTarget class NautobotDiffSyncTestCase(TransactionTestCase): diff --git a/nautobot_ssot/tests/servicenow/test_adapter_servicenow.py b/nautobot_ssot/tests/servicenow/test_adapter_servicenow.py index df3c4e775..ad202f229 100644 --- a/nautobot_ssot/tests/servicenow/test_adapter_servicenow.py +++ b/nautobot_ssot/tests/servicenow/test_adapter_servicenow.py @@ -1,10 +1,10 @@ """Unit tests for the ServiceNowDiffSync adapter class.""" -from nautobot.extras.models import JobResult from nautobot.core.testing import TransactionTestCase +from nautobot.extras.models import JobResult -from nautobot_ssot.integrations.servicenow.jobs import ServiceNowDataTarget from nautobot_ssot.integrations.servicenow.diffsync.adapter_servicenow import ServiceNowDiffSync +from nautobot_ssot.integrations.servicenow.jobs import ServiceNowDataTarget class MockServiceNowClient: diff --git a/nautobot_ssot/tests/servicenow/test_jobs.py b/nautobot_ssot/tests/servicenow/test_jobs.py index 0052f0be1..b1856c168 100644 --- a/nautobot_ssot/tests/servicenow/test_jobs.py +++ b/nautobot_ssot/tests/servicenow/test_jobs.py @@ -5,8 +5,7 @@ from django.test import TestCase, override_settings from django.urls import reverse - -from nautobot.dcim.models import Device, DeviceType, Interface, Manufacturer, Location, LocationType +from nautobot.dcim.models import Device, DeviceType, Interface, Location, LocationType, Manufacturer from nautobot.extras.choices import SecretsGroupAccessTypeChoices, SecretsGroupSecretTypeChoices from nautobot.extras.models import Role, Secret, SecretsGroup, SecretsGroupAssociation, Status diff --git a/nautobot_ssot/tests/test_api.py b/nautobot_ssot/tests/test_api.py index 430619f14..25496b965 100644 --- a/nautobot_ssot/tests/test_api.py +++ b/nautobot_ssot/tests/test_api.py @@ -2,12 +2,11 @@ from django.contrib.auth import get_user_model from django.urls import reverse -from nautobot.users.models import Token from nautobot.core.testing import TestCase +from nautobot.users.models import Token from rest_framework import status from rest_framework.test import APIClient - User = get_user_model() diff --git a/nautobot_ssot/tests/test_basic.py b/nautobot_ssot/tests/test_basic.py index 30fc318ed..d72f2d02e 100644 --- a/nautobot_ssot/tests/test_basic.py +++ b/nautobot_ssot/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_ssot/tests/test_contrib_adapter.py b/nautobot_ssot/tests/test_contrib_adapter.py index 5451c0e59..3c21e86f3 100644 --- a/nautobot_ssot/tests/test_contrib_adapter.py +++ b/nautobot_ssot/tests/test_contrib_adapter.py @@ -9,9 +9,8 @@ from django.contrib.contenttypes.models import ContentType from django.db import connection from django.test.utils import CaptureQueriesContext -from nautobot.core.testing import TestCase from nautobot.circuits import models as circuits_models - +from nautobot.core.testing import TestCase from nautobot.dcim import models as dcim_models from nautobot.extras import models as extras_models from nautobot.extras.choices import RelationshipTypeChoices @@ -19,16 +18,16 @@ from nautobot.tenancy import models as tenancy_models from typing_extensions import Annotated, TypedDict -from nautobot_ssot.contrib import NautobotAdapter, NautobotModel, CustomFieldAnnotation +from nautobot_ssot.contrib import CustomFieldAnnotation, NautobotAdapter, NautobotModel from nautobot_ssot.tests.contrib_base_classes import ( - TestCaseWithDeviceData, - NautobotDevice, NautobotCable, - TestAdapter, - NautobotTenantGroup, + NautobotDevice, NautobotTenant, - TenantModelCustomRelationship, + NautobotTenantGroup, ProviderModelCustomRelationship, + TenantModelCustomRelationship, + TestAdapter, + TestCaseWithDeviceData, ) diff --git a/nautobot_ssot/tests/test_contrib_model.py b/nautobot_ssot/tests/test_contrib_model.py index 01901211b..247df505f 100644 --- a/nautobot_ssot/tests/test_contrib_model.py +++ b/nautobot_ssot/tests/test_contrib_model.py @@ -1,29 +1,29 @@ """Tests for contrib.NautobotModel.""" -from unittest.mock import MagicMock from typing import List, Optional +from unittest.mock import MagicMock from django.contrib.contenttypes.models import ContentType from nautobot.circuits import models as circuits_models from nautobot.core.testing import TestCase from nautobot.dcim import models as dcim_models from nautobot.dcim.choices import InterfaceTypeChoices -from nautobot.extras.choices import RelationshipTypeChoices from nautobot.extras import models as extras_models +from nautobot.extras.choices import RelationshipTypeChoices from nautobot.tenancy import models as tenancy_models -from nautobot_ssot.contrib import NautobotModel, NautobotAdapter +from nautobot_ssot.contrib import NautobotAdapter, NautobotModel from nautobot_ssot.tests.contrib_base_classes import ( - TenantModelCustomRelationship, - ProviderModelCustomRelationship, - TestCaseWithDeviceData, NautobotTenant, - TagModel, + ProviderModelCustomRelationship, TagDict, + TagModel, + TenantModelCustomRelationship, + TestCaseWithDeviceData, ) from nautobot_ssot.tests.test_contrib_adapter import ( - CustomRelationShipTestAdapterSource, CustomRelationShipTestAdapterDestination, + CustomRelationShipTestAdapterSource, ) diff --git a/nautobot_ssot/tests/test_jobs.py b/nautobot_ssot/tests/test_jobs.py index fbca132b0..b4052b242 100644 --- a/nautobot_ssot/tests/test_jobs.py +++ b/nautobot_ssot/tests/test_jobs.py @@ -5,13 +5,12 @@ from django.db.utils import IntegrityError, OperationalError from django.test import override_settings - -from nautobot.extras.models import JobResult from nautobot.core.testing import TransactionTestCase +from nautobot.extras.models import JobResult from nautobot_ssot.choices import SyncLogEntryActionChoices, SyncLogEntryStatusChoices -from nautobot_ssot.tests.jobs import DataSyncBaseJob, DataSource, DataTarget from nautobot_ssot.models import SyncLogEntry +from nautobot_ssot.tests.jobs import DataSource, DataSyncBaseJob, DataTarget @override_settings(JOBS_ROOT=os.path.join(os.path.dirname(__file__), "jobs")) diff --git a/nautobot_ssot/tests/test_management.py b/nautobot_ssot/tests/test_management.py index 11f1bac4e..9c1d41b88 100644 --- a/nautobot_ssot/tests/test_management.py +++ b/nautobot_ssot/tests/test_management.py @@ -5,7 +5,6 @@ from django.contrib.contenttypes.models import ContentType from django.core.management import call_command from django.test import TestCase - from nautobot.dcim.models import ( Device, DeviceType, diff --git a/nautobot_ssot/tests/test_models.py b/nautobot_ssot/tests/test_models.py index 2f68ccf74..6ea5b0d96 100644 --- a/nautobot_ssot/tests/test_models.py +++ b/nautobot_ssot/tests/test_models.py @@ -3,9 +3,9 @@ import datetime import time import uuid + from django.test import TestCase from django.utils.timezone import now - from nautobot.extras.choices import JobResultStatusChoices from nautobot.extras.models import Job, JobResult diff --git a/nautobot_ssot/tests/test_render_diff.py b/nautobot_ssot/tests/test_render_diff.py index 3590b346d..e0600c625 100644 --- a/nautobot_ssot/tests/test_render_diff.py +++ b/nautobot_ssot/tests/test_render_diff.py @@ -1,8 +1,8 @@ """Test Render_diff templatetags.""" import unittest -from nautobot_ssot.templatetags.render_diff import render_diff +from nautobot_ssot.templatetags.render_diff import render_diff test_params = [ ( diff --git a/nautobot_ssot/tests/test_views.py b/nautobot_ssot/tests/test_views.py index cbaada4c0..1c75b8e9b 100644 --- a/nautobot_ssot/tests/test_views.py +++ b/nautobot_ssot/tests/test_views.py @@ -5,11 +5,10 @@ from django.contrib.contenttypes.models import ContentType from django.urls import reverse - -from nautobot.extras.models import Job, JobResult -from nautobot.users.models import ObjectPermission from nautobot.apps.testing import ViewTestCases from nautobot.core.testing.utils import disable_warnings +from nautobot.extras.models import Job, JobResult +from nautobot.users.models import ObjectPermission from nautobot_ssot.choices import SyncLogEntryActionChoices, SyncLogEntryStatusChoices from nautobot_ssot.models import Sync, SyncLogEntry diff --git a/nautobot_ssot/utils.py b/nautobot_ssot/utils.py index 72f32ad0c..84ea0554c 100644 --- a/nautobot_ssot/utils.py +++ b/nautobot_ssot/utils.py @@ -6,7 +6,6 @@ from nautobot.extras.choices import SecretsGroupAccessTypeChoices, SecretsGroupSecretTypeChoices from nautobot.extras.models import SecretsGroup - logger = logging.getLogger("nautobot.ssot") diff --git a/poetry.lock b/poetry.lock index 770c7dd39..81210318c 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 = "alabaster" @@ -251,30 +251,6 @@ tzdata = {version = "*", optional = true, markers = "extra == \"tzdata\""} [package.extras] tzdata = ["tzdata"] -[[package]] -name = "bandit" -version = "1.7.9" -description = "Security oriented static analyser for python code." -optional = false -python-versions = ">=3.8" -files = [ - {file = "bandit-1.7.9-py3-none-any.whl", hash = "sha256:52077cb339000f337fb25f7e045995c4ad01511e716e5daac37014b9752de8ec"}, - {file = "bandit-1.7.9.tar.gz", hash = "sha256:7c395a436743018f7be0a4cbb0a4ea9b902b6d87264ddecf8cfdc73b4f78ff61"}, -] - -[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 = "billiard" version = "4.2.0" @@ -286,52 +262,6 @@ files = [ {file = "billiard-4.2.0.tar.gz", hash = "sha256:9a3c3184cb275aa17a732f93f65b20c525d3d9f253722d26a82194803ade5a2c"}, ] -[[package]] -name = "black" -version = "24.8.0" -description = "The uncompromising code formatter." -optional = false -python-versions = ">=3.8" -files = [ - {file = "black-24.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:09cdeb74d494ec023ded657f7092ba518e8cf78fa8386155e4a03fdcc44679e6"}, - {file = "black-24.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:81c6742da39f33b08e791da38410f32e27d632260e599df7245cccee2064afeb"}, - {file = "black-24.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:707a1ca89221bc8a1a64fb5e15ef39cd755633daa672a9db7498d1c19de66a42"}, - {file = "black-24.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:d6417535d99c37cee4091a2f24eb2b6d5ec42b144d50f1f2e436d9fe1916fe1a"}, - {file = "black-24.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fb6e2c0b86bbd43dee042e48059c9ad7830abd5c94b0bc518c0eeec57c3eddc1"}, - {file = "black-24.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:837fd281f1908d0076844bc2b801ad2d369c78c45cf800cad7b61686051041af"}, - {file = "black-24.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62e8730977f0b77998029da7971fa896ceefa2c4c4933fcd593fa599ecbf97a4"}, - {file = "black-24.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:72901b4913cbac8972ad911dc4098d5753704d1f3c56e44ae8dce99eecb0e3af"}, - {file = "black-24.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7c046c1d1eeb7aea9335da62472481d3bbf3fd986e093cffd35f4385c94ae368"}, - {file = "black-24.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:649f6d84ccbae73ab767e206772cc2d7a393a001070a4c814a546afd0d423aed"}, - {file = "black-24.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b59b250fdba5f9a9cd9d0ece6e6d993d91ce877d121d161e4698af3eb9c1018"}, - {file = "black-24.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:6e55d30d44bed36593c3163b9bc63bf58b3b30e4611e4d88a0c3c239930ed5b2"}, - {file = "black-24.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:505289f17ceda596658ae81b61ebbe2d9b25aa78067035184ed0a9d855d18afd"}, - {file = "black-24.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b19c9ad992c7883ad84c9b22aaa73562a16b819c1d8db7a1a1a49fb7ec13c7d2"}, - {file = "black-24.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1f13f7f386f86f8121d76599114bb8c17b69d962137fc70efe56137727c7047e"}, - {file = "black-24.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:f490dbd59680d809ca31efdae20e634f3fae27fba3ce0ba3208333b713bc3920"}, - {file = "black-24.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:eab4dd44ce80dea27dc69db40dab62d4ca96112f87996bca68cd75639aeb2e4c"}, - {file = "black-24.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3c4285573d4897a7610054af5a890bde7c65cb466040c5f0c8b732812d7f0e5e"}, - {file = "black-24.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e84e33b37be070ba135176c123ae52a51f82306def9f7d063ee302ecab2cf47"}, - {file = "black-24.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:73bbf84ed136e45d451a260c6b73ed674652f90a2b3211d6a35e78054563a9bb"}, - {file = "black-24.8.0-py3-none-any.whl", hash = "sha256:972085c618ee94f402da1af548a4f218c754ea7e5dc70acb168bfaca4c2542ed"}, - {file = "black-24.8.0.tar.gz", hash = "sha256:2500945420b6784c38b9ee885af039f5e7471ef284ab03fa35ecdde4688cd83f"}, -] - -[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 = "case-insensitive-dictionary" version = "0.2.1" @@ -1576,22 +1506,6 @@ files = [ [package.extras] devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benchmark", "pytest-cache", "validictory"] -[[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 = "fonttools" version = "4.53.1" @@ -2179,13 +2093,13 @@ files = [ [[package]] name = "ipfabric" -version = "6.9.3" +version = "6.9.4" description = "Python package for interacting with IP Fabric" optional = true python-versions = "<4.0,>=3.8" files = [ - {file = "ipfabric-6.9.3-py3-none-any.whl", hash = "sha256:b6cd6be5d586f3fc0ac4cd2ca2b4102742837bc992200b79c57471d6474b5c30"}, - {file = "ipfabric-6.9.3.tar.gz", hash = "sha256:d6b5ee24276ea82ad6836b0912a7be8a9467d0d94eeb8742fa464049ed06d1ca"}, + {file = "ipfabric-6.9.4-py3-none-any.whl", hash = "sha256:31d65d4de544233ddc1278b651c1ccf2ac798bde2ce20528ce232e5db602d2f1"}, + {file = "ipfabric-6.9.4.tar.gz", hash = "sha256:6733e0b7447f7c4274735d1010d5879a3952cf540a3f3f458d256aff6a4a1b92"}, ] [package.dependencies] @@ -2552,6 +2466,20 @@ 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"] +[[package]] +name = "markdown-version-annotations" +version = "1.0.1" +description = "Markdown plugin to add custom admonitions for documenting version differences" +optional = false +python-versions = "<4.0,>=3.7" +files = [ + {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] +markdown = ">=3.3.7,<4.0.0" + [[package]] name = "markupsafe" version = "2.1.5" @@ -2757,34 +2685,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" @@ -2802,27 +2730,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" @@ -2835,17 +2787,6 @@ 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.25.2" @@ -2954,17 +2895,6 @@ files = [ {file = "msgpack-1.0.8.tar.gz", hash = "sha256:95c02b0e27e706e48d0e5426d1710ca78e0f0628d6e89d5b5a5b91a5f12274f3"}, ] -[[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"}, -] - [[package]] name = "myst-parser" version = "2.0.0" @@ -3203,6 +3133,16 @@ files = [ {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, ] +[[package]] +name = "paginate" +version = "0.5.6" +description = "Divides large result sets into pages for easier browsing" +optional = false +python-versions = "*" +files = [ + {file = "paginate-0.5.6.tar.gz", hash = "sha256:5e6007b6a9398177a7e1648d04fdd9f8c9766a1a945bceac82f1929e8c78af2d"}, +] + [[package]] name = "parameterized" version = "0.8.1" @@ -3242,17 +3182,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" @@ -3488,6 +3417,7 @@ files = [ {file = "psycopg2_binary-2.9.9-cp311-cp311-win32.whl", hash = "sha256:dc4926288b2a3e9fd7b50dc6a1909a13bbdadfc67d93f3374d984e56f885579d"}, {file = "psycopg2_binary-2.9.9-cp311-cp311-win_amd64.whl", hash = "sha256:b76bedd166805480ab069612119ea636f5ab8f8771e640ae103e05a4aae3e417"}, {file = "psycopg2_binary-2.9.9-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:8532fd6e6e2dc57bcb3bc90b079c60de896d2128c5d9d6f24a63875a95a088cf"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0605eaed3eb239e87df0d5e3c6489daae3f7388d455d0c0b4df899519c6a38d"}, {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f8544b092a29a6ddd72f3556a9fcf249ec412e10ad28be6a0c0d948924f2212"}, {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2d423c8d8a3c82d08fe8af900ad5b613ce3632a1249fd6a223941d0735fce493"}, {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e5afae772c00980525f6d6ecf7cbca55676296b580c0e6abb407f15f3706996"}, @@ -3496,6 +3426,8 @@ files = [ {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:cb16c65dcb648d0a43a2521f2f0a2300f40639f6f8c1ecbc662141e4e3e1ee07"}, {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:911dda9c487075abd54e644ccdf5e5c16773470a6a5d3826fda76699410066fb"}, {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:57fede879f08d23c85140a360c6a77709113efd1c993923c59fde17aa27599fe"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-win32.whl", hash = "sha256:64cf30263844fa208851ebb13b0732ce674d8ec6a0c86a4e160495d299ba3c93"}, + {file = "psycopg2_binary-2.9.9-cp312-cp312-win_amd64.whl", hash = "sha256:81ff62668af011f9a48787564ab7eded4e9fb17a4a6a74af5ffa6a457400d2ab"}, {file = "psycopg2_binary-2.9.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2293b001e319ab0d869d660a704942c9e2cce19745262a8aba2115ef41a0a42a"}, {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03ef7df18daf2c4c07e2695e8cfd5ee7f748a1d54d802330985a78d2a5a6dca9"}, {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a602ea5aff39bb9fac6308e9c9d82b9a35c2bf288e184a816002c9fae930b77"}, @@ -3766,17 +3698,6 @@ azure-key-vault = ["azure-identity (>=1.16.0)", "azure-keyvault-secrets (>=4.8.0 toml = ["tomli (>=2.0.1)"] yaml = ["pyyaml (>=6.0.1)"] -[[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" @@ -4405,25 +4326,6 @@ files = [ decorator = ">=3.4.2" py = ">=1.4.26,<2.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.20.0" @@ -4538,29 +4440,29 @@ files = [ [[package]] name = "ruff" -version = "0.6.1" +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.6.1-py3-none-linux_armv6l.whl", hash = "sha256:b4bb7de6a24169dc023f992718a9417380301b0c2da0fe85919f47264fb8add9"}, - {file = "ruff-0.6.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:45efaae53b360c81043e311cdec8a7696420b3d3e8935202c2846e7a97d4edae"}, - {file = "ruff-0.6.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:bc60c7d71b732c8fa73cf995efc0c836a2fd8b9810e115be8babb24ae87e0850"}, - {file = "ruff-0.6.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c7477c3b9da822e2db0b4e0b59e61b8a23e87886e727b327e7dcaf06213c5cf"}, - {file = "ruff-0.6.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3a0af7ab3f86e3dc9f157a928e08e26c4b40707d0612b01cd577cc84b8905cc9"}, - {file = "ruff-0.6.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:392688dbb50fecf1bf7126731c90c11a9df1c3a4cdc3f481b53e851da5634fa5"}, - {file = "ruff-0.6.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:5278d3e095ccc8c30430bcc9bc550f778790acc211865520f3041910a28d0024"}, - {file = "ruff-0.6.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fe6d5f65d6f276ee7a0fc50a0cecaccb362d30ef98a110f99cac1c7872df2f18"}, - {file = "ruff-0.6.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2e0dd11e2ae553ee5c92a81731d88a9883af8db7408db47fc81887c1f8b672e"}, - {file = "ruff-0.6.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d812615525a34ecfc07fd93f906ef5b93656be01dfae9a819e31caa6cfe758a1"}, - {file = "ruff-0.6.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:faaa4060f4064c3b7aaaa27328080c932fa142786f8142aff095b42b6a2eb631"}, - {file = "ruff-0.6.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:99d7ae0df47c62729d58765c593ea54c2546d5de213f2af2a19442d50a10cec9"}, - {file = "ruff-0.6.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:9eb18dfd7b613eec000e3738b3f0e4398bf0153cb80bfa3e351b3c1c2f6d7b15"}, - {file = "ruff-0.6.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:c62bc04c6723a81e25e71715aa59489f15034d69bf641df88cb38bdc32fd1dbb"}, - {file = "ruff-0.6.1-py3-none-win32.whl", hash = "sha256:9fb4c4e8b83f19c9477a8745e56d2eeef07a7ff50b68a6998f7d9e2e3887bdc4"}, - {file = "ruff-0.6.1-py3-none-win_amd64.whl", hash = "sha256:c2ebfc8f51ef4aca05dad4552bbcf6fe8d1f75b2f6af546cc47cc1c1ca916b5b"}, - {file = "ruff-0.6.1-py3-none-win_arm64.whl", hash = "sha256:3bc81074971b0ffad1bd0c52284b22411f02a11a012082a76ac6da153536e014"}, - {file = "ruff-0.6.1.tar.gz", hash = "sha256:af3ffd8c6563acb8848d33cd19a69b9bfe943667f0419ca083f8ebe4224a3436"}, + {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]] @@ -4847,20 +4749,6 @@ pure-eval = "*" [package.extras] tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] -[[package]] -name = "stevedore" -version = "5.2.0" -description = "Manage dynamic plugins for Python applications" -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"}, -] - -[package.dependencies] -pbr = ">=2.0.0,<2.1.0 || >2.1.0" - [[package]] name = "structlog" version = "22.3.0" @@ -5165,4 +5053,4 @@ servicenow = ["Jinja2", "PyYAML", "ijson", "oauthlib", "python-magic", "pytz", " [metadata] lock-version = "2.0" python-versions = ">=3.8,<3.12" -content-hash = "522e3769ae36368dd494f283e8f419296db9f3238e272b62ba90854ba8653cac" +content-hash = "bf0e6910c05f2f59adfd8351f25b196fb6f28e3c6903d2fbe630433ffd4db491" diff --git a/pyproject.toml b/pyproject.toml index 651ee901e..0a749a19c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "nautobot-ssot" -version = "3.0.0" +version = "3.0.1" description = "Nautobot Single Source of Truth" authors = ["Network to Code, LLC "] license = "Apache-2.0" @@ -56,32 +56,29 @@ retry = "^0.9.2" dnacentersdk = { version = "^2.5.6", optional = true } [tool.poetry.group.dev.dependencies] -bandit = "*" -black = "*" coverage = "*" -django-debug-toolbar = "<4.4" -django-extensions = "*" -flake8 = "*" +django-debug-toolbar = "*" invoke = "*" ipython = "*" jedi = "^0.17.2" pylint = "*" pylint-django = "*" pylint-nautobot = "*" -ruff = "*" +ruff = "0.5.5" yamllint = "*" markdown-include = "*" 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 = "*" -mkdocstrings-python = "*" +mkdocstrings = "0.25.2" +mkdocstrings-python = "1.10.8" +griffe = "1.1.1" towncrier = "~23.6.0" requests-mock = "^1.10.0" parameterized = "^0.8.1" @@ -169,30 +166,6 @@ nautobot-device-lifecycle-mgmt = [ "nautobot-device-lifecycle-mgmt", ] -[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 - | nautobot_ssot/integrations/servicenow/third_party - )/ - | 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" @@ -203,12 +176,10 @@ ignore=".venv" 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 = """, line-too-long, too-few-public-methods, - """ +""" [tool.pylint.miscellaneous] # Don't flag TODO as a failure, let us commit with things that still need to be done in the code @@ -228,42 +199,47 @@ target-version = "py38" [tool.ruff.lint] select = [ - "D", # pydocstyle + "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 # Package specific ignores - "D104", - "D417", + "D104", # Missing docstring in public package + "D417", # Missing argument descriptions in the docstring for ... ] [tool.ruff.lint.pydocstyle] convention = "google" -[tool.ruff.per-file-ignores] +[tool.ruff.lint.per-file-ignores] "nautobot_ssot/migrations/*" = [ - "D", # pydocstyle + "D", ] "nautobot_ssot/tests/*" = [ - "D", # pydocstyle + "D", + "S" ] "nautobot_ssot/integrations/servicenow/third_party/*" = [ - "D", # pydocstyle + "D", # pydocstyle ] [build-system] diff --git a/tasks.py b/tasks.py index 3d8272349..270b43314 100644 --- a/tasks.py +++ b/tasks.py @@ -48,7 +48,7 @@ def is_truthy(arg): namespace.configure( { "nautobot_ssot": { - "nautobot_ver": "2.1.0", + "nautobot_ver": "2.3.1", "project_name": "nautobot-ssot", "python_ver": "3.11", "local": False, @@ -187,15 +187,15 @@ 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 = "" for env_name in env: - compose_command += f" --env={env_name}" + command_env_args += f" --env={env_name}" - 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) @@ -524,7 +524,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( @@ -679,28 +684,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 @@ -720,38 +703,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="concise"): +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 @@ -783,7 +767,7 @@ def check_migrations(context): "verbose": "Enable verbose test output.", } ) -def unittest( +def unittest( # noqa: PLR0913 context, keepdb=False, label="nautobot_ssot", @@ -831,14 +815,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...") @@ -871,11 +849,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"}, + )