Skip to content

Narrow RegexValidator.regex instance level type to Pattern[str] #2650

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion django-stubs/core/validators.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ _Regex: TypeAlias = str | Pattern[str]
_ValidatorCallable: TypeAlias = Callable[[Any], None] # noqa: PYI047

class RegexValidator(_Deconstructible):
regex: _Regex # Pattern[str] on instance, but may be str on class definition
regex: Pattern[str]
message: _StrOrPromise
code: str
inverse_match: bool
Expand Down
7 changes: 7 additions & 0 deletions scripts/stubtest/allowlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -550,3 +550,10 @@ django.contrib.gis.forms.BaseModelFormSet.save_m2m

# Dynamically generated in https://github.com/django/django/blob/0ee06c04e0256094270db3ffe8b5dafa6a8457a3/django/core/mail/backends/locmem.py#L24
django.core.mail.outbox

# The type system does not allow to represent an attribute with different type at the class level (`str | Pattern[str]`)
# and instance (`Pattern[str]`) level. But in order to have more precise type at the instance level, we restrict the types
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But in order to have more precise type at the instance level, we restrict the types

Sorry, we can't do that either. We can allow something that does not work to happen (false negative), but this will block valid useges (false positive). That's something we try to avoid, unless we are 100% sure that it is worth it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then I guess we cannot do more currently. At least I did not find a way. I tried another approach using __new__ but could not get it to work properly for both case either.

I'll close the PR, we might be able to revisit once the type system allows to represent this.

Thanks for the review nonetheless!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe #2615 will find a way

# allowed at the class level to a subset. In an ideal world, these should probably have different attribute names.
django.core.validators.RegexValidator.regex
django.contrib.auth.validators.ASCIIUsernameValidator.regex
django.contrib.auth.validators.UnicodeUsernameValidator.regex
32 changes: 32 additions & 0 deletions tests/assert_type/core/test_validators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import re
from re import Pattern

from django.contrib.auth.validators import UnicodeUsernameValidator
from django.core.validators import RegexValidator
from typing_extensions import assert_type

assert_type(RegexValidator().regex, Pattern[str])
RegexValidator().regex = re.compile("")

assert_type(UnicodeUsernameValidator().regex, Pattern[str])
UnicodeUsernameValidator().regex = re.compile("")

# expect "Pattern[str]"
RegexValidator().regex = "" # type: ignore[assignment] # pyright: ignore[reportAttributeAccessIssue]
UnicodeUsernameValidator().regex = "" # type: ignore[assignment] # pyright: ignore[reportAttributeAccessIssue]


class RegexSubtype(RegexValidator):
regex = re.compile("abc")


# We would like to improve on these, it should allow "str | Pattern[str]":
assert_type(RegexValidator.regex, Pattern[str])
assert_type(UnicodeUsernameValidator.regex, Pattern[str])

RegexValidator.regex = "" # type: ignore[assignment] # pyright: ignore[reportAttributeAccessIssue]
UnicodeUsernameValidator.regex = "" # type: ignore[assignment] # pyright: ignore[reportAttributeAccessIssue]


class StrSubtype(RegexValidator):
regex = "abc" # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
Loading