content: import operator
  
  from django.core import validators
  from django.core.exceptions import ValidationError
  from django.utils.translation import gettext_lazy as _
  
  # NOTE: As this module may be imported by configuration.py, we cannot import
  # anything from NetBox itself.
  
  
  class IsEqualValidator(validators.BaseValidator):
      """
      Employed by CustomValidator to require a specific value.
      """
      message = _("Ensure this value is equal to %(limit_value)s.")
      code = "is_equal"
  
      def compare(self, a, b):
          return a != b
  
  
  class IsNotEqualValidator(validators.BaseValidator):
      """
      Employed by CustomValidator to exclude a specific value.
      """
      message = _("Ensure this value does not equal %(limit_value)s.")
      code = "is_not_equal"
  
      def compare(self, a, b):
          return a == b
  
  
  class IsEmptyValidator:
      """
      Employed by CustomValidator to enforce required fields.
      """
      message = _("This field must be empty.")
      code = 'is_empty'
  
      def __init__(self, enforce=True):
          self._enforce = enforce
  
      def __call__(self, value):
          if self._enforce and value not in validators.EMPTY_VALUES:
              raise ValidationError(self.message, code=self.code)
  
  
  class IsNotEmptyValidator:
      """
      Employed by CustomValidator to enforce prohibited fields.
      """
      message = _("This field must not be empty.")
      code = 'not_empty'
  
      def __init__(self, enforce=True):
          self._enforce = enforce
  
      def __call__(self, value):
          if self._enforce and value in validators.EMPTY_VALUES:
              raise ValidationError(self.message, code=self.code)
  
  
  class CustomValidator:
      """
      This class enables the application of user-defined validation rules to NetBox models. It can be instantiated by
      passing a dictionary of validation rules in the form {attribute: rules}, where 'rules' is a dictionary mapping
      descriptors (e.g. min_length or regex) to values.
  
      A CustomValidator instance is applied by calling it with the instance being validated:
  
          validator = CustomValidator({'name': {'min_length: 10}})
          site = Site(name='abcdef')
          validator(site)  # Raises ValidationError
  
      :param validation_rules: A dictionary mapping object attributes to validation rules
      """
      REQUEST_TOKEN = 'request'
  
      VALIDATORS = {
          'eq': IsEqualValidator,
          'neq': IsNotEqualValidator,
          'min': validators.MinValueValidator,
          'max': validators.MaxValueValidator,
          'min_length': validators.MinLengthValidator,
          'max_length': validators.MaxLengthValidator,
          'regex': validators.RegexValidator,
          'required': IsNotEmptyValidator,
          'prohibited': IsEmptyValidator,
      }
  
      def __init__(self, validation_rules=None):
          self.validation_rules = validation_rules or {}
          if type(self.validation_rules) is not dict:
              raise ValueError(_("Validation rules must be passed as a dictionary"))
  
      def __call__(self, instance, request=None):
          """
          Validate the instance and (optional) request against the validation rule(s).
          """
          for attr_path, rules in self.validation_rules.items():
  
              # The rule applies to the current request
              if attr_path.split('.')[0] == self.REQUEST_TOKEN:
                  # Skip if no request has been provided (we can't validate)
                  if request is None:
                      continue
                  attr = self._get_request_attr(request, attr_path)
              # The rule applies to the instance
              else:
                  attr = self._get_instance_attr(instance, attr_path)
  
              # Validate the attribute's value against each of the rules defined for it
              for descriptor, value in rules.items():
                  validator = self.get_validator(descriptor, value)
                  try:
                      validator(attr)
                  except ValidationError as exc:
                      raise ValidationError(
                          _("Custom validation failed for {attribute}: {exception}").format(
                              attribute=attr_path, exception=exc
                          )
                      )
  
          # Execute custom validation logic (if any)
          self.validate(instance, request)
  
      @staticmethod
      def _get_request_attr(request, name):
          name = name.split('.', maxsplit=1)[1]  # Remove token
          try:
              return operator.attrgetter(name)(request)
          except AttributeError:
              raise ValidationError(_('Invalid attribute "{name}" for request').format(name=name))
  
      @staticmethod
      def _get_instance_attr(instance, name):
          # Attempt to resolve many-to-many fields to their stored values
          m2m_fields = [f.name for f in instance._meta.local_many_to_many]
          if name in m2m_fields:
              if name in getattr(instance, '_m2m_values', []):
                  return instance._m2m_values[name]
              if instance.pk:
                  return list(getattr(instance, name).all())
              return []
  
          # Raise a ValidationError for unknown attributes
          try:
              return operator.attrgetter(name)(instance)
          except AttributeError:
              raise ValidationError(_('Invalid attribute "{name}" for {model}').format(
                  name=name,
                  model=instance.__class__.__name__
              ))
  
      def get_validator(self, descriptor, value):
          """
          Instantiate and return the appropriate validator based on the descriptor given. For
          example, 'min' returns MinValueValidator(value).
          """
          if descriptor not in self.VALIDATORS:
              raise NotImplementedError(
                  f"Unknown validation type for {self.__class__.__name__}: '{descriptor}'"
              )
          validator_cls = self.VALIDATORS.get(descriptor)
          return validator_cls(value)
  
      def validate(self, instance, request):
          """
          Custom validation method, to be overridden by the user. Validation failures should
          raise a ValidationError exception.
          """
          return
  
      def fail(self, message, field=None):
          """
          Raise a ValidationError exception. Associate the provided message with a form/serializer field if specified.
          """
          if field is not None:
              raise ValidationError({field: message})
          raise ValidationError(message)
  