Update CablePath to throw a "UnsupportedCablePath" exception instead of a validation error.

This commit is contained in:
Daniel Sheppard 2024-07-01 22:17:50 -05:00
parent 7f486517cc
commit d4d4e5058b
4 changed files with 15 additions and 12 deletions

View File

@ -0,0 +1,2 @@
class UnsupportedCablePath(Exception):
pass

View File

@ -27,6 +27,7 @@ __all__ = (
'CableTermination', 'CableTermination',
) )
from ..exceptions import UnsupportedCablePath
trace_paths = Signal() trace_paths = Signal()
@ -532,7 +533,7 @@ class CablePath(models.Model):
# Ensure all originating terminations are attached to the same link # Ensure all originating terminations are attached to the same link
if len(terminations) > 1 and not all(t.link == terminations[0].link for t in terminations[1:]): if len(terminations) > 1 and not all(t.link == terminations[0].link for t in terminations[1:]):
raise ValidationError(_("All originating terminations must start must be attached to the same link")) raise UnsupportedCablePath(_("All originating terminations must start must be attached to the same link"))
path = [] path = []
position_stack = [] position_stack = []
@ -544,12 +545,12 @@ class CablePath(models.Model):
# Terminations must all be of the same type # Terminations must all be of the same type
if not all(isinstance(t, type(terminations[0])) for t in terminations[1:]): if not all(isinstance(t, type(terminations[0])) for t in terminations[1:]):
raise ValidationError(_("All mid-span terminations must have the same termination type")) raise UnsupportedCablePath(_("All mid-span terminations must have the same termination type"))
# All mid-span terminations must all be attached to the same device # All mid-span terminations must all be attached to the same device
if (not isinstance(terminations[0], PathEndpoint) and not if (not isinstance(terminations[0], PathEndpoint) and not
all(t.parent_object == terminations[0].parent_object for t in terminations[1:])): all(t.parent_object == terminations[0].parent_object for t in terminations[1:])):
raise ValidationError(_("All mid-span terminations must have the same parent object")) raise UnsupportedCablePath(_("All mid-span terminations must have the same parent object"))
# Check for a split path (e.g. rear port fanning out to multiple front ports with # Check for a split path (e.g. rear port fanning out to multiple front ports with
# different cables attached) # different cables attached)
@ -573,9 +574,9 @@ class CablePath(models.Model):
# Otherwise, halt the trace if no link exists # Otherwise, halt the trace if no link exists
break break
if not all(type(link) in (Cable, WirelessLink) for link in links): if not all(type(link) in (Cable, WirelessLink) for link in links):
raise ValidationError(_("All links must be cable or wireless")) raise UnsupportedCablePath(_("All links must be cable or wireless"))
if not all(isinstance(link, type(links[0])) for link in links): if not all(isinstance(link, type(links[0])) for link in links):
raise ValidationError(_("All links must match first link type")) raise UnsupportedCablePath(_("All links must match first link type"))
# Step 3: Record asymmetric paths as split # Step 3: Record asymmetric paths as split
not_connected_terminations = [termination.link for termination in terminations if termination.link is None] not_connected_terminations = [termination.link for termination in terminations if termination.link is None]
@ -653,7 +654,7 @@ class CablePath(models.Model):
# Ensure we have a number of positions equal to the amount of remote terminations # Ensure we have a number of positions equal to the amount of remote terminations
if len(remote_terminations) != len(positions): if len(remote_terminations) != len(positions):
raise ValidationError( raise UnsupportedCablePath(
_("All positions counts within the path on opposite ends of links must match") _("All positions counts within the path on opposite ends of links must match")
) )
@ -663,7 +664,7 @@ class CablePath(models.Model):
position = positions.pop() position = positions.pop()
q_filter |= Q(rear_port_id=rt.pk, rear_port_position=position) q_filter |= Q(rear_port_id=rt.pk, rear_port_position=position)
if q_filter is Q(): if q_filter is Q():
raise ValidationError(_("Remote termination position filter is missing")) raise UnsupportedCablePath(_("Remote termination position filter is missing"))
front_ports = FrontPort.objects.filter(q_filter) front_ports = FrontPort.objects.filter(q_filter)
# Obtain the individual front ports based on the termination and position # Obtain the individual front ports based on the termination and position
elif position_stack: elif position_stack:

View File

@ -1,8 +1,8 @@
from django.core.exceptions import ValidationError
from django.test import TestCase from django.test import TestCase
from circuits.models import * from circuits.models import *
from dcim.choices import LinkStatusChoices from dcim.choices import LinkStatusChoices
from dcim.exceptions import UnsupportedCablePath
from dcim.models import * from dcim.models import *
from dcim.svg import CableTraceSVG from dcim.svg import CableTraceSVG
from dcim.utils import object_to_path_node from dcim.utils import object_to_path_node
@ -2262,7 +2262,7 @@ class CablePathTestCase(TestCase):
b_terminations=[frontport1, frontport3], b_terminations=[frontport1, frontport3],
label='C1' label='C1'
) )
with self.assertRaises(ValidationError): with self.assertRaises(UnsupportedCablePath):
cable1.save() cable1.save()
self.assertPathDoesNotExist( self.assertPathDoesNotExist(
@ -2281,7 +2281,7 @@ class CablePathTestCase(TestCase):
label='C3' label='C3'
) )
with self.assertRaises(ValidationError): with self.assertRaises(UnsupportedCablePath):
cable3.save() cable3.save()
self.assertPathDoesNotExist( self.assertPathDoesNotExist(

View File

@ -3,7 +3,6 @@ from collections import defaultdict
from copy import deepcopy from copy import deepcopy
from django.contrib import messages from django.contrib import messages
from django.core.exceptions import ValidationError
from django.db import router, transaction from django.db import router, transaction
from django.db.models import ProtectedError, RestrictedError from django.db.models import ProtectedError, RestrictedError
from django.db.models.deletion import Collector from django.db.models.deletion import Collector
@ -14,6 +13,7 @@ from django.utils.html import escape
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from dcim.exceptions import UnsupportedCablePath
from extras.signals import clear_events from extras.signals import clear_events
from utilities.error_handlers import handle_protectederror from utilities.error_handlers import handle_protectederror
from utilities.exceptions import AbortRequest, PermissionsViolation from utilities.exceptions import AbortRequest, PermissionsViolation
@ -309,7 +309,7 @@ class ObjectEditView(GetReturnURLMixin, BaseObjectView):
clear_events.send(sender=self) clear_events.send(sender=self)
# Catch any validation errors thrown in the model.save() or form.save() methods # Catch any validation errors thrown in the model.save() or form.save() methods
except ValidationError as e: except UnsupportedCablePath as e:
logger.debug(e.message) logger.debug(e.message)
form.add_error(None, e.message) form.add_error(None, e.message)
clear_events.send(sender=self) clear_events.send(sender=self)