From 23e653406089902b214610e2b5d2f9885d090f9b Mon Sep 17 00:00:00 2001 From: Daniel Sheppard Date: Mon, 7 Oct 2024 14:58:50 -0500 Subject: [PATCH 01/10] Fixes: #17636 - Correct typo in Power Outlet Template form for Power Port field --- netbox/dcim/forms/model_forms.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/netbox/dcim/forms/model_forms.py b/netbox/dcim/forms/model_forms.py index 4f08ea896..908312a8a 100644 --- a/netbox/dcim/forms/model_forms.py +++ b/netbox/dcim/forms/model_forms.py @@ -954,7 +954,7 @@ class PowerOutletTemplateForm(ModularComponentTemplateForm): queryset=PowerPortTemplate.objects.all(), required=False, query_params={ - 'devicetype_id': '$device_type', + 'device_type_id': '$device_type', } ) @@ -1001,8 +1001,8 @@ class FrontPortTemplateForm(ModularComponentTemplateForm): queryset=RearPortTemplate.objects.all(), required=False, query_params={ - 'devicetype_id': '$device_type', - 'moduletype_id': '$module_type', + 'device_type_id': '$device_type', + 'module_type_id': '$module_type', } ) @@ -1063,7 +1063,7 @@ class InventoryItemTemplateForm(ComponentTemplateForm): queryset=InventoryItemTemplate.objects.all(), required=False, query_params={ - 'devicetype_id': '$device_type' + 'device_type_id': '$device_type' } ) role = DynamicModelChoiceField( From 2172ddde61734eaca5c3761309520c42291f95fb Mon Sep 17 00:00:00 2001 From: Craig Askings Date: Thu, 10 Oct 2024 00:28:53 +1000 Subject: [PATCH 02/10] Add EVPN-VPWS to L2VPNTypeChoices (#17694) * Add EVPN-VPWS to the availbable L2VPN Connection Types * Updated documentation to reference the new L2VPN type. --- docs/models/vpn/l2vpn.md | 1 + netbox/vpn/choices.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/docs/models/vpn/l2vpn.md b/docs/models/vpn/l2vpn.md index 79b7435bf..1167c1c17 100644 --- a/docs/models/vpn/l2vpn.md +++ b/docs/models/vpn/l2vpn.md @@ -28,6 +28,7 @@ The technology employed in forming and operating the L2VPN. Choices include: * VXLAN-EVPN * MPLS-EVPN * PBB-EVPN +* EVPN-VPWS !!! note Designating the type as VPWS, EPL, EP-LAN, EP-TREE will limit the L2VPN instance to two terminations. diff --git a/netbox/vpn/choices.py b/netbox/vpn/choices.py index 4aa97f615..751454049 100644 --- a/netbox/vpn/choices.py +++ b/netbox/vpn/choices.py @@ -219,6 +219,7 @@ class L2VPNTypeChoices(ChoiceSet): TYPE_VXLAN_EVPN = 'vxlan-evpn' TYPE_MPLS_EVPN = 'mpls-evpn' TYPE_PBB_EVPN = 'pbb-evpn' + TYPE_EVPN_VPWS = 'evpn-vpws' CHOICES = ( ('VPLS', ( @@ -232,6 +233,7 @@ class L2VPNTypeChoices(ChoiceSet): ('L2VPN E-VPN', ( (TYPE_MPLS_EVPN, 'MPLS EVPN'), (TYPE_PBB_EVPN, 'PBB EVPN'), + (TYPE_EVPN_VPWS, 'EVPN VPWS') )), ('E-Line', ( (TYPE_EPL, 'EPL'), From ec89a9b10699cda0bf64bb736e5435520a24de8d Mon Sep 17 00:00:00 2001 From: gellis713 Date: Wed, 9 Oct 2024 09:30:40 -0500 Subject: [PATCH 03/10] Fix parsing of extra_choices (#17691) * Align strawberry resolver with expected return type * Align test data with expected representation of extra_choices in CustomFieldChoiceSet model --------- Co-authored-by: Griffin Ellis --- netbox/extras/graphql/types.py | 2 +- netbox/extras/tests/test_api.py | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/netbox/extras/graphql/types.py b/netbox/extras/graphql/types.py index a43f80cc3..a53c7bed3 100644 --- a/netbox/extras/graphql/types.py +++ b/netbox/extras/graphql/types.py @@ -84,7 +84,7 @@ class CustomFieldType(ObjectType): class CustomFieldChoiceSetType(ObjectType): choices_for: List[Annotated["CustomFieldType", strawberry.lazy('extras.graphql.types')]] - extra_choices: List[str] | None + extra_choices: List[List[str]] | None @strawberry_django.type( diff --git a/netbox/extras/tests/test_api.py b/netbox/extras/tests/test_api.py index 5defbd0bd..acd94d009 100644 --- a/netbox/extras/tests/test_api.py +++ b/netbox/extras/tests/test_api.py @@ -244,9 +244,18 @@ class CustomFieldChoiceSetTest(APIViewTestCases.APIViewTestCase): @classmethod def setUpTestData(cls): choice_sets = ( - CustomFieldChoiceSet(name='Choice Set 1', extra_choices=['1A', '1B', '1C', '1D', '1E']), - CustomFieldChoiceSet(name='Choice Set 2', extra_choices=['2A', '2B', '2C', '2D', '2E']), - CustomFieldChoiceSet(name='Choice Set 3', extra_choices=['3A', '3B', '3C', '3D', '3E']), + CustomFieldChoiceSet( + name='Choice Set 1', + extra_choices=[['1A', '1A'], ['1B', '1B'], ['1C', '1C'], ['1D', '1D'], ['1E', '1E']], + ), + CustomFieldChoiceSet( + name='Choice Set 2', + extra_choices=[['2A', '2A'], ['2B', '2B'], ['2C', '2C'], ['2D', '2D'], ['2E', '2E']], + ), + CustomFieldChoiceSet( + name='Choice Set 3', + extra_choices=[['3A', '3A'], ['3B', '3B'], ['3C', '3C'], ['3D', '3D'], ['3E', '3E']], + ), ) CustomFieldChoiceSet.objects.bulk_create(choice_sets) From f851bd80b902f18c1fcc4e84595c9f54b93b8d15 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 9 Oct 2024 15:59:40 -0400 Subject: [PATCH 04/10] Add triage priority to issue templates --- .github/ISSUE_TEMPLATE/01-feature_request.yaml | 15 +++++++++++++++ .github/ISSUE_TEMPLATE/02-bug_report.yaml | 14 ++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/01-feature_request.yaml b/.github/ISSUE_TEMPLATE/01-feature_request.yaml index fb4bab623..f07db712d 100644 --- a/.github/ISSUE_TEMPLATE/01-feature_request.yaml +++ b/.github/ISSUE_TEMPLATE/01-feature_request.yaml @@ -24,6 +24,21 @@ body: - Data model extension - New functionality - Change to existing functionality + - Other + validations: + required: true + - type: dropdown + attributes: + label: Triage priority + description: > + Issue triage may be prioritized in some cases. Select whichever of the following + conditions applies, if any. + options: + - I volunteer to perform this work (if approved) + - I'm a NetBox Labs customer + - This is a very minor change + - N/A + default: 3 validations: required: true - type: textarea diff --git a/.github/ISSUE_TEMPLATE/02-bug_report.yaml b/.github/ISSUE_TEMPLATE/02-bug_report.yaml index f31e024b4..892981402 100644 --- a/.github/ISSUE_TEMPLATE/02-bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/02-bug_report.yaml @@ -22,6 +22,20 @@ body: - Self-hosted validations: required: true + - type: dropdown + attributes: + label: Triage priority + description: > + Issue triage may be prioritized in some cases. Select whichever of the following + conditions applies, if any. + options: + - I volunteer to perform this work (if approved) + - I'm a NetBox Labs customer + - This is preventing me from using NetBox + - N/A + default: 3 + validations: + required: true - type: input attributes: label: NetBox Version From 8e636c5427b775abb5656f58fc1569b3c06150c9 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 9 Oct 2024 16:07:13 -0400 Subject: [PATCH 05/10] Changelog for #17216, #17562, #17636 --- docs/release-notes/version-4.1.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/release-notes/version-4.1.md b/docs/release-notes/version-4.1.md index 1cb985965..5b353d54f 100644 --- a/docs/release-notes/version-4.1.md +++ b/docs/release-notes/version-4.1.md @@ -7,13 +7,16 @@ * [#11671](https://github.com/netbox-community/netbox/issues/11671) - Display device's rack position in cable traces * [#15829](https://github.com/netbox-community/netbox/issues/15829) - Rename Microsoft Azure AD SSO backend to Microsoft Entra ID * [#17079](https://github.com/netbox-community/netbox/issues/17079) - Introduce additional choices for device airflow direction +* [#17216](https://github.com/netbox-community/netbox/issues/17216) - Add EVPN-VPWS L2VPN type * [#17655](https://github.com/netbox-community/netbox/issues/17655) - Limit the display of tagged VLANs within interface tables * [#17669](https://github.com/netbox-community/netbox/issues/17669) - Enable filtering VLANs by assigned device or VM interface ### Bug Fixes * [#16024](https://github.com/netbox-community/netbox/issues/16024) - Fix AND/OR filtering in GraphQL API for selection fields +* [#17562](https://github.com/netbox-community/netbox/issues/17562) - Fix GraphQL API query support for custom field choices * [#17566](https://github.com/netbox-community/netbox/issues/17566) - Fix AttributeError exception resulting from background jobs with no associated object type +* [#17636](https://github.com/netbox-community/netbox/issues/17636) - Fix filtering of related objects when adding a power port, rear port, or inventory item template to a device type * [#17648](https://github.com/netbox-community/netbox/issues/17648) - Fix AttributeError exception when attempting to delete a background job under certain conditions * [#17663](https://github.com/netbox-community/netbox/issues/17663) - Fix extended lookups for choice field filters * [#17671](https://github.com/netbox-community/netbox/issues/17671) - Fix the display of rack types in global search results From e3c3ca191c3a06a1a0e93437a2eebeabf837fc18 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 10 Oct 2024 05:02:05 +0000 Subject: [PATCH 06/10] Update source translation strings --- netbox/translations/en/LC_MESSAGES/django.po | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/netbox/translations/en/LC_MESSAGES/django.po b/netbox/translations/en/LC_MESSAGES/django.po index 6b6040a07..e25594d5b 100644 --- a/netbox/translations/en/LC_MESSAGES/django.po +++ b/netbox/translations/en/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-08 05:02+0000\n" +"POT-Creation-Date: 2024-10-10 05:01+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -15077,19 +15077,19 @@ msgstr "" msgid "Group {n}" msgstr "" -#: netbox/vpn/choices.py:241 +#: netbox/vpn/choices.py:243 msgid "Ethernet Private LAN" msgstr "" -#: netbox/vpn/choices.py:242 +#: netbox/vpn/choices.py:244 msgid "Ethernet Virtual Private LAN" msgstr "" -#: netbox/vpn/choices.py:245 +#: netbox/vpn/choices.py:247 msgid "Ethernet Private Tree" msgstr "" -#: netbox/vpn/choices.py:246 +#: netbox/vpn/choices.py:248 msgid "Ethernet Virtual Private Tree" msgstr "" From e59f776e0206d24137563273b39177246aa14ea4 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 10 Oct 2024 14:52:47 -0400 Subject: [PATCH 07/10] Closes #17725: Clean up `import` statements (#17728) * #17725: Resolve all F401 errors * Tweak noqa designation --- netbox/circuits/apps.py | 2 +- netbox/circuits/forms/bulk_import.py | 1 - netbox/circuits/graphql/filters.py | 3 +-- netbox/core/api/schema.py | 4 +--- netbox/core/api/serializers_/jobs.py | 2 -- netbox/core/apps.py | 4 ++-- netbox/dcim/api/serializers_/manufacturers.py | 2 -- netbox/dcim/api/serializers_/platforms.py | 2 -- netbox/dcim/api/serializers_/power.py | 2 -- netbox/dcim/api/serializers_/roles.py | 2 -- netbox/dcim/apps.py | 2 +- netbox/dcim/forms/connections.py | 2 +- netbox/dcim/graphql/mixins.py | 1 - netbox/dcim/models/device_components.py | 3 +-- netbox/dcim/utils.py | 2 -- netbox/extras/api/serializers_/configtemplates.py | 2 -- netbox/extras/api/serializers_/customlinks.py | 2 -- netbox/extras/api/serializers_/exporttemplates.py | 2 -- netbox/extras/api/serializers_/savedfilters.py | 2 -- netbox/extras/api/serializers_/tags.py | 2 -- netbox/extras/api/views.py | 3 +-- netbox/extras/apps.py | 2 +- netbox/extras/dashboard/widgets.py | 1 - netbox/extras/lookups.py | 3 ++- netbox/extras/tests/test_api.py | 2 -- netbox/extras/validators.py | 1 - netbox/extras/views.py | 3 +-- netbox/ipam/api/serializers_/roles.py | 2 -- netbox/ipam/api/serializers_/services.py | 2 -- netbox/ipam/api/serializers_/vrfs.py | 2 -- netbox/ipam/apps.py | 2 +- netbox/ipam/graphql/mixins.py | 1 - netbox/netbox/api/serializers/nested.py | 2 -- netbox/netbox/plugins/urls.py | 1 - netbox/netbox/plugins/views.py | 2 -- netbox/netbox/settings.py | 6 ++---- netbox/netbox/tests/dummy_plugin/views.py | 2 +- netbox/tenancy/apps.py | 2 +- netbox/tenancy/filtersets.py | 1 - netbox/tenancy/graphql/mixins.py | 2 -- netbox/users/apps.py | 2 +- netbox/users/tests/test_views.py | 4 +--- .../management/commands/calculate_cached_counts.py | 1 - netbox/utilities/markdown.py | 2 +- netbox/utilities/release.py | 4 ++-- netbox/utilities/serializers/json.py | 2 +- netbox/utilities/templatetags/form_helpers.py | 4 +--- netbox/virtualization/api/serializers_/clusters.py | 2 -- netbox/virtualization/apps.py | 2 +- netbox/vpn/api/serializers_/crypto.py | 2 -- netbox/vpn/apps.py | 2 +- netbox/wireless/api/serializers_/wirelesslinks.py | 2 -- netbox/wireless/apps.py | 2 +- netbox/wireless/filtersets.py | 2 +- 54 files changed, 29 insertions(+), 90 deletions(-) diff --git a/netbox/circuits/apps.py b/netbox/circuits/apps.py index df6804303..4d5f177e2 100644 --- a/netbox/circuits/apps.py +++ b/netbox/circuits/apps.py @@ -7,7 +7,7 @@ class CircuitsConfig(AppConfig): def ready(self): from netbox.models.features import register_models - from . import signals, search + from . import signals, search # noqa: F401 # Register models register_models(*self.get_models()) diff --git a/netbox/circuits/forms/bulk_import.py b/netbox/circuits/forms/bulk_import.py index 1e7b6361a..dc334ae88 100644 --- a/netbox/circuits/forms/bulk_import.py +++ b/netbox/circuits/forms/bulk_import.py @@ -1,5 +1,4 @@ from django import forms -from django.utils.safestring import mark_safe from django.utils.translation import gettext_lazy as _ from circuits.choices import * diff --git a/netbox/circuits/graphql/filters.py b/netbox/circuits/graphql/filters.py index 3ded6e681..b8398b2b9 100644 --- a/netbox/circuits/graphql/filters.py +++ b/netbox/circuits/graphql/filters.py @@ -1,7 +1,6 @@ -import strawberry import strawberry_django -from circuits import filtersets, models +from circuits import filtersets, models from netbox.graphql.filter_mixins import autotype_decorator, BaseFilterMixin __all__ = ( diff --git a/netbox/core/api/schema.py b/netbox/core/api/schema.py index 7c4ae722e..1ac822b8c 100644 --- a/netbox/core/api/schema.py +++ b/netbox/core/api/schema.py @@ -8,10 +8,8 @@ from drf_spectacular.plumbing import ( build_basic_type, build_choice_field, build_media_type_object, build_object_type, get_doc, ) from drf_spectacular.types import OpenApiTypes -from rest_framework import serializers -from rest_framework.relations import ManyRelatedField -from netbox.api.fields import ChoiceField, SerializedPKRelatedField +from netbox.api.fields import ChoiceField from netbox.api.serializers import WritableNestedSerializer # see netbox.api.routers.NetBoxRouter diff --git a/netbox/core/api/serializers_/jobs.py b/netbox/core/api/serializers_/jobs.py index e5e07aa41..544dddb56 100644 --- a/netbox/core/api/serializers_/jobs.py +++ b/netbox/core/api/serializers_/jobs.py @@ -1,5 +1,3 @@ -from rest_framework import serializers - from core.choices import * from core.models import Job from netbox.api.fields import ChoiceField, ContentTypeField diff --git a/netbox/core/apps.py b/netbox/core/apps.py index 855ac3170..1dfc7a65e 100644 --- a/netbox/core/apps.py +++ b/netbox/core/apps.py @@ -16,9 +16,9 @@ class CoreConfig(AppConfig): name = "core" def ready(self): - from core.api import schema # noqa + from core.api import schema # noqa: F401 from netbox.models.features import register_models - from . import data_backends, events, search + from . import data_backends, events, search # noqa: F401 # Register models register_models(*self.get_models()) diff --git a/netbox/dcim/api/serializers_/manufacturers.py b/netbox/dcim/api/serializers_/manufacturers.py index 61158e0f7..1a1eea6ec 100644 --- a/netbox/dcim/api/serializers_/manufacturers.py +++ b/netbox/dcim/api/serializers_/manufacturers.py @@ -1,5 +1,3 @@ -from rest_framework import serializers - from dcim.models import Manufacturer from netbox.api.fields import RelatedObjectCountField from netbox.api.serializers import NetBoxModelSerializer diff --git a/netbox/dcim/api/serializers_/platforms.py b/netbox/dcim/api/serializers_/platforms.py index 3c846f8fd..2f4745701 100644 --- a/netbox/dcim/api/serializers_/platforms.py +++ b/netbox/dcim/api/serializers_/platforms.py @@ -1,5 +1,3 @@ -from rest_framework import serializers - from dcim.models import Platform from extras.api.serializers_.configtemplates import ConfigTemplateSerializer from netbox.api.fields import RelatedObjectCountField diff --git a/netbox/dcim/api/serializers_/power.py b/netbox/dcim/api/serializers_/power.py index fc65a0732..4c2cf54fb 100644 --- a/netbox/dcim/api/serializers_/power.py +++ b/netbox/dcim/api/serializers_/power.py @@ -1,5 +1,3 @@ -from rest_framework import serializers - from dcim.choices import * from dcim.models import PowerFeed, PowerPanel from netbox.api.fields import ChoiceField, RelatedObjectCountField diff --git a/netbox/dcim/api/serializers_/roles.py b/netbox/dcim/api/serializers_/roles.py index e9c9d3563..8f922da10 100644 --- a/netbox/dcim/api/serializers_/roles.py +++ b/netbox/dcim/api/serializers_/roles.py @@ -1,5 +1,3 @@ -from rest_framework import serializers - from dcim.models import DeviceRole, InventoryItemRole from extras.api.serializers_.configtemplates import ConfigTemplateSerializer from netbox.api.fields import RelatedObjectCountField diff --git a/netbox/dcim/apps.py b/netbox/dcim/apps.py index 4df66e367..9653d3b93 100644 --- a/netbox/dcim/apps.py +++ b/netbox/dcim/apps.py @@ -10,7 +10,7 @@ class DCIMConfig(AppConfig): def ready(self): from netbox.models.features import register_models from utilities.counters import connect_counters - from . import signals, search + from . import signals, search # noqa: F401 from .models import CableTermination, Device, DeviceType, VirtualChassis # Register models diff --git a/netbox/dcim/forms/connections.py b/netbox/dcim/forms/connections.py index f107c3476..324f8ecfd 100644 --- a/netbox/dcim/forms/connections.py +++ b/netbox/dcim/forms/connections.py @@ -4,7 +4,7 @@ from django.utils.translation import gettext_lazy as _ from circuits.models import Circuit, CircuitTermination from dcim.models import * -from utilities.forms.fields import DynamicModelChoiceField, DynamicModelMultipleChoiceField +from utilities.forms.fields import DynamicModelMultipleChoiceField from .model_forms import CableForm diff --git a/netbox/dcim/graphql/mixins.py b/netbox/dcim/graphql/mixins.py index 589af50c8..a489ef1f6 100644 --- a/netbox/dcim/graphql/mixins.py +++ b/netbox/dcim/graphql/mixins.py @@ -1,7 +1,6 @@ from typing import Annotated, List, Union import strawberry -import strawberry_django __all__ = ( 'CabledObjectMixin', diff --git a/netbox/dcim/models/device_components.py b/netbox/dcim/models/device_components.py index f5fbaa956..b1f951541 100644 --- a/netbox/dcim/models/device_components.py +++ b/netbox/dcim/models/device_components.py @@ -4,7 +4,7 @@ from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelatio from django.core.exceptions import ValidationError from django.core.validators import MaxValueValidator, MinValueValidator from django.db import models -from django.db.models import F, Sum +from django.db.models import Sum from django.urls import reverse from django.utils.translation import gettext_lazy as _ from mptt.models import MPTTModel, TreeForeignKey @@ -22,7 +22,6 @@ from utilities.tracking import TrackingModelMixin from wireless.choices import * from wireless.utils import get_channel_attr - __all__ = ( 'BaseInterface', 'CabledObjectModel', diff --git a/netbox/dcim/utils.py b/netbox/dcim/utils.py index eadd2da96..4d4228490 100644 --- a/netbox/dcim/utils.py +++ b/netbox/dcim/utils.py @@ -1,5 +1,3 @@ -import itertools - from django.contrib.contenttypes.models import ContentType from django.db import transaction diff --git a/netbox/extras/api/serializers_/configtemplates.py b/netbox/extras/api/serializers_/configtemplates.py index 30d2fb468..c4a683c74 100644 --- a/netbox/extras/api/serializers_/configtemplates.py +++ b/netbox/extras/api/serializers_/configtemplates.py @@ -1,5 +1,3 @@ -from rest_framework import serializers - from core.api.serializers_.data import DataFileSerializer, DataSourceSerializer from extras.models import ConfigTemplate from netbox.api.serializers import ValidatedModelSerializer diff --git a/netbox/extras/api/serializers_/customlinks.py b/netbox/extras/api/serializers_/customlinks.py index 6391e0471..8cc4f5f77 100644 --- a/netbox/extras/api/serializers_/customlinks.py +++ b/netbox/extras/api/serializers_/customlinks.py @@ -1,5 +1,3 @@ -from rest_framework import serializers - from core.models import ObjectType from extras.models import CustomLink from netbox.api.fields import ContentTypeField diff --git a/netbox/extras/api/serializers_/exporttemplates.py b/netbox/extras/api/serializers_/exporttemplates.py index faef9bb9e..11f502a02 100644 --- a/netbox/extras/api/serializers_/exporttemplates.py +++ b/netbox/extras/api/serializers_/exporttemplates.py @@ -1,5 +1,3 @@ -from rest_framework import serializers - from core.api.serializers_.data import DataFileSerializer, DataSourceSerializer from core.models import ObjectType from extras.models import ExportTemplate diff --git a/netbox/extras/api/serializers_/savedfilters.py b/netbox/extras/api/serializers_/savedfilters.py index 140303797..fb0744e59 100644 --- a/netbox/extras/api/serializers_/savedfilters.py +++ b/netbox/extras/api/serializers_/savedfilters.py @@ -1,5 +1,3 @@ -from rest_framework import serializers - from core.models import ObjectType from extras.models import SavedFilter from netbox.api.fields import ContentTypeField diff --git a/netbox/extras/api/serializers_/tags.py b/netbox/extras/api/serializers_/tags.py index 946ed3c8a..e4e62845a 100644 --- a/netbox/extras/api/serializers_/tags.py +++ b/netbox/extras/api/serializers_/tags.py @@ -1,5 +1,3 @@ -from rest_framework import serializers - from core.models import ObjectType from extras.models import Tag from netbox.api.fields import ContentTypeField, RelatedObjectCountField diff --git a/netbox/extras/api/views.py b/netbox/extras/api/views.py index cf2cab316..e4c3c7f3e 100644 --- a/netbox/extras/api/views.py +++ b/netbox/extras/api/views.py @@ -1,6 +1,5 @@ from django.http import Http404 from django.shortcuts import get_object_or_404 -from django.utils.module_loading import import_string from django_rq.queues import get_connection from drf_spectacular.utils import extend_schema, extend_schema_view from rest_framework import status @@ -15,8 +14,8 @@ from rq import Worker from core.models import ObjectType from extras import filtersets -from extras.models import * from extras.jobs import ScriptJob +from extras.models import * from netbox.api.authentication import IsAuthenticatedOrLoginNotRequired from netbox.api.features import SyncedDataMixin from netbox.api.metadata import ContentTypeMetadata diff --git a/netbox/extras/apps.py b/netbox/extras/apps.py index c565988bc..21232f95f 100644 --- a/netbox/extras/apps.py +++ b/netbox/extras/apps.py @@ -6,7 +6,7 @@ class ExtrasConfig(AppConfig): def ready(self): from netbox.models.features import register_models - from . import dashboard, lookups, search, signals + from . import dashboard, lookups, search, signals # noqa: F401 # Register models register_models(*self.get_models()) diff --git a/netbox/extras/dashboard/widgets.py b/netbox/extras/dashboard/widgets.py index 091819bd1..c56e4cd7d 100644 --- a/netbox/extras/dashboard/widgets.py +++ b/netbox/extras/dashboard/widgets.py @@ -15,7 +15,6 @@ from django.utils.translation import gettext as _ from core.models import ObjectType from extras.choices import BookmarkOrderingChoices -from netbox.choices import ButtonColorChoices from utilities.object_types import object_type_identifier, object_type_name from utilities.permissions import get_permission_for_model from utilities.querydict import dict_to_querydict diff --git a/netbox/extras/lookups.py b/netbox/extras/lookups.py index a8d89c943..c496cce78 100644 --- a/netbox/extras/lookups.py +++ b/netbox/extras/lookups.py @@ -1,4 +1,5 @@ -from django.db.models import CharField, TextField, Lookup +from django.db.models import CharField, Lookup + from .fields import CachedValueField diff --git a/netbox/extras/tests/test_api.py b/netbox/extras/tests/test_api.py index acd94d009..63baf44d3 100644 --- a/netbox/extras/tests/test_api.py +++ b/netbox/extras/tests/test_api.py @@ -12,7 +12,6 @@ from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Rack, Loca from extras.choices import * from extras.models import * from extras.scripts import BooleanVar, IntegerVar, Script as PythonClass, StringVar -from netbox.events import * from users.models import Group, User from utilities.testing import APITestCase, APIViewTestCases @@ -793,7 +792,6 @@ class ScriptTest(APITestCase): super().setUp() # Monkey-patch the Script model to return our TestScriptClass above - from extras.api.views import ScriptViewSet Script.python_class = self.python_class def test_get_script(self): diff --git a/netbox/extras/validators.py b/netbox/extras/validators.py index 6823c1978..306acf01b 100644 --- a/netbox/extras/validators.py +++ b/netbox/extras/validators.py @@ -1,4 +1,3 @@ -import inspect import operator from django.core import validators diff --git a/netbox/extras/views.py b/netbox/extras/views.py index b3d942fd8..321842260 100644 --- a/netbox/extras/views.py +++ b/netbox/extras/views.py @@ -6,8 +6,8 @@ from django.db.models import Count, Q from django.http import HttpResponseBadRequest, HttpResponseForbidden, HttpResponse from django.shortcuts import get_object_or_404, redirect, render from django.urls import reverse -from django.utils.module_loading import import_string from django.utils import timezone +from django.utils.module_loading import import_string from django.utils.translation import gettext as _ from django.views.generic import View @@ -20,7 +20,6 @@ from extras.choices import LogLevelChoices from extras.dashboard.forms import DashboardWidgetAddForm, DashboardWidgetForm from extras.dashboard.utils import get_widget_class from netbox.constants import DEFAULT_ACTION_PERMISSIONS -from netbox.registry import registry from netbox.views import generic from netbox.views.generic.mixins import TableMixin from utilities.forms import ConfirmationForm, get_field_value diff --git a/netbox/ipam/api/serializers_/roles.py b/netbox/ipam/api/serializers_/roles.py index 9a97a8570..99fd6f470 100644 --- a/netbox/ipam/api/serializers_/roles.py +++ b/netbox/ipam/api/serializers_/roles.py @@ -1,5 +1,3 @@ -from rest_framework import serializers - from ipam.models import Role from netbox.api.fields import RelatedObjectCountField from netbox.api.serializers import NetBoxModelSerializer diff --git a/netbox/ipam/api/serializers_/services.py b/netbox/ipam/api/serializers_/services.py index e0b2014f6..61b330d01 100644 --- a/netbox/ipam/api/serializers_/services.py +++ b/netbox/ipam/api/serializers_/services.py @@ -1,5 +1,3 @@ -from rest_framework import serializers - from dcim.api.serializers_.devices import DeviceSerializer from ipam.choices import * from ipam.models import IPAddress, Service, ServiceTemplate diff --git a/netbox/ipam/api/serializers_/vrfs.py b/netbox/ipam/api/serializers_/vrfs.py index ad54dc095..a23909108 100644 --- a/netbox/ipam/api/serializers_/vrfs.py +++ b/netbox/ipam/api/serializers_/vrfs.py @@ -1,5 +1,3 @@ -from rest_framework import serializers - from ipam.models import RouteTarget, VRF from netbox.api.fields import RelatedObjectCountField, SerializedPKRelatedField from netbox.api.serializers import NetBoxModelSerializer diff --git a/netbox/ipam/apps.py b/netbox/ipam/apps.py index 244ec7d6d..c118d5464 100644 --- a/netbox/ipam/apps.py +++ b/netbox/ipam/apps.py @@ -7,7 +7,7 @@ class IPAMConfig(AppConfig): def ready(self): from netbox.models.features import register_models - from . import signals, search + from . import signals, search # noqa: F401 # Register models register_models(*self.get_models()) diff --git a/netbox/ipam/graphql/mixins.py b/netbox/ipam/graphql/mixins.py index 73cc60ec4..757e62c74 100644 --- a/netbox/ipam/graphql/mixins.py +++ b/netbox/ipam/graphql/mixins.py @@ -1,7 +1,6 @@ from typing import Annotated, List import strawberry -import strawberry_django __all__ = ( 'IPAddressesMixin', diff --git a/netbox/netbox/api/serializers/nested.py b/netbox/netbox/api/serializers/nested.py index 04033c71f..4a5fc6214 100644 --- a/netbox/netbox/api/serializers/nested.py +++ b/netbox/netbox/api/serializers/nested.py @@ -1,5 +1,3 @@ -from rest_framework import serializers - from extras.models import Tag from utilities.api import get_related_object_by_attrs from .base import BaseModelSerializer diff --git a/netbox/netbox/plugins/urls.py b/netbox/netbox/plugins/urls.py index 075bda811..deb20732f 100644 --- a/netbox/netbox/plugins/urls.py +++ b/netbox/netbox/plugins/urls.py @@ -3,7 +3,6 @@ from importlib import import_module from django.apps import apps from django.conf import settings from django.conf.urls import include -from django.contrib.admin.views.decorators import staff_member_required from django.urls import path from django.utils.module_loading import import_string, module_has_submodule diff --git a/netbox/netbox/plugins/views.py b/netbox/netbox/plugins/views.py index 777a4c69e..6a10f2e2c 100644 --- a/netbox/netbox/plugins/views.py +++ b/netbox/netbox/plugins/views.py @@ -2,9 +2,7 @@ from collections import OrderedDict from django.apps import apps from django.conf import settings -from django.shortcuts import render from django.urls.exceptions import NoReverseMatch -from django.views.generic import View from drf_spectacular.utils import extend_schema from rest_framework import permissions from rest_framework.response import Response diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index 358f41ff8..9c5078ccb 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -5,14 +5,12 @@ import os import platform import sys import warnings -from urllib.parse import urlencode, urlsplit +from urllib.parse import urlencode -import django import requests from django.contrib.messages import constants as messages from django.core.exceptions import ImproperlyConfigured, ValidationError from django.core.validators import URLValidator -from django.utils.encoding import force_str from django.utils.translation import gettext_lazy as _ from netbox.config import PARAMS as CONFIG_PARAMS @@ -252,7 +250,7 @@ if STORAGE_BACKEND is not None: # django-storage-swift elif STORAGE_BACKEND == 'swift.storage.SwiftStorage': try: - import swift.utils # type: ignore + import swift.utils # noqa: F401 except ModuleNotFoundError as e: if getattr(e, 'name') == 'swift': raise ImproperlyConfigured( diff --git a/netbox/netbox/tests/dummy_plugin/views.py b/netbox/netbox/tests/dummy_plugin/views.py index f6cf6a5c5..c4d80731f 100644 --- a/netbox/netbox/tests/dummy_plugin/views.py +++ b/netbox/netbox/tests/dummy_plugin/views.py @@ -8,7 +8,7 @@ from dcim.models import Site from utilities.views import register_model_view from .models import DummyModel # Trigger registration of custom column -from .tables import mycol +from .tables import mycol # noqa: F401 class DummyModelsView(View): diff --git a/netbox/tenancy/apps.py b/netbox/tenancy/apps.py index 7fec97d73..d08d178e9 100644 --- a/netbox/tenancy/apps.py +++ b/netbox/tenancy/apps.py @@ -6,7 +6,7 @@ class TenancyConfig(AppConfig): def ready(self): from netbox.models.features import register_models - from . import search + from . import search # noqa: F401 # Register models register_models(*self.get_models()) diff --git a/netbox/tenancy/filtersets.py b/netbox/tenancy/filtersets.py index 75096b00e..e2de18231 100644 --- a/netbox/tenancy/filtersets.py +++ b/netbox/tenancy/filtersets.py @@ -2,7 +2,6 @@ import django_filters from django.db.models import Q from django.utils.translation import gettext as _ -from extras.filters import TagFilter from netbox.filtersets import NetBoxModelFilterSet, OrganizationalModelFilterSet from utilities.filters import ContentTypeFilter, TreeNodeMultipleChoiceFilter from .models import * diff --git a/netbox/tenancy/graphql/mixins.py b/netbox/tenancy/graphql/mixins.py index 8b4c41c9b..2d97ba718 100644 --- a/netbox/tenancy/graphql/mixins.py +++ b/netbox/tenancy/graphql/mixins.py @@ -1,8 +1,6 @@ from typing import Annotated, List import strawberry -import strawberry_django - __all__ = ( 'ContactAssignmentsMixin', diff --git a/netbox/users/apps.py b/netbox/users/apps.py index cd61a59bc..4bfd612d9 100644 --- a/netbox/users/apps.py +++ b/netbox/users/apps.py @@ -6,7 +6,7 @@ class UsersConfig(AppConfig): def ready(self): from netbox.models.features import register_models - from . import signals + from . import signals # noqa: F401 # Register models register_models(*self.get_models()) diff --git a/netbox/users/tests/test_views.py b/netbox/users/tests/test_views.py index 86da7dda2..8386364dd 100644 --- a/netbox/users/tests/test_views.py +++ b/netbox/users/tests/test_views.py @@ -1,8 +1,6 @@ -from django.test import override_settings - from core.models import ObjectType from users.models import * -from utilities.testing import ViewTestCases, create_test_user, extract_form_failures +from utilities.testing import ViewTestCases, create_test_user class UserTestCase( diff --git a/netbox/utilities/management/commands/calculate_cached_counts.py b/netbox/utilities/management/commands/calculate_cached_counts.py index f7810604f..a0e841e23 100644 --- a/netbox/utilities/management/commands/calculate_cached_counts.py +++ b/netbox/utilities/management/commands/calculate_cached_counts.py @@ -1,7 +1,6 @@ from collections import defaultdict from django.core.management.base import BaseCommand -from django.db.models import Count, OuterRef, Subquery from netbox.registry import registry from utilities.counters import update_counts diff --git a/netbox/utilities/markdown.py b/netbox/utilities/markdown.py index 655539acb..0bf4e6a30 100644 --- a/netbox/utilities/markdown.py +++ b/netbox/utilities/markdown.py @@ -14,7 +14,7 @@ class StrikethroughExtension(markdown.Extension): """ def extendMarkdown(self, md): md.inlinePatterns.register( - markdown.inlinepatterns.SimpleTagPattern(STRIKE_RE, 'del'), + SimpleTagPattern(STRIKE_RE, 'del'), 'strikethrough', 200 ) diff --git a/netbox/utilities/release.py b/netbox/utilities/release.py index 256588b0b..f389e8009 100644 --- a/netbox/utilities/release.py +++ b/netbox/utilities/release.py @@ -1,9 +1,9 @@ import datetime import os -import yaml from dataclasses import asdict, dataclass, field -from typing import List, Union +from typing import Union +import yaml from django.core.exceptions import ImproperlyConfigured from utilities.datetime import datetime_from_timestamp diff --git a/netbox/utilities/serializers/json.py b/netbox/utilities/serializers/json.py index b728b0a34..e64e9e0f6 100644 --- a/netbox/utilities/serializers/json.py +++ b/netbox/utilities/serializers/json.py @@ -1,5 +1,5 @@ from django.contrib.postgres.fields import ArrayField -from django.core.serializers.json import Deserializer, Serializer as Serializer_ # noqa +from django.core.serializers.json import Deserializer, Serializer as Serializer_ # noqa: F401 from django.utils.encoding import is_protected_type # NOTE: Module must contain both Serializer and Deserializer diff --git a/netbox/utilities/templatetags/form_helpers.py b/netbox/utilities/templatetags/form_helpers.py index 242bd7b1c..ec53fe97c 100644 --- a/netbox/utilities/templatetags/form_helpers.py +++ b/netbox/utilities/templatetags/form_helpers.py @@ -1,8 +1,6 @@ -import warnings - from django import template -from utilities.forms.rendering import FieldSet, InlineFields, ObjectAttribute, TabbedGroups +from utilities.forms.rendering import InlineFields, ObjectAttribute, TabbedGroups __all__ = ( 'getfield', diff --git a/netbox/virtualization/api/serializers_/clusters.py b/netbox/virtualization/api/serializers_/clusters.py index b16487132..b64b6e7ba 100644 --- a/netbox/virtualization/api/serializers_/clusters.py +++ b/netbox/virtualization/api/serializers_/clusters.py @@ -1,5 +1,3 @@ -from rest_framework import serializers - from dcim.api.serializers_.sites import SiteSerializer from netbox.api.fields import ChoiceField, RelatedObjectCountField from netbox.api.serializers import NetBoxModelSerializer diff --git a/netbox/virtualization/apps.py b/netbox/virtualization/apps.py index 8a61bc523..ebcc591bf 100644 --- a/netbox/virtualization/apps.py +++ b/netbox/virtualization/apps.py @@ -9,7 +9,7 @@ class VirtualizationConfig(AppConfig): def ready(self): from netbox.models.features import register_models from utilities.counters import connect_counters - from . import search, signals + from . import search, signals # noqa: F401 from .models import VirtualMachine # Register models diff --git a/netbox/vpn/api/serializers_/crypto.py b/netbox/vpn/api/serializers_/crypto.py index 700917b89..c11b8de2b 100644 --- a/netbox/vpn/api/serializers_/crypto.py +++ b/netbox/vpn/api/serializers_/crypto.py @@ -1,5 +1,3 @@ -from rest_framework import serializers - from netbox.api.fields import ChoiceField, SerializedPKRelatedField from netbox.api.serializers import NetBoxModelSerializer from vpn.choices import * diff --git a/netbox/vpn/apps.py b/netbox/vpn/apps.py index 9a3751cb2..1afa0d527 100644 --- a/netbox/vpn/apps.py +++ b/netbox/vpn/apps.py @@ -7,7 +7,7 @@ class VPNConfig(AppConfig): def ready(self): from netbox.models.features import register_models - from . import search + from . import search # noqa: F401 # Register models register_models(*self.get_models()) diff --git a/netbox/wireless/api/serializers_/wirelesslinks.py b/netbox/wireless/api/serializers_/wirelesslinks.py index 1f3bcfdea..c1d8e4f10 100644 --- a/netbox/wireless/api/serializers_/wirelesslinks.py +++ b/netbox/wireless/api/serializers_/wirelesslinks.py @@ -1,5 +1,3 @@ -from rest_framework import serializers - from dcim.api.serializers_.device_components import InterfaceSerializer from dcim.choices import LinkStatusChoices from netbox.api.fields import ChoiceField diff --git a/netbox/wireless/apps.py b/netbox/wireless/apps.py index 24e1869b6..ea2d9bbc0 100644 --- a/netbox/wireless/apps.py +++ b/netbox/wireless/apps.py @@ -6,7 +6,7 @@ class WirelessConfig(AppConfig): def ready(self): from netbox.models.features import register_models - from . import signals, search + from . import signals, search # noqa: F401 # Register models register_models(*self.get_models()) diff --git a/netbox/wireless/filtersets.py b/netbox/wireless/filtersets.py index 9f60388ce..537b2ec5c 100644 --- a/netbox/wireless/filtersets.py +++ b/netbox/wireless/filtersets.py @@ -6,7 +6,7 @@ from dcim.models import Interface from ipam.models import VLAN from netbox.filtersets import OrganizationalModelFilterSet, NetBoxModelFilterSet from tenancy.filtersets import TenancyFilterSet -from utilities.filters import MultiValueNumberFilter, TreeNodeMultipleChoiceFilter +from utilities.filters import TreeNodeMultipleChoiceFilter from .choices import * from .models import * From 4e763462e607b4722138555d8657e894180e393b Mon Sep 17 00:00:00 2001 From: Arthur Hanson Date: Thu, 10 Oct 2024 13:08:48 -0700 Subject: [PATCH 08/10] 17713 fix underscore in datasource.sync (#17729) --- netbox/core/models/data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/core/models/data.py b/netbox/core/models/data.py index 97f9fdac7..717449506 100644 --- a/netbox/core/models/data.py +++ b/netbox/core/models/data.py @@ -201,7 +201,7 @@ class DataSource(JobsMixin, PrimaryModel): logger.debug(f"Updated {updated_count} files") # Bulk delete deleted files - deleted_count, _ = DataFile.objects.filter(pk__in=deleted_file_ids).delete() + deleted_count, __ = DataFile.objects.filter(pk__in=deleted_file_ids).delete() logger.debug(f"Deleted {deleted_count} files") # Walk the local replication to find new files From 1e6f2224750c973d94f1d171f53eab444ffb1b89 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 11 Oct 2024 05:02:14 +0000 Subject: [PATCH 09/10] Update source translation strings --- netbox/translations/en/LC_MESSAGES/django.po | 446 +++++++++---------- 1 file changed, 223 insertions(+), 223 deletions(-) diff --git a/netbox/translations/en/LC_MESSAGES/django.po b/netbox/translations/en/LC_MESSAGES/django.po index e25594d5b..2880bf73f 100644 --- a/netbox/translations/en/LC_MESSAGES/django.po +++ b/netbox/translations/en/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-10 05:01+0000\n" +"POT-Creation-Date: 2024-10-11 05:02+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -188,7 +188,7 @@ msgstr "" #: netbox/circuits/filtersets.py:56 netbox/circuits/forms/bulk_edit.py:188 #: netbox/circuits/forms/bulk_edit.py:216 -#: netbox/circuits/forms/bulk_import.py:125 +#: netbox/circuits/forms/bulk_import.py:124 #: netbox/circuits/forms/filtersets.py:51 #: netbox/circuits/forms/filtersets.py:171 #: netbox/circuits/forms/filtersets.py:209 @@ -333,7 +333,7 @@ msgstr "" #: netbox/templates/inc/filter_list.html:45 #: netbox/templates/ipam/ipaddress_assign.html:29 #: netbox/templates/search.html:7 netbox/templates/search.html:26 -#: netbox/tenancy/filtersets.py:100 netbox/users/filtersets.py:23 +#: netbox/tenancy/filtersets.py:99 netbox/users/filtersets.py:23 #: netbox/users/filtersets.py:57 netbox/users/filtersets.py:102 #: netbox/users/filtersets.py:150 netbox/utilities/forms/forms.py:104 #: netbox/utilities/templates/navigation/menu.html:16 @@ -342,7 +342,7 @@ msgstr "" #: netbox/circuits/filtersets.py:264 netbox/circuits/forms/bulk_edit.py:172 #: netbox/circuits/forms/bulk_edit.py:246 -#: netbox/circuits/forms/bulk_import.py:116 +#: netbox/circuits/forms/bulk_import.py:115 #: netbox/circuits/forms/filtersets.py:198 #: netbox/circuits/forms/filtersets.py:214 #: netbox/circuits/forms/filtersets.py:260 @@ -522,9 +522,9 @@ msgstr "" #: netbox/circuits/forms/bulk_edit.py:51 netbox/circuits/forms/bulk_edit.py:73 #: netbox/circuits/forms/bulk_edit.py:123 -#: netbox/circuits/forms/bulk_import.py:37 -#: netbox/circuits/forms/bulk_import.py:52 -#: netbox/circuits/forms/bulk_import.py:75 +#: netbox/circuits/forms/bulk_import.py:36 +#: netbox/circuits/forms/bulk_import.py:51 +#: netbox/circuits/forms/bulk_import.py:74 #: netbox/circuits/forms/filtersets.py:70 #: netbox/circuits/forms/filtersets.py:88 #: netbox/circuits/forms/filtersets.py:116 @@ -573,7 +573,7 @@ msgid "Color" msgstr "" #: netbox/circuits/forms/bulk_edit.py:118 -#: netbox/circuits/forms/bulk_import.py:88 +#: netbox/circuits/forms/bulk_import.py:87 #: netbox/circuits/forms/filtersets.py:126 netbox/core/forms/bulk_edit.py:18 #: netbox/core/forms/filtersets.py:33 netbox/core/tables/change_logging.py:32 #: netbox/core/tables/data.py:20 netbox/core/tables/jobs.py:18 @@ -627,14 +627,14 @@ msgid "Type" msgstr "" #: netbox/circuits/forms/bulk_edit.py:128 -#: netbox/circuits/forms/bulk_import.py:81 +#: netbox/circuits/forms/bulk_import.py:80 #: netbox/circuits/forms/filtersets.py:139 #: netbox/circuits/forms/model_forms.py:98 msgid "Provider account" msgstr "" #: netbox/circuits/forms/bulk_edit.py:136 -#: netbox/circuits/forms/bulk_import.py:94 +#: netbox/circuits/forms/bulk_import.py:93 #: netbox/circuits/forms/filtersets.py:150 netbox/core/forms/filtersets.py:38 #: netbox/core/forms/filtersets.py:79 netbox/core/tables/data.py:23 #: netbox/core/tables/jobs.py:26 netbox/core/tables/tasks.py:88 @@ -703,8 +703,8 @@ msgstr "" #: netbox/circuits/forms/bulk_edit.py:142 #: netbox/circuits/forms/bulk_edit.py:233 -#: netbox/circuits/forms/bulk_import.py:99 -#: netbox/circuits/forms/bulk_import.py:159 +#: netbox/circuits/forms/bulk_import.py:98 +#: netbox/circuits/forms/bulk_import.py:158 #: netbox/circuits/forms/filtersets.py:119 #: netbox/circuits/forms/filtersets.py:241 netbox/dcim/forms/bulk_edit.py:122 #: netbox/dcim/forms/bulk_edit.py:187 netbox/dcim/forms/bulk_edit.py:346 @@ -868,21 +868,21 @@ msgstr "" msgid "Priority" msgstr "" -#: netbox/circuits/forms/bulk_import.py:40 -#: netbox/circuits/forms/bulk_import.py:55 -#: netbox/circuits/forms/bulk_import.py:78 +#: netbox/circuits/forms/bulk_import.py:39 +#: netbox/circuits/forms/bulk_import.py:54 +#: netbox/circuits/forms/bulk_import.py:77 msgid "Assigned provider" msgstr "" -#: netbox/circuits/forms/bulk_import.py:84 +#: netbox/circuits/forms/bulk_import.py:83 msgid "Assigned provider account" msgstr "" -#: netbox/circuits/forms/bulk_import.py:91 +#: netbox/circuits/forms/bulk_import.py:90 msgid "Type of circuit" msgstr "" -#: netbox/circuits/forms/bulk_import.py:96 netbox/dcim/forms/bulk_import.py:90 +#: netbox/circuits/forms/bulk_import.py:95 netbox/dcim/forms/bulk_import.py:90 #: netbox/dcim/forms/bulk_import.py:149 netbox/dcim/forms/bulk_import.py:250 #: netbox/dcim/forms/bulk_import.py:507 netbox/dcim/forms/bulk_import.py:661 #: netbox/dcim/forms/bulk_import.py:1373 netbox/ipam/forms/bulk_import.py:194 @@ -894,8 +894,8 @@ msgstr "" msgid "Operational status" msgstr "" -#: netbox/circuits/forms/bulk_import.py:103 -#: netbox/circuits/forms/bulk_import.py:163 +#: netbox/circuits/forms/bulk_import.py:102 +#: netbox/circuits/forms/bulk_import.py:162 #: netbox/dcim/forms/bulk_import.py:111 netbox/dcim/forms/bulk_import.py:156 #: netbox/dcim/forms/bulk_import.py:338 netbox/dcim/forms/bulk_import.py:483 #: netbox/dcim/forms/bulk_import.py:1223 netbox/dcim/forms/bulk_import.py:1368 @@ -911,7 +911,7 @@ msgstr "" msgid "Assigned tenant" msgstr "" -#: netbox/circuits/forms/bulk_import.py:121 +#: netbox/circuits/forms/bulk_import.py:120 #: netbox/templates/circuits/inc/circuit_termination.html:6 #: netbox/templates/circuits/inc/circuit_termination_fields.html:15 #: netbox/templates/dcim/cable.html:68 netbox/templates/dcim/cable.html:72 @@ -919,7 +919,7 @@ msgstr "" msgid "Termination" msgstr "" -#: netbox/circuits/forms/bulk_import.py:131 +#: netbox/circuits/forms/bulk_import.py:130 #: netbox/circuits/forms/filtersets.py:147 #: netbox/circuits/forms/filtersets.py:227 #: netbox/circuits/forms/model_forms.py:144 @@ -1130,9 +1130,9 @@ msgstr "" #: netbox/circuits/models/circuits.py:27 netbox/dcim/models/cables.py:67 #: netbox/dcim/models/device_component_templates.py:518 #: netbox/dcim/models/device_component_templates.py:618 -#: netbox/dcim/models/device_components.py:976 -#: netbox/dcim/models/device_components.py:1050 -#: netbox/dcim/models/device_components.py:1205 +#: netbox/dcim/models/device_components.py:975 +#: netbox/dcim/models/device_components.py:1049 +#: netbox/dcim/models/device_components.py:1204 #: netbox/dcim/models/devices.py:479 netbox/dcim/models/racks.py:224 #: netbox/extras/models/tags.py:28 msgid "color" @@ -1251,7 +1251,7 @@ msgstr "" #: netbox/circuits/models/circuits.py:281 #: netbox/dcim/models/device_component_templates.py:61 -#: netbox/dcim/models/device_components.py:69 netbox/dcim/models/racks.py:685 +#: netbox/dcim/models/device_components.py:68 netbox/dcim/models/racks.py:685 #: netbox/extras/models/configs.py:45 netbox/extras/models/configs.py:219 #: netbox/extras/models/customfields.py:125 netbox/extras/models/models.py:61 #: netbox/extras/models/models.py:158 netbox/extras/models/models.py:396 @@ -1287,7 +1287,7 @@ msgstr "" #: netbox/circuits/models/providers.py:104 netbox/core/models/data.py:39 #: netbox/core/models/jobs.py:45 #: netbox/dcim/models/device_component_templates.py:43 -#: netbox/dcim/models/device_components.py:54 netbox/dcim/models/devices.py:593 +#: netbox/dcim/models/device_components.py:53 netbox/dcim/models/devices.py:593 #: netbox/dcim/models/devices.py:1323 netbox/dcim/models/devices.py:1388 #: netbox/dcim/models/power.py:39 netbox/dcim/models/power.py:92 #: netbox/dcim/models/racks.py:262 netbox/dcim/models/sites.py:138 @@ -2057,13 +2057,13 @@ msgstr "" #: netbox/dcim/models/device_component_templates.py:414 #: netbox/dcim/models/device_component_templates.py:513 #: netbox/dcim/models/device_component_templates.py:613 -#: netbox/dcim/models/device_components.py:284 -#: netbox/dcim/models/device_components.py:313 -#: netbox/dcim/models/device_components.py:346 -#: netbox/dcim/models/device_components.py:464 -#: netbox/dcim/models/device_components.py:606 -#: netbox/dcim/models/device_components.py:971 -#: netbox/dcim/models/device_components.py:1045 netbox/dcim/models/power.py:102 +#: netbox/dcim/models/device_components.py:283 +#: netbox/dcim/models/device_components.py:312 +#: netbox/dcim/models/device_components.py:345 +#: netbox/dcim/models/device_components.py:463 +#: netbox/dcim/models/device_components.py:605 +#: netbox/dcim/models/device_components.py:970 +#: netbox/dcim/models/device_components.py:1044 netbox/dcim/models/power.py:102 #: netbox/extras/models/customfields.py:78 netbox/extras/models/search.py:41 #: netbox/virtualization/models/clusters.py:61 netbox/vpn/models/l2vpn.py:32 msgid "type" @@ -2078,7 +2078,7 @@ msgstr "" #: netbox/core/models/data.py:59 #: netbox/dcim/models/device_component_templates.py:419 -#: netbox/dcim/models/device_components.py:513 +#: netbox/dcim/models/device_components.py:512 #: netbox/extras/models/models.py:70 netbox/extras/models/models.py:301 #: netbox/extras/models/models.py:526 netbox/users/models/permissions.py:29 msgid "enabled" @@ -3114,7 +3114,7 @@ msgstr "" #: netbox/dcim/filtersets.py:1103 netbox/dcim/forms/common.py:18 #: netbox/dcim/forms/filtersets.py:818 netbox/dcim/forms/filtersets.py:1385 -#: netbox/dcim/models/device_components.py:519 +#: netbox/dcim/models/device_components.py:518 #: netbox/virtualization/filtersets.py:230 #: netbox/virtualization/filtersets.py:301 #: netbox/virtualization/forms/filtersets.py:172 @@ -3233,7 +3233,7 @@ msgstr "" #: netbox/dcim/filtersets.py:1613 netbox/dcim/forms/bulk_edit.py:1489 #: netbox/dcim/forms/bulk_import.py:891 netbox/dcim/forms/filtersets.py:1428 #: netbox/dcim/forms/model_forms.py:1378 -#: netbox/dcim/models/device_components.py:712 +#: netbox/dcim/models/device_components.py:711 #: netbox/dcim/tables/devices.py:626 netbox/ipam/filtersets.py:316 #: netbox/ipam/filtersets.py:327 netbox/ipam/filtersets.py:483 #: netbox/ipam/filtersets.py:584 netbox/ipam/filtersets.py:595 @@ -3353,12 +3353,12 @@ msgstr "" msgid "Master (name)" msgstr "" -#: netbox/dcim/filtersets.py:1939 netbox/tenancy/filtersets.py:246 +#: netbox/dcim/filtersets.py:1939 netbox/tenancy/filtersets.py:245 msgid "Tenant (ID)" msgstr "" #: netbox/dcim/filtersets.py:1945 netbox/extras/filtersets.py:618 -#: netbox/tenancy/filtersets.py:252 +#: netbox/tenancy/filtersets.py:251 msgid "Tenant (slug)" msgstr "" @@ -3883,7 +3883,7 @@ msgstr "" #: netbox/dcim/forms/bulk_edit.py:1039 #: netbox/dcim/models/device_component_templates.py:283 -#: netbox/dcim/models/device_components.py:357 +#: netbox/dcim/models/device_components.py:356 msgid "Maximum power draw (watts)" msgstr "" @@ -3893,7 +3893,7 @@ msgstr "" #: netbox/dcim/forms/bulk_edit.py:1045 #: netbox/dcim/models/device_component_templates.py:290 -#: netbox/dcim/models/device_components.py:364 +#: netbox/dcim/models/device_components.py:363 msgid "Allocated power draw (watts)" msgstr "" @@ -3915,7 +3915,7 @@ msgstr "" #: netbox/dcim/forms/bulk_import.py:876 netbox/dcim/forms/filtersets.py:1394 #: netbox/dcim/forms/object_import.py:90 #: netbox/dcim/models/device_component_templates.py:438 -#: netbox/dcim/models/device_components.py:671 +#: netbox/dcim/models/device_components.py:670 msgid "PoE mode" msgstr "" @@ -3923,7 +3923,7 @@ msgstr "" #: netbox/dcim/forms/bulk_import.py:882 netbox/dcim/forms/filtersets.py:1399 #: netbox/dcim/forms/object_import.py:95 #: netbox/dcim/models/device_component_templates.py:444 -#: netbox/dcim/models/device_components.py:677 +#: netbox/dcim/models/device_components.py:676 msgid "PoE type" msgstr "" @@ -4527,7 +4527,7 @@ msgstr "" msgid "IPv6 address with prefix length, e.g. 2001:db8::1/64" msgstr "" -#: netbox/dcim/forms/common.py:24 netbox/dcim/models/device_components.py:528 +#: netbox/dcim/forms/common.py:24 netbox/dcim/models/device_components.py:527 #: netbox/templates/dcim/interface.html:57 #: netbox/templates/virtualization/vminterface.html:55 #: netbox/virtualization/forms/bulk_edit.py:225 @@ -4683,7 +4683,7 @@ msgid "Mgmt only" msgstr "" #: netbox/dcim/forms/filtersets.py:1389 netbox/dcim/forms/model_forms.py:1383 -#: netbox/dcim/models/device_components.py:630 +#: netbox/dcim/models/device_components.py:629 #: netbox/templates/dcim/interface.html:129 msgid "WWN" msgstr "" @@ -5005,7 +5005,7 @@ msgstr "" #: netbox/dcim/models/cables.py:62 #: netbox/dcim/models/device_component_templates.py:55 -#: netbox/dcim/models/device_components.py:63 +#: netbox/dcim/models/device_components.py:62 #: netbox/extras/models/customfields.py:111 msgid "label" msgstr "" @@ -5103,7 +5103,7 @@ msgid "" msgstr "" #: netbox/dcim/models/device_component_templates.py:58 -#: netbox/dcim/models/device_components.py:66 +#: netbox/dcim/models/device_components.py:65 msgid "Physical label" msgstr "" @@ -5140,12 +5140,12 @@ msgid "console server port templates" msgstr "" #: netbox/dcim/models/device_component_templates.py:279 -#: netbox/dcim/models/device_components.py:353 +#: netbox/dcim/models/device_components.py:352 msgid "maximum draw" msgstr "" #: netbox/dcim/models/device_component_templates.py:286 -#: netbox/dcim/models/device_components.py:360 +#: netbox/dcim/models/device_components.py:359 msgid "allocated draw" msgstr "" @@ -5158,18 +5158,18 @@ msgid "power port templates" msgstr "" #: netbox/dcim/models/device_component_templates.py:316 -#: netbox/dcim/models/device_components.py:383 +#: netbox/dcim/models/device_components.py:382 #, python-brace-format msgid "Allocated draw cannot exceed the maximum draw ({maximum_draw}W)." msgstr "" #: netbox/dcim/models/device_component_templates.py:348 -#: netbox/dcim/models/device_components.py:478 +#: netbox/dcim/models/device_components.py:477 msgid "feed leg" msgstr "" #: netbox/dcim/models/device_component_templates.py:352 -#: netbox/dcim/models/device_components.py:482 +#: netbox/dcim/models/device_components.py:481 msgid "Phase (for three-phase feeds)" msgstr "" @@ -5192,17 +5192,17 @@ msgid "Parent power port ({power_port}) must belong to the same module type" msgstr "" #: netbox/dcim/models/device_component_templates.py:424 -#: netbox/dcim/models/device_components.py:612 +#: netbox/dcim/models/device_components.py:611 msgid "management only" msgstr "" #: netbox/dcim/models/device_component_templates.py:432 -#: netbox/dcim/models/device_components.py:551 +#: netbox/dcim/models/device_components.py:550 msgid "bridge interface" msgstr "" #: netbox/dcim/models/device_component_templates.py:450 -#: netbox/dcim/models/device_components.py:637 +#: netbox/dcim/models/device_components.py:636 msgid "wireless role" msgstr "" @@ -5215,7 +5215,7 @@ msgid "interface templates" msgstr "" #: netbox/dcim/models/device_component_templates.py:464 -#: netbox/dcim/models/device_components.py:805 +#: netbox/dcim/models/device_components.py:804 #: netbox/virtualization/models/virtualmachines.py:405 msgid "An interface cannot be bridged to itself." msgstr "" @@ -5231,7 +5231,7 @@ msgid "Bridge interface ({bridge}) must belong to the same module type" msgstr "" #: netbox/dcim/models/device_component_templates.py:527 -#: netbox/dcim/models/device_components.py:985 +#: netbox/dcim/models/device_components.py:984 msgid "rear port position" msgstr "" @@ -5256,7 +5256,7 @@ msgid "" msgstr "" #: netbox/dcim/models/device_component_templates.py:622 -#: netbox/dcim/models/device_components.py:1054 +#: netbox/dcim/models/device_components.py:1053 msgid "positions" msgstr "" @@ -5269,12 +5269,12 @@ msgid "rear port templates" msgstr "" #: netbox/dcim/models/device_component_templates.py:663 -#: netbox/dcim/models/device_components.py:1104 +#: netbox/dcim/models/device_components.py:1103 msgid "position" msgstr "" #: netbox/dcim/models/device_component_templates.py:666 -#: netbox/dcim/models/device_components.py:1107 +#: netbox/dcim/models/device_components.py:1106 msgid "Identifier to reference when renaming installed components" msgstr "" @@ -5302,12 +5302,12 @@ msgid "" msgstr "" #: netbox/dcim/models/device_component_templates.py:769 -#: netbox/dcim/models/device_components.py:1263 +#: netbox/dcim/models/device_components.py:1262 msgid "part ID" msgstr "" #: netbox/dcim/models/device_component_templates.py:771 -#: netbox/dcim/models/device_components.py:1265 +#: netbox/dcim/models/device_components.py:1264 msgid "Manufacturer-assigned part identifier" msgstr "" @@ -5319,411 +5319,411 @@ msgstr "" msgid "inventory item templates" msgstr "" -#: netbox/dcim/models/device_components.py:106 +#: netbox/dcim/models/device_components.py:105 msgid "Components cannot be moved to a different device." msgstr "" -#: netbox/dcim/models/device_components.py:145 +#: netbox/dcim/models/device_components.py:144 msgid "cable end" msgstr "" -#: netbox/dcim/models/device_components.py:151 +#: netbox/dcim/models/device_components.py:150 msgid "mark connected" msgstr "" -#: netbox/dcim/models/device_components.py:153 +#: netbox/dcim/models/device_components.py:152 msgid "Treat as if a cable is connected" msgstr "" -#: netbox/dcim/models/device_components.py:171 +#: netbox/dcim/models/device_components.py:170 msgid "Must specify cable end (A or B) when attaching a cable." msgstr "" -#: netbox/dcim/models/device_components.py:175 +#: netbox/dcim/models/device_components.py:174 msgid "Cable end must not be set without a cable." msgstr "" -#: netbox/dcim/models/device_components.py:179 +#: netbox/dcim/models/device_components.py:178 msgid "Cannot mark as connected with a cable attached." msgstr "" -#: netbox/dcim/models/device_components.py:203 +#: netbox/dcim/models/device_components.py:202 #, python-brace-format msgid "{class_name} models must declare a parent_object property" msgstr "" -#: netbox/dcim/models/device_components.py:288 -#: netbox/dcim/models/device_components.py:317 -#: netbox/dcim/models/device_components.py:350 -#: netbox/dcim/models/device_components.py:468 +#: netbox/dcim/models/device_components.py:287 +#: netbox/dcim/models/device_components.py:316 +#: netbox/dcim/models/device_components.py:349 +#: netbox/dcim/models/device_components.py:467 msgid "Physical port type" msgstr "" -#: netbox/dcim/models/device_components.py:291 -#: netbox/dcim/models/device_components.py:320 +#: netbox/dcim/models/device_components.py:290 +#: netbox/dcim/models/device_components.py:319 msgid "speed" msgstr "" -#: netbox/dcim/models/device_components.py:295 -#: netbox/dcim/models/device_components.py:324 +#: netbox/dcim/models/device_components.py:294 +#: netbox/dcim/models/device_components.py:323 msgid "Port speed in bits per second" msgstr "" -#: netbox/dcim/models/device_components.py:301 +#: netbox/dcim/models/device_components.py:300 msgid "console port" msgstr "" -#: netbox/dcim/models/device_components.py:302 +#: netbox/dcim/models/device_components.py:301 msgid "console ports" msgstr "" -#: netbox/dcim/models/device_components.py:330 +#: netbox/dcim/models/device_components.py:329 msgid "console server port" msgstr "" -#: netbox/dcim/models/device_components.py:331 +#: netbox/dcim/models/device_components.py:330 msgid "console server ports" msgstr "" -#: netbox/dcim/models/device_components.py:370 +#: netbox/dcim/models/device_components.py:369 msgid "power port" msgstr "" -#: netbox/dcim/models/device_components.py:371 +#: netbox/dcim/models/device_components.py:370 msgid "power ports" msgstr "" -#: netbox/dcim/models/device_components.py:488 +#: netbox/dcim/models/device_components.py:487 msgid "power outlet" msgstr "" -#: netbox/dcim/models/device_components.py:489 +#: netbox/dcim/models/device_components.py:488 msgid "power outlets" msgstr "" -#: netbox/dcim/models/device_components.py:500 +#: netbox/dcim/models/device_components.py:499 #, python-brace-format msgid "Parent power port ({power_port}) must belong to the same device" msgstr "" -#: netbox/dcim/models/device_components.py:531 netbox/vpn/models/crypto.py:81 +#: netbox/dcim/models/device_components.py:530 netbox/vpn/models/crypto.py:81 #: netbox/vpn/models/crypto.py:226 msgid "mode" msgstr "" -#: netbox/dcim/models/device_components.py:535 +#: netbox/dcim/models/device_components.py:534 msgid "IEEE 802.1Q tagging strategy" msgstr "" -#: netbox/dcim/models/device_components.py:543 +#: netbox/dcim/models/device_components.py:542 msgid "parent interface" msgstr "" -#: netbox/dcim/models/device_components.py:603 +#: netbox/dcim/models/device_components.py:602 msgid "parent LAG" msgstr "" -#: netbox/dcim/models/device_components.py:613 +#: netbox/dcim/models/device_components.py:612 msgid "This interface is used only for out-of-band management" msgstr "" -#: netbox/dcim/models/device_components.py:618 +#: netbox/dcim/models/device_components.py:617 msgid "speed (Kbps)" msgstr "" -#: netbox/dcim/models/device_components.py:621 +#: netbox/dcim/models/device_components.py:620 msgid "duplex" msgstr "" -#: netbox/dcim/models/device_components.py:631 +#: netbox/dcim/models/device_components.py:630 msgid "64-bit World Wide Name" msgstr "" -#: netbox/dcim/models/device_components.py:643 +#: netbox/dcim/models/device_components.py:642 msgid "wireless channel" msgstr "" -#: netbox/dcim/models/device_components.py:650 +#: netbox/dcim/models/device_components.py:649 msgid "channel frequency (MHz)" msgstr "" -#: netbox/dcim/models/device_components.py:651 -#: netbox/dcim/models/device_components.py:659 +#: netbox/dcim/models/device_components.py:650 +#: netbox/dcim/models/device_components.py:658 msgid "Populated by selected channel (if set)" msgstr "" -#: netbox/dcim/models/device_components.py:665 +#: netbox/dcim/models/device_components.py:664 msgid "transmit power (dBm)" msgstr "" -#: netbox/dcim/models/device_components.py:690 netbox/wireless/models.py:117 +#: netbox/dcim/models/device_components.py:689 netbox/wireless/models.py:117 msgid "wireless LANs" msgstr "" -#: netbox/dcim/models/device_components.py:698 +#: netbox/dcim/models/device_components.py:697 #: netbox/virtualization/models/virtualmachines.py:335 msgid "untagged VLAN" msgstr "" -#: netbox/dcim/models/device_components.py:704 +#: netbox/dcim/models/device_components.py:703 #: netbox/virtualization/models/virtualmachines.py:341 msgid "tagged VLANs" msgstr "" -#: netbox/dcim/models/device_components.py:746 +#: netbox/dcim/models/device_components.py:745 #: netbox/virtualization/models/virtualmachines.py:377 msgid "interface" msgstr "" -#: netbox/dcim/models/device_components.py:747 +#: netbox/dcim/models/device_components.py:746 #: netbox/virtualization/models/virtualmachines.py:378 msgid "interfaces" msgstr "" -#: netbox/dcim/models/device_components.py:758 +#: netbox/dcim/models/device_components.py:757 #, python-brace-format msgid "{display_type} interfaces cannot have a cable attached." msgstr "" -#: netbox/dcim/models/device_components.py:766 +#: netbox/dcim/models/device_components.py:765 #, python-brace-format msgid "{display_type} interfaces cannot be marked as connected." msgstr "" -#: netbox/dcim/models/device_components.py:775 +#: netbox/dcim/models/device_components.py:774 #: netbox/virtualization/models/virtualmachines.py:390 msgid "An interface cannot be its own parent." msgstr "" -#: netbox/dcim/models/device_components.py:779 +#: netbox/dcim/models/device_components.py:778 msgid "Only virtual interfaces may be assigned to a parent interface." msgstr "" -#: netbox/dcim/models/device_components.py:786 +#: netbox/dcim/models/device_components.py:785 #, python-brace-format msgid "" "The selected parent interface ({interface}) belongs to a different device " "({device})" msgstr "" -#: netbox/dcim/models/device_components.py:792 +#: netbox/dcim/models/device_components.py:791 #, python-brace-format msgid "" "The selected parent interface ({interface}) belongs to {device}, which is " "not part of virtual chassis {virtual_chassis}." msgstr "" -#: netbox/dcim/models/device_components.py:812 +#: netbox/dcim/models/device_components.py:811 #, python-brace-format msgid "" "The selected bridge interface ({bridge}) belongs to a different device " "({device})." msgstr "" -#: netbox/dcim/models/device_components.py:818 +#: netbox/dcim/models/device_components.py:817 #, python-brace-format msgid "" "The selected bridge interface ({interface}) belongs to {device}, which is " "not part of virtual chassis {virtual_chassis}." msgstr "" -#: netbox/dcim/models/device_components.py:829 +#: netbox/dcim/models/device_components.py:828 msgid "Virtual interfaces cannot have a parent LAG interface." msgstr "" -#: netbox/dcim/models/device_components.py:833 +#: netbox/dcim/models/device_components.py:832 msgid "A LAG interface cannot be its own parent." msgstr "" -#: netbox/dcim/models/device_components.py:840 +#: netbox/dcim/models/device_components.py:839 #, python-brace-format msgid "" "The selected LAG interface ({lag}) belongs to a different device ({device})." msgstr "" -#: netbox/dcim/models/device_components.py:846 +#: netbox/dcim/models/device_components.py:845 #, python-brace-format msgid "" "The selected LAG interface ({lag}) belongs to {device}, which is not part of " "virtual chassis {virtual_chassis}." msgstr "" -#: netbox/dcim/models/device_components.py:857 +#: netbox/dcim/models/device_components.py:856 msgid "Virtual interfaces cannot have a PoE mode." msgstr "" -#: netbox/dcim/models/device_components.py:861 +#: netbox/dcim/models/device_components.py:860 msgid "Virtual interfaces cannot have a PoE type." msgstr "" -#: netbox/dcim/models/device_components.py:867 +#: netbox/dcim/models/device_components.py:866 msgid "Must specify PoE mode when designating a PoE type." msgstr "" -#: netbox/dcim/models/device_components.py:874 +#: netbox/dcim/models/device_components.py:873 msgid "Wireless role may be set only on wireless interfaces." msgstr "" -#: netbox/dcim/models/device_components.py:876 +#: netbox/dcim/models/device_components.py:875 msgid "Channel may be set only on wireless interfaces." msgstr "" -#: netbox/dcim/models/device_components.py:882 +#: netbox/dcim/models/device_components.py:881 msgid "Channel frequency may be set only on wireless interfaces." msgstr "" -#: netbox/dcim/models/device_components.py:886 +#: netbox/dcim/models/device_components.py:885 msgid "Cannot specify custom frequency with channel selected." msgstr "" -#: netbox/dcim/models/device_components.py:892 +#: netbox/dcim/models/device_components.py:891 msgid "Channel width may be set only on wireless interfaces." msgstr "" -#: netbox/dcim/models/device_components.py:894 +#: netbox/dcim/models/device_components.py:893 msgid "Cannot specify custom width with channel selected." msgstr "" -#: netbox/dcim/models/device_components.py:902 +#: netbox/dcim/models/device_components.py:901 #, python-brace-format msgid "" "The untagged VLAN ({untagged_vlan}) must belong to the same site as the " "interface's parent device, or it must be global." msgstr "" -#: netbox/dcim/models/device_components.py:991 +#: netbox/dcim/models/device_components.py:990 msgid "Mapped position on corresponding rear port" msgstr "" -#: netbox/dcim/models/device_components.py:1007 +#: netbox/dcim/models/device_components.py:1006 msgid "front port" msgstr "" -#: netbox/dcim/models/device_components.py:1008 +#: netbox/dcim/models/device_components.py:1007 msgid "front ports" msgstr "" -#: netbox/dcim/models/device_components.py:1022 +#: netbox/dcim/models/device_components.py:1021 #, python-brace-format msgid "Rear port ({rear_port}) must belong to the same device" msgstr "" -#: netbox/dcim/models/device_components.py:1030 +#: netbox/dcim/models/device_components.py:1029 #, python-brace-format msgid "" "Invalid rear port position ({rear_port_position}): Rear port {name} has only " "{positions} positions." msgstr "" -#: netbox/dcim/models/device_components.py:1060 +#: netbox/dcim/models/device_components.py:1059 msgid "Number of front ports which may be mapped" msgstr "" -#: netbox/dcim/models/device_components.py:1065 +#: netbox/dcim/models/device_components.py:1064 msgid "rear port" msgstr "" -#: netbox/dcim/models/device_components.py:1066 +#: netbox/dcim/models/device_components.py:1065 msgid "rear ports" msgstr "" -#: netbox/dcim/models/device_components.py:1080 +#: netbox/dcim/models/device_components.py:1079 #, python-brace-format msgid "" "The number of positions cannot be less than the number of mapped front ports " "({frontport_count})" msgstr "" -#: netbox/dcim/models/device_components.py:1121 +#: netbox/dcim/models/device_components.py:1120 msgid "module bay" msgstr "" -#: netbox/dcim/models/device_components.py:1122 +#: netbox/dcim/models/device_components.py:1121 msgid "module bays" msgstr "" -#: netbox/dcim/models/device_components.py:1139 +#: netbox/dcim/models/device_components.py:1138 #: netbox/dcim/models/devices.py:1217 msgid "A module bay cannot belong to a module installed within it." msgstr "" -#: netbox/dcim/models/device_components.py:1165 +#: netbox/dcim/models/device_components.py:1164 msgid "device bay" msgstr "" -#: netbox/dcim/models/device_components.py:1166 +#: netbox/dcim/models/device_components.py:1165 msgid "device bays" msgstr "" -#: netbox/dcim/models/device_components.py:1176 +#: netbox/dcim/models/device_components.py:1175 #, python-brace-format msgid "This type of device ({device_type}) does not support device bays." msgstr "" -#: netbox/dcim/models/device_components.py:1182 +#: netbox/dcim/models/device_components.py:1181 msgid "Cannot install a device into itself." msgstr "" -#: netbox/dcim/models/device_components.py:1190 +#: netbox/dcim/models/device_components.py:1189 #, python-brace-format msgid "" "Cannot install the specified device; device is already installed in {bay}." msgstr "" -#: netbox/dcim/models/device_components.py:1211 +#: netbox/dcim/models/device_components.py:1210 msgid "inventory item role" msgstr "" -#: netbox/dcim/models/device_components.py:1212 +#: netbox/dcim/models/device_components.py:1211 msgid "inventory item roles" msgstr "" -#: netbox/dcim/models/device_components.py:1269 +#: netbox/dcim/models/device_components.py:1268 #: netbox/dcim/models/devices.py:607 netbox/dcim/models/devices.py:1174 #: netbox/dcim/models/racks.py:313 #: netbox/virtualization/models/virtualmachines.py:131 msgid "serial number" msgstr "" -#: netbox/dcim/models/device_components.py:1277 +#: netbox/dcim/models/device_components.py:1276 #: netbox/dcim/models/devices.py:615 netbox/dcim/models/devices.py:1181 #: netbox/dcim/models/racks.py:320 msgid "asset tag" msgstr "" -#: netbox/dcim/models/device_components.py:1278 +#: netbox/dcim/models/device_components.py:1277 msgid "A unique tag used to identify this item" msgstr "" -#: netbox/dcim/models/device_components.py:1281 +#: netbox/dcim/models/device_components.py:1280 msgid "discovered" msgstr "" -#: netbox/dcim/models/device_components.py:1283 +#: netbox/dcim/models/device_components.py:1282 msgid "This item was automatically discovered" msgstr "" -#: netbox/dcim/models/device_components.py:1301 +#: netbox/dcim/models/device_components.py:1300 msgid "inventory item" msgstr "" -#: netbox/dcim/models/device_components.py:1302 +#: netbox/dcim/models/device_components.py:1301 msgid "inventory items" msgstr "" -#: netbox/dcim/models/device_components.py:1313 +#: netbox/dcim/models/device_components.py:1312 msgid "Cannot assign self as parent." msgstr "" -#: netbox/dcim/models/device_components.py:1321 +#: netbox/dcim/models/device_components.py:1320 msgid "Parent inventory item does not belong to the same device." msgstr "" -#: netbox/dcim/models/device_components.py:1327 +#: netbox/dcim/models/device_components.py:1326 msgid "Cannot move an inventory item with dependent children" msgstr "" -#: netbox/dcim/models/device_components.py:1335 +#: netbox/dcim/models/device_components.py:1334 msgid "Cannot assign inventory item to component on another device" msgstr "" @@ -7222,80 +7222,80 @@ msgstr "" msgid "Unregistered widget class: {name}" msgstr "" -#: netbox/extras/dashboard/widgets.py:126 +#: netbox/extras/dashboard/widgets.py:125 #, python-brace-format msgid "{class_name} must define a render() method." msgstr "" -#: netbox/extras/dashboard/widgets.py:145 +#: netbox/extras/dashboard/widgets.py:144 msgid "Note" msgstr "" -#: netbox/extras/dashboard/widgets.py:146 +#: netbox/extras/dashboard/widgets.py:145 msgid "Display some arbitrary custom content. Markdown is supported." msgstr "" -#: netbox/extras/dashboard/widgets.py:159 +#: netbox/extras/dashboard/widgets.py:158 msgid "Object Counts" msgstr "" -#: netbox/extras/dashboard/widgets.py:160 +#: netbox/extras/dashboard/widgets.py:159 msgid "" "Display a set of NetBox models and the number of objects created for each " "type." msgstr "" -#: netbox/extras/dashboard/widgets.py:170 +#: netbox/extras/dashboard/widgets.py:169 msgid "Filters to apply when counting the number of objects" msgstr "" -#: netbox/extras/dashboard/widgets.py:178 +#: netbox/extras/dashboard/widgets.py:177 msgid "Invalid format. Object filters must be passed as a dictionary." msgstr "" -#: netbox/extras/dashboard/widgets.py:209 +#: netbox/extras/dashboard/widgets.py:208 msgid "Object List" msgstr "" -#: netbox/extras/dashboard/widgets.py:210 +#: netbox/extras/dashboard/widgets.py:209 msgid "Display an arbitrary list of objects." msgstr "" -#: netbox/extras/dashboard/widgets.py:223 +#: netbox/extras/dashboard/widgets.py:222 msgid "The default number of objects to display" msgstr "" -#: netbox/extras/dashboard/widgets.py:235 +#: netbox/extras/dashboard/widgets.py:234 msgid "Invalid format. URL parameters must be passed as a dictionary." msgstr "" -#: netbox/extras/dashboard/widgets.py:275 +#: netbox/extras/dashboard/widgets.py:274 msgid "RSS Feed" msgstr "" -#: netbox/extras/dashboard/widgets.py:280 +#: netbox/extras/dashboard/widgets.py:279 msgid "Embed an RSS feed from an external website." msgstr "" -#: netbox/extras/dashboard/widgets.py:287 +#: netbox/extras/dashboard/widgets.py:286 msgid "Feed URL" msgstr "" -#: netbox/extras/dashboard/widgets.py:292 +#: netbox/extras/dashboard/widgets.py:291 msgid "The maximum number of objects to display" msgstr "" -#: netbox/extras/dashboard/widgets.py:297 +#: netbox/extras/dashboard/widgets.py:296 msgid "How long to stored the cached content (in seconds)" msgstr "" -#: netbox/extras/dashboard/widgets.py:349 netbox/templates/account/base.html:10 +#: netbox/extras/dashboard/widgets.py:348 netbox/templates/account/base.html:10 #: netbox/templates/account/bookmarks.html:7 #: netbox/templates/inc/user_menu.html:48 msgid "Bookmarks" msgstr "" -#: netbox/extras/dashboard/widgets.py:353 +#: netbox/extras/dashboard/widgets.py:352 msgid "Show your personal bookmarks" msgstr "" @@ -7338,8 +7338,8 @@ msgstr "" msgid "Tenant group" msgstr "" -#: netbox/extras/filtersets.py:607 netbox/tenancy/filtersets.py:189 -#: netbox/tenancy/filtersets.py:209 +#: netbox/extras/filtersets.py:607 netbox/tenancy/filtersets.py:188 +#: netbox/tenancy/filtersets.py:208 msgid "Tenant group (slug)" msgstr "" @@ -8800,64 +8800,64 @@ msgstr "" msgid "Method" msgstr "" -#: netbox/extras/validators.py:16 +#: netbox/extras/validators.py:15 #, python-format msgid "Ensure this value is equal to %(limit_value)s." msgstr "" -#: netbox/extras/validators.py:27 +#: netbox/extras/validators.py:26 #, python-format msgid "Ensure this value does not equal %(limit_value)s." msgstr "" -#: netbox/extras/validators.py:38 +#: netbox/extras/validators.py:37 msgid "This field must be empty." msgstr "" -#: netbox/extras/validators.py:53 +#: netbox/extras/validators.py:52 msgid "This field must not be empty." msgstr "" -#: netbox/extras/validators.py:95 +#: netbox/extras/validators.py:94 msgid "Validation rules must be passed as a dictionary" msgstr "" -#: netbox/extras/validators.py:120 +#: netbox/extras/validators.py:119 #, python-brace-format msgid "Custom validation failed for {attribute}: {exception}" msgstr "" -#: netbox/extras/validators.py:134 +#: netbox/extras/validators.py:133 #, python-brace-format msgid "Invalid attribute \"{name}\" for request" msgstr "" -#: netbox/extras/validators.py:151 +#: netbox/extras/validators.py:150 #, python-brace-format msgid "Invalid attribute \"{name}\" for {model}" msgstr "" -#: netbox/extras/views.py:961 +#: netbox/extras/views.py:960 msgid "Your dashboard has been reset." msgstr "" -#: netbox/extras/views.py:1007 +#: netbox/extras/views.py:1006 msgid "Added widget: " msgstr "" -#: netbox/extras/views.py:1048 +#: netbox/extras/views.py:1047 msgid "Updated widget: " msgstr "" -#: netbox/extras/views.py:1084 +#: netbox/extras/views.py:1083 msgid "Deleted widget: " msgstr "" -#: netbox/extras/views.py:1086 +#: netbox/extras/views.py:1085 msgid "Error deleting widget: " msgstr "" -#: netbox/extras/views.py:1173 +#: netbox/extras/views.py:1172 msgid "Unable to run script: RQ worker process not running." msgstr "" @@ -10975,63 +10975,63 @@ msgstr "" msgid "Cannot delete stores from registry" msgstr "" -#: netbox/netbox/settings.py:762 +#: netbox/netbox/settings.py:760 msgid "Czech" msgstr "" -#: netbox/netbox/settings.py:763 +#: netbox/netbox/settings.py:761 msgid "Danish" msgstr "" -#: netbox/netbox/settings.py:764 +#: netbox/netbox/settings.py:762 msgid "German" msgstr "" -#: netbox/netbox/settings.py:765 +#: netbox/netbox/settings.py:763 msgid "English" msgstr "" -#: netbox/netbox/settings.py:766 +#: netbox/netbox/settings.py:764 msgid "Spanish" msgstr "" -#: netbox/netbox/settings.py:767 +#: netbox/netbox/settings.py:765 msgid "French" msgstr "" -#: netbox/netbox/settings.py:768 +#: netbox/netbox/settings.py:766 msgid "Italian" msgstr "" -#: netbox/netbox/settings.py:769 +#: netbox/netbox/settings.py:767 msgid "Japanese" msgstr "" -#: netbox/netbox/settings.py:770 +#: netbox/netbox/settings.py:768 msgid "Dutch" msgstr "" -#: netbox/netbox/settings.py:771 +#: netbox/netbox/settings.py:769 msgid "Polish" msgstr "" -#: netbox/netbox/settings.py:772 +#: netbox/netbox/settings.py:770 msgid "Portuguese" msgstr "" -#: netbox/netbox/settings.py:773 +#: netbox/netbox/settings.py:771 msgid "Russian" msgstr "" -#: netbox/netbox/settings.py:774 +#: netbox/netbox/settings.py:772 msgid "Turkish" msgstr "" -#: netbox/netbox/settings.py:775 +#: netbox/netbox/settings.py:773 msgid "Ukrainian" msgstr "" -#: netbox/netbox/settings.py:776 +#: netbox/netbox/settings.py:774 msgid "Chinese" msgstr "" @@ -13680,7 +13680,7 @@ msgid "" "Click here to attempt loading NetBox again." msgstr "" -#: netbox/templates/tenancy/contact.html:18 netbox/tenancy/filtersets.py:148 +#: netbox/templates/tenancy/contact.html:18 netbox/tenancy/filtersets.py:147 #: netbox/tenancy/forms/bulk_edit.py:137 netbox/tenancy/forms/filtersets.py:102 #: netbox/tenancy/forms/forms.py:56 netbox/tenancy/forms/model_forms.py:106 #: netbox/tenancy/forms/model_forms.py:130 netbox/tenancy/tables/contacts.py:98 @@ -13707,7 +13707,7 @@ msgid "Add Contact Group" msgstr "" #: netbox/templates/tenancy/contactrole.html:15 -#: netbox/tenancy/filtersets.py:153 netbox/tenancy/forms/forms.py:61 +#: netbox/tenancy/filtersets.py:152 netbox/tenancy/forms/forms.py:61 #: netbox/tenancy/forms/model_forms.py:87 msgid "Contact Role" msgstr "" @@ -14011,57 +14011,57 @@ msgstr "" msgid "Distance" msgstr "" -#: netbox/tenancy/filtersets.py:29 +#: netbox/tenancy/filtersets.py:28 msgid "Parent contact group (ID)" msgstr "" -#: netbox/tenancy/filtersets.py:35 +#: netbox/tenancy/filtersets.py:34 msgid "Parent contact group (slug)" msgstr "" -#: netbox/tenancy/filtersets.py:41 netbox/tenancy/filtersets.py:68 -#: netbox/tenancy/filtersets.py:111 +#: netbox/tenancy/filtersets.py:40 netbox/tenancy/filtersets.py:67 +#: netbox/tenancy/filtersets.py:110 msgid "Contact group (ID)" msgstr "" -#: netbox/tenancy/filtersets.py:48 netbox/tenancy/filtersets.py:75 -#: netbox/tenancy/filtersets.py:118 +#: netbox/tenancy/filtersets.py:47 netbox/tenancy/filtersets.py:74 +#: netbox/tenancy/filtersets.py:117 msgid "Contact group (slug)" msgstr "" -#: netbox/tenancy/filtersets.py:105 +#: netbox/tenancy/filtersets.py:104 msgid "Contact (ID)" msgstr "" -#: netbox/tenancy/filtersets.py:122 +#: netbox/tenancy/filtersets.py:121 msgid "Contact role (ID)" msgstr "" -#: netbox/tenancy/filtersets.py:128 +#: netbox/tenancy/filtersets.py:127 msgid "Contact role (slug)" msgstr "" -#: netbox/tenancy/filtersets.py:159 +#: netbox/tenancy/filtersets.py:158 msgid "Contact group" msgstr "" -#: netbox/tenancy/filtersets.py:170 +#: netbox/tenancy/filtersets.py:169 msgid "Parent tenant group (ID)" msgstr "" -#: netbox/tenancy/filtersets.py:176 +#: netbox/tenancy/filtersets.py:175 msgid "Parent tenant group (slug)" msgstr "" -#: netbox/tenancy/filtersets.py:182 netbox/tenancy/filtersets.py:202 +#: netbox/tenancy/filtersets.py:181 netbox/tenancy/filtersets.py:201 msgid "Tenant group (ID)" msgstr "" -#: netbox/tenancy/filtersets.py:235 +#: netbox/tenancy/filtersets.py:234 msgid "Tenant Group (ID)" msgstr "" -#: netbox/tenancy/filtersets.py:242 +#: netbox/tenancy/filtersets.py:241 msgid "Tenant Group (slug)" msgstr "" From 7ac6dff96d79f37467a764f996e4f990c5d524ae Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Fri, 11 Oct 2024 07:43:46 -0400 Subject: [PATCH 10/10] Closes #17733: Replace `pycodestyle` with `ruff` (#17734) * Resolve F541 errors * Resolve F841 errors * Resolve F811 errors * Resolve F901 errors * Resolve E714 errors * Ignore F821 errors for GraphQL mixins * Replace pycodestyle with ruff * Move ignores to ruff.toml --- .github/workflows/ci.yml | 4 +- docs/development/getting-started.md | 4 +- docs/development/style-guide.md | 36 ++++++------- netbox/circuits/api/nested_serializers.py | 2 +- netbox/circuits/tests/test_views.py | 2 +- netbox/core/api/nested_serializers.py | 2 +- netbox/core/data_backends.py | 2 +- netbox/core/graphql/mixins.py | 2 +- .../management/commands/syncdatasource.py | 4 +- netbox/core/models/data.py | 2 +- netbox/core/models/jobs.py | 4 +- netbox/dcim/api/nested_serializers.py | 2 +- netbox/dcim/forms/object_create.py | 4 +- netbox/dcim/graphql/mixins.py | 40 +++++++------- .../dcim/management/commands/trace_paths.py | 2 +- .../dcim/models/device_component_templates.py | 1 - netbox/dcim/tables/devicetypes.py | 3 +- netbox/dcim/tests/test_api.py | 4 +- netbox/dcim/tests/test_filtersets.py | 7 --- netbox/dcim/tests/test_models.py | 54 +++++++++---------- netbox/dcim/tests/test_views.py | 2 +- netbox/extras/api/nested_serializers.py | 2 +- netbox/extras/jobs.py | 2 +- .../management/commands/housekeeping.py | 4 +- netbox/extras/management/commands/reindex.py | 4 +- .../extras/management/commands/runscript.py | 2 +- netbox/extras/models/customfields.py | 2 +- netbox/extras/scripts.py | 2 +- netbox/extras/tests/test_customvalidators.py | 2 +- netbox/extras/tests/test_models.py | 8 +-- netbox/extras/tests/test_views.py | 2 +- netbox/ipam/api/nested_serializers.py | 2 +- netbox/ipam/api/views.py | 6 +-- netbox/ipam/graphql/mixins.py | 4 +- netbox/ipam/tests/test_api.py | 2 - netbox/ipam/tests/test_views.py | 8 +-- netbox/netbox/config/__init__.py | 2 +- netbox/netbox/data_backends.py | 2 +- netbox/netbox/navigation/menu.py | 32 +++++------ netbox/netbox/settings.py | 2 +- netbox/netbox/staging.py | 2 +- netbox/netbox/tests/dummy_plugin/views.py | 4 +- netbox/netbox/tests/test_authentication.py | 2 +- netbox/netbox/tests/test_import.py | 1 - netbox/tenancy/api/nested_serializers.py | 2 +- netbox/tenancy/graphql/mixins.py | 2 +- netbox/users/api/nested_serializers.py | 2 +- netbox/users/api/views.py | 2 +- netbox/users/forms/model_forms.py | 1 - netbox/users/tests/test_preferences.py | 4 +- netbox/utilities/forms/fields/dynamic.py | 2 +- netbox/utilities/html.py | 2 +- netbox/utilities/tests/test_api.py | 4 +- netbox/utilities/tests/test_counters.py | 2 +- .../virtualization/api/nested_serializers.py | 2 +- netbox/virtualization/tests/test_views.py | 14 ++--- netbox/virtualization/views.py | 4 +- netbox/vpn/api/nested_serializers.py | 2 +- netbox/vpn/filtersets.py | 11 ---- netbox/vpn/tests/test_filtersets.py | 7 --- netbox/vpn/tests/test_views.py | 8 +-- netbox/wireless/api/nested_serializers.py | 2 +- netbox/wireless/tests/test_views.py | 6 +-- ruff.toml | 2 + scripts/git-hooks/pre-commit | 4 +- 65 files changed, 168 insertions(+), 199 deletions(-) create mode 100644 ruff.toml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b4be03742..c3b4876c3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -73,7 +73,7 @@ jobs: run: | python -m pip install --upgrade pip pip install -r requirements.txt - pip install pycodestyle coverage tblib + pip install ruff coverage tblib - name: Build documentation run: mkdocs build @@ -85,7 +85,7 @@ jobs: run: python netbox/manage.py makemigrations --check - name: Check PEP8 compliance - run: pycodestyle --ignore=W504,E501 --exclude=node_modules netbox/ + run: ruff check netbox/ - name: Check UI ESLint, TypeScript, and Prettier Compliance run: yarn --cwd netbox/project-static validate diff --git a/docs/development/getting-started.md b/docs/development/getting-started.md index 4dbdb63b2..374ed34b0 100644 --- a/docs/development/getting-started.md +++ b/docs/development/getting-started.md @@ -70,10 +70,10 @@ NetBox ships with a [git pre-commit hook](https://githooks.com/) script that aut cd .git/hooks/ ln -s ../../scripts/git-hooks/pre-commit ``` -For the pre-commit hooks to work, you will also need to install the pycodestyle package: +For the pre-commit hooks to work, you will also need to install the [ruff](https://docs.astral.sh/ruff/) linter: ```no-highlight -python -m pip install pycodestyle +python -m pip install ruff ``` ...and set up the yarn packages as shown in the [Web UI Development Guide](web-ui.md) diff --git a/docs/development/style-guide.md b/docs/development/style-guide.md index 9e5606749..0d4caf395 100644 --- a/docs/development/style-guide.md +++ b/docs/development/style-guide.md @@ -1,6 +1,6 @@ # Style Guide -NetBox generally follows the [Django style guide](https://docs.djangoproject.com/en/stable/internals/contributing/writing-code/coding-style/), which is itself based on [PEP 8](https://www.python.org/dev/peps/pep-0008/). [Pycodestyle](https://github.com/pycqa/pycodestyle) is used to validate code formatting, ignoring certain violations. +NetBox generally follows the [Django style guide](https://docs.djangoproject.com/en/stable/internals/contributing/writing-code/coding-style/), which is itself based on [PEP 8](https://www.python.org/dev/peps/pep-0008/). [ruff](https://docs.astral.sh/ruff/) is used for linting (with certain [exceptions](#linter-exceptions)). ## Code @@ -20,32 +20,32 @@ NetBox generally follows the [Django style guide](https://docs.djangoproject.com * Nested API serializers generate minimal representations of an object. These are stored separately from the primary serializers to avoid circular dependencies. Always import nested serializers from other apps directly. For example, from within the DCIM app you would write `from ipam.api.nested_serializers import NestedIPAddressSerializer`. -### PEP 8 Exceptions +### Linting -NetBox ignores certain PEP8 assertions. These are listed below. +The [ruff](https://docs.astral.sh/ruff/) linter is used to enforce code style. A [pre-commit hook](./getting-started.md#3-enable-pre-commit-hooks) which runs this automatically is included with NetBox. To invoke `ruff` manually, run: -#### Wildcard Imports +``` +ruff check netbox/ +``` + +#### Linter Exceptions + +The following rules are ignored when linting. + +##### [E501](https://docs.astral.sh/ruff/rules/line-too-long/): Line too long + +NetBox does not enforce a hard restriction on line length, although a maximum length of 120 characters is strongly encouraged for Python code where possible. The maximum length does not apply to HTML templates or to automatically generated code (e.g. database migrations). + +##### [F403](https://docs.astral.sh/ruff/rules/undefined-local-with-import-star/): Undefined local with import star Wildcard imports (for example, `from .constants import *`) are acceptable under any of the following conditions: * The library being import contains only constant declarations (e.g. `constants.py`) * The library being imported explicitly defines `__all__` -#### Maximum Line Length (E501) +##### [F405](https://docs.astral.sh/ruff/rules/undefined-local-with-import-star-usage/): Undefined local with import star usage -NetBox does not restrict lines to a maximum length of 79 characters. We use a maximum line length of 120 characters, however this is not enforced by CI. The maximum length does not apply to HTML templates or to automatically generated code (e.g. database migrations). - -#### Line Breaks Following Binary Operators (W504) - -Line breaks are permitted following binary operators. - -### Enforcing Code Style - -The [`pycodestyle`](https://pypi.org/project/pycodestyle/) utility (formerly `pep8`) is used by the CI process to enforce code style. A [pre-commit hook](./getting-started.md#3-enable-pre-commit-hooks) which runs this automatically is included with NetBox. To invoke `pycodestyle` manually, run: - -``` -pycodestyle --ignore=W504,E501 netbox/ -``` +The justification for ignoring this rule is the same as F403 above. ### Introducing New Dependencies diff --git a/netbox/circuits/api/nested_serializers.py b/netbox/circuits/api/nested_serializers.py index 6de2cbf54..487749872 100644 --- a/netbox/circuits/api/nested_serializers.py +++ b/netbox/circuits/api/nested_serializers.py @@ -18,7 +18,7 @@ __all__ = [ # TODO: Remove in v4.2 warnings.warn( - f"Dedicated nested serializers will be removed in NetBox v4.2. Use Serializer(nested=True) instead.", + "Dedicated nested serializers will be removed in NetBox v4.2. Use Serializer(nested=True) instead.", DeprecationWarning ) diff --git a/netbox/circuits/tests/test_views.py b/netbox/circuits/tests/test_views.py index 87e6d99b7..b06ade30b 100644 --- a/netbox/circuits/tests/test_views.py +++ b/netbox/circuits/tests/test_views.py @@ -171,7 +171,7 @@ class CircuitTestCase(ViewTestCases.PrimaryObjectViewTestCase): ) cls.csv_update_data = ( - f"id,cid,description,status", + "id,cid,description,status", f"{circuits[0].pk},Circuit 7,New description7,{CircuitStatusChoices.STATUS_DECOMMISSIONED}", f"{circuits[1].pk},Circuit 8,New description8,{CircuitStatusChoices.STATUS_DECOMMISSIONED}", f"{circuits[2].pk},Circuit 9,New description9,{CircuitStatusChoices.STATUS_DECOMMISSIONED}", diff --git a/netbox/core/api/nested_serializers.py b/netbox/core/api/nested_serializers.py index 3b40853cf..df7b41ca7 100644 --- a/netbox/core/api/nested_serializers.py +++ b/netbox/core/api/nested_serializers.py @@ -16,7 +16,7 @@ __all__ = ( # TODO: Remove in v4.2 warnings.warn( - f"Dedicated nested serializers will be removed in NetBox v4.2. Use Serializer(nested=True) instead.", + "Dedicated nested serializers will be removed in NetBox v4.2. Use Serializer(nested=True) instead.", DeprecationWarning ) diff --git a/netbox/core/data_backends.py b/netbox/core/data_backends.py index 8b36c6995..770a3b258 100644 --- a/netbox/core/data_backends.py +++ b/netbox/core/data_backends.py @@ -34,7 +34,7 @@ class LocalBackend(DataBackend): @contextmanager def fetch(self): - logger.debug(f"Data source type is local; skipping fetch") + logger.debug("Data source type is local; skipping fetch") local_path = urlparse(self.url).path # Strip file:// scheme yield local_path diff --git a/netbox/core/graphql/mixins.py b/netbox/core/graphql/mixins.py index 43f8761d1..5195b52a0 100644 --- a/netbox/core/graphql/mixins.py +++ b/netbox/core/graphql/mixins.py @@ -15,7 +15,7 @@ __all__ = ( class ChangelogMixin: @strawberry_django.field - def changelog(self, info) -> List[Annotated["ObjectChangeType", strawberry.lazy('.types')]]: + def changelog(self, info) -> List[Annotated["ObjectChangeType", strawberry.lazy('.types')]]: # noqa: F821 content_type = ContentType.objects.get_for_model(self) object_changes = ObjectChange.objects.filter( changed_object_type=content_type, diff --git a/netbox/core/management/commands/syncdatasource.py b/netbox/core/management/commands/syncdatasource.py index aa8137952..990b6eb2a 100644 --- a/netbox/core/management/commands/syncdatasource.py +++ b/netbox/core/management/commands/syncdatasource.py @@ -26,7 +26,7 @@ class Command(BaseCommand): if invalid_names := set(options['name']) - found_names: raise CommandError(f"Invalid data source names: {', '.join(invalid_names)}") else: - raise CommandError(f"Must specify at least one data source, or set --all.") + raise CommandError("Must specify at least one data source, or set --all.") if len(options['name']) > 1: self.stdout.write(f"Syncing {len(datasources)} data sources.") @@ -43,4 +43,4 @@ class Command(BaseCommand): raise e if len(options['name']) > 1: - self.stdout.write(f"Finished.") + self.stdout.write("Finished.") diff --git a/netbox/core/models/data.py b/netbox/core/models/data.py index 717449506..6824b4605 100644 --- a/netbox/core/models/data.py +++ b/netbox/core/models/data.py @@ -125,7 +125,7 @@ class DataSource(JobsMixin, PrimaryModel): # Ensure URL scheme matches selected type if self.backend_class.is_local and self.url_scheme not in ('file', ''): raise ValidationError({ - 'source_url': f"URLs for local sources must start with file:// (or specify no scheme)" + 'source_url': "URLs for local sources must start with file:// (or specify no scheme)" }) def to_objectchange(self, action): diff --git a/netbox/core/models/jobs.py b/netbox/core/models/jobs.py index 655647ebb..e1b5715dd 100644 --- a/netbox/core/models/jobs.py +++ b/netbox/core/models/jobs.py @@ -118,9 +118,9 @@ class Job(models.Model): # TODO: Employ dynamic registration if self.object_type: if self.object_type.model == 'reportmodule': - return reverse(f'extras:report_result', kwargs={'job_pk': self.pk}) + return reverse('extras:report_result', kwargs={'job_pk': self.pk}) elif self.object_type.model == 'scriptmodule': - return reverse(f'extras:script_result', kwargs={'job_pk': self.pk}) + return reverse('extras:script_result', kwargs={'job_pk': self.pk}) return reverse('core:job', args=[self.pk]) def get_status_color(self): diff --git a/netbox/dcim/api/nested_serializers.py b/netbox/dcim/api/nested_serializers.py index 5d83b9145..4b8f0db4a 100644 --- a/netbox/dcim/api/nested_serializers.py +++ b/netbox/dcim/api/nested_serializers.py @@ -56,7 +56,7 @@ __all__ = [ # TODO: Remove in v4.2 warnings.warn( - f"Dedicated nested serializers will be removed in NetBox v4.2. Use Serializer(nested=True) instead.", + "Dedicated nested serializers will be removed in NetBox v4.2. Use Serializer(nested=True) instead.", DeprecationWarning ) diff --git a/netbox/dcim/forms/object_create.py b/netbox/dcim/forms/object_create.py index f811700b4..d18c7ed14 100644 --- a/netbox/dcim/forms/object_create.py +++ b/netbox/dcim/forms/object_create.py @@ -261,8 +261,8 @@ class FrontPortCreateForm(ComponentCreateForm, model_forms.FrontPortForm): # TODO: Clean up the application of HTMXSelect attributes attrs={ 'hx-get': '.', - 'hx-include': f'#form_fields', - 'hx-target': f'#form_fields', + 'hx-include': '#form_fields', + 'hx-target': '#form_fields', } ) ) diff --git a/netbox/dcim/graphql/mixins.py b/netbox/dcim/graphql/mixins.py index a489ef1f6..2e5ab7ea7 100644 --- a/netbox/dcim/graphql/mixins.py +++ b/netbox/dcim/graphql/mixins.py @@ -10,18 +10,18 @@ __all__ = ( @strawberry.type class CabledObjectMixin: - cable: Annotated["CableType", strawberry.lazy('dcim.graphql.types')] | None + cable: Annotated["CableType", strawberry.lazy('dcim.graphql.types')] | None # noqa: F821 link_peers: List[Annotated[Union[ - Annotated["CircuitTerminationType", strawberry.lazy('circuits.graphql.types')], - Annotated["ConsolePortType", strawberry.lazy('dcim.graphql.types')], - Annotated["ConsoleServerPortType", strawberry.lazy('dcim.graphql.types')], - Annotated["FrontPortType", strawberry.lazy('dcim.graphql.types')], - Annotated["InterfaceType", strawberry.lazy('dcim.graphql.types')], - Annotated["PowerFeedType", strawberry.lazy('dcim.graphql.types')], - Annotated["PowerOutletType", strawberry.lazy('dcim.graphql.types')], - Annotated["PowerPortType", strawberry.lazy('dcim.graphql.types')], - Annotated["RearPortType", strawberry.lazy('dcim.graphql.types')], + Annotated["CircuitTerminationType", strawberry.lazy('circuits.graphql.types')], # noqa: F821 + Annotated["ConsolePortType", strawberry.lazy('dcim.graphql.types')], # noqa: F821 + Annotated["ConsoleServerPortType", strawberry.lazy('dcim.graphql.types')], # noqa: F821 + Annotated["FrontPortType", strawberry.lazy('dcim.graphql.types')], # noqa: F821 + Annotated["InterfaceType", strawberry.lazy('dcim.graphql.types')], # noqa: F821 + Annotated["PowerFeedType", strawberry.lazy('dcim.graphql.types')], # noqa: F821 + Annotated["PowerOutletType", strawberry.lazy('dcim.graphql.types')], # noqa: F821 + Annotated["PowerPortType", strawberry.lazy('dcim.graphql.types')], # noqa: F821 + Annotated["RearPortType", strawberry.lazy('dcim.graphql.types')], # noqa: F821 ], strawberry.union("LinkPeerType")]] @@ -29,14 +29,14 @@ class CabledObjectMixin: class PathEndpointMixin: connected_endpoints: List[Annotated[Union[ - Annotated["CircuitTerminationType", strawberry.lazy('circuits.graphql.types')], - Annotated["ConsolePortType", strawberry.lazy('dcim.graphql.types')], - Annotated["ConsoleServerPortType", strawberry.lazy('dcim.graphql.types')], - Annotated["FrontPortType", strawberry.lazy('dcim.graphql.types')], - Annotated["InterfaceType", strawberry.lazy('dcim.graphql.types')], - Annotated["PowerFeedType", strawberry.lazy('dcim.graphql.types')], - Annotated["PowerOutletType", strawberry.lazy('dcim.graphql.types')], - Annotated["PowerPortType", strawberry.lazy('dcim.graphql.types')], - Annotated["ProviderNetworkType", strawberry.lazy('circuits.graphql.types')], - Annotated["RearPortType", strawberry.lazy('dcim.graphql.types')], + Annotated["CircuitTerminationType", strawberry.lazy('circuits.graphql.types')], # noqa: F821 + Annotated["ConsolePortType", strawberry.lazy('dcim.graphql.types')], # noqa: F821 + Annotated["ConsoleServerPortType", strawberry.lazy('dcim.graphql.types')], # noqa: F821 + Annotated["FrontPortType", strawberry.lazy('dcim.graphql.types')], # noqa: F821 + Annotated["InterfaceType", strawberry.lazy('dcim.graphql.types')], # noqa: F821 + Annotated["PowerFeedType", strawberry.lazy('dcim.graphql.types')], # noqa: F821 + Annotated["PowerOutletType", strawberry.lazy('dcim.graphql.types')], # noqa: F821 + Annotated["PowerPortType", strawberry.lazy('dcim.graphql.types')], # noqa: F821 + Annotated["ProviderNetworkType", strawberry.lazy('circuits.graphql.types')], # noqa: F821 + Annotated["RearPortType", strawberry.lazy('dcim.graphql.types')], # noqa: F821 ], strawberry.union("ConnectedEndpointType")]] diff --git a/netbox/dcim/management/commands/trace_paths.py b/netbox/dcim/management/commands/trace_paths.py index d34a428e4..592aeb6a7 100644 --- a/netbox/dcim/management/commands/trace_paths.py +++ b/netbox/dcim/management/commands/trace_paths.py @@ -60,7 +60,7 @@ class Command(BaseCommand): self.stdout.write((self.style.SUCCESS(f' Deleted {deleted_count} paths'))) # Reinitialize the model's PK sequence - self.stdout.write(f'Resetting database sequence for CablePath model') + self.stdout.write('Resetting database sequence for CablePath model') sequence_sql = connection.ops.sequence_reset_sql(no_style(), [CablePath]) with connection.cursor() as cursor: for sql in sequence_sql: diff --git a/netbox/dcim/models/device_component_templates.py b/netbox/dcim/models/device_component_templates.py index 5f6aa08e3..3a71c424d 100644 --- a/netbox/dcim/models/device_component_templates.py +++ b/netbox/dcim/models/device_component_templates.py @@ -160,7 +160,6 @@ class ModularComponentTemplateModel(ComponentTemplateModel): def _get_module_tree(self, module): modules = [] - all_module_bays = module.device.modulebays.all().select_related('module') while module: modules.append(module) if module.module_bay: diff --git a/netbox/dcim/tables/devicetypes.py b/netbox/dcim/tables/devicetypes.py index 69ff8b3a2..e8a4e35f1 100644 --- a/netbox/dcim/tables/devicetypes.py +++ b/netbox/dcim/tables/devicetypes.py @@ -1,6 +1,5 @@ -from django.utils.translation import gettext_lazy as _ import django_tables2 as tables -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from dcim import models from netbox.tables import NetBoxTable, columns diff --git a/netbox/dcim/tests/test_api.py b/netbox/dcim/tests/test_api.py index 573fdbb96..1b460cd59 100644 --- a/netbox/dcim/tests/test_api.py +++ b/netbox/dcim/tests/test_api.py @@ -2135,12 +2135,12 @@ class ConnectedDeviceTest(APITestCase): def test_get_connected_device(self): url = reverse('dcim-api:connected-device-list') - url_params = f'?peer_device=TestDevice1&peer_interface=eth0' + url_params = '?peer_device=TestDevice1&peer_interface=eth0' response = self.client.get(url + url_params, **self.header) self.assertHttpStatus(response, status.HTTP_200_OK) self.assertEqual(response.data['name'], 'TestDevice2') - url_params = f'?peer_device=TestDevice1&peer_interface=eth1' + url_params = '?peer_device=TestDevice1&peer_interface=eth1' response = self.client.get(url + url_params, **self.header) self.assertHttpStatus(response, status.HTTP_404_NOT_FOUND) diff --git a/netbox/dcim/tests/test_filtersets.py b/netbox/dcim/tests/test_filtersets.py index afb360d76..6c65cad93 100644 --- a/netbox/dcim/tests/test_filtersets.py +++ b/netbox/dcim/tests/test_filtersets.py @@ -4838,13 +4838,6 @@ class InventoryItemTestCase(TestCase, ChangeLoggedFilterSetTests): params = {'device_role': [role[0].slug, role[1].slug]} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4) - def test_role(self): - role = DeviceRole.objects.all()[:2] - params = {'role_id': [role[0].pk, role[1].pk]} - self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4) - params = {'role': [role[0].slug, role[1].slug]} - self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4) - def test_device(self): devices = Device.objects.all()[:2] params = {'device_id': [devices[0].pk, devices[1].pk]} diff --git a/netbox/dcim/tests/test_models.py b/netbox/dcim/tests/test_models.py index 1c3dbb90b..70431c2e1 100644 --- a/netbox/dcim/tests/test_models.py +++ b/netbox/dcim/tests/test_models.py @@ -662,10 +662,8 @@ class ModuleBayTestCase(TestCase): def test_module_bay_recursion(self): module_bay_1 = ModuleBay.objects.get(name='Module Bay 1') - module_bay_2 = ModuleBay.objects.get(name='Module Bay 2') module_bay_3 = ModuleBay.objects.get(name='Module Bay 3') module_1 = Module.objects.get(module_bay=module_bay_1) - module_2 = Module.objects.get(module_bay=module_bay_2) module_3 = Module.objects.get(module_bay=module_bay_3) # Confirm error if ModuleBay recurses @@ -681,8 +679,6 @@ class ModuleBayTestCase(TestCase): module_1.save() def test_single_module_token(self): - module_bays = ModuleBay.objects.all() - modules = Module.objects.all() device_type = DeviceType.objects.first() device_role = DeviceRole.objects.first() site = Site.objects.first() @@ -708,7 +704,7 @@ class ModuleBayTestCase(TestCase): location=location, rack=rack ) - cp = device.consoleports.first() + device.consoleports.first() def test_nested_module_token(self): pass @@ -733,39 +729,41 @@ class CableTestCase(TestCase): device2 = Device.objects.create( device_type=devicetype, role=role, name='TestDevice2', site=site ) - interface1 = Interface.objects.create(device=device1, name='eth0') - interface2 = Interface.objects.create(device=device2, name='eth0') - interface3 = Interface.objects.create(device=device2, name='eth1') - Cable(a_terminations=[interface1], b_terminations=[interface2]).save() + interfaces = ( + Interface(device=device1, name='eth0'), + Interface(device=device2, name='eth0'), + Interface(device=device2, name='eth1'), + ) + Interface.objects.bulk_create(interfaces) + Cable(a_terminations=[interfaces[0]], b_terminations=[interfaces[1]]).save() + PowerPort.objects.create(device=device2, name='psu1') - power_port1 = PowerPort.objects.create(device=device2, name='psu1') - patch_pannel = Device.objects.create( + patch_panel = Device.objects.create( device_type=devicetype, role=role, name='TestPatchPanel', site=site ) - rear_port1 = RearPort.objects.create(device=patch_pannel, name='RP1', type='8p8c') - front_port1 = FrontPort.objects.create( - device=patch_pannel, name='FP1', type='8p8c', rear_port=rear_port1, rear_port_position=1 + rear_ports = ( + RearPort(device=patch_panel, name='RP1', type='8p8c'), + RearPort(device=patch_panel, name='RP2', type='8p8c', positions=2), + RearPort(device=patch_panel, name='RP3', type='8p8c', positions=3), + RearPort(device=patch_panel, name='RP4', type='8p8c', positions=3), ) - rear_port2 = RearPort.objects.create(device=patch_pannel, name='RP2', type='8p8c', positions=2) - front_port2 = FrontPort.objects.create( - device=patch_pannel, name='FP2', type='8p8c', rear_port=rear_port2, rear_port_position=1 - ) - rear_port3 = RearPort.objects.create(device=patch_pannel, name='RP3', type='8p8c', positions=3) - front_port3 = FrontPort.objects.create( - device=patch_pannel, name='FP3', type='8p8c', rear_port=rear_port3, rear_port_position=1 - ) - rear_port4 = RearPort.objects.create(device=patch_pannel, name='RP4', type='8p8c', positions=3) - front_port4 = FrontPort.objects.create( - device=patch_pannel, name='FP4', type='8p8c', rear_port=rear_port4, rear_port_position=1 + RearPort.objects.bulk_create(rear_ports) + front_ports = ( + FrontPort(device=patch_panel, name='FP1', type='8p8c', rear_port=rear_ports[0], rear_port_position=1), + FrontPort(device=patch_panel, name='FP2', type='8p8c', rear_port=rear_ports[1], rear_port_position=1), + FrontPort(device=patch_panel, name='FP3', type='8p8c', rear_port=rear_ports[2], rear_port_position=1), + FrontPort(device=patch_panel, name='FP4', type='8p8c', rear_port=rear_ports[3], rear_port_position=1), ) + FrontPort.objects.bulk_create(front_ports) + provider = Provider.objects.create(name='Provider 1', slug='provider-1') provider_network = ProviderNetwork.objects.create(name='Provider Network 1', provider=provider) circuittype = CircuitType.objects.create(name='Circuit Type 1', slug='circuit-type-1') circuit1 = Circuit.objects.create(provider=provider, type=circuittype, cid='1') circuit2 = Circuit.objects.create(provider=provider, type=circuittype, cid='2') - circuittermination1 = CircuitTermination.objects.create(circuit=circuit1, site=site, term_side='A') - circuittermination2 = CircuitTermination.objects.create(circuit=circuit1, site=site, term_side='Z') - circuittermination3 = CircuitTermination.objects.create(circuit=circuit2, provider_network=provider_network, term_side='A') + CircuitTermination.objects.create(circuit=circuit1, site=site, term_side='A') + CircuitTermination.objects.create(circuit=circuit1, site=site, term_side='Z') + CircuitTermination.objects.create(circuit=circuit2, provider_network=provider_network, term_side='A') def test_cable_creation(self): """ diff --git a/netbox/dcim/tests/test_views.py b/netbox/dcim/tests/test_views.py index 7d6c34337..e290a6d1d 100644 --- a/netbox/dcim/tests/test_views.py +++ b/netbox/dcim/tests/test_views.py @@ -2571,7 +2571,7 @@ class InterfaceTestCase(ViewTestCases.DeviceComponentViewTestCase): } cls.csv_data = ( - f"device,name,type,vrf.pk,poe_mode,poe_type", + "device,name,type,vrf.pk,poe_mode,poe_type", f"Device 1,Interface 4,1000base-t,{vrfs[0].pk},pse,type1-ieee802.3af", f"Device 1,Interface 5,1000base-t,{vrfs[0].pk},pse,type1-ieee802.3af", f"Device 1,Interface 6,1000base-t,{vrfs[0].pk},pse,type1-ieee802.3af", diff --git a/netbox/extras/api/nested_serializers.py b/netbox/extras/api/nested_serializers.py index ba291b34e..235cdd6d6 100644 --- a/netbox/extras/api/nested_serializers.py +++ b/netbox/extras/api/nested_serializers.py @@ -24,7 +24,7 @@ __all__ = [ # TODO: Remove in v4.2 warnings.warn( - f"Dedicated nested serializers will be removed in NetBox v4.2. Use Serializer(nested=True) instead.", + "Dedicated nested serializers will be removed in NetBox v4.2. Use Serializer(nested=True) instead.", DeprecationWarning ) diff --git a/netbox/extras/jobs.py b/netbox/extras/jobs.py index e540ef439..64a7d6a69 100644 --- a/netbox/extras/jobs.py +++ b/netbox/extras/jobs.py @@ -48,7 +48,7 @@ class ScriptJob(JobRunner): except AbortTransaction: script.log_info(message=_("Database changes have been reverted automatically.")) if script.failed: - logger.warning(f"Script failed") + logger.warning("Script failed") raise except Exception as e: diff --git a/netbox/extras/management/commands/housekeeping.py b/netbox/extras/management/commands/housekeeping.py index cb8137ee2..ade486fc0 100644 --- a/netbox/extras/management/commands/housekeeping.py +++ b/netbox/extras/management/commands/housekeeping.py @@ -95,7 +95,7 @@ class Command(BaseCommand): self.stdout.write("[*] Checking for latest release") if settings.ISOLATED_DEPLOYMENT: if options['verbosity']: - self.stdout.write(f"\tSkipping: ISOLATED_DEPLOYMENT is enabled") + self.stdout.write("\tSkipping: ISOLATED_DEPLOYMENT is enabled") elif settings.RELEASE_CHECK_URL: headers = { 'Accept': 'application/vnd.github.v3+json', @@ -129,7 +129,7 @@ class Command(BaseCommand): self.stdout.write(f"\tRequest error: {exc}", self.style.ERROR) else: if options['verbosity']: - self.stdout.write(f"\tSkipping: RELEASE_CHECK_URL not set") + self.stdout.write("\tSkipping: RELEASE_CHECK_URL not set") if options['verbosity']: self.stdout.write("Finished.", self.style.SUCCESS) diff --git a/netbox/extras/management/commands/reindex.py b/netbox/extras/management/commands/reindex.py index 5aab74511..21442be93 100644 --- a/netbox/extras/management/commands/reindex.py +++ b/netbox/extras/management/commands/reindex.py @@ -96,9 +96,9 @@ class Command(BaseCommand): if i: self.stdout.write(f'{i} entries cached.') else: - self.stdout.write(f'No objects found.') + self.stdout.write('No objects found.') - msg = f'Completed.' + msg = 'Completed.' if total_count := search_backend.size: msg += f' Total entries: {total_count}' self.stdout.write(msg, self.style.SUCCESS) diff --git a/netbox/extras/management/commands/runscript.py b/netbox/extras/management/commands/runscript.py index ab0d6d894..d5fb435ad 100644 --- a/netbox/extras/management/commands/runscript.py +++ b/netbox/extras/management/commands/runscript.py @@ -51,7 +51,7 @@ class Command(BaseCommand): user = User.objects.filter(is_superuser=True).order_by('pk')[0] # Setup logging to Stdout - formatter = logging.Formatter(f'[%(asctime)s][%(levelname)s] - %(message)s') + formatter = logging.Formatter('[%(asctime)s][%(levelname)s] - %(message)s') stdouthandler = logging.StreamHandler(sys.stdout) stdouthandler.setLevel(logging.DEBUG) stdouthandler.setFormatter(formatter) diff --git a/netbox/extras/models/customfields.py b/netbox/extras/models/customfields.py index 91de7df0d..8b7fc0cb6 100644 --- a/netbox/extras/models/customfields.py +++ b/netbox/extras/models/customfields.py @@ -283,7 +283,7 @@ class CustomField(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel): """ for ct in content_types: model = ct.model_class() - instances = model.objects.exclude(**{f'custom_field_data__contains': self.name}) + instances = model.objects.exclude(**{'custom_field_data__contains': self.name}) for instance in instances: instance.custom_field_data[self.name] = self.default model.objects.bulk_update(instances, ['custom_field_data'], batch_size=100) diff --git a/netbox/extras/scripts.py b/netbox/extras/scripts.py index 96d08d8af..f2bd75a1d 100644 --- a/netbox/extras/scripts.py +++ b/netbox/extras/scripts.py @@ -554,7 +554,7 @@ class BaseScript: """ Run the report and save its results. Each test method will be executed in order. """ - self.logger.info(f"Running report") + self.logger.info("Running report") try: for test_name in self.tests: diff --git a/netbox/extras/tests/test_customvalidators.py b/netbox/extras/tests/test_customvalidators.py index 49deb9da5..9f85b4913 100644 --- a/netbox/extras/tests/test_customvalidators.py +++ b/netbox/extras/tests/test_customvalidators.py @@ -162,7 +162,7 @@ class CustomValidatorTest(TestCase): Site(name='abcdef123', slug='abcdef123').clean() @override_settings(CUSTOM_VALIDATORS={'dcim.site': [region_validator]}) - def test_valid(self): + def test_related_object(self): region1 = Region(name='Foo', slug='foo') region1.save() region2 = Region(name='Bar', slug='bar') diff --git a/netbox/extras/tests/test_models.py b/netbox/extras/tests/test_models.py index c92a1bc54..188a06a3f 100644 --- a/netbox/extras/tests/test_models.py +++ b/netbox/extras/tests/test_models.py @@ -49,11 +49,11 @@ class ConfigContextTest(TestCase): sitegroup = SiteGroup.objects.create(name='Site Group') site = Site.objects.create(name='Site 1', slug='site-1', region=region, group=sitegroup) location = Location.objects.create(name='Location 1', slug='location-1', site=site) - platform = Platform.objects.create(name='Platform') + Platform.objects.create(name='Platform') tenantgroup = TenantGroup.objects.create(name='Tenant Group') - tenant = Tenant.objects.create(name='Tenant', group=tenantgroup) - tag1 = Tag.objects.create(name='Tag', slug='tag') - tag2 = Tag.objects.create(name='Tag2', slug='tag2') + Tenant.objects.create(name='Tenant', group=tenantgroup) + Tag.objects.create(name='Tag', slug='tag') + Tag.objects.create(name='Tag2', slug='tag2') Device.objects.create( name='Device 1', diff --git a/netbox/extras/tests/test_views.py b/netbox/extras/tests/test_views.py index 796d36180..5d82fae4c 100644 --- a/netbox/extras/tests/test_views.py +++ b/netbox/extras/tests/test_views.py @@ -417,7 +417,7 @@ class EventRulesTestCase(ViewTestCases.PrimaryObjectViewTestCase): } cls.csv_data = ( - f'name,object_types,event_types,action_type,action_object', + 'name,object_types,event_types,action_type,action_object', f'Webhook 4,dcim.site,"{OBJECT_CREATED},{OBJECT_UPDATED}",webhook,Webhook 1', ) diff --git a/netbox/ipam/api/nested_serializers.py b/netbox/ipam/api/nested_serializers.py index 57a1a65d5..8b10f29df 100644 --- a/netbox/ipam/api/nested_serializers.py +++ b/netbox/ipam/api/nested_serializers.py @@ -30,7 +30,7 @@ __all__ = [ # TODO: Remove in v4.2 warnings.warn( - f"Dedicated nested serializers will be removed in NetBox v4.2. Use Serializer(nested=True) instead.", + "Dedicated nested serializers will be removed in NetBox v4.2. Use Serializer(nested=True) instead.", DeprecationWarning ) diff --git a/netbox/ipam/api/views.py b/netbox/ipam/api/views.py index cac90bb87..ffd4d5b7d 100644 --- a/netbox/ipam/api/views.py +++ b/netbox/ipam/api/views.py @@ -186,13 +186,13 @@ class AvailableObjectsView(ObjectValidationMixin, APIView): """ Return the parent object. """ - raise NotImplemented() + raise NotImplementedError() def get_available_objects(self, parent, limit=None): """ Return all available objects for the parent. """ - raise NotImplemented() + raise NotImplementedError() def get_extra_context(self, parent): """ @@ -250,7 +250,7 @@ class AvailableObjectsView(ObjectValidationMixin, APIView): # Determine if the requested number of objects is available if not self.check_sufficient_available(serializer.validated_data, available_objects): return Response( - {"detail": f"Insufficient resources are available to satisfy the request"}, + {"detail": "Insufficient resources are available to satisfy the request"}, status=status.HTTP_409_CONFLICT ) diff --git a/netbox/ipam/graphql/mixins.py b/netbox/ipam/graphql/mixins.py index 757e62c74..692741871 100644 --- a/netbox/ipam/graphql/mixins.py +++ b/netbox/ipam/graphql/mixins.py @@ -10,9 +10,9 @@ __all__ = ( @strawberry.type class IPAddressesMixin: - ip_addresses: List[Annotated["IPAddressType", strawberry.lazy('ipam.graphql.types')]] + ip_addresses: List[Annotated["IPAddressType", strawberry.lazy('ipam.graphql.types')]] # noqa: F821 @strawberry.type class VLANGroupsMixin: - vlan_groups: List[Annotated["VLANGroupType", strawberry.lazy('ipam.graphql.types')]] + vlan_groups: List[Annotated["VLANGroupType", strawberry.lazy('ipam.graphql.types')]] # noqa: F821 diff --git a/netbox/ipam/tests/test_api.py b/netbox/ipam/tests/test_api.py index 59335cbbe..1d2cdf1b7 100644 --- a/netbox/ipam/tests/test_api.py +++ b/netbox/ipam/tests/test_api.py @@ -700,8 +700,6 @@ class IPAddressTest(APIViewTestCases.APIViewTestCase): device1.primary_ip4 = ip_addresses[0] device1.save() - ip2 = ip_addresses[1] - url = reverse('ipam-api:ipaddress-detail', kwargs={'pk': ip1.pk}) self.add_permissions('ipam.change_ipaddress') diff --git a/netbox/ipam/tests/test_views.py b/netbox/ipam/tests/test_views.py index 2acb80ac1..95b311878 100644 --- a/netbox/ipam/tests/test_views.py +++ b/netbox/ipam/tests/test_views.py @@ -50,7 +50,7 @@ class ASNRangeTestCase(ViewTestCases.PrimaryObjectViewTestCase): } cls.csv_data = ( - f"name,slug,rir,tenant,start,end,description", + "name,slug,rir,tenant,start,end,description", f"ASN Range 4,asn-range-4,{rirs[1].name},{tenants[1].name},400,499,Fourth range", f"ASN Range 5,asn-range-5,{rirs[1].name},{tenants[1].name},500,599,Fifth range", f"ASN Range 6,asn-range-6,{rirs[1].name},{tenants[1].name},600,699,Sixth range", @@ -770,14 +770,14 @@ class VLANGroupTestCase(ViewTestCases.OrganizationalObjectViewTestCase): } cls.csv_data = ( - f"name,slug,scope_type,scope_id,description", - f"VLAN Group 4,vlan-group-4,,,Fourth VLAN group", + "name,slug,scope_type,scope_id,description", + "VLAN Group 4,vlan-group-4,,,Fourth VLAN group", f"VLAN Group 5,vlan-group-5,dcim.site,{sites[0].pk},Fifth VLAN group", f"VLAN Group 6,vlan-group-6,dcim.site,{sites[1].pk},Sixth VLAN group", ) cls.csv_update_data = ( - f"id,name,description", + "id,name,description", f"{vlan_groups[0].pk},VLAN Group 7,Fourth VLAN group7", f"{vlan_groups[1].pk},VLAN Group 8,Fifth VLAN group8", f"{vlan_groups[2].pk},VLAN Group 9,Sixth VLAN group9", diff --git a/netbox/netbox/config/__init__.py b/netbox/netbox/config/__init__.py index 1c16d6769..23108f1d2 100644 --- a/netbox/netbox/config/__init__.py +++ b/netbox/netbox/config/__init__.py @@ -85,7 +85,7 @@ class Config: logger.debug("Loaded configuration data from database") except DatabaseError: # The database may not be available yet (e.g. when running a management command) - logger.warning(f"Skipping config initialization (database unavailable)") + logger.warning("Skipping config initialization (database unavailable)") return revision.activate() diff --git a/netbox/netbox/data_backends.py b/netbox/netbox/data_backends.py index d5bab75c1..e3a3de4d1 100644 --- a/netbox/netbox/data_backends.py +++ b/netbox/netbox/data_backends.py @@ -50,4 +50,4 @@ class DataBackend: 2. Yields the local path at which data has been replicated 3. Performs any necessary cleanup """ - raise NotImplemented() + raise NotImplementedError() diff --git a/netbox/netbox/navigation/menu.py b/netbox/netbox/navigation/menu.py index a1d65d6e2..9d8ffaaf8 100644 --- a/netbox/netbox/navigation/menu.py +++ b/netbox/netbox/navigation/menu.py @@ -386,57 +386,57 @@ ADMIN_MENU = Menu( label=_('Authentication'), items=( MenuItem( - link=f'users:user_list', + link='users:user_list', link_text=_('Users'), auth_required=True, - permissions=[f'users.view_user'], + permissions=['users.view_user'], buttons=( MenuItemButton( - link=f'users:user_add', + link='users:user_add', title='Add', icon_class='mdi mdi-plus-thick', - permissions=[f'users.add_user'] + permissions=['users.add_user'] ), MenuItemButton( - link=f'users:user_import', + link='users:user_import', title='Import', icon_class='mdi mdi-upload', - permissions=[f'users.add_user'] + permissions=['users.add_user'] ) ) ), MenuItem( - link=f'users:group_list', + link='users:group_list', link_text=_('Groups'), auth_required=True, - permissions=[f'users.view_group'], + permissions=['users.view_group'], buttons=( MenuItemButton( - link=f'users:group_add', + link='users:group_add', title='Add', icon_class='mdi mdi-plus-thick', - permissions=[f'users.add_group'] + permissions=['users.add_group'] ), MenuItemButton( - link=f'users:group_import', + link='users:group_import', title='Import', icon_class='mdi mdi-upload', - permissions=[f'users.add_group'] + permissions=['users.add_group'] ) ) ), MenuItem( - link=f'users:token_list', + link='users:token_list', link_text=_('API Tokens'), auth_required=True, - permissions=[f'users.view_token'], + permissions=['users.view_token'], buttons=get_model_buttons('users', 'token') ), MenuItem( - link=f'users:objectpermission_list', + link='users:objectpermission_list', link_text=_('Permissions'), auth_required=True, - permissions=[f'users.view_objectpermission'], + permissions=['users.view_objectpermission'], buttons=get_model_buttons('users', 'objectpermission', actions=['add']) ), ), diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index 9c5078ccb..a8ac68d4d 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -198,7 +198,7 @@ if len(SECRET_KEY) < 50: if RELEASE_CHECK_URL: try: URLValidator()(RELEASE_CHECK_URL) - except ValidationError as e: + except ValidationError: raise ImproperlyConfigured( "RELEASE_CHECK_URL must be a valid URL. Example: https://api.github.com/repos/netbox-community/netbox" ) diff --git a/netbox/netbox/staging.py b/netbox/netbox/staging.py index 4d37fb7ad..e6b946403 100644 --- a/netbox/netbox/staging.py +++ b/netbox/netbox/staging.py @@ -80,7 +80,7 @@ class checkout: Create Change instances for all actions stored in the queue. """ if not self.queue: - logger.debug(f"No queued changes; aborting") + logger.debug("No queued changes; aborting") return logger.debug(f"Processing {len(self.queue)} queued changes") diff --git a/netbox/netbox/tests/dummy_plugin/views.py b/netbox/netbox/tests/dummy_plugin/views.py index c4d80731f..82f250fc1 100644 --- a/netbox/netbox/tests/dummy_plugin/views.py +++ b/netbox/netbox/tests/dummy_plugin/views.py @@ -21,7 +21,7 @@ class DummyModelsView(View): class DummyModelAddView(View): def get(self, request): - return HttpResponse(f"Create an instance") + return HttpResponse("Create an instance") def post(self, request): instance = DummyModel( @@ -29,7 +29,7 @@ class DummyModelAddView(View): number=random.randint(1, 100000) ) instance.save() - return HttpResponse(f"Instance created") + return HttpResponse("Instance created") @register_model_view(Site, 'extra', path='other-stuff') diff --git a/netbox/netbox/tests/test_authentication.py b/netbox/netbox/tests/test_authentication.py index 5c7a30dc7..ae6d3f4c2 100644 --- a/netbox/netbox/tests/test_authentication.py +++ b/netbox/netbox/tests/test_authentication.py @@ -106,7 +106,7 @@ class ExternalAuthenticationTestCase(TestCase): self.assertEqual(settings.REMOTE_AUTH_HEADER, 'HTTP_REMOTE_USER') # Client should not be authenticated - response = self.client.get(reverse('home'), follow=True, **headers) + self.client.get(reverse('home'), follow=True, **headers) self.assertNotIn('_auth_user_id', self.client.session) @override_settings( diff --git a/netbox/netbox/tests/test_import.py b/netbox/netbox/tests/test_import.py index 03690029c..16711ef72 100644 --- a/netbox/netbox/tests/test_import.py +++ b/netbox/netbox/tests/test_import.py @@ -77,7 +77,6 @@ class CSVImportTestCase(ModelViewTestCase): self.assertHttpStatus(self.client.post(self._get_url('import'), data), 302) regions = Region.objects.all() self.assertEqual(regions.count(), 4) - region = Region.objects.get(slug="region-4") self.assertEqual( list(regions[0].tags.values_list('name', flat=True)), ['Alpha', 'Bravo'] diff --git a/netbox/tenancy/api/nested_serializers.py b/netbox/tenancy/api/nested_serializers.py index 5f339ecba..5adb78863 100644 --- a/netbox/tenancy/api/nested_serializers.py +++ b/netbox/tenancy/api/nested_serializers.py @@ -15,7 +15,7 @@ __all__ = [ # TODO: Remove in v4.2 warnings.warn( - f"Dedicated nested serializers will be removed in NetBox v4.2. Use Serializer(nested=True) instead.", + "Dedicated nested serializers will be removed in NetBox v4.2. Use Serializer(nested=True) instead.", DeprecationWarning ) diff --git a/netbox/tenancy/graphql/mixins.py b/netbox/tenancy/graphql/mixins.py index 2d97ba718..9cdba100e 100644 --- a/netbox/tenancy/graphql/mixins.py +++ b/netbox/tenancy/graphql/mixins.py @@ -10,4 +10,4 @@ __all__ = ( @strawberry.type class ContactAssignmentsMixin: - assignments: List[Annotated["ContactAssignmentType", strawberry.lazy('tenancy.graphql.types')]] + assignments: List[Annotated["ContactAssignmentType", strawberry.lazy('tenancy.graphql.types')]] # noqa: F821 diff --git a/netbox/users/api/nested_serializers.py b/netbox/users/api/nested_serializers.py index 2a5763476..201e38901 100644 --- a/netbox/users/api/nested_serializers.py +++ b/netbox/users/api/nested_serializers.py @@ -18,7 +18,7 @@ __all__ = [ # TODO: Remove in v4.2 warnings.warn( - f"Dedicated nested serializers will be removed in NetBox v4.2. Use Serializer(nested=True) instead.", + "Dedicated nested serializers will be removed in NetBox v4.2. Use Serializer(nested=True) instead.", DeprecationWarning ) diff --git a/netbox/users/api/views.py b/netbox/users/api/views.py index 240f68d36..bba9a4ec3 100644 --- a/netbox/users/api/views.py +++ b/netbox/users/api/views.py @@ -73,7 +73,7 @@ class TokenProvisionView(APIView): def perform_create(self, serializer): model = serializer.Meta.model - logger = logging.getLogger(f'netbox.api.views.TokenProvisionView') + logger = logging.getLogger('netbox.api.views.TokenProvisionView') logger.info(f"Creating new {model._meta.verbose_name}") serializer.save() diff --git a/netbox/users/forms/model_forms.py b/netbox/users/forms/model_forms.py index 639b9f726..42c3b15f0 100644 --- a/netbox/users/forms/model_forms.py +++ b/netbox/users/forms/model_forms.py @@ -36,7 +36,6 @@ class UserConfigFormMetaclass(forms.models.ModelFormMetaclass): # Emulate a declared field for each supported user preference preference_fields = {} for field_name, preference in PREFERENCES.items(): - description = f'{preference.description}
' if preference.description else '' help_text = f'{field_name}' if preference.description: help_text = f'{preference.description}
{help_text}' diff --git a/netbox/users/tests/test_preferences.py b/netbox/users/tests/test_preferences.py index b5037ec3f..13120d328 100644 --- a/netbox/users/tests/test_preferences.py +++ b/netbox/users/tests/test_preferences.py @@ -51,11 +51,11 @@ class UserPreferencesTest(TestCase): # Check that table ordering preference has been recorded self.user.refresh_from_db() - ordering = self.user.config.get(f'tables.SiteTable.ordering') + ordering = self.user.config.get('tables.SiteTable.ordering') self.assertEqual(ordering, ['status']) # Check that a recorded preference is honored by default - self.user.config.set(f'tables.SiteTable.ordering', ['-status'], commit=True) + self.user.config.set('tables.SiteTable.ordering', ['-status'], commit=True) table = SiteTable(Site.objects.all()) request = RequestFactory().get(url) request.user = self.user diff --git a/netbox/utilities/forms/fields/dynamic.py b/netbox/utilities/forms/fields/dynamic.py index bec067ba2..6666c0e4d 100644 --- a/netbox/utilities/forms/fields/dynamic.py +++ b/netbox/utilities/forms/fields/dynamic.py @@ -142,7 +142,7 @@ class DynamicModelChoiceMixin: if data: # When the field is multiple choice pass the data as a list if it's not already - if isinstance(bound_field.field, DynamicModelMultipleChoiceField) and not type(data) is list: + if isinstance(bound_field.field, DynamicModelMultipleChoiceField) and type(data) is not list: data = [data] field_name = getattr(self, 'to_field_name') or 'pk' diff --git a/netbox/utilities/html.py b/netbox/utilities/html.py index f99dabe5a..c9203d169 100644 --- a/netbox/utilities/html.py +++ b/netbox/utilities/html.py @@ -59,7 +59,7 @@ def highlight(value, highlight, trim_pre=None, trim_post=None, trim_placeholder= else: highlight = re.escape(highlight) pre, match, post = re.split(fr'({highlight})', value, maxsplit=1, flags=re.IGNORECASE) - except ValueError as e: + except ValueError: # Match not found return escape(value) diff --git a/netbox/utilities/tests/test_api.py b/netbox/utilities/tests/test_api.py index 81be70a34..ba0c3c4f8 100644 --- a/netbox/utilities/tests/test_api.py +++ b/netbox/utilities/tests/test_api.py @@ -149,7 +149,7 @@ class APIPaginationTestCase(APITestCase): self.assertHttpStatus(response, status.HTTP_200_OK) self.assertEqual(response.data['count'], 100) - self.assertTrue(response.data['next'].endswith(f'?limit=10&offset=10')) + self.assertTrue(response.data['next'].endswith('?limit=10&offset=10')) self.assertIsNone(response.data['previous']) self.assertEqual(len(response.data['results']), 10) @@ -159,7 +159,7 @@ class APIPaginationTestCase(APITestCase): self.assertHttpStatus(response, status.HTTP_200_OK) self.assertEqual(response.data['count'], 100) - self.assertTrue(response.data['next'].endswith(f'?limit=20&offset=20')) + self.assertTrue(response.data['next'].endswith('?limit=20&offset=20')) self.assertIsNone(response.data['previous']) self.assertEqual(len(response.data['results']), 20) diff --git a/netbox/utilities/tests/test_counters.py b/netbox/utilities/tests/test_counters.py index b87e73ace..45823065e 100644 --- a/netbox/utilities/tests/test_counters.py +++ b/netbox/utilities/tests/test_counters.py @@ -85,7 +85,7 @@ class CountersTest(TestCase): def test_mptt_child_delete(self): device1, device2 = Device.objects.all() inventory_item1 = InventoryItem.objects.create(device=device1, name='Inventory Item 1') - inventory_item2 = InventoryItem.objects.create(device=device1, name='Inventory Item 2', parent=inventory_item1) + InventoryItem.objects.create(device=device1, name='Inventory Item 2', parent=inventory_item1) device1.refresh_from_db() self.assertEqual(device1.inventory_item_count, 2) diff --git a/netbox/virtualization/api/nested_serializers.py b/netbox/virtualization/api/nested_serializers.py index a2395faa5..59016f74d 100644 --- a/netbox/virtualization/api/nested_serializers.py +++ b/netbox/virtualization/api/nested_serializers.py @@ -18,7 +18,7 @@ __all__ = [ # TODO: Remove in v4.2 warnings.warn( - f"Dedicated nested serializers will be removed in NetBox v4.2. Use Serializer(nested=True) instead.", + "Dedicated nested serializers will be removed in NetBox v4.2. Use Serializer(nested=True) instead.", DeprecationWarning ) diff --git a/netbox/virtualization/tests/test_views.py b/netbox/virtualization/tests/test_views.py index 0daa55a5c..3c6a058c9 100644 --- a/netbox/virtualization/tests/test_views.py +++ b/netbox/virtualization/tests/test_views.py @@ -354,14 +354,14 @@ class VMInterfaceTestCase(ViewTestCases.DeviceComponentViewTestCase): } cls.csv_data = ( - f"virtual_machine,name,vrf.pk", + "virtual_machine,name,vrf.pk", f"Virtual Machine 2,Interface 4,{vrfs[0].pk}", f"Virtual Machine 2,Interface 5,{vrfs[0].pk}", f"Virtual Machine 2,Interface 6,{vrfs[0].pk}", ) cls.csv_update_data = ( - f"id,name,description", + "id,name,description", f"{interfaces[0].pk},Interface 7,New description 7", f"{interfaces[1].pk},Interface 8,New description 8", f"{interfaces[2].pk},Interface 9,New description 9", @@ -438,14 +438,14 @@ class VirtualDiskTestCase(ViewTestCases.DeviceComponentViewTestCase): } cls.csv_data = ( - f"virtual_machine,name,size,description", - f"Virtual Machine 1,Disk 4,20,Fourth", - f"Virtual Machine 1,Disk 5,20,Fifth", - f"Virtual Machine 1,Disk 6,20,Sixth", + "virtual_machine,name,size,description", + "Virtual Machine 1,Disk 4,20,Fourth", + "Virtual Machine 1,Disk 5,20,Fifth", + "Virtual Machine 1,Disk 6,20,Sixth", ) cls.csv_update_data = ( - f"id,name,size", + "id,name,size", f"{disks[0].pk},disk1,20", f"{disks[1].pk},disk2,20", f"{disks[2].pk},disk3,20", diff --git a/netbox/virtualization/views.py b/netbox/virtualization/views.py index ad3487b8b..0828d3a2a 100644 --- a/netbox/virtualization/views.py +++ b/netbox/virtualization/views.py @@ -657,7 +657,7 @@ class VirtualMachineBulkAddInterfaceView(generic.BulkComponentCreateView): default_return_url = 'virtualization:virtualmachine_list' def get_required_permission(self): - return f'virtualization.add_vminterface' + return 'virtualization.add_vminterface' class VirtualMachineBulkAddVirtualDiskView(generic.BulkComponentCreateView): @@ -671,4 +671,4 @@ class VirtualMachineBulkAddVirtualDiskView(generic.BulkComponentCreateView): default_return_url = 'virtualization:virtualmachine_list' def get_required_permission(self): - return f'virtualization.add_virtualdisk' + return 'virtualization.add_virtualdisk' diff --git a/netbox/vpn/api/nested_serializers.py b/netbox/vpn/api/nested_serializers.py index c1a90cbea..59e394c2e 100644 --- a/netbox/vpn/api/nested_serializers.py +++ b/netbox/vpn/api/nested_serializers.py @@ -21,7 +21,7 @@ __all__ = ( # TODO: Remove in v4.2 warnings.warn( - f"Dedicated nested serializers will be removed in NetBox v4.2. Use Serializer(nested=True) instead.", + "Dedicated nested serializers will be removed in NetBox v4.2. Use Serializer(nested=True) instead.", DeprecationWarning ) diff --git a/netbox/vpn/filtersets.py b/netbox/vpn/filtersets.py index 92aa702c6..6403b662f 100644 --- a/netbox/vpn/filtersets.py +++ b/netbox/vpn/filtersets.py @@ -147,17 +147,6 @@ class IKEProposalFilterSet(NetBoxModelFilterSet): group = django_filters.MultipleChoiceFilter( choices=DHGroupChoices ) - ike_policy_id = django_filters.ModelMultipleChoiceFilter( - field_name='ike_policies', - queryset=IKEPolicy.objects.all(), - label=_('IKE policy (ID)'), - ) - ike_policy = django_filters.ModelMultipleChoiceFilter( - field_name='ike_policies__name', - queryset=IKEPolicy.objects.all(), - to_field_name='name', - label=_('IKE policy (name)'), - ) class Meta: model = IKEProposal diff --git a/netbox/vpn/tests/test_filtersets.py b/netbox/vpn/tests/test_filtersets.py index 0b9c79420..d2b893766 100644 --- a/netbox/vpn/tests/test_filtersets.py +++ b/netbox/vpn/tests/test_filtersets.py @@ -385,13 +385,6 @@ class IKEProposalTestCase(TestCase, ChangeLoggedFilterSetTests): params = {'sa_lifetime': [1000, 2000]} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) - def test_ike_policy(self): - ike_policies = IKEPolicy.objects.all()[:2] - params = {'ike_policy_id': [ike_policies[0].pk, ike_policies[1].pk]} - self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) - params = {'ike_policy': [ike_policies[0].name, ike_policies[1].name]} - self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) - class IKEPolicyTestCase(TestCase, ChangeLoggedFilterSetTests): queryset = IKEPolicy.objects.all() diff --git a/netbox/vpn/tests/test_views.py b/netbox/vpn/tests/test_views.py index 105ca0b6f..05ac527fe 100644 --- a/netbox/vpn/tests/test_views.py +++ b/netbox/vpn/tests/test_views.py @@ -542,9 +542,9 @@ class IPSecProfileTestCase(ViewTestCases.PrimaryObjectViewTestCase): cls.csv_data = ( "name,mode,ike_policy,ipsec_policy", - f"IKE Proposal 4,ah,IKE Policy 2,IPSec Policy 2", - f"IKE Proposal 5,ah,IKE Policy 2,IPSec Policy 2", - f"IKE Proposal 6,ah,IKE Policy 2,IPSec Policy 2", + "IKE Proposal 4,ah,IKE Policy 2,IPSec Policy 2", + "IKE Proposal 5,ah,IKE Policy 2,IPSec Policy 2", + "IKE Proposal 6,ah,IKE Policy 2,IPSec Policy 2", ) cls.csv_update_data = ( @@ -661,7 +661,7 @@ class L2VPNTerminationTestCase( ) cls.csv_update_data = ( - f"id,l2vpn", + "id,l2vpn", f"{terminations[0].pk},{l2vpns[0].name}", f"{terminations[1].pk},{l2vpns[0].name}", f"{terminations[2].pk},{l2vpns[0].name}", diff --git a/netbox/wireless/api/nested_serializers.py b/netbox/wireless/api/nested_serializers.py index 433164e60..9b8b6c3e3 100644 --- a/netbox/wireless/api/nested_serializers.py +++ b/netbox/wireless/api/nested_serializers.py @@ -12,7 +12,7 @@ __all__ = ( # TODO: Remove in v4.2 warnings.warn( - f"Dedicated nested serializers will be removed in NetBox v4.2. Use Serializer(nested=True) instead.", + "Dedicated nested serializers will be removed in NetBox v4.2. Use Serializer(nested=True) instead.", DeprecationWarning ) diff --git a/netbox/wireless/tests/test_views.py b/netbox/wireless/tests/test_views.py index 055edf73c..a4dc2aae5 100644 --- a/netbox/wireless/tests/test_views.py +++ b/netbox/wireless/tests/test_views.py @@ -102,14 +102,14 @@ class WirelessLANTestCase(ViewTestCases.PrimaryObjectViewTestCase): } cls.csv_data = ( - f"group,ssid,status,tenant", + "group,ssid,status,tenant", f"Wireless LAN Group 2,WLAN4,{WirelessLANStatusChoices.STATUS_ACTIVE},{tenants[0].name}", f"Wireless LAN Group 2,WLAN5,{WirelessLANStatusChoices.STATUS_DISABLED},{tenants[1].name}", f"Wireless LAN Group 2,WLAN6,{WirelessLANStatusChoices.STATUS_RESERVED},{tenants[2].name}", ) cls.csv_update_data = ( - f"id,ssid", + "id,ssid", f"{wireless_lans[0].pk},WLAN7", f"{wireless_lans[1].pk},WLAN8", f"{wireless_lans[2].pk},WLAN9", @@ -167,7 +167,7 @@ class WirelessLinkTestCase(ViewTestCases.PrimaryObjectViewTestCase): } cls.csv_data = ( - f"interface_a,interface_b,status,tenant", + "interface_a,interface_b,status,tenant", f"{interfaces[6].pk},{interfaces[7].pk},connected,{tenants[0].name}", f"{interfaces[8].pk},{interfaces[9].pk},connected,{tenants[1].name}", f"{interfaces[10].pk},{interfaces[11].pk},connected,{tenants[2].name}", diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 000000000..854404469 --- /dev/null +++ b/ruff.toml @@ -0,0 +1,2 @@ +[lint] +ignore = ["E501", "F403", "F405"] diff --git a/scripts/git-hooks/pre-commit b/scripts/git-hooks/pre-commit index 2ccf8df89..4b4ca172f 100755 --- a/scripts/git-hooks/pre-commit +++ b/scripts/git-hooks/pre-commit @@ -28,8 +28,8 @@ if [ ${NOVALIDATE} ]; then exit $EXIT fi -echo "Validating PEP8 compliance..." -pycodestyle --ignore=W504,E501 --exclude=node_modules netbox/ +echo "Linting with ruff..." +ruff check netbox/ if [ $? != 0 ]; then EXIT=1 fi