I am trying to overwrite the RegisterSerializer class provided by dj-rest-auth.
I am running into an issue, which I believe is due to how I am trying to extend the ValidationError class
I have overwritten the is_valid method as so:
def is_valid(self, raise_exception=False):
try:
# we first replace password1 and password2 in initial_data (by default, dj-rest-auth
# expects these fields -- our API just asks for 'password', and we rely on frontend
# for password1=password2 verification)
if "password" not in self.initial_data:
raise CustomValidationError(
GenericAPIErrorCodes.MALFORMED_REQUEST, "Password field is required"
)
# Set "password1" and "password2" to the value of "password"
self.initial_data["password1"] = self.initial_data["password"]
self.initial_data["password2"] = self.initial_data["password"]
output = super().is_valid(raise_exception=raise_exception)
return output
except CustomValidationError as exc:
raise exc # furthering the error up the chain
except DjangoCoreValidationError as exc:
raise CustomValidationError(
code=GenericAPIErrorCodes.MALFORMED_REQUEST.value, detail=exc.message
)
except Exception as exc:
print(exc)
raise CustomValidationError(
code=GenericAPIErrorCodes.MALFORMED_REQUEST.value, detail=""
)
The error is getting thrown from line "output = super().is_valid(...)", which eventually ends up calling:
def clean_password(self, password, user=None):
# We catch errors coming out of clean password function and replace them with our own
try:
print("cleaning pass!")
super().clean_password(password, user=user)
print("cleaned!")
except Exception as e:
print("yes!")
raise CustomValidationError(
code=AuthErrorCodes.INVALID_PASSWORD.value,
detail="Passwords must be at least 6 characters long, avoid common passwords, be dissimilar from the username, contain at least one digit, one uppercase character, one lowercase character, one special character, and not exceed 20 characters in length.",
)
which is a function I overwrote originally from allauth.account.adapter to throw a custom errror:
class CustomValidationError(serializers.ValidationError):
def __init__(self, code: str, detail: str):
super().__init__({"error": {"code": code, "detail": detail}})
self.code = code # Add the code attribute
self.detail = detail
# To make it JSON serializable
def to_dict(self):
return {"error": {"code": self.code, "detail": self.detail}}
I have stepped through is_valid function using the debugger line by line. I have confirmed that it goes directly from super().is_valid -> clean_password -> is_valid.
The issue I am having is that the exception is not caught by CustomValidationError. When I print out 'exc' in the generic 'Exception' handler, I get:
"{'password1': ErrorDetail(string='Passwords must be at least 6 characters long, avoid common passwords, be dissimilar from the username, contain at least one digit, one uppercase character, one lowercase character, one special character, and not exceed 20 characters in length.', code='invalid')}"
This is extremely confusing. This doesn't match the format of CustomValidationError at all, and I don't understand why it isn't being caught by the CustomValidationError except statement. It is almost as if some invisible middleware is being applied, but I stepped through each step line by line and didn't see any other transformations being applied.
Why is the CustomValidationError not being caught by the except statement, and why is the error strangely formatted (i.e., not formatted as a CustomValidationError) when printing exc?
I believe it is due to how I am trying to extend the ValidationError class, as if I switch to extending a generic Exception the error is appropriately caught