diff --git a/netbox/account/views.py b/netbox/account/views.py index b0502f939..98c81642f 100644 --- a/netbox/account/views.py +++ b/netbox/account/views.py @@ -140,9 +140,8 @@ class LoginView(View): return response - else: - username = form['username'].value() - logger.debug(f"Login form validation failed for username: {remove_linebreaks(username)}") + username = form['username'].value() + logger.debug(f"Login form validation failed for username: {remove_linebreaks(username)}") return render(request, self.template_name, { 'form': form, diff --git a/netbox/circuits/models/virtual_circuits.py b/netbox/circuits/models/virtual_circuits.py index bdaa6309c..798f676f2 100644 --- a/netbox/circuits/models/virtual_circuits.py +++ b/netbox/circuits/models/virtual_circuits.py @@ -185,6 +185,8 @@ class VirtualCircuitTermination( return self.virtual_circuit.terminations.filter( role=VirtualCircuitTerminationRoleChoices.ROLE_HUB ) + # Fallback for unexpected roles + return self.virtual_circuit.terminations.none() def clean(self): super().clean() diff --git a/netbox/core/api/schema.py b/netbox/core/api/schema.py index adc341f9c..c11ca53f7 100644 --- a/netbox/core/api/schema.py +++ b/netbox/core/api/schema.py @@ -39,7 +39,7 @@ class ChoiceFieldFix(OpenApiSerializerFieldExtension): if direction == 'request': return build_cf - elif direction == "response": + if direction == "response": value = build_cf label = { **build_basic_type(OpenApiTypes.STR), @@ -53,6 +53,10 @@ class ChoiceFieldFix(OpenApiSerializerFieldExtension): } ) + # TODO: This function should never implicitly/explicitly return `None` + # The fallback should be well-defined (drf-spectacular expects request/response naming). + return None + def viewset_handles_bulk_create(view): """Check if view automatically provides list-based bulk create""" @@ -75,8 +79,7 @@ class NetBoxAutoSchema(AutoSchema): def is_bulk_action(self): if hasattr(self.view, "action") and self.view.action in BULK_ACTIONS: return True - else: - return False + return False def get_operation_id(self): """ @@ -316,8 +319,7 @@ class FixSerializedPKRelatedField(OpenApiSerializerFieldExtension): if direction == "response": component = auto_schema.resolve_serializer(self.target.serializer, direction) return component.ref if component else None - else: - return build_basic_type(OpenApiTypes.INT) + return build_basic_type(OpenApiTypes.INT) class FixIntegerRangeSerializerSchema(OpenApiSerializerExtension): diff --git a/netbox/core/api/serializers_/object_types.py b/netbox/core/api/serializers_/object_types.py index c36796b5f..e9e7db5ef 100644 --- a/netbox/core/api/serializers_/object_types.py +++ b/netbox/core/api/serializers_/object_types.py @@ -34,14 +34,14 @@ class ObjectTypeSerializer(BaseModelSerializer): @extend_schema_field(OpenApiTypes.STR) def get_rest_api_endpoint(self, obj): if not (model := obj.model_class()): - return + return None try: return get_action_url(model, action='list', rest_api=True) except NoReverseMatch: - return + return None @extend_schema_field(OpenApiTypes.STR) def get_description(self, obj): if not (model := obj.model_class()): - return + return None return inspect.getdoc(model) diff --git a/netbox/core/api/views.py b/netbox/core/api/views.py index ab766c9dc..bea332f1b 100644 --- a/netbox/core/api/views.py +++ b/netbox/core/api/views.py @@ -285,5 +285,4 @@ class BackgroundTaskViewSet(BaseRQViewSet): stopped_jobs = stop_rq_job(id) if len(stopped_jobs) == 1: return HttpResponse(status=200) - else: - return HttpResponse(status=204) + return HttpResponse(status=204) diff --git a/netbox/core/management/commands/nbshell.py b/netbox/core/management/commands/nbshell.py index 7b7cee0bc..637719a61 100644 --- a/netbox/core/management/commands/nbshell.py +++ b/netbox/core/management/commands/nbshell.py @@ -144,7 +144,7 @@ class Command(BaseCommand): # If Python code has been passed, execute it and exit. if options['command']: exec(options['command'], namespace) - return + return None # Try to enable tab-complete try: diff --git a/netbox/core/models/data.py b/netbox/core/models/data.py index 8b4d0fd79..1047fbd14 100644 --- a/netbox/core/models/data.py +++ b/netbox/core/models/data.py @@ -98,6 +98,7 @@ class DataSource(JobsMixin, PrimaryModel): def get_type_display(self): if backend := registry['data_backends'].get(self.type): return backend.label + return None def get_status_color(self): return DataSourceStatusChoices.colors.get(self.status) diff --git a/netbox/core/models/files.py b/netbox/core/models/files.py index 63027c587..49cfbe2a3 100644 --- a/netbox/core/models/files.py +++ b/netbox/core/models/files.py @@ -79,8 +79,7 @@ class ManagedFile(SyncedDataMixin, models.Model): 'scripts': settings.SCRIPTS_ROOT, 'reports': settings.REPORTS_ROOT, }[self.file_root] - else: - return "" + return "" def sync_data(self): if self.data_file: diff --git a/netbox/core/models/jobs.py b/netbox/core/models/jobs.py index f48947883..cc759c952 100644 --- a/netbox/core/models/jobs.py +++ b/netbox/core/models/jobs.py @@ -146,7 +146,7 @@ class Job(models.Model): if self.object_type: if self.object_type.model == 'reportmodule': return reverse('extras:report_result', kwargs={'job_pk': self.pk}) - elif self.object_type.model == 'scriptmodule': + if self.object_type.model == 'scriptmodule': return reverse('extras:script_result', kwargs={'job_pk': self.pk}) return reverse('core:job', args=[self.pk]) diff --git a/netbox/core/models/object_types.py b/netbox/core/models/object_types.py index 1daeb2c4b..bb18f50b6 100644 --- a/netbox/core/models/object_types.py +++ b/netbox/core/models/object_types.py @@ -218,19 +218,22 @@ class ObjectType(ContentType): def app_verbose_name(self): if model := self.model_class(): return model._meta.app_config.verbose_name + return None @property def model_verbose_name(self): if model := self.model_class(): return model._meta.verbose_name + return None @property def model_verbose_name_plural(self): if model := self.model_class(): return model._meta.verbose_name_plural + return None @property def is_plugin_model(self): if not (model := self.model_class()): - return # Return null if model class is invalid + return None # Return null if model class is invalid return isinstance(model._meta.app_config, PluginConfig) diff --git a/netbox/dcim/api/serializers_/base.py b/netbox/dcim/api/serializers_/base.py index 3b9142f1d..c60454937 100644 --- a/netbox/dcim/api/serializers_/base.py +++ b/netbox/dcim/api/serializers_/base.py @@ -23,6 +23,7 @@ class ConnectedEndpointsSerializer(serializers.ModelSerializer): def get_connected_endpoints_type(self, obj): if endpoints := obj.connected_endpoints: return f'{endpoints[0]._meta.app_label}.{endpoints[0]._meta.model_name}' + return None @extend_schema_field(serializers.ListField(allow_null=True)) def get_connected_endpoints(self, obj): @@ -33,6 +34,7 @@ class ConnectedEndpointsSerializer(serializers.ModelSerializer): serializer = get_serializer_for_model(endpoints[0]) context = {'request': self.context['request']} return serializer(endpoints, nested=True, many=True, context=context).data + return None @extend_schema_field(serializers.BooleanField) def get_connected_endpoints_reachable(self, obj): diff --git a/netbox/dcim/api/views.py b/netbox/dcim/api/views.py index 8a9d32c69..da1f2379e 100644 --- a/netbox/dcim/api/views.py +++ b/netbox/dcim/api/views.py @@ -222,24 +222,26 @@ class RackViewSet(NetBoxModelViewSet): ) return HttpResponse(drawing.tostring(), content_type='image/svg+xml') - else: - # Return a JSON representation of the rack units in the elevation - elevation = rack.get_rack_units( - face=data['face'], - user=request.user, - exclude=data['exclude'], - expand_devices=data['expand_devices'] - ) + # Return a JSON representation of the rack units in the elevation + elevation = rack.get_rack_units( + face=data['face'], + user=request.user, + exclude=data['exclude'], + expand_devices=data['expand_devices'] + ) - # Enable filtering rack units by ID - if q := data['q']: - q = q.lower() - elevation = [u for u in elevation if q in str(u['id']) or q in str(u['name']).lower()] + # Enable filtering rack units by ID + if q := data['q']: + q = q.lower() + elevation = [u for u in elevation if q in str(u['id']) or q in str(u['name']).lower()] - page = self.paginate_queryset(elevation) - if page is not None: - rack_units = serializers.RackUnitSerializer(page, many=True, context={'request': request}) - return self.get_paginated_response(rack_units.data) + page = self.paginate_queryset(elevation) + if page is not None: + rack_units = serializers.RackUnitSerializer(page, many=True, context={'request': request}) + return self.get_paginated_response(rack_units.data) + + # TODO: This endpoint should always return an HttpResponse/DRF Response; `None` is not a meaningful result. + return None # diff --git a/netbox/dcim/filtersets.py b/netbox/dcim/filtersets.py index 09f76d60b..98ca71cdf 100644 --- a/netbox/dcim/filtersets.py +++ b/netbox/dcim/filtersets.py @@ -704,14 +704,12 @@ class DeviceTypeFilterSet(PrimaryModelFilterSet): def _has_front_image(self, queryset, name, value): if value: return queryset.exclude(front_image='') - else: - return queryset.filter(front_image='') + return queryset.filter(front_image='') def _has_rear_image(self, queryset, name, value): if value: return queryset.exclude(rear_image='') - else: - return queryset.filter(rear_image='') + return queryset.filter(rear_image='') def _console_ports(self, queryset, name, value): return queryset.exclude(consoleporttemplates__isnull=value) @@ -1855,8 +1853,7 @@ class CabledObjectFilterSet(django_filters.FilterSet): def filter_occupied(self, queryset, name, value): if value: return queryset.filter(Q(cable__isnull=False) | Q(mark_connected=True)) - else: - return queryset.filter(cable__isnull=True, mark_connected=False) + return queryset.filter(cable__isnull=True, mark_connected=False) class PathEndpointFilterSet(django_filters.FilterSet): @@ -1867,8 +1864,7 @@ class PathEndpointFilterSet(django_filters.FilterSet): def filter_connected(self, queryset, name, value): if value: return queryset.filter(_path__is_active=True) - else: - return queryset.filter(Q(_path__isnull=True) | Q(_path__is_active=False)) + return queryset.filter(Q(_path__isnull=True) | Q(_path__is_active=False)) @register_filterset @@ -2045,8 +2041,7 @@ class MACAddressFilterSet(PrimaryModelFilterSet): } if value: return queryset.exclude(**params) - else: - return queryset.filter(**params) + return queryset.filter(**params) def filter_primary(self, queryset, name, value): interface_mac_ids = Interface.objects.filter(primary_mac_address_id__isnull=False).values_list( @@ -2058,8 +2053,7 @@ class MACAddressFilterSet(PrimaryModelFilterSet): query = Q(pk__in=interface_mac_ids) | Q(pk__in=vminterface_mac_ids) if value: return queryset.filter(query) - else: - return queryset.exclude(query) + return queryset.exclude(query) class CommonInterfaceFilterSet(django_filters.FilterSet): @@ -2302,12 +2296,11 @@ class InterfaceFilterSet( Q(wireless_link__isnull=False) | Q(mark_connected=True) ) - else: - return queryset.filter( - cable__isnull=True, - wireless_link__isnull=True, - mark_connected=False - ) + return queryset.filter( + cable__isnull=True, + wireless_link__isnull=True, + mark_connected=False + ) @register_filterset @@ -2677,10 +2670,9 @@ class CableFilterSet(TenancyFilterSet, PrimaryModelFilterSet): .values("id") ) return queryset.exclude(id__in=terminated_ids) - else: - return queryset.filter(terminations__cable_end=CableEndChoices.SIDE_A).filter( - terminations__cable_end=CableEndChoices.SIDE_B - ) + return queryset.filter(terminations__cable_end=CableEndChoices.SIDE_A).filter( + terminations__cable_end=CableEndChoices.SIDE_B + ) def filter_by_termination_object(self, queryset, model, value): # Filter by specific termination object(s) diff --git a/netbox/dcim/forms/bulk_edit.py b/netbox/dcim/forms/bulk_edit.py index 8f4396e20..3e84124ef 100644 --- a/netbox/dcim/forms/bulk_edit.py +++ b/netbox/dcim/forms/bulk_edit.py @@ -1598,7 +1598,7 @@ class InterfaceBulkEditForm( if not self.cleaned_data['mode']: if self.cleaned_data['untagged_vlan']: raise forms.ValidationError({'untagged_vlan': _("Interface mode must be specified to assign VLANs")}) - elif self.cleaned_data['tagged_vlans']: + if self.cleaned_data['tagged_vlans']: raise forms.ValidationError({'tagged_vlans': _("Interface mode must be specified to assign VLANs")}) # Untagged interfaces cannot be assigned tagged VLANs diff --git a/netbox/dcim/forms/bulk_import.py b/netbox/dcim/forms/bulk_import.py index e26ab3b0d..e5a06118e 100644 --- a/netbox/dcim/forms/bulk_import.py +++ b/netbox/dcim/forms/bulk_import.py @@ -796,8 +796,7 @@ class ModuleImportForm(ModuleCommonForm, PrimaryModelImportForm): # Make sure replicate_components is True when it's not included in the uploaded data if 'replicate_components' not in self.data: return True - else: - return self.cleaned_data['replicate_components'] + return self.cleaned_data['replicate_components'] # @@ -1079,8 +1078,7 @@ class InterfaceImportForm(OwnerCSVMixin, NetBoxModelImportForm): # Make sure enabled is True when it's not included in the uploaded data if 'enabled' not in self.data: return True - else: - return self.cleaned_data['enabled'] + return self.cleaned_data['enabled'] def clean_vdcs(self): for vdc in self.cleaned_data['vdcs']: diff --git a/netbox/dcim/forms/model_forms.py b/netbox/dcim/forms/model_forms.py index 2ad36d4fc..1d5e05b5f 100644 --- a/netbox/dcim/forms/model_forms.py +++ b/netbox/dcim/forms/model_forms.py @@ -1360,7 +1360,7 @@ class InventoryItemTemplateForm(ComponentTemplateForm): ] if len(selected_objects) > 1: raise forms.ValidationError(_("An InventoryItem can only be assigned to a single component.")) - elif selected_objects: + if selected_objects: self.instance.component = self.cleaned_data[selected_objects[0]] else: self.instance.component = None @@ -1846,7 +1846,7 @@ class InventoryItemForm(DeviceComponentForm): ] if len(selected_objects) > 1: raise forms.ValidationError(_("An InventoryItem can only be assigned to a single component.")) - elif selected_objects: + if selected_objects: self.instance.component = self.cleaned_data[selected_objects[0]] else: self.instance.component = None @@ -1981,7 +1981,7 @@ class MACAddressForm(PrimaryModelForm): raise forms.ValidationError({ selected_objects[1]: _("A MAC address can only be assigned to a single object.") }) - elif selected_objects: + if selected_objects: self.instance.assigned_object = self.cleaned_data[selected_objects[0]] else: self.instance.assigned_object = None diff --git a/netbox/dcim/graphql/filters.py b/netbox/dcim/graphql/filters.py index df878d3a3..dc6dd6c17 100644 --- a/netbox/dcim/graphql/filters.py +++ b/netbox/dcim/graphql/filters.py @@ -486,8 +486,7 @@ class MACAddressFilter(PrimaryModelFilter): query = Q(**{f'{prefix}pk__in': interface_mac_ids}) | Q(**{f'{prefix}pk__in': vminterface_mac_ids}) if value: return Q(query) - else: - return ~Q(query) + return ~Q(query) @strawberry_django.filter_type(models.Interface, lookups=True) @@ -571,8 +570,7 @@ class InterfaceFilter( def connected(self, queryset, value: bool, prefix: str): if value is True: return queryset, Q(**{f"{prefix}_path__is_active": True}) - else: - return queryset, Q(**{f"{prefix}_path__isnull": True}) | Q(**{f"{prefix}_path__is_active": False}) + return queryset, Q(**{f"{prefix}_path__isnull": True}) | Q(**{f"{prefix}_path__is_active": False}) @strawberry_django.filter_field def kind( @@ -583,10 +581,11 @@ class InterfaceFilter( ): if value == InterfaceKindEnum.KIND_PHYSICAL: return queryset, ~Q(**{f"{prefix}type__in": NONCONNECTABLE_IFACE_TYPES}) - elif value == InterfaceKindEnum.KIND_VIRTUAL: + if value == InterfaceKindEnum.KIND_VIRTUAL: return queryset, Q(**{f"{prefix}type__in": VIRTUAL_IFACE_TYPES}) - elif value == InterfaceKindEnum.KIND_WIRELESS: + if value == InterfaceKindEnum.KIND_WIRELESS: return queryset, Q(**{f"{prefix}type__in": WIRELESS_IFACE_TYPES}) + return queryset, Q() @strawberry_django.filter_type(models.InterfaceTemplate, lookups=True) diff --git a/netbox/dcim/graphql/gfk_mixins.py b/netbox/dcim/graphql/gfk_mixins.py index 4d0948207..8350f664f 100644 --- a/netbox/dcim/graphql/gfk_mixins.py +++ b/netbox/dcim/graphql/gfk_mixins.py @@ -66,6 +66,7 @@ class InventoryItemTemplateComponentType: return PowerPortTemplateType if type(instance) is RearPortTemplate: return RearPortTemplateType + return None class InventoryItemComponentType: @@ -96,6 +97,7 @@ class InventoryItemComponentType: return PowerPortType if type(instance) is RearPort: return RearPortType + return None class ConnectedEndpointType: @@ -135,3 +137,4 @@ class ConnectedEndpointType: return ProviderNetworkType if type(instance) is RearPort: return RearPortType + return None diff --git a/netbox/dcim/models/cables.py b/netbox/dcim/models/cables.py index 09ca106c7..21cd37e02 100644 --- a/netbox/dcim/models/cables.py +++ b/netbox/dcim/models/cables.py @@ -673,12 +673,14 @@ class CablePath(models.Model): if self.path: ct_id, _ = decompile_path_node(self.path[0][0]) return ContentType.objects.get_for_id(ct_id) + return None @property def destination_type(self): if self.is_complete: ct_id, _ = decompile_path_node(self.path[-1][0]) return ContentType.objects.get_for_id(ct_id) + return None @property def _path_decompiled(self): @@ -921,7 +923,7 @@ class CablePath(models.Model): if not circuit_terminations.exists(): break - elif all([ct._provider_network for ct in circuit_terminations]): + if all([ct._provider_network for ct in circuit_terminations]): # Circuit terminates to a ProviderNetwork path.extend([ [object_to_path_node(ct) for ct in circuit_terminations], @@ -929,14 +931,14 @@ class CablePath(models.Model): ]) is_complete = True break - elif all([ct.termination and not ct.cable for ct in circuit_terminations]): + if all([ct.termination and not ct.cable for ct in circuit_terminations]): # Circuit terminates to a Region/Site/etc. path.extend([ [object_to_path_node(ct) for ct in circuit_terminations], [object_to_path_node(ct.termination) for ct in circuit_terminations], ]) break - elif any([ct.cable in links for ct in circuit_terminations]): + if any([ct.cable in links for ct in circuit_terminations]): # No valid path is_split = True break diff --git a/netbox/dcim/models/device_components.py b/netbox/dcim/models/device_components.py index feda9db71..176f00d85 100644 --- a/netbox/dcim/models/device_components.py +++ b/netbox/dcim/models/device_components.py @@ -731,6 +731,7 @@ class BaseInterface(models.Model): def mac_address(self): if self.primary_mac_address: return self.primary_mac_address.mac_address + return None class Interface( @@ -943,7 +944,7 @@ class Interface( "The selected parent interface ({interface}) belongs to a different device ({device})" ).format(interface=self.parent, device=self.parent.device) }) - elif self.parent.device.virtual_chassis != self.device.virtual_chassis: + if self.parent.device.virtual_chassis != self.device.virtual_chassis: raise ValidationError({ 'parent': _( "The selected parent interface ({interface}) belongs to {device}, which is not part of " @@ -965,7 +966,7 @@ class Interface( "The selected bridge interface ({bridge}) belongs to a different device ({device})." ).format(bridge=self.bridge, device=self.bridge.device) }) - elif self.bridge.device.virtual_chassis != self.device.virtual_chassis: + if self.bridge.device.virtual_chassis != self.device.virtual_chassis: raise ValidationError({ 'bridge': _( "The selected bridge interface ({interface}) belongs to {device}, which is not part of virtual " @@ -993,7 +994,7 @@ class Interface( "The selected LAG interface ({lag}) belongs to a different device ({device})." ).format(lag=self.lag, device=self.lag.device) }) - elif self.lag.device.virtual_chassis != self.device.virtual_chassis: + if self.lag.device.virtual_chassis != self.device.virtual_chassis: raise ValidationError({ 'lag': _( "The selected LAG interface ({lag}) belongs to {device}, which is not part of virtual chassis " @@ -1085,8 +1086,7 @@ class Interface( # Return the opposite side of the attached wireless link if self.wireless_link.interface_a == self: return [self.wireless_link.interface_b] - else: - return [self.wireless_link.interface_a] + return [self.wireless_link.interface_a] return [] @property diff --git a/netbox/dcim/models/devices.py b/netbox/dcim/models/devices.py index fd5e7a7ec..4a5d0b3cd 100644 --- a/netbox/dcim/models/devices.py +++ b/netbox/dcim/models/devices.py @@ -762,11 +762,11 @@ class Device( def __str__(self): if self.label and self.asset_tag: return f'{self.label} ({self.asset_tag})' - elif self.label: + if self.label: return self.label - elif self.device_type and self.asset_tag: + if self.device_type and self.asset_tag: return f'{self.device_type.manufacturer} {self.device_type.model} ({self.asset_tag})' - elif self.device_type: + if self.device_type: return f'{self.device_type.manufacturer} {self.device_type.model} ({self.pk})' return super().__str__() @@ -1046,6 +1046,7 @@ class Device( return self.name if self.virtual_chassis: return f'{self.virtual_chassis.name}:{self.vc_position}' + return None @property def identifier(self): @@ -1058,12 +1059,11 @@ class Device( def primary_ip(self): if ConfigItem('PREFER_IPV4')() and self.primary_ip4: return self.primary_ip4 - elif self.primary_ip6: + if self.primary_ip6: return self.primary_ip6 - elif self.primary_ip4: + if self.primary_ip4: return self.primary_ip4 - else: - return None + return None @property def interfaces_count(self): @@ -1278,12 +1278,11 @@ class VirtualDeviceContext(PrimaryModel): def primary_ip(self): if ConfigItem('PREFER_IPV4')() and self.primary_ip4: return self.primary_ip4 - elif self.primary_ip6: + if self.primary_ip6: return self.primary_ip6 - elif self.primary_ip4: + if self.primary_ip4: return self.primary_ip4 - else: - return None + return None def clean(self): super().clean() @@ -1369,7 +1368,7 @@ class MACAddress(PrimaryModel): raise ValidationError( _("Cannot unassign MAC Address while it is designated as the primary MAC for an object") ) - elif original_assigned_object != assigned_object: + if original_assigned_object != assigned_object: raise ValidationError( _("Cannot reassign MAC Address while it is designated as the primary MAC for an object") ) diff --git a/netbox/dcim/models/mixins.py b/netbox/dcim/models/mixins.py index d05498590..2098b8b3b 100644 --- a/netbox/dcim/models/mixins.py +++ b/netbox/dcim/models/mixins.py @@ -35,6 +35,7 @@ class RenderConfigMixin(models.Model): return self.role.config_template if self.platform and self.platform.config_template: return self.platform.config_template + return None class CachedScopeMixin(models.Model): diff --git a/netbox/dcim/svg/cables.py b/netbox/dcim/svg/cables.py index 2d780fd61..1a8844daf 100644 --- a/netbox/dcim/svg/cables.py +++ b/netbox/dcim/svg/cables.py @@ -190,11 +190,10 @@ class CableTraceSVG: if hasattr(instance, 'role'): # Device return instance.role.color - elif instance._meta.model_name == 'circuit' and instance.type.color: + if instance._meta.model_name == 'circuit' and instance.type.color: return instance.type.color - else: - # Other parent object - return 'e0e0e0' + # Other parent object + return 'e0e0e0' def draw_parent_objects(self, obj_list): """ diff --git a/netbox/extras/api/serializers_/scripts.py b/netbox/extras/api/serializers_/scripts.py index 9e41e64d1..a7d5b9c2a 100644 --- a/netbox/extras/api/serializers_/scripts.py +++ b/netbox/extras/api/serializers_/scripts.py @@ -32,8 +32,7 @@ class ScriptSerializer(ValidatedModelSerializer): return { k: v.__class__.__name__ for k, v in obj.python_class()._get_vars().items() } - else: - return {} + return {} @extend_schema_field(serializers.CharField()) def get_display(self, obj): @@ -43,8 +42,7 @@ class ScriptSerializer(ValidatedModelSerializer): def get_description(self, obj): if obj.python_class: return obj.python_class().description - else: - return None + return None class ScriptDetailSerializer(ScriptSerializer): diff --git a/netbox/extras/dashboard/widgets.py b/netbox/extras/dashboard/widgets.py index 23303df63..bb3eac01e 100644 --- a/netbox/extras/dashboard/widgets.py +++ b/netbox/extras/dashboard/widgets.py @@ -278,7 +278,7 @@ class ObjectListWidget(DashboardWidget): model = ObjectType.objects.get_by_natural_key(app_label, model_name).model_class() if not model: logger.debug(f"Dashboard Widget model_class not found: {app_label}:{model_name}") - return + return None # Evaluate user's permission. Note that this controls only whether the HTMX element is # embedded on the page: The view itself will also evaluate permissions separately. diff --git a/netbox/extras/forms/bulk_import.py b/netbox/extras/forms/bulk_import.py index f98de1dd5..91d5b2751 100644 --- a/netbox/extras/forms/bulk_import.py +++ b/netbox/extras/forms/bulk_import.py @@ -117,6 +117,7 @@ class CustomFieldChoiceSetImportForm(OwnerCSVMixin, CSVModelForm): value, label = line, line data.append((value, label)) return data + return None class CustomLinkImportForm(OwnerCSVMixin, CSVModelForm): diff --git a/netbox/extras/forms/model_forms.py b/netbox/extras/forms/model_forms.py index 189a38418..6a5e8f209 100644 --- a/netbox/extras/forms/model_forms.py +++ b/netbox/extras/forms/model_forms.py @@ -390,6 +390,7 @@ class TableConfigForm(forms.ModelForm): return columns.split(',') if type(columns) is str else columns if self.instance is not None: return self.instance.columns + return None class BookmarkForm(forms.ModelForm): diff --git a/netbox/extras/lookups.py b/netbox/extras/lookups.py index 678239080..d32259312 100644 --- a/netbox/extras/lookups.py +++ b/netbox/extras/lookups.py @@ -45,8 +45,7 @@ class Empty(Lookup): sql, params = compiler.compile(self.lhs) if self.rhs: return f"CAST(LENGTH({sql}) AS BOOLEAN) IS NOT TRUE", params - else: - return f"CAST(LENGTH({sql}) AS BOOLEAN) IS TRUE", params + return f"CAST(LENGTH({sql}) AS BOOLEAN) IS TRUE", params class JSONEmpty(Lookup): diff --git a/netbox/extras/models/mixins.py b/netbox/extras/models/mixins.py index 14540ffcf..47a0b97e8 100644 --- a/netbox/extras/models/mixins.py +++ b/netbox/extras/models/mixins.py @@ -58,8 +58,7 @@ class PythonModuleMixin: if name == '__init__': # File is a package return os.path.basename(path) - else: - return name + return name def get_module(self): """ diff --git a/netbox/extras/models/models.py b/netbox/extras/models/models.py index e44a359f6..8aca58a08 100644 --- a/netbox/extras/models/models.py +++ b/netbox/extras/models/models.py @@ -291,8 +291,7 @@ class Webhook(CustomFieldsMixin, ExportTemplatesMixin, TagsMixin, OwnerMixin, Ch """ if self.body_template: return render_jinja2(self.body_template, context) - else: - return json.dumps(context, cls=JSONEncoder) + return json.dumps(context, cls=JSONEncoder) def render_payload_url(self, context): """ diff --git a/netbox/extras/views.py b/netbox/extras/views.py index 5cfacca51..cf8f12580 100644 --- a/netbox/extras/views.py +++ b/netbox/extras/views.py @@ -1470,10 +1470,9 @@ class BaseScriptView(generic.ObjectView): def get_object(self, **kwargs): if pk := kwargs.get('pk', False): return get_object_or_404(self.queryset, pk=pk) - elif (module := kwargs.get('module')) and (name := kwargs.get('name', False)): + if (module := kwargs.get('module')) and (name := kwargs.get('name', False)): return get_object_or_404(self.queryset, module__file_path=f'{module}.py', name=name) - else: - raise Http404 + raise Http404 def _get_script_class(self, script): """ @@ -1481,6 +1480,7 @@ class BaseScriptView(generic.ObjectView): """ if script_class := script.python_class: return script_class() + return None class ScriptView(BaseScriptView): @@ -1674,7 +1674,7 @@ class ScriptResultView(TableMixin, generic.ObjectView): response['Content-Disposition'] = f'attachment; filename="{filename}"' return response - elif job.completed: + if job.completed: table = self.get_table(job, request, bulk_actions=False) log_threshold = request.GET.get('log_threshold', LogLevelChoices.LOG_INFO) diff --git a/netbox/extras/webhooks.py b/netbox/extras/webhooks.py index 033e3b20b..e30fe976e 100644 --- a/netbox/extras/webhooks.py +++ b/netbox/extras/webhooks.py @@ -124,8 +124,7 @@ def send_webhook(event_rule, object_type, event_type, data, timestamp, username, if 200 <= response.status_code <= 299: logger.info(f"Request succeeded; response status {response.status_code}") return f"Status {response.status_code} returned, webhook successfully processed." - else: - logger.warning(f"Request failed; response status {response.status_code}: {response.content}") - raise requests.exceptions.RequestException( - f"Status {response.status_code} returned with content '{response.content}', webhook FAILED to process." - ) + logger.warning(f"Request failed; response status {response.status_code}: {response.content}") + raise requests.exceptions.RequestException( + f"Status {response.status_code} returned with content '{response.content}', webhook FAILED to process." + ) diff --git a/netbox/ipam/api/serializers_/ip.py b/netbox/ipam/api/serializers_/ip.py index e4a6f12cc..d1e97c218 100644 --- a/netbox/ipam/api/serializers_/ip.py +++ b/netbox/ipam/api/serializers_/ip.py @@ -95,7 +95,7 @@ class PrefixLengthSerializer(serializers.Serializer): raise serializers.ValidationError({ 'prefix_length': 'Invalid prefix length ({}) for IPv4'.format(requested_prefix) }) - elif prefix.family == 6 and requested_prefix > 128: + if prefix.family == 6 and requested_prefix > 128: raise serializers.ValidationError({ 'prefix_length': 'Invalid prefix length ({}) for IPv6'.format(requested_prefix) }) @@ -174,11 +174,11 @@ class AvailableIPRequestSerializer(serializers.Serializer): parent.mask_length ) }) - elif parent.family == 4 and prefix_length > 32: + if parent.family == 4 and prefix_length > 32: raise serializers.ValidationError({ 'prefix_length': 'Invalid prefix length ({}) for IPv6'.format(prefix_length) }) - elif parent.family == 6 and prefix_length > 128: + if parent.family == 6 and prefix_length > 128: raise serializers.ValidationError({ 'prefix_length': 'Invalid prefix length ({}) for IPv4'.format(prefix_length) }) diff --git a/netbox/ipam/filtersets.py b/netbox/ipam/filtersets.py index eb65f1bba..a2e5b8eb8 100644 --- a/netbox/ipam/filtersets.py +++ b/netbox/ipam/filtersets.py @@ -473,8 +473,7 @@ class PrefixFilterSet(PrimaryModelFilterSet, ScopedFilterSet, TenancyFilterSet, if '/' in value: return queryset.filter(prefix__net_contains_or_equals=str(netaddr.IPNetwork(value).cidr)) # Searching by IP address - else: - return queryset.filter(prefix__net_contains=str(netaddr.IPAddress(value))) + return queryset.filter(prefix__net_contains=str(netaddr.IPAddress(value))) except (AddrFormatError, ValueError): return queryset.none() @@ -809,11 +808,10 @@ class IPAddressFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFi assigned_object_type__in=content_types, assigned_object_id__isnull=False ) - else: - return queryset.exclude( - assigned_object_type__in=content_types, - assigned_object_id__isnull=False - ) + return queryset.exclude( + assigned_object_type__in=content_types, + assigned_object_id__isnull=False + ) def _assigned(self, queryset, name, value): if value: @@ -821,11 +819,10 @@ class IPAddressFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFi assigned_object_type__isnull=True, assigned_object_id__isnull=True ) - else: - return queryset.filter( - assigned_object_type__isnull=True, - assigned_object_id__isnull=True - ) + return queryset.filter( + assigned_object_type__isnull=True, + assigned_object_id__isnull=True + ) @register_filterset diff --git a/netbox/ipam/forms/bulk_import.py b/netbox/ipam/forms/bulk_import.py index bbb9587b4..93107d88e 100644 --- a/netbox/ipam/forms/bulk_import.py +++ b/netbox/ipam/forms/bulk_import.py @@ -372,15 +372,13 @@ class IPAddressImportForm(PrimaryModelImportForm): # Make sure is_primary is None when it's not included in the uploaded data if 'is_primary' not in self.data: return None - else: - return self.cleaned_data['is_primary'] + return self.cleaned_data['is_primary'] def clean_is_oob(self): # Make sure is_oob is None when it's not included in the uploaded data if 'is_oob' not in self.data: return None - else: - return self.cleaned_data['is_oob'] + return self.cleaned_data['is_oob'] def clean(self): super().clean() diff --git a/netbox/ipam/forms/model_forms.py b/netbox/ipam/forms/model_forms.py index 6cb378f32..e20f056c8 100644 --- a/netbox/ipam/forms/model_forms.py +++ b/netbox/ipam/forms/model_forms.py @@ -392,7 +392,7 @@ class IPAddressForm(TenancyForm, PrimaryModelForm): raise forms.ValidationError({ selected_objects[1]: _("An IP address can only be assigned to a single object.") }) - elif selected_objects: + if selected_objects: assigned_object = self.cleaned_data[selected_objects[0]] if self.instance.pk and self.instance.assigned_object and assigned_object != self.instance.assigned_object: if self.cleaned_data['primary_for_parent']: diff --git a/netbox/ipam/lookups.py b/netbox/ipam/lookups.py index c493b7876..045877eb3 100644 --- a/netbox/ipam/lookups.py +++ b/netbox/ipam/lookups.py @@ -122,7 +122,7 @@ class NetIn(Lookup): if with_mask and not without_mask: return address_in_clause, with_mask - elif not with_mask and without_mask: + if not with_mask and without_mask: return host_in_clause, without_mask in_clause = '({}) OR ({})'.format(address_in_clause, host_in_clause) diff --git a/netbox/ipam/models/ip.py b/netbox/ipam/models/ip.py index 7de01a7ec..67cf11953 100644 --- a/netbox/ipam/models/ip.py +++ b/netbox/ipam/models/ip.py @@ -167,6 +167,7 @@ class Aggregate(ContactsMixin, GetAvailablePrefixesMixin, PrimaryModel): def ipv6_full(self): if self.prefix and self.prefix.version == 6: return netaddr.IPAddress(self.prefix).format(netaddr.ipv6_full) + return None def get_child_prefixes(self): """ @@ -344,6 +345,7 @@ class Prefix(ContactsMixin, GetAvailablePrefixesMixin, CachedScopeMixin, Primary def ipv6_full(self): if self.prefix and self.prefix.version == 6: return netaddr.IPAddress(self.prefix).format(netaddr.ipv6_full) + return None @property def depth(self): @@ -395,8 +397,7 @@ class Prefix(ContactsMixin, GetAvailablePrefixesMixin, CachedScopeMixin, Primary """ if self.vrf is None and self.status == PrefixStatusChoices.STATUS_CONTAINER: return Prefix.objects.filter(prefix__net_contained=str(self.prefix)) - else: - return Prefix.objects.filter(prefix__net_contained=str(self.prefix), vrf=self.vrf) + return Prefix.objects.filter(prefix__net_contained=str(self.prefix), vrf=self.vrf) def get_child_ranges(self, **kwargs): """ @@ -416,8 +417,7 @@ class Prefix(ContactsMixin, GetAvailablePrefixesMixin, CachedScopeMixin, Primary """ if self.vrf is None and self.status == PrefixStatusChoices.STATUS_CONTAINER: return IPAddress.objects.filter(address__net_host_contained=str(self.prefix)) - else: - return IPAddress.objects.filter(address__net_host_contained=str(self.prefix), vrf=self.vrf) + return IPAddress.objects.filter(address__net_host_contained=str(self.prefix), vrf=self.vrf) def get_available_ips(self): """ @@ -827,6 +827,7 @@ class IPAddress(ContactsMixin, PrimaryModel): def ipv6_full(self): if self.address and self.address.version == 6: return netaddr.IPAddress(self.address).format(netaddr.ipv6_full) + return None def get_duplicates(self): return IPAddress.objects.filter( @@ -852,6 +853,7 @@ class IPAddress(ContactsMixin, PrimaryModel): ]) if available_ips: return next(iter(available_ips)) + return None def get_related_ips(self): """ diff --git a/netbox/ipam/views.py b/netbox/ipam/views.py index 00f970c5d..cbea4f318 100644 --- a/netbox/ipam/views.py +++ b/netbox/ipam/views.py @@ -923,7 +923,7 @@ class IPAddressEditView(generic.ObjectEditView): def get_extra_addanother_params(self, request): if 'interface' in request.GET: return {'interface': request.GET['interface']} - elif 'vminterface' in request.GET: + if 'vminterface' in request.GET: return {'vminterface': request.GET['vminterface']} return {} diff --git a/netbox/netbox/api/authentication.py b/netbox/netbox/api/authentication.py index af9087481..ae1ccc83f 100644 --- a/netbox/netbox/api/authentication.py +++ b/netbox/netbox/api/authentication.py @@ -25,10 +25,10 @@ class TokenAuthentication(BaseAuthentication): def authenticate(self, request): # Authorization header is not present; ignore if not (auth := get_authorization_header(request).split()): - return + return None # Unrecognized header; ignore if auth[0].lower() not in (V1_KEYWORD.lower().encode(), V2_KEYWORD.lower().encode()): - return + return None # Check for extraneous token content if len(auth) != 2: raise exceptions.AuthenticationFailed( @@ -150,6 +150,7 @@ class TokenPermissions(DjangoObjectPermissions): # If token authentication is in use, verify that the token allows write operations (for unsafe methods). if request.method in SAFE_METHODS or request.auth.write_enabled: return True + return False def has_permission(self, request, view): diff --git a/netbox/netbox/api/fields.py b/netbox/netbox/api/fields.py index 0e790b2df..1d72d9467 100644 --- a/netbox/netbox/api/fields.py +++ b/netbox/netbox/api/fields.py @@ -47,8 +47,7 @@ class ChoiceField(serializers.Field): if data is None: if self.allow_null: return True, None - else: - data = '' + data = '' return super().validate_empty_values(data) def to_representation(self, obj): @@ -59,6 +58,7 @@ class ChoiceField(serializers.Field): 'value': obj, 'label': self._choices.get(obj, ''), } + return None def to_internal_value(self, data): if data == '': diff --git a/netbox/netbox/api/pagination.py b/netbox/netbox/api/pagination.py index 1650628a9..15fb49da8 100644 --- a/netbox/netbox/api/pagination.py +++ b/netbox/netbox/api/pagination.py @@ -40,8 +40,7 @@ class OptionalLimitOffsetPagination(LimitOffsetPagination): if self.limit: return list(queryset[self.offset:self.offset + self.limit]) - else: - return list(queryset[self.offset:]) + return list(queryset[self.offset:]) def get_limit(self, request): max_limit = self.default_limit diff --git a/netbox/netbox/authentication/__init__.py b/netbox/netbox/authentication/__init__.py index e1245def7..19b1e58ca 100644 --- a/netbox/netbox/authentication/__init__.py +++ b/netbox/netbox/authentication/__init__.py @@ -211,7 +211,7 @@ class RemoteUserBackend(_RemoteUserBackend): logger.debug( f"trying to authenticate {remote_user} with groups {remote_groups}") if not remote_user: - return + return None user = None username = self.clean_username(remote_user) @@ -235,8 +235,7 @@ class RemoteUserBackend(_RemoteUserBackend): return self.configure_groups(user, remote_groups) else: return user - else: - return None + return None def _is_superuser(self, user): logger = logging.getLogger('netbox.auth.RemoteUserBackend') diff --git a/netbox/netbox/filtersets.py b/netbox/netbox/filtersets.py index 138229a70..14ef4d158 100644 --- a/netbox/netbox/filtersets.py +++ b/netbox/netbox/filtersets.py @@ -138,13 +138,13 @@ class BaseFilterSet(django_filters.FilterSet): )): return FILTER_NUMERIC_BASED_LOOKUP_MAP - elif isinstance(existing_filter, ( + if isinstance(existing_filter, ( filters.TreeNodeMultipleChoiceFilter, )): # TreeNodeMultipleChoiceFilter only support negation but must maintain the `in` lookup expression return FILTER_TREENODE_NEGATION_LOOKUP_MAP - elif isinstance(existing_filter, ( + if isinstance(existing_filter, ( django_filters.ModelChoiceFilter, django_filters.ModelMultipleChoiceFilter, TagFilter @@ -152,7 +152,7 @@ class BaseFilterSet(django_filters.FilterSet): # These filter types support only negation return FILTER_NEGATION_LOOKUP_MAP - elif isinstance(existing_filter, ( + if isinstance(existing_filter, ( django_filters.filters.CharFilter, django_filters.ChoiceFilter, django_filters.MultipleChoiceFilter, @@ -387,7 +387,7 @@ class AttributeFiltersMixin: def _get_field_lookup(self, key): if not key.startswith(self.attribute_filter_prefix): - return + return None lookup = key.split(self.attribute_filter_prefix, 1)[1] # Strip prefix return f'{self.attributes_field_name}__{lookup}' diff --git a/netbox/netbox/graphql/filter_lookups.py b/netbox/netbox/graphql/filter_lookups.py index 88ca374d2..953de2382 100644 --- a/netbox/netbox/graphql/filter_lookups.py +++ b/netbox/netbox/graphql/filter_lookups.py @@ -186,12 +186,11 @@ class TreeNodeFilter: # Handle different relationship types if isinstance(model_field, (ManyToManyField, ManyToManyRel)): return queryset, Q(**{f'{model_field_name}__in': related_model.objects.filter(q_filter)}) - elif isinstance(model_field, ForeignKey): + if isinstance(model_field, ForeignKey): return queryset, Q(**{f'{model_field_name}__{k}': v for k, v in q_filter.children}) - elif isinstance(model_field, ManyToOneRel): + if isinstance(model_field, ManyToOneRel): return queryset, Q(**{f'{model_field_name}__in': related_model.objects.filter(q_filter)}) - else: - return queryset, Q(**{f'{model_field_name}__{k}': v for k, v in q_filter.children}) + return queryset, Q(**{f'{model_field_name}__{k}': v for k, v in q_filter.children}) def generate_tree_node_q_filter(model_class, filter_value: TreeNodeFilter) -> Q: @@ -205,17 +204,17 @@ def generate_tree_node_q_filter(model_class, filter_value: TreeNodeFilter) -> Q: if filter_value.match_type == TreeNodeMatch.EXACT: return Q(id=filter_value.id) - elif filter_value.match_type == TreeNodeMatch.DESCENDANTS: + if filter_value.match_type == TreeNodeMatch.DESCENDANTS: return Q(tree_id=node.tree_id, lft__gt=node.lft, rght__lt=node.rght) - elif filter_value.match_type == TreeNodeMatch.SELF_AND_DESCENDANTS: + if filter_value.match_type == TreeNodeMatch.SELF_AND_DESCENDANTS: return Q(tree_id=node.tree_id, lft__gte=node.lft, rght__lte=node.rght) - elif filter_value.match_type == TreeNodeMatch.CHILDREN: + if filter_value.match_type == TreeNodeMatch.CHILDREN: return Q(tree_id=node.tree_id, level=node.level + 1, lft__gt=node.lft, rght__lt=node.rght) - elif filter_value.match_type == TreeNodeMatch.SIBLINGS: + if filter_value.match_type == TreeNodeMatch.SIBLINGS: return Q(tree_id=node.tree_id, level=node.level, parent=node.parent) & ~Q(id=node.id) - elif filter_value.match_type == TreeNodeMatch.ANCESTORS: + if filter_value.match_type == TreeNodeMatch.ANCESTORS: return Q(tree_id=node.tree_id, lft__lt=node.lft, rght__gt=node.rght) - elif filter_value.match_type == TreeNodeMatch.PARENT: + if filter_value.match_type == TreeNodeMatch.PARENT: return Q(id=node.parent_id) if node.parent_id else Q(pk__in=[]) return Q() diff --git a/netbox/netbox/graphql/types.py b/netbox/netbox/graphql/types.py index dcef7b22b..109753853 100644 --- a/netbox/netbox/graphql/types.py +++ b/netbox/netbox/graphql/types.py @@ -34,8 +34,7 @@ class BaseObjectType: # Enforce object permissions on the queryset if hasattr(queryset, 'restrict'): return queryset.restrict(info.context.request.user, 'view') - else: - return queryset + return queryset @strawberry_django.field def display(self) -> str: diff --git a/netbox/netbox/graphql/views.py b/netbox/netbox/graphql/views.py index 800432fbd..04469b383 100644 --- a/netbox/netbox/graphql/views.py +++ b/netbox/netbox/graphql/views.py @@ -37,7 +37,6 @@ class NetBoxGraphQLView(GraphQLView): if settings.LOGIN_REQUIRED and not request.user.is_authenticated: if request.accepts("text/html"): return redirect_to_login(reverse('graphql')) - else: - return HttpResponseForbidden("No credentials provided.") + return HttpResponseForbidden("No credentials provided.") return super().dispatch(request, *args, **kwargs) diff --git a/netbox/netbox/middleware.py b/netbox/netbox/middleware.py index 45a48c2be..68c01245c 100644 --- a/netbox/netbox/middleware.py +++ b/netbox/netbox/middleware.py @@ -71,7 +71,7 @@ class CoreMiddleware: """ # Don't catch exceptions when in debug mode if settings.DEBUG: - return + return None # Cleanly handle exceptions that occur from REST API requests if is_api_request(request): @@ -79,7 +79,7 @@ class CoreMiddleware: # Ignore Http404s (defer to Django's built-in 404 handling) if isinstance(exception, Http404): - return + return None # Determine the type of exception. If it's a common issue, return a custom error page with instructions. custom_template = None @@ -93,6 +93,7 @@ class CoreMiddleware: # Return a custom error message, or fall back to Django's default 500 error handling if custom_template: return handler_500(request, template_name=custom_template) + return None class RemoteUserMiddleware(RemoteUserMiddleware_): @@ -139,10 +140,9 @@ class RemoteUserMiddleware(RemoteUserMiddleware_): if request.user.is_authenticated: if request.user.get_username() == self.clean_username(username, request): return self.get_response(request) - else: - # An authenticated user is associated with the request, but - # it does not match the authorized user in the header. - self._remove_invalid_user(request) + # An authenticated user is associated with the request, but + # it does not match the authorized user in the header. + self._remove_invalid_user(request) # We are seeing this user for the first time in this session, attempt # to authenticate the user. @@ -250,3 +250,4 @@ class MaintenanceModeMiddleware: messages.error(request, error_message) return HttpResponseRedirect(request.path_info) + return None diff --git a/netbox/netbox/models/features.py b/netbox/netbox/models/features.py index c627b4b22..3ac65d894 100644 --- a/netbox/netbox/models/features.py +++ b/netbox/netbox/models/features.py @@ -246,7 +246,7 @@ class CustomFieldsMixin(models.Model): # Skip hidden fields if 'omit_hidden' is True if omit_hidden and field.ui_visible == CustomFieldUIVisibleChoices.HIDDEN: continue - elif omit_hidden and field.ui_visible == CustomFieldUIVisibleChoices.IF_SET and not value: + if omit_hidden and field.ui_visible == CustomFieldUIVisibleChoices.IF_SET and not value: continue data[field] = field.deserialize(value) @@ -611,6 +611,7 @@ class SyncedDataMixin(models.Model): return DataFile.objects.get(source=self.data_source, path=self.data_path) except DataFile.DoesNotExist: pass + return None def sync(self, save=False): """ diff --git a/netbox/netbox/object_actions.py b/netbox/netbox/object_actions.py index 688082f13..412f0c1e5 100644 --- a/netbox/netbox/object_actions.py +++ b/netbox/netbox/object_actions.py @@ -49,7 +49,7 @@ class ObjectAction: try: return get_action_url(obj, action=cls.name, kwargs=kwargs) except NoReverseMatch: - return + return None @classmethod def get_url_params(cls, context): diff --git a/netbox/netbox/search/__init__.py b/netbox/netbox/search/__init__.py index a024f93ea..8f355b278 100644 --- a/netbox/netbox/search/__init__.py +++ b/netbox/netbox/search/__init__.py @@ -84,6 +84,7 @@ class SearchIndex: """ if value := getattr(instance, field_name): return str(value) + return None @classmethod def get_category(cls): diff --git a/netbox/netbox/search/backends.py b/netbox/netbox/search/backends.py index 2aa1fbcf6..12dfbdcff 100644 --- a/netbox/netbox/search/backends.py +++ b/netbox/netbox/search/backends.py @@ -248,7 +248,7 @@ class CachedValueSearchBackend(SearchBackend): try: get_indexer(instance) except KeyError: - return + return None ct = ContentType.objects.get_for_model(instance) qs = CachedValue.objects.filter(object_type=ct, object_id=instance.pk) diff --git a/netbox/netbox/tables/columns.py b/netbox/netbox/tables/columns.py index 12b781cf4..0d376de31 100644 --- a/netbox/netbox/tables/columns.py +++ b/netbox/netbox/tables/columns.py @@ -61,15 +61,18 @@ class DateColumn(tables.Column): def render(self, value): if value: return value.isoformat() + return None def value(self, value): if value: return value.isoformat() + return None @classmethod def from_field(cls, field, **kwargs): if isinstance(field, DateField): return cls(**kwargs) + return None @library.register @@ -89,15 +92,18 @@ class DateTimeColumn(tables.Column): current_tz = zoneinfo.ZoneInfo(settings.TIME_ZONE) value = value.astimezone(current_tz) return f"{value.date().isoformat()} {value.time().isoformat(timespec=self.timespec)}" + return None def value(self, value): if value: return value.isoformat() + return None @classmethod def from_field(cls, field, **kwargs): if isinstance(field, DateTimeField): return cls(**kwargs) + return None class DurationColumn(tables.Column): diff --git a/netbox/netbox/tests/test_base_classes.py b/netbox/netbox/tests/test_base_classes.py index 0a8085a5e..012dede69 100644 --- a/netbox/netbox/tests/test_base_classes.py +++ b/netbox/netbox/tests/test_base_classes.py @@ -70,7 +70,7 @@ class FormClassesTestCase(TestCase): Return the base form class for creating/editing the given model. """ if model._meta.app_label == 'dummy_plugin': - return + return None if issubclass(model, PrimaryModel): return PrimaryModelForm if issubclass(model, OrganizationalModel): @@ -79,6 +79,7 @@ class FormClassesTestCase(TestCase): return NestedGroupModelForm if issubclass(model, NetBoxModel): return NetBoxModelForm + return None @staticmethod def get_bulk_edit_form_base_class(model): @@ -86,7 +87,7 @@ class FormClassesTestCase(TestCase): Return the base form class for bulk editing the given model. """ if model._meta.app_label == 'dummy_plugin': - return + return None if issubclass(model, PrimaryModel): return PrimaryModelBulkEditForm if issubclass(model, OrganizationalModel): @@ -95,6 +96,7 @@ class FormClassesTestCase(TestCase): return NestedGroupModelBulkEditForm if issubclass(model, NetBoxModel): return NetBoxModelBulkEditForm + return None @staticmethod def get_import_form_base_class(model): @@ -102,7 +104,7 @@ class FormClassesTestCase(TestCase): Return the base form class for importing the given model. """ if model._meta.app_label == 'dummy_plugin': - return + return None if issubclass(model, PrimaryModel): return PrimaryModelImportForm if issubclass(model, OrganizationalModel): @@ -111,6 +113,7 @@ class FormClassesTestCase(TestCase): return NestedGroupModelImportForm if issubclass(model, NetBoxModel): return NetBoxModelImportForm + return None @staticmethod def get_filterset_form_base_class(model): @@ -118,7 +121,7 @@ class FormClassesTestCase(TestCase): Return the base form class for the given model's FilterSet. """ if model._meta.app_label == 'dummy_plugin': - return + return None if issubclass(model, PrimaryModel): return PrimaryModelFilterSetForm if issubclass(model, OrganizationalModel): @@ -127,6 +130,7 @@ class FormClassesTestCase(TestCase): return NestedGroupModelFilterSetForm if issubclass(model, NetBoxModel): return NetBoxModelFilterSetForm + return None def test_model_form_base_classes(self): """ @@ -182,7 +186,7 @@ class FilterSetClassesTestCase(TestCase): Return the base FilterSet class for the given model. """ if model._meta.app_label == 'dummy_plugin': - return + return None if issubclass(model, PrimaryModel): return PrimaryModelFilterSet if issubclass(model, OrganizationalModel): @@ -191,6 +195,7 @@ class FilterSetClassesTestCase(TestCase): return NestedGroupModelFilterSet if issubclass(model, NetBoxModel): return NetBoxModelFilterSet + return None def test_model_filterset_base_classes(self): """ @@ -222,7 +227,7 @@ class TableClassesTestCase(TestCase): Return the base table class for the given model. """ if model._meta.app_label == 'dummy_plugin': - return + return None if issubclass(model, PrimaryModel): return PrimaryModelTable if issubclass(model, OrganizationalModel): @@ -231,6 +236,7 @@ class TableClassesTestCase(TestCase): return NestedGroupModelTable if issubclass(model, NetBoxModel): return NetBoxTable + return None def test_model_table_base_classes(self): """ @@ -266,7 +272,7 @@ class SerializerClassesTestCase(TestCase): Return the base serializer class for the given model. """ if model._meta.app_label == 'dummy_plugin': - return + return None if issubclass(model, PrimaryModel): return PrimaryModelSerializer if issubclass(model, OrganizationalModel): @@ -275,6 +281,7 @@ class SerializerClassesTestCase(TestCase): return NestedGroupModelSerializer if issubclass(model, NetBoxModel): return NetBoxModelSerializer + return None def test_model_serializer_base_classes(self): """ @@ -306,7 +313,7 @@ class GraphQLTypeClassesTestCase(TestCase): Return the base GraphQL type for the given model. """ if model._meta.app_label == 'dummy_plugin': - return + return None if issubclass(model, PrimaryModel): return PrimaryObjectType if issubclass(model, OrganizationalModel): @@ -315,6 +322,7 @@ class GraphQLTypeClassesTestCase(TestCase): return NestedGroupObjectType if issubclass(model, NetBoxModel): return NetBoxObjectType + return None def test_model_type_base_classes(self): """ diff --git a/netbox/netbox/views/generic/bulk_views.py b/netbox/netbox/views/generic/bulk_views.py index febf312b2..e36aa6328 100644 --- a/netbox/netbox/views/generic/bulk_views.py +++ b/netbox/netbox/views/generic/bulk_views.py @@ -169,22 +169,21 @@ class ObjectListView(BaseMultiObjectView, ActionsMixin, TableMixin): return self.export_table(table, columns, delimiter=delimiter) # Render an ExportTemplate - elif request.GET['export']: + if request.GET['export']: template = get_object_or_404(ExportTemplate, object_types=object_type, name=request.GET['export']) return self.export_template(template, request) # Check for YAML export support on the model - elif hasattr(model, 'to_yaml'): + if hasattr(model, 'to_yaml'): response = HttpResponse(self.export_yaml(), content_type='text/yaml') filename = 'netbox_{}.yaml'.format(self.queryset.model._meta.verbose_name_plural) response['Content-Disposition'] = 'attachment; filename="{}"'.format(filename) return response # Fall back to default table/YAML export - else: - table = self.get_table(self.queryset, request, has_table_actions) - delimiter = request.user.config.get('csv_delimiter') - return self.export_table(table, delimiter=delimiter) + table = self.get_table(self.queryset, request, has_table_actions) + delimiter = request.user.config.get('csv_delimiter') + return self.export_table(table, delimiter=delimiter) # Render the objects table table = self.get_table(self.queryset, request, has_table_actions) @@ -353,7 +352,7 @@ class BulkImportView(GetReturnURLMixin, BaseMultiObjectView): for field in form.visible_fields(): if field.is_hidden: continue - elif field.field.required: + if field.field.required: required_fields[field.name] = field.field else: optional_fields[field.name] = field.field @@ -581,7 +580,7 @@ class BulkImportView(GetReturnURLMixin, BaseMultiObjectView): # Handle background job if is_background_request(request): request.job.logger.info(msg) - return + return None messages.success(request, msg) return redirect(f"{redirect_url}?modified_by_request={request.id}") @@ -787,7 +786,7 @@ class BulkEditView(GetReturnURLMixin, BaseMultiObjectView): # Handle background job if is_background_request(request): request.job.logger.info(msg) - return + return None messages.success(self.request, msg) return redirect(self.get_return_url(request)) @@ -1010,7 +1009,7 @@ class BulkDeleteView(GetReturnURLMixin, BaseMultiObjectView): # Handle background job if is_background_request(request): request.job.logger.info(msg) - return + return None messages.success(request, msg) @@ -1032,8 +1031,7 @@ class BulkDeleteView(GetReturnURLMixin, BaseMultiObjectView): return redirect(self.get_return_url(request)) - else: - logger.debug("Form validation failed") + logger.debug("Form validation failed") else: form = BulkDeleteForm(model, initial={ diff --git a/netbox/netbox/views/generic/object_views.py b/netbox/netbox/views/generic/object_views.py index 82a3aa8d6..c6630d341 100644 --- a/netbox/netbox/views/generic/object_views.py +++ b/netbox/netbox/views/generic/object_views.py @@ -413,8 +413,7 @@ class ObjectDeleteView(GetReturnURLMixin, BaseObjectView): return HttpResponse(headers={ 'HX-Redirect': obj.get_absolute_url(), }) - else: - return redirect(obj.get_absolute_url()) + return redirect(obj.get_absolute_url()) # # Request handlers @@ -499,8 +498,7 @@ class ObjectDeleteView(GetReturnURLMixin, BaseObjectView): return redirect(return_url) return redirect(self.get_return_url(request, obj)) - else: - logger.debug("Form validation failed") + logger.debug("Form validation failed") return render(request, self.template_name, { 'object': obj, @@ -607,8 +605,7 @@ class ComponentCreateView(GetReturnURLMixin, BaseObjectView): # Redirect user on success if '_addanother' in request.POST and safe_for_redirect(request.get_full_path()): return redirect(request.get_full_path()) - else: - return redirect(self.get_return_url(request)) + return redirect(self.get_return_url(request)) except (AbortRequest, PermissionsViolation) as e: logger.debug(e.message) diff --git a/netbox/netbox/views/generic/utils.py b/netbox/netbox/views/generic/utils.py index 61d73e811..274308013 100644 --- a/netbox/netbox/views/generic/utils.py +++ b/netbox/netbox/views/generic/utils.py @@ -11,3 +11,4 @@ def get_prerequisite_model(queryset): model = apps.get_model(prereq) if not model.objects.exists(): return model + return None diff --git a/netbox/users/filtersets.py b/netbox/users/filtersets.py index 0d2e599d8..122fcd913 100644 --- a/netbox/users/filtersets.py +++ b/netbox/users/filtersets.py @@ -250,8 +250,7 @@ class ObjectPermissionFilterSet(BaseFilterSet): action = name.split('_')[1] if value: return queryset.filter(actions__contains=[action]) - else: - return queryset.exclude(actions__contains=[action]) + return queryset.exclude(actions__contains=[action]) @register_filterset diff --git a/netbox/users/models/tokens.py b/netbox/users/models/tokens.py index e58fc5830..8bdab2142 100644 --- a/netbox/users/models/tokens.py +++ b/netbox/users/models/tokens.py @@ -209,6 +209,7 @@ class Token(models.Model): return 'Token ' if self.v2: return f'Bearer {TOKEN_PREFIX}{self.key}.' + return None def clean(self): super().clean() @@ -288,6 +289,7 @@ class Token(models.Model): return False digest = hmac.new(pepper.encode('utf-8'), token.encode('utf-8'), hashlib.sha256).hexdigest() return digest == self.hmac_digest + return False def validate_client_ip(self, client_ip): """ diff --git a/netbox/utilities/fields.py b/netbox/utilities/fields.py index e2814465a..137ef6b8b 100644 --- a/netbox/utilities/fields.py +++ b/netbox/utilities/fields.py @@ -133,15 +133,14 @@ class RestrictedGenericForeignKey(GenericForeignKey): ct_id = getattr(obj, ct_attname) if ct_id is None: return None - else: - if model := self.get_content_type( - id=ct_id, using=obj._state.db - ).model_class(): - return ( - model._meta.pk.get_prep_value(getattr(obj, self.fk_field)), - model, - ) - return None + if model := self.get_content_type( + id=ct_id, using=obj._state.db + ).model_class(): + return ( + model._meta.pk.get_prep_value(getattr(obj, self.fk_field)), + model, + ) + return None return ( ret_val, diff --git a/netbox/utilities/forms/fields/expandable.py b/netbox/utilities/forms/fields/expandable.py index 959271a85..a279985ee 100644 --- a/netbox/utilities/forms/fields/expandable.py +++ b/netbox/utilities/forms/fields/expandable.py @@ -50,6 +50,6 @@ class ExpandableIPAddressField(forms.CharField): # Hackish address family detection but it's all we have to work with if '.' in value and re.search(IP4_EXPANSION_PATTERN, value): return list(expand_ipaddress_pattern(value, 4)) - elif ':' in value and re.search(IP6_EXPANSION_PATTERN, value): + if ':' in value and re.search(IP6_EXPANSION_PATTERN, value): return list(expand_ipaddress_pattern(value, 6)) return [value] diff --git a/netbox/utilities/forms/utils.py b/netbox/utilities/forms/utils.py index d79cdac02..1aad09b28 100644 --- a/netbox/utilities/forms/utils.py +++ b/netbox/utilities/forms/utils.py @@ -139,7 +139,7 @@ def get_field_value(form, field_name): if form.is_bound and field_name in form.data: if (value := form.data[field_name]) is None: - return + return None if hasattr(field, 'valid_value') and field.valid_value(value): return value diff --git a/netbox/utilities/html.py b/netbox/utilities/html.py index c9203d169..5b93fa1cf 100644 --- a/netbox/utilities/html.py +++ b/netbox/utilities/html.py @@ -37,8 +37,7 @@ def foreground_color(bg_color, dark='000000', light='ffffff'): r, g, b = [int(bg_color[c:c + 2], 16) for c in (0, 2, 4)] if r * 0.299 + g * 0.587 + b * 0.114 > THRESHOLD: return dark - else: - return light + return light def highlight(value, highlight, trim_pre=None, trim_post=None, trim_placeholder='...'): diff --git a/netbox/utilities/jobs.py b/netbox/utilities/jobs.py index 8682c8239..7ecd19aa9 100644 --- a/netbox/utilities/jobs.py +++ b/netbox/utilities/jobs.py @@ -25,7 +25,7 @@ def process_request_as_job(view, request, name=None): # Check that the request that is not already being processed as a background job (would be a loop) if is_background_request(request): - return + return None # Create a serializable copy of the original request request_copy = copy_safe_request(request) diff --git a/netbox/utilities/proxy.py b/netbox/utilities/proxy.py index 0cc2b00ed..47d6760ea 100644 --- a/netbox/utilities/proxy.py +++ b/netbox/utilities/proxy.py @@ -54,3 +54,4 @@ def resolve_proxies(url=None, protocol=None, context=None): router = import_string(item) if type(item) is str else item if proxies := router().route(url=url, protocol=protocol, context=context): return proxies + return None diff --git a/netbox/utilities/query.py b/netbox/utilities/query.py index 408ec87f2..e672984c0 100644 --- a/netbox/utilities/query.py +++ b/netbox/utilities/query.py @@ -67,7 +67,7 @@ def reapply_model_ordering(queryset: QuerySet) -> QuerySet: # MPTT-based models are exempt from this; use caution when annotating querysets of these models if any(isinstance(manager, TreeManager) for manager in queryset.model._meta.local_managers): return queryset - elif queryset.ordered: + if queryset.ordered: return queryset ordering = queryset.model._meta.ordering diff --git a/netbox/utilities/rqworker.py b/netbox/utilities/rqworker.py index 61f594767..4bd6bf7dd 100644 --- a/netbox/utilities/rqworker.py +++ b/netbox/utilities/rqworker.py @@ -34,3 +34,4 @@ def get_rq_retry(): retry_interval = get_config().RQ_RETRY_INTERVAL if retry_max: return Retry(max=retry_max, interval=retry_interval) + return None diff --git a/netbox/utilities/tables.py b/netbox/utilities/tables.py index 50f46e8a0..f5027f90e 100644 --- a/netbox/utilities/tables.py +++ b/netbox/utilities/tables.py @@ -33,13 +33,13 @@ def get_table_for_model(model, name=None): try: return import_string(f'{model._meta.app_label}.tables.{name}') except ImportError: - return + return None def get_table_ordering(request, table): """ - Given a request, return the prescribed table ordering, if any. This may be necessary to determine prior to rendering - the table itself. + Given a request, return the prescribed table ordering, if any. + This may be necessary to determine before rendering the table itself. """ # Check for an explicit ordering if 'sort' in request.GET: @@ -49,6 +49,7 @@ def get_table_ordering(request, table): if request.user.is_authenticated: if preference := request.user.config.get(f'tables.{table.__name__}.ordering'): return preference + return None def linkify_phone(value): diff --git a/netbox/utilities/templatetags/builtins/filters.py b/netbox/utilities/templatetags/builtins/filters.py index 0ee370253..5c7b3be4b 100644 --- a/netbox/utilities/templatetags/builtins/filters.py +++ b/netbox/utilities/templatetags/builtins/filters.py @@ -227,12 +227,11 @@ def isodate(value): if type(value) is datetime.date: text = value.isoformat() return mark_safe(f'{text}') - elif type(value) is datetime.datetime: + if type(value) is datetime.datetime: local_value = localtime(value) if value.tzinfo else value text = local_value.date().isoformat() return mark_safe(f'{text}') - else: - return '' + return '' @register.filter() diff --git a/netbox/utilities/templatetags/form_helpers.py b/netbox/utilities/templatetags/form_helpers.py index ec53fe97c..0a3078ccf 100644 --- a/netbox/utilities/templatetags/form_helpers.py +++ b/netbox/utilities/templatetags/form_helpers.py @@ -37,10 +37,9 @@ def widget_type(field): """ if hasattr(field, 'widget'): return field.widget.__class__.__name__.lower() - elif hasattr(field, 'field'): + if hasattr(field, 'field'): return field.field.widget.__class__.__name__.lower() - else: - return None + return None # diff --git a/netbox/utilities/templatetags/helpers.py b/netbox/utilities/templatetags/helpers.py index 89261b335..5613085ed 100644 --- a/netbox/utilities/templatetags/helpers.py +++ b/netbox/utilities/templatetags/helpers.py @@ -199,14 +199,13 @@ def humanize_speed(speed): return '' if speed >= 1000000000 and speed % 1000000000 == 0: return '{} Tbps'.format(int(speed / 1000000000)) - elif speed >= 1000000 and speed % 1000000 == 0: + if speed >= 1000000 and speed % 1000000 == 0: return '{} Gbps'.format(int(speed / 1000000)) - elif speed >= 1000 and speed % 1000 == 0: + if speed >= 1000 and speed % 1000 == 0: return '{} Mbps'.format(int(speed / 1000)) - elif speed >= 1000: + if speed >= 1000: return '{} Mbps'.format(float(speed) / 1000) - else: - return '{} Kbps'.format(speed) + return '{} Kbps'.format(speed) def _humanize_megabytes(mb, divisor=1000): @@ -373,8 +372,7 @@ def querystring(request, **kwargs): querystring = querydict.urlencode(safe='/') if querystring: return '?' + querystring - else: - return '' + return '' @register.inclusion_tag('helpers/utilization_graph.html') diff --git a/netbox/utilities/testing/filtersets.py b/netbox/utilities/testing/filtersets.py index adb0bc6fa..5348fbb07 100644 --- a/netbox/utilities/testing/filtersets.py +++ b/netbox/utilities/testing/filtersets.py @@ -66,7 +66,7 @@ class BaseFilterSetTests: return [(f'{filter_name}_id', django_filters.ModelMultipleChoiceFilter)] # Many-to-many relationships (forward & backward) - elif type(field) in (ManyToManyField, ManyToManyRel): + if type(field) in (ManyToManyField, ManyToManyRel): filter_name = self.get_m2m_filter_name(field) filter_name = self.filter_name_map.get(filter_name, filter_name) diff --git a/netbox/utilities/testing/views.py b/netbox/utilities/testing/views.py index c07f7eacb..353f69222 100644 --- a/netbox/utilities/testing/views.py +++ b/netbox/utilities/testing/views.py @@ -635,10 +635,9 @@ class ViewTestCases: available = ', '.join(self.csv_data.keys()) raise ValueError(f"Scenario '{scenario_name}' not found in csv_data. Available: {available}") return '\n'.join(self.csv_data[scenario_name]) - elif isinstance(self.csv_data, (tuple, list)): + if isinstance(self.csv_data, (tuple, list)): return '\n'.join(self.csv_data) - else: - raise TypeError(f'csv_data must be a tuple, list, or dictionary, got {type(self.csv_data)}') + raise TypeError(f'csv_data must be a tuple, list, or dictionary, got {type(self.csv_data)}') def _get_update_csv_data(self): return self.csv_update_data, '\n'.join(self.csv_update_data) diff --git a/netbox/virtualization/forms/bulk_import.py b/netbox/virtualization/forms/bulk_import.py index b29d24b45..e3c96c384 100644 --- a/netbox/virtualization/forms/bulk_import.py +++ b/netbox/virtualization/forms/bulk_import.py @@ -252,8 +252,7 @@ class VMInterfaceImportForm(OwnerCSVMixin, NetBoxModelImportForm): # Make sure enabled is True when it's not included in the uploaded data if 'enabled' not in self.data: return True - else: - return self.cleaned_data['enabled'] + return self.cleaned_data['enabled'] class VirtualDiskImportForm(OwnerCSVMixin, NetBoxModelImportForm): diff --git a/netbox/virtualization/models/virtualmachines.py b/netbox/virtualization/models/virtualmachines.py index f4679c9c2..c56a07457 100644 --- a/netbox/virtualization/models/virtualmachines.py +++ b/netbox/virtualization/models/virtualmachines.py @@ -260,12 +260,11 @@ class VirtualMachine(ContactsMixin, ImageAttachmentsMixin, RenderConfigMixin, Co def primary_ip(self): if get_config().PREFER_IPV4 and self.primary_ip4: return self.primary_ip4 - elif self.primary_ip6: + if self.primary_ip6: return self.primary_ip6 - elif self.primary_ip4: + if self.primary_ip4: return self.primary_ip4 - else: - return None + return None # diff --git a/netbox/vpn/models/l2vpn.py b/netbox/vpn/models/l2vpn.py index bab7510ff..6fb045ab5 100644 --- a/netbox/vpn/models/l2vpn.py +++ b/netbox/vpn/models/l2vpn.py @@ -80,8 +80,7 @@ class L2VPN(ContactsMixin, PrimaryModel): def can_add_termination(self): if self.type in L2VPNTypeChoices.P2P and self.terminations.count() >= 2: return False - else: - return True + return True class L2VPNTermination(NetBoxModel): @@ -151,9 +150,9 @@ class L2VPNTermination(NetBoxModel): obj_type = ObjectType.objects.get_for_model(self.assigned_object) if obj_type.model == 'vminterface': return self.assigned_object.virtual_machine - elif obj_type.model == 'interface': + if obj_type.model == 'interface': return self.assigned_object.device - elif obj_type.model == 'vminterface': + if obj_type.model == 'vminterface': return self.assigned_object.virtual_machine return None diff --git a/ruff.toml b/ruff.toml index e4dd6f574..4520fd198 100644 --- a/ruff.toml +++ b/ruff.toml @@ -37,10 +37,12 @@ extend-select = [ "E501", # pycodestyle: line too long (enforced with `line-length` above) "W", # pycodestyle warnings (various style warnings, often whitespace/newlines) "I", # import sorting (isort-equivalent) + "RET", # return semantics (flake8-return family) ] ignore = [ "F403", # pyflakes: `from ... import *` used; unable to detect undefined names "F405", # pyflakes: name may be undefined or defined from star imports + "RET504", # return: unnecessary assignment before `return` (e.g., `x = expr; return x` -> `return expr`) "UP032", # pyupgrade: prefer f-strings over `str.format(...)` ] preview = true