Refs #33476 -- Refactored code to strictly match 88 characters line length.

This commit is contained in:
Mariusz Felisiak 2022-02-04 08:08:27 +01:00
parent 9c19aff7c7
commit 7119f40c98
404 changed files with 5944 additions and 2842 deletions

View File

@ -224,9 +224,9 @@ class Apps:
and model.__module__ == app_models[model_name].__module__ and model.__module__ == app_models[model_name].__module__
): ):
warnings.warn( warnings.warn(
"Model '%s.%s' was already registered. " "Model '%s.%s' was already registered. Reloading models is not "
"Reloading models is not advised as it can lead to inconsistencies, " "advised as it can lead to inconsistencies, most notably with "
"most notably with related models." % (app_label, model_name), "related models." % (app_label, model_name),
RuntimeWarning, RuntimeWarning,
stacklevel=2, stacklevel=2,
) )

View File

@ -21,8 +21,8 @@ DEBUG = False
# on a live site. # on a live site.
DEBUG_PROPAGATE_EXCEPTIONS = False DEBUG_PROPAGATE_EXCEPTIONS = False
# People who get code error notifications. # People who get code error notifications. In the format
# In the format [('Full Name', 'email@example.com'), ('Full Name', 'anotheremail@example.com')] # [('Full Name', 'email@example.com'), ('Full Name', 'anotheremail@example.com')]
ADMINS = [] ADMINS = []
# List of IP addresses, as strings, that: # List of IP addresses, as strings, that:
@ -319,7 +319,8 @@ DATA_UPLOAD_MAX_NUMBER_FIELDS = 1000
FILE_UPLOAD_TEMP_DIR = None FILE_UPLOAD_TEMP_DIR = None
# The numeric mode to set newly-uploaded files to. The value should be a mode # The numeric mode to set newly-uploaded files to. The value should be a mode
# you'd pass directly to os.chmod; see https://docs.python.org/library/os.html#files-and-directories. # you'd pass directly to os.chmod; see
# https://docs.python.org/library/os.html#files-and-directories.
FILE_UPLOAD_PERMISSIONS = 0o644 FILE_UPLOAD_PERMISSIONS = 0o644
# The numeric mode to assign to newly-created directories, when uploading files. # The numeric mode to assign to newly-created directories, when uploading files.

View File

@ -447,9 +447,9 @@ class BaseModelAdminChecks:
): ):
return [ return [
checks.Error( checks.Error(
"The value of '%s' cannot include the ManyToManyField '%s', " "The value of '%s' cannot include the ManyToManyField "
"because that field manually specifies a relationship model." "'%s', because that field manually specifies a "
% (label, field_name), "relationship model." % (label, field_name),
obj=obj.__class__, obj=obj.__class__,
id="admin.E013", id="admin.E013",
) )
@ -568,8 +568,8 @@ class BaseModelAdminChecks:
return [ return [
checks.Error( checks.Error(
"The value of '%s' refers to '%s', which is not an " "The value of '%s' refers to '%s', which is not an "
"instance of ForeignKey, and does not have a 'choices' definition." "instance of ForeignKey, and does not have a 'choices' "
% (label, field_name), "definition." % (label, field_name),
obj=obj.__class__, obj=obj.__class__,
id="admin.E023", id="admin.E023",
) )
@ -585,8 +585,8 @@ class BaseModelAdminChecks:
if val not in (HORIZONTAL, VERTICAL): if val not in (HORIZONTAL, VERTICAL):
return [ return [
checks.Error( checks.Error(
"The value of '%s' must be either admin.HORIZONTAL or admin.VERTICAL." "The value of '%s' must be either admin.HORIZONTAL or "
% label, "admin.VERTICAL." % label,
obj=obj.__class__, obj=obj.__class__,
id="admin.E024", id="admin.E024",
) )
@ -598,7 +598,8 @@ class BaseModelAdminChecks:
if not callable(obj.view_on_site) and not isinstance(obj.view_on_site, bool): if not callable(obj.view_on_site) and not isinstance(obj.view_on_site, bool):
return [ return [
checks.Error( checks.Error(
"The value of 'view_on_site' must be a callable or a boolean value.", "The value of 'view_on_site' must be a callable or a boolean "
"value.",
obj=obj.__class__, obj=obj.__class__,
id="admin.E025", id="admin.E025",
) )
@ -643,9 +644,9 @@ class BaseModelAdminChecks:
): ):
return [ return [
checks.Error( checks.Error(
"The value of '%s' refers to '%s', which must not be a DateTimeField, " "The value of '%s' refers to '%s', which must not be a "
"a ForeignKey, a OneToOneField, or a ManyToManyField." "DateTimeField, a ForeignKey, a OneToOneField, or a "
% (label, field_name), "ManyToManyField." % (label, field_name),
obj=obj.__class__, obj=obj.__class__,
id="admin.E028", id="admin.E028",
) )
@ -955,8 +956,8 @@ class ModelAdminChecks(BaseModelAdminChecks):
if field_name not in obj.list_display: if field_name not in obj.list_display:
return [ return [
checks.Error( checks.Error(
"The value of '%s' refers to '%s', which is not defined in 'list_display'." "The value of '%s' refers to '%s', which is not defined in "
% (label, field_name), "'list_display'." % (label, field_name),
obj=obj.__class__, obj=obj.__class__,
id="admin.E111", id="admin.E111",
) )
@ -1027,8 +1028,8 @@ class ModelAdminChecks(BaseModelAdminChecks):
except (NotRelationField, FieldDoesNotExist): except (NotRelationField, FieldDoesNotExist):
return [ return [
checks.Error( checks.Error(
"The value of '%s' refers to '%s', which does not refer to a Field." "The value of '%s' refers to '%s', which does not refer to a "
% (label, field), "Field." % (label, field),
obj=obj.__class__, obj=obj.__class__,
id="admin.E116", id="admin.E116",
) )
@ -1107,8 +1108,8 @@ class ModelAdminChecks(BaseModelAdminChecks):
elif obj.list_display_links and field_name in obj.list_display_links: elif obj.list_display_links and field_name in obj.list_display_links:
return [ return [
checks.Error( checks.Error(
"The value of '%s' cannot be in both 'list_editable' and 'list_display_links'." "The value of '%s' cannot be in both 'list_editable' and "
% field_name, "'list_display_links'." % field_name,
obj=obj.__class__, obj=obj.__class__,
id="admin.E123", id="admin.E123",
) )
@ -1122,9 +1123,9 @@ class ModelAdminChecks(BaseModelAdminChecks):
): ):
return [ return [
checks.Error( checks.Error(
"The value of '%s' refers to the first field in 'list_display' ('%s'), " "The value of '%s' refers to the first field in 'list_display' "
"which cannot be used unless 'list_display_links' is set." "('%s'), which cannot be used unless 'list_display_links' is "
% (label, obj.list_display[0]), "set." % (label, obj.list_display[0]),
obj=obj.__class__, obj=obj.__class__,
id="admin.E124", id="admin.E124",
) )
@ -1132,8 +1133,8 @@ class ModelAdminChecks(BaseModelAdminChecks):
elif not field.editable: elif not field.editable:
return [ return [
checks.Error( checks.Error(
"The value of '%s' refers to '%s', which is not editable through the admin." "The value of '%s' refers to '%s', which is not editable "
% (label, field_name), "through the admin." % (label, field_name),
obj=obj.__class__, obj=obj.__class__,
id="admin.E125", id="admin.E125",
) )

View File

@ -64,7 +64,8 @@ class LogEntry(models.Model):
null=True, null=True,
) )
object_id = models.TextField(_("object id"), blank=True, null=True) object_id = models.TextField(_("object id"), blank=True, null=True)
# Translators: 'repr' means representation (https://docs.python.org/library/functions.html#repr) # Translators: 'repr' means representation
# (https://docs.python.org/library/functions.html#repr)
object_repr = models.CharField(_("object repr"), max_length=200) object_repr = models.CharField(_("object repr"), max_length=200)
action_flag = models.PositiveSmallIntegerField( action_flag = models.PositiveSmallIntegerField(
_("action flag"), choices=ACTION_FLAG_CHOICES _("action flag"), choices=ACTION_FLAG_CHOICES

View File

@ -1276,7 +1276,9 @@ class ModelAdmin(BaseModelAdmin):
"has_add_permission": self.has_add_permission(request), "has_add_permission": self.has_add_permission(request),
"has_change_permission": self.has_change_permission(request, obj), "has_change_permission": self.has_change_permission(request, obj),
"has_delete_permission": self.has_delete_permission(request, obj), "has_delete_permission": self.has_delete_permission(request, obj),
"has_editable_inline_admin_formsets": has_editable_inline_admin_formsets, "has_editable_inline_admin_formsets": (
has_editable_inline_admin_formsets
),
"has_file_field": context["adminform"].form.is_multipart() "has_file_field": context["adminform"].form.is_multipart()
or any( or any(
admin_formset.formset.is_multipart() admin_formset.formset.is_multipart()
@ -1383,7 +1385,8 @@ class ModelAdmin(BaseModelAdmin):
elif "_addanother" in request.POST: elif "_addanother" in request.POST:
msg = format_html( msg = format_html(
_( _(
"The {name}{obj}” was added successfully. You may add another {name} below." "The {name}{obj}” was added successfully. You may add another "
"{name} below."
), ),
**msg_dict, **msg_dict,
) )
@ -1444,7 +1447,8 @@ class ModelAdmin(BaseModelAdmin):
if "_continue" in request.POST: if "_continue" in request.POST:
msg = format_html( msg = format_html(
_( _(
"The {name}{obj}” was changed successfully. You may edit it again below." "The {name}{obj}” was changed successfully. You may edit it "
"again below."
), ),
**msg_dict, **msg_dict,
) )
@ -1458,7 +1462,8 @@ class ModelAdmin(BaseModelAdmin):
elif "_saveasnew" in request.POST: elif "_saveasnew" in request.POST:
msg = format_html( msg = format_html(
_( _(
"The {name}{obj}” was added successfully. You may edit it again below." "The {name}{obj}” was added successfully. You may edit it again "
"below."
), ),
**msg_dict, **msg_dict,
) )
@ -1476,7 +1481,8 @@ class ModelAdmin(BaseModelAdmin):
elif "_addanother" in request.POST: elif "_addanother" in request.POST:
msg = format_html( msg = format_html(
_( _(
"The {name}{obj}” was changed successfully. You may add another {name} below." "The {name}{obj}” was changed successfully. You may add another "
"{name} below."
), ),
**msg_dict, **msg_dict,
) )
@ -2389,8 +2395,9 @@ class InlineModelAdmin(BaseModelAdmin):
objs = [] objs = []
for p in collector.protected: for p in collector.protected:
objs.append( objs.append(
# Translators: Model verbose name and instance representation, # Translators: Model verbose name and instance
# suitable to be an item in a list. # representation, suitable to be an item in a
# list.
_("%(class_name)s %(instance)s") _("%(class_name)s %(instance)s")
% {"class_name": p._meta.verbose_name, "instance": p} % {"class_name": p._meta.verbose_name, "instance": p}
) )

View File

@ -32,7 +32,7 @@ def get_admin_log(parser, token):
Usage:: Usage::
{% get_admin_log [limit] as [varname] for_user [context_var_containing_user_obj] %} {% get_admin_log [limit] as [varname] for_user [context_var_with_user_obj] %}
Examples:: Examples::

View File

@ -70,12 +70,14 @@ def authenticate(request=None, **credentials):
try: try:
backend_signature.bind(request, **credentials) backend_signature.bind(request, **credentials)
except TypeError: except TypeError:
# This backend doesn't accept these credentials as arguments. Try the next one. # This backend doesn't accept these credentials as arguments. Try
# the next one.
continue continue
try: try:
user = backend.authenticate(request, **credentials) user = backend.authenticate(request, **credentials)
except PermissionDenied: except PermissionDenied:
# This backend says to stop in our tracks - this user should not be allowed in at all. # This backend says to stop in our tracks - this user should not be
# allowed in at all.
break break
if user is None: if user is None:
continue continue

View File

@ -61,8 +61,8 @@ def check_user_model(app_configs=None, **kwargs):
]: ]:
errors.append( errors.append(
checks.Error( checks.Error(
"'%s.%s' must be unique because it is named as the 'USERNAME_FIELD'." "'%s.%s' must be unique because it is named as the "
% (cls._meta.object_name, cls.USERNAME_FIELD), "'USERNAME_FIELD'." % (cls._meta.object_name, cls.USERNAME_FIELD),
obj=cls, obj=cls,
id="auth.E003", id="auth.E003",
) )
@ -72,7 +72,10 @@ def check_user_model(app_configs=None, **kwargs):
checks.Warning( checks.Warning(
"'%s.%s' is named as the 'USERNAME_FIELD', but it is not unique." "'%s.%s' is named as the 'USERNAME_FIELD', but it is not unique."
% (cls._meta.object_name, cls.USERNAME_FIELD), % (cls._meta.object_name, cls.USERNAME_FIELD),
hint="Ensure that your authentication backend(s) can handle non-unique usernames.", hint=(
"Ensure that your authentication backend(s) can handle "
"non-unique usernames."
),
obj=cls, obj=cls,
id="auth.W004", id="auth.W004",
) )
@ -197,8 +200,8 @@ def check_models_permissions(app_configs=None, **kwargs):
if codename in builtin_permissions: if codename in builtin_permissions:
errors.append( errors.append(
checks.Error( checks.Error(
"The permission codenamed '%s' clashes with a builtin permission " "The permission codenamed '%s' clashes with a builtin "
"for model '%s'." % (codename, opts.label), "permission for model '%s'." % (codename, opts.label),
obj=model, obj=model,
id="auth.E005", id="auth.E005",
) )

View File

@ -24,7 +24,10 @@ class Command(BaseCommand):
parser.add_argument( parser.add_argument(
"username", "username",
nargs="?", nargs="?",
help="Username to change password for; by default, it's the current username.", help=(
"Username to change password for; by default, it's the current "
"username."
),
) )
parser.add_argument( parser.add_argument(
"--database", "--database",

View File

@ -102,14 +102,20 @@ class Migration(migrations.Migration):
"is_superuser", "is_superuser",
models.BooleanField( models.BooleanField(
default=False, default=False,
help_text="Designates that this user has all permissions without explicitly assigning them.", help_text=(
"Designates that this user has all permissions without "
"explicitly assigning them."
),
verbose_name="superuser status", verbose_name="superuser status",
), ),
), ),
( (
"username", "username",
models.CharField( models.CharField(
help_text="Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.", help_text=(
"Required. 30 characters or fewer. Letters, digits and "
"@/./+/-/_ only."
),
unique=True, unique=True,
max_length=30, max_length=30,
verbose_name="username", verbose_name="username",
@ -138,7 +144,9 @@ class Migration(migrations.Migration):
"is_staff", "is_staff",
models.BooleanField( models.BooleanField(
default=False, default=False,
help_text="Designates whether the user can log into this admin site.", help_text=(
"Designates whether the user can log into this admin site."
),
verbose_name="staff status", verbose_name="staff status",
), ),
), ),
@ -148,8 +156,8 @@ class Migration(migrations.Migration):
default=True, default=True,
verbose_name="active", verbose_name="active",
help_text=( help_text=(
"Designates whether this user should be treated as active. Unselect this instead of deleting " "Designates whether this user should be treated as active. "
"accounts." "Unselect this instead of deleting accounts."
), ),
), ),
), ),
@ -168,8 +176,8 @@ class Migration(migrations.Migration):
related_name="user_set", related_name="user_set",
related_query_name="user", related_query_name="user",
help_text=( help_text=(
"The groups this user belongs to. A user will get all permissions granted to each of their " "The groups this user belongs to. A user will get all "
"groups." "permissions granted to each of their groups."
), ),
), ),
), ),

View File

@ -17,7 +17,10 @@ class Migration(migrations.Migration):
error_messages={"unique": "A user with that username already exists."}, error_messages={"unique": "A user with that username already exists."},
max_length=30, max_length=30,
validators=[validators.UnicodeUsernameValidator()], validators=[validators.UnicodeUsernameValidator()],
help_text="Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.", help_text=(
"Required. 30 characters or fewer. Letters, digits and @/./+/-/_ "
"only."
),
unique=True, unique=True,
verbose_name="username", verbose_name="username",
), ),

View File

@ -14,7 +14,10 @@ class Migration(migrations.Migration):
name="username", name="username",
field=models.CharField( field=models.CharField(
error_messages={"unique": "A user with that username already exists."}, error_messages={"unique": "A user with that username already exists."},
help_text="Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.", help_text=(
"Required. 30 characters or fewer. Letters, digits and @/./+/-/_ "
"only."
),
max_length=30, max_length=30,
unique=True, unique=True,
validators=[validators.UnicodeUsernameValidator()], validators=[validators.UnicodeUsernameValidator()],

View File

@ -14,7 +14,10 @@ class Migration(migrations.Migration):
name="username", name="username",
field=models.CharField( field=models.CharField(
error_messages={"unique": "A user with that username already exists."}, error_messages={"unique": "A user with that username already exists."},
help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.", help_text=(
"Required. 150 characters or fewer. Letters, digits and @/./+/-/_ "
"only."
),
max_length=150, max_length=150,
unique=True, unique=True,
validators=[validators.UnicodeUsernameValidator()], validators=[validators.UnicodeUsernameValidator()],

View File

@ -25,8 +25,9 @@ class AccessMixin:
login_url = self.login_url or settings.LOGIN_URL login_url = self.login_url or settings.LOGIN_URL
if not login_url: if not login_url:
raise ImproperlyConfigured( raise ImproperlyConfigured(
"{0} is missing the login_url attribute. Define {0}.login_url, settings.LOGIN_URL, or override " f"{self.__class__.__name__} is missing the login_url attribute. Define "
"{0}.get_login_url().".format(self.__class__.__name__) f"{self.__class__.__name__}.login_url, settings.LOGIN_URL, or override "
f"{self.__class__.__name__}.get_login_url()."
) )
return str(login_url) return str(login_url)
@ -84,8 +85,10 @@ class PermissionRequiredMixin(AccessMixin):
""" """
if self.permission_required is None: if self.permission_required is None:
raise ImproperlyConfigured( raise ImproperlyConfigured(
"{0} is missing the permission_required attribute. Define {0}.permission_required, or override " f"{self.__class__.__name__} is missing the "
"{0}.get_permission_required().".format(self.__class__.__name__) f"permission_required attribute. Define "
f"{self.__class__.__name__}.permission_required, or override "
f"{self.__class__.__name__}.get_permission_required()."
) )
if isinstance(self.permission_required, str): if isinstance(self.permission_required, str):
perms = (self.permission_required,) perms = (self.permission_required,)

View File

@ -435,7 +435,8 @@ class AnonymousUser:
def __int__(self): def __int__(self):
raise TypeError( raise TypeError(
"Cannot cast AnonymousUser to int. Are you trying to use it in place of User?" "Cannot cast AnonymousUser to int. Are you trying to use it in place of "
"User?"
) )
def save(self): def save(self):

View File

@ -28,7 +28,10 @@ def get_password_validators(validator_config):
try: try:
klass = import_string(validator["NAME"]) klass = import_string(validator["NAME"])
except ImportError: except ImportError:
msg = "The module in NAME could not be imported: %s. Check your AUTH_PASSWORD_VALIDATORS setting." msg = (
"The module in NAME could not be imported: %s. Check your "
"AUTH_PASSWORD_VALIDATORS setting."
)
raise ImproperlyConfigured(msg % validator["NAME"]) raise ImproperlyConfigured(msg % validator["NAME"])
validators.append(klass(**validator.get("OPTIONS", {}))) validators.append(klass(**validator.get("OPTIONS", {})))
@ -105,8 +108,10 @@ class MinimumLengthValidator:
if len(password) < self.min_length: if len(password) < self.min_length:
raise ValidationError( raise ValidationError(
ngettext( ngettext(
"This password is too short. It must contain at least %(min_length)d character.", "This password is too short. It must contain at least "
"This password is too short. It must contain at least %(min_length)d characters.", "%(min_length)d character.",
"This password is too short. It must contain at least "
"%(min_length)d characters.",
self.min_length, self.min_length,
), ),
code="password_too_short", code="password_too_short",

View File

@ -19,8 +19,8 @@ class GenericInlineModelAdminChecks(InlineModelAdminChecks):
return [] return []
def _check_relation(self, obj, parent_model): def _check_relation(self, obj, parent_model):
# There's no FK, but we do need to confirm that the ct_field and ct_fk_field are valid, # There's no FK, but we do need to confirm that the ct_field and
# and that they are part of a GenericForeignKey. # ct_fk_field are valid, and that they are part of a GenericForeignKey.
gfks = [ gfks = [
f f
@ -75,7 +75,8 @@ class GenericInlineModelAdminChecks(InlineModelAdminChecks):
return [ return [
checks.Error( checks.Error(
"'%s' has no GenericForeignKey using content type field '%s' and object ID field '%s'." "'%s' has no GenericForeignKey using content type field '%s' and "
"object ID field '%s'."
% ( % (
obj.model._meta.label, obj.model._meta.label,
obj.ct_field, obj.ct_field,

View File

@ -120,8 +120,9 @@ class ContentTypeManager(models.Manager):
def _add_to_cache(self, using, ct): def _add_to_cache(self, using, ct):
"""Insert a ContentType into the cache.""" """Insert a ContentType into the cache."""
# Note it's possible for ContentType objects to be stale; model_class() will return None. # Note it's possible for ContentType objects to be stale; model_class()
# Hence, there is no reliance on model._meta.app_label here, just using the model fields instead. # will return None. Hence, there is no reliance on
# model._meta.app_label here, just using the model fields instead.
key = (ct.app_label, ct.model) key = (ct.app_label, ct.model)
self._cache.setdefault(using, {})[key] = ct self._cache.setdefault(using, {})[key] = ct
self._cache.setdefault(using, {})[ct.id] = ct self._cache.setdefault(using, {})[ct.id] = ct

View File

@ -12,7 +12,8 @@ class FlatpageForm(forms.ModelForm):
max_length=100, max_length=100,
regex=r"^[-\w/\.~]+$", regex=r"^[-\w/\.~]+$",
help_text=_( help_text=_(
"Example: “/about/contact/”. Make sure to have leading and trailing slashes." "Example: “/about/contact/”. Make sure to have leading and trailing "
"slashes."
), ),
error_messages={ error_messages={
"invalid": _( "invalid": _(

View File

@ -34,8 +34,8 @@ class Migration(migrations.Migration):
"template_name", "template_name",
models.CharField( models.CharField(
help_text=( help_text=(
"Example: “flatpages/contact_page.html”. If this isnt provided, the system will use " "Example: “flatpages/contact_page.html”. If this isnt "
"“flatpages/default.html”." "provided, the system will use “flatpages/default.html”."
), ),
max_length=70, max_length=70,
verbose_name="template name", verbose_name="template name",
@ -46,7 +46,10 @@ class Migration(migrations.Migration):
"registration_required", "registration_required",
models.BooleanField( models.BooleanField(
default=False, default=False,
help_text="If this is checked, only logged-in users will be able to view the page.", help_text=(
"If this is checked, only logged-in users will be able to "
"view the page."
),
verbose_name="registration required", verbose_name="registration required",
), ),
), ),

View File

@ -158,12 +158,14 @@ class BaseSpatialOperations:
# Routines for getting the OGC-compliant models. # Routines for getting the OGC-compliant models.
def geometry_columns(self): def geometry_columns(self):
raise NotImplementedError( raise NotImplementedError(
"Subclasses of BaseSpatialOperations must provide a geometry_columns() method." "Subclasses of BaseSpatialOperations must provide a geometry_columns() "
"method."
) )
def spatial_ref_sys(self): def spatial_ref_sys(self):
raise NotImplementedError( raise NotImplementedError(
"subclasses of BaseSpatialOperations must a provide spatial_ref_sys() method" "subclasses of BaseSpatialOperations must a provide spatial_ref_sys() "
"method"
) )
distance_expr_for_lookup = staticmethod(Distance) distance_expr_for_lookup = staticmethod(Distance)

View File

@ -20,7 +20,8 @@ class DatabaseFeatures(BaseSpatialFeatures, OracleDatabaseFeatures):
skips.update( skips.update(
{ {
"Oracle doesn't support spatial operators in constraints.": { "Oracle doesn't support spatial operators in constraints.": {
"gis_tests.gis_migrations.test_operations.OperationTests.test_add_check_constraint", "gis_tests.gis_migrations.test_operations.OperationTests."
"test_add_check_constraint",
}, },
} }
) )

View File

@ -40,7 +40,10 @@ class SDORelate(SpatialOperator):
sql_template = "SDO_RELATE(%(lhs)s, %(rhs)s, 'mask=%(mask)s') = 'TRUE'" sql_template = "SDO_RELATE(%(lhs)s, %(rhs)s, 'mask=%(mask)s') = 'TRUE'"
def check_relate_argument(self, arg): def check_relate_argument(self, arg):
masks = "TOUCH|OVERLAPBDYDISJOINT|OVERLAPBDYINTERSECT|EQUAL|INSIDE|COVEREDBY|CONTAINS|COVERS|ANYINTERACT|ON" masks = (
"TOUCH|OVERLAPBDYDISJOINT|OVERLAPBDYINTERSECT|EQUAL|INSIDE|COVEREDBY|"
"CONTAINS|COVERS|ANYINTERACT|ON"
)
mask_regex = re.compile(r"^(%s)(\+(%s))*$" % (masks, masks), re.I) mask_regex = re.compile(r"^(%s)(\+(%s))*$" % (masks, masks), re.I)
if not isinstance(arg, str) or not mask_regex.match(arg): if not isinstance(arg, str) or not mask_regex.match(arg):
raise ValueError('Invalid SDO_RELATE mask: "%s"' % arg) raise ValueError('Invalid SDO_RELATE mask: "%s"' % arg)
@ -105,7 +108,8 @@ class OracleOperations(BaseSpatialOperations, DatabaseOperations):
"exact": SDOOperator(func="SDO_EQUAL"), "exact": SDOOperator(func="SDO_EQUAL"),
"overlaps": SDOOperator(func="SDO_OVERLAPS"), "overlaps": SDOOperator(func="SDO_OVERLAPS"),
"same_as": SDOOperator(func="SDO_EQUAL"), "same_as": SDOOperator(func="SDO_EQUAL"),
"relate": SDORelate(), # Oracle uses a different syntax, e.g., 'mask=inside+touch' # Oracle uses a different syntax, e.g., 'mask=inside+touch'
"relate": SDORelate(),
"touches": SDOOperator(func="SDO_TOUCH"), "touches": SDOOperator(func="SDO_TOUCH"),
"within": SDOOperator(func="SDO_INSIDE"), "within": SDOOperator(func="SDO_INSIDE"),
"dwithin": SDODWithin(), "dwithin": SDODWithin(),

View File

@ -16,7 +16,10 @@ class OracleGISSchemaEditor(DatabaseSchemaEditor):
), ),
%(srid)s %(srid)s
)""" )"""
sql_add_spatial_index = "CREATE INDEX %(index)s ON %(table)s(%(column)s) INDEXTYPE IS MDSYS.SPATIAL_INDEX" sql_add_spatial_index = (
"CREATE INDEX %(index)s ON %(table)s(%(column)s) "
"INDEXTYPE IS MDSYS.SPATIAL_INDEX"
)
sql_drop_spatial_index = "DROP INDEX %(index)s" sql_drop_spatial_index = "DROP INDEX %(index)s"
sql_clear_geometry_table_metadata = ( sql_clear_geometry_table_metadata = (
"DELETE FROM USER_SDO_GEOM_METADATA WHERE TABLE_NAME = %(table)s" "DELETE FROM USER_SDO_GEOM_METADATA WHERE TABLE_NAME = %(table)s"

View File

@ -56,7 +56,7 @@ STRUCT_SIZE = {
# whether the band data is stored as part of the datum or is to be found on the # whether the band data is stored as part of the datum or is to be found on the
# server's filesystem. There are currently 11 supported pixel value types, so 4 # server's filesystem. There are currently 11 supported pixel value types, so 4
# bits are enough to account for all. Reserve the upper 4 bits for generic # bits are enough to account for all. Reserve the upper 4 bits for generic
# flags. # flags. See
# See https://trac.osgeo.org/postgis/wiki/WKTRaster/RFC/RFC1_V0SerialFormat#Pixeltypeandstorageflag # https://trac.osgeo.org/postgis/wiki/WKTRaster/RFC/RFC1_V0SerialFormat#Pixeltypeandstorageflag
BANDTYPE_PIXTYPE_MASK = 0x0F BANDTYPE_PIXTYPE_MASK = 0x0F
BANDTYPE_FLAG_HASNODATA = 1 << 6 BANDTYPE_FLAG_HASNODATA = 1 << 6

View File

@ -22,7 +22,9 @@ class PostGISIntrospection(DatabaseIntrospection):
# dictionary isn't updated until introspection is performed here. # dictionary isn't updated until introspection is performed here.
with self.connection.cursor() as cursor: with self.connection.cursor() as cursor:
cursor.execute( cursor.execute(
"SELECT oid, typname FROM pg_type WHERE typname IN ('geometry', 'geography')" "SELECT oid, typname "
"FROM pg_type "
"WHERE typname IN ('geometry', 'geography')"
) )
self.postgis_oid_lookup = dict(cursor.fetchall()) self.postgis_oid_lookup = dict(cursor.fetchall())
self.data_types_reverse.update( self.data_types_reverse.update(

View File

@ -56,7 +56,8 @@ class PostGISOperator(SpatialOperator):
if lookup.band_lhs is not None and lhs_is_raster: if lookup.band_lhs is not None and lhs_is_raster:
if not self.func: if not self.func:
raise ValueError( raise ValueError(
"Band indices are not allowed for this operator, it works on bbox only." "Band indices are not allowed for this operator, it works on bbox "
"only."
) )
template_params["lhs"] = "%s, %s" % ( template_params["lhs"] = "%s, %s" % (
template_params["lhs"], template_params["lhs"],
@ -66,7 +67,8 @@ class PostGISOperator(SpatialOperator):
if lookup.band_rhs is not None and rhs_is_raster: if lookup.band_rhs is not None and rhs_is_raster:
if not self.func: if not self.func:
raise ValueError( raise ValueError(
"Band indices are not allowed for this operator, it works on bbox only." "Band indices are not allowed for this operator, it works on bbox "
"only."
) )
template_params["rhs"] = "%s, %s" % ( template_params["rhs"] = "%s, %s" % (
template_params["rhs"], template_params["rhs"],

View File

@ -317,9 +317,11 @@ class Distance(DistanceResultMixin, OracleToleranceMixin, GeoFunc):
) )
if not geography and self.geo_field.geodetic(connection): if not geography and self.geo_field.geodetic(connection):
# Geometry fields with geodetic (lon/lat) coordinates need special distance functions # Geometry fields with geodetic (lon/lat) coordinates need special
# distance functions.
if self.spheroid: if self.spheroid:
# DistanceSpheroid is more accurate and resource intensive than DistanceSphere # DistanceSpheroid is more accurate and resource intensive than
# DistanceSphere.
function = connection.ops.spatial_function_name("DistanceSpheroid") function = connection.ops.spatial_function_name("DistanceSpheroid")
# Replace boolean param by the real spheroid of the base field # Replace boolean param by the real spheroid of the base field
clone.source_expressions.append( clone.source_expressions.append(

View File

@ -202,7 +202,8 @@ class BBContainsLookup(GISLookup):
@BaseSpatialField.register_lookup @BaseSpatialField.register_lookup
class BBOverlapsLookup(GISLookup): class BBOverlapsLookup(GISLookup):
""" """
The 'bboverlaps' operator returns true if A's bounding box overlaps B's bounding box. The 'bboverlaps' operator returns true if A's bounding box overlaps B's
bounding box.
""" """
lookup_name = "bboverlaps" lookup_name = "bboverlaps"
@ -307,7 +308,8 @@ class DistanceLookupBase(GISLookup):
) )
elif len(self.rhs_params) == 3 and self.rhs_params[2] != "spheroid": elif len(self.rhs_params) == 3 and self.rhs_params[2] != "spheroid":
raise ValueError( raise ValueError(
"For 4-element tuples the last argument must be the 'spheroid' directive." "For 4-element tuples the last argument must be the 'spheroid' "
"directive."
) )
# Check if the second parameter is a band index. # Check if the second parameter is a band index.

View File

@ -28,7 +28,7 @@
>>> print(mpnt.proj) >>> print(mpnt.proj)
+proj=longlat +ellps=clrk66 +datum=NAD27 +no_defs +proj=longlat +ellps=clrk66 +datum=NAD27 +no_defs
>>> print(mpnt) >>> print(mpnt)
MULTIPOINT (-89.999930378602485 29.999797886557641,-89.999930378602485 29.999797886557641) MULTIPOINT (-89.99993037860248 29.99979788655764,-89.99993037860248 29.99979788655764)
The OGRGeomType class is to make it easy to specify an OGR geometry type: The OGRGeomType class is to make it easy to specify an OGR geometry type:
>>> from django.contrib.gis.gdal import OGRGeomType >>> from django.contrib.gis.gdal import OGRGeomType

View File

@ -19,7 +19,10 @@ from django.utils.encoding import force_bytes, force_str
# #
# The OGR_L_* routines are relevant here. # The OGR_L_* routines are relevant here.
class Layer(GDALBase): class Layer(GDALBase):
"A class that wraps an OGR Layer, needs to be instantiated from a DataSource object." """
A class that wraps an OGR Layer, needs to be instantiated from a DataSource
object.
"""
def __init__(self, layer_ptr, ds): def __init__(self, layer_ptr, ds):
""" """
@ -192,7 +195,8 @@ class Layer(GDALBase):
capi.set_spatial_filter(self.ptr, None) capi.set_spatial_filter(self.ptr, None)
else: else:
raise TypeError( raise TypeError(
"Spatial filter must be either an OGRGeometry instance, a 4-tuple, or None." "Spatial filter must be either an OGRGeometry instance, a 4-tuple, or "
"None."
) )
spatial_filter = property(_get_spatial_filter, _set_spatial_filter) spatial_filter = property(_get_spatial_filter, _set_spatial_filter)

View File

@ -131,7 +131,8 @@ class SpatialReference(GDALBase):
4326 4326
>>> print(srs['TOWGS84', 4]) # the fourth value in this wkt >>> print(srs['TOWGS84', 4]) # the fourth value in this wkt
0 0
>>> print(srs['UNIT|AUTHORITY']) # For the units authority, have to use the pipe symbole. >>> # For the units authority, have to use the pipe symbole.
>>> print(srs['UNIT|AUTHORITY'])
EPSG EPSG
>>> print(srs['UNIT|AUTHORITY', 1]) # The authority value for the units >>> print(srs['UNIT|AUTHORITY', 1]) # The authority value for the units
9122 9122

View File

@ -32,7 +32,8 @@ class Polygon(GEOSGeometry):
ext_ring, *init_holes = args ext_ring, *init_holes = args
n_holes = len(init_holes) n_holes = len(init_holes)
# If initialized as Polygon(shell, (LinearRing, LinearRing)) [for backward-compatibility] # If initialized as Polygon(shell, (LinearRing, LinearRing))
# [for backward-compatibility]
if n_holes == 1 and isinstance(init_holes[0], (tuple, list)): if n_holes == 1 and isinstance(init_holes[0], (tuple, list)):
if not init_holes[0]: if not init_holes[0]:
init_holes = () init_holes = ()
@ -101,7 +102,8 @@ class Polygon(GEOSGeometry):
self, self,
param, param,
msg=( msg=(
"Parameter must be a sequence of LinearRings or objects that can initialize to LinearRings" "Parameter must be a sequence of LinearRings or objects that can "
"initialize to LinearRings"
), ),
): ):
"Try to construct a ring from the given parameter." "Try to construct a ring from the given parameter."

View File

@ -34,8 +34,8 @@ class ListOptionAction(argparse.Action):
class Command(BaseCommand): class Command(BaseCommand):
help = ( help = (
"Inspects the given OGR-compatible data source (e.g., a shapefile) and outputs\n" "Inspects the given OGR-compatible data source (e.g., a shapefile) and "
"a GeoDjango model with the given model name. For example:\n" "outputs\na GeoDjango model with the given model name. For example:\n"
" ./manage.py ogrinspect zipcode.shp Zipcode" " ./manage.py ogrinspect zipcode.shp Zipcode"
) )

View File

@ -25,7 +25,8 @@ class Serializer(JSONSerializer):
self._init_options() self._init_options()
self._cts = {} # cache of CoordTransform's self._cts = {} # cache of CoordTransform's
self.stream.write( self.stream.write(
'{"type": "FeatureCollection", "crs": {"type": "name", "properties": {"name": "EPSG:%d"}},' '{"type": "FeatureCollection", '
'"crs": {"type": "name", "properties": {"name": "EPSG:%d"}},'
' "features": [' % self.srid ' "features": [' % self.srid
) )
@ -53,7 +54,8 @@ class Serializer(JSONSerializer):
data["properties"]["pk"] = obj._meta.pk.value_to_string(obj) data["properties"]["pk"] = obj._meta.pk.value_to_string(obj)
if self._geometry: if self._geometry:
if self._geometry.srid != self.srid: if self._geometry.srid != self.srid:
# If needed, transform the geometry in the srid of the global geojson srid # If needed, transform the geometry in the srid of the global
# geojson srid.
if self._geometry.srid not in self._cts: if self._geometry.srid not in self._cts:
srs = SpatialReference(self.srid) srs = SpatialReference(self.srid)
self._cts[self._geometry.srid] = CoordTransform( self._cts[self._geometry.srid] = CoordTransform(

View File

@ -42,7 +42,8 @@ class KMLSitemap(Sitemap):
elif isinstance(source, (list, tuple)): elif isinstance(source, (list, tuple)):
if len(source) != 3: if len(source) != 3:
raise ValueError( raise ValueError(
"Must specify a 3-tuple of (app_label, module_name, field_name)." "Must specify a 3-tuple of (app_label, module_name, "
"field_name)."
) )
kml_sources.append(source) kml_sources.append(source)
else: else:

View File

@ -233,7 +233,8 @@ class LayerMapping:
if isinstance(model_field, GeometryField): if isinstance(model_field, GeometryField):
if self.geom_field: if self.geom_field:
raise LayerMapError( raise LayerMapError(
"LayerMapping does not support more than one GeometryField per model." "LayerMapping does not support more than one GeometryField per "
"model."
) )
# Getting the coordinate dimension of the geometry field. # Getting the coordinate dimension of the geometry field.
@ -695,7 +696,8 @@ class LayerMapping:
# Incremental saving is requested at the given interval (step) # Incremental saving is requested at the given interval (step)
if default_range: if default_range:
raise LayerMapError( raise LayerMapError(
"The `step` keyword may not be used in conjunction with the `fid_range` keyword." "The `step` keyword may not be used in conjunction with the "
"`fid_range` keyword."
) )
beg, num_feat, num_saved = (0, 0, 0) beg, num_feat, num_saved = (0, 0, 0)
indices = range(step, nfeat, step) indices = range(step, nfeat, step)

View File

@ -209,7 +209,9 @@ def _ogrinspect(
# may also be mapped to `DecimalField` if specified in the # may also be mapped to `DecimalField` if specified in the
# `decimal` keyword. # `decimal` keyword.
if field_name.lower() in decimal_fields: if field_name.lower() in decimal_fields:
yield " %s = models.DecimalField(max_digits=%d, decimal_places=%d%s)" % ( yield (
" %s = models.DecimalField(max_digits=%d, decimal_places=%d%s)"
) % (
mfield, mfield,
width, width,
precision, precision,

View File

@ -256,7 +256,8 @@ class NaturalTimeFormatter:
), ),
} }
future_substrings = { future_substrings = {
# Translators: 'naturaltime-future' strings will be included in '%(delta)s from now' # Translators: 'naturaltime-future' strings will be included in
# '%(delta)s from now'.
"year": npgettext_lazy( "year": npgettext_lazy(
"naturaltime-future", "%(num)d year", "%(num)d years", "num" "naturaltime-future", "%(num)d year", "%(num)d years", "num"
), ),

View File

@ -18,7 +18,10 @@ class ExclusionConstraintExpression(IndexExpression):
class ExclusionConstraint(BaseConstraint): class ExclusionConstraint(BaseConstraint):
template = "CONSTRAINT %(name)s EXCLUDE USING %(index_type)s (%(expressions)s)%(include)s%(where)s%(deferrable)s" template = (
"CONSTRAINT %(name)s EXCLUDE USING %(index_type)s "
"(%(expressions)s)%(include)s%(where)s%(deferrable)s"
)
def __init__( def __init__(
self, self,

View File

@ -54,7 +54,8 @@ class RangeField(models.Field):
raise TypeError( raise TypeError(
f"Cannot use 'default_bounds' with {self.__class__.__name__}." f"Cannot use 'default_bounds' with {self.__class__.__name__}."
) )
# Initializing base_field here ensures that its model matches the model for self. # Initializing base_field here ensures that its model matches the model
# for self.
if hasattr(self, "base_field"): if hasattr(self, "base_field"):
self.base_field = self.base_field() self.base_field = self.base_field()
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)

View File

@ -185,9 +185,8 @@ class CollationOperation(Operation):
) )
def create_collation(self, schema_editor): def create_collation(self, schema_editor):
if ( if self.deterministic is False and not (
self.deterministic is False schema_editor.connection.features.supports_non_deterministic_collations
and not schema_editor.connection.features.supports_non_deterministic_collations
): ):
raise NotSupportedError( raise NotSupportedError(
"Non-deterministic collations require PostgreSQL 12+." "Non-deterministic collations require PostgreSQL 12+."

View File

@ -12,16 +12,20 @@ from django.utils.translation import ngettext_lazy
class ArrayMaxLengthValidator(MaxLengthValidator): class ArrayMaxLengthValidator(MaxLengthValidator):
message = ngettext_lazy( message = ngettext_lazy(
"List contains %(show_value)d item, it should contain no more than %(limit_value)d.", "List contains %(show_value)d item, it should contain no more than "
"List contains %(show_value)d items, it should contain no more than %(limit_value)d.", "%(limit_value)d.",
"List contains %(show_value)d items, it should contain no more than "
"%(limit_value)d.",
"limit_value", "limit_value",
) )
class ArrayMinLengthValidator(MinLengthValidator): class ArrayMinLengthValidator(MinLengthValidator):
message = ngettext_lazy( message = ngettext_lazy(
"List contains %(show_value)d item, it should contain no fewer than %(limit_value)d.", "List contains %(show_value)d item, it should contain no fewer than "
"List contains %(show_value)d items, it should contain no fewer than %(limit_value)d.", "%(limit_value)d.",
"List contains %(show_value)d items, it should contain no fewer than "
"%(limit_value)d.",
"limit_value", "limit_value",
) )

View File

@ -32,7 +32,8 @@ class Migration(migrations.Migration):
"old_path", "old_path",
models.CharField( models.CharField(
help_text=( help_text=(
"This should be an absolute path, excluding the domain name. Example: “/events/search/”." "This should be an absolute path, excluding the domain "
"name. Example: “/events/search/”."
), ),
max_length=200, max_length=200,
verbose_name="redirect from", verbose_name="redirect from",
@ -42,7 +43,10 @@ class Migration(migrations.Migration):
( (
"new_path", "new_path",
models.CharField( models.CharField(
help_text="This can be either an absolute path (as above) or a full URL starting with “http://”.", help_text=(
"This can be either an absolute path (as above) or a full "
"URL starting with “http://”."
),
max_length=200, max_length=200,
verbose_name="redirect to", verbose_name="redirect to",
blank=True, blank=True,

View File

@ -10,7 +10,8 @@ class Redirect(models.Model):
max_length=200, max_length=200,
db_index=True, db_index=True,
help_text=_( help_text=_(
"This should be an absolute path, excluding the domain name. Example: “/events/search/”." "This should be an absolute path, excluding the domain name. Example: "
"“/events/search/”."
), ),
) )
new_path = models.CharField( new_path = models.CharField(

View File

@ -48,7 +48,8 @@ def _get_sitemap_full_url(sitemap_url, sitemap_uses_https=True):
if sitemap_url is None: if sitemap_url is None:
raise SitemapNotFound( raise SitemapNotFound(
"You didn't provide a sitemap_url, and the sitemap URL couldn't be auto-detected." "You didn't provide a sitemap_url, and the sitemap URL couldn't be "
"auto-detected."
) )
Site = django_apps.get_model("sites.Site") Site = django_apps.get_model("sites.Site")

View File

@ -20,7 +20,10 @@ class SitemapIndexItem:
# RemovedInDjango50Warning # RemovedInDjango50Warning
def __str__(self): def __str__(self):
msg = "Calling `__str__` on SitemapIndexItem is deprecated, use the `location` attribute instead." msg = (
"Calling `__str__` on SitemapIndexItem is deprecated, use the `location` "
"attribute instead."
)
warnings.warn(msg, RemovedInDjango50Warning, stacklevel=2) warnings.warn(msg, RemovedInDjango50Warning, stacklevel=2)
return self.location return self.location

View File

@ -35,7 +35,8 @@ class CurrentSiteManager(models.Manager):
if not field.many_to_many and not isinstance(field, (models.ForeignKey)): if not field.many_to_many and not isinstance(field, (models.ForeignKey)):
return [ return [
checks.Error( checks.Error(
"CurrentSiteManager cannot use '%s.%s' as it is not a foreign key or a many-to-many field." "CurrentSiteManager cannot use '%s.%s' as it is not a foreign key "
"or a many-to-many field."
% (self.model._meta.object_name, field_name), % (self.model._meta.object_name, field_name),
obj=self, obj=self,
id="sites.E002", id="sites.E002",

View File

@ -83,7 +83,10 @@ class Command(BaseCommand):
"--no-default-ignore", "--no-default-ignore",
action="store_false", action="store_false",
dest="use_default_ignore_patterns", dest="use_default_ignore_patterns",
help="Don't ignore the common private glob-style patterns (defaults to 'CVS', '.*' and '*~').", help=(
"Don't ignore the common private glob-style patterns (defaults to "
"'CVS', '.*' and '*~')."
),
) )
def set_options(self, **options): def set_options(self, **options):
@ -169,7 +172,8 @@ class Command(BaseCommand):
message = ["\n"] message = ["\n"]
if self.dry_run: if self.dry_run:
message.append( message.append(
"You have activated the --dry-run option so no files will be modified.\n\n" "You have activated the --dry-run option so no files will be "
"modified.\n\n"
) )
message.append( message.append(

View File

@ -77,7 +77,8 @@ class BaseMemcachedCache(BaseCache):
def set(self, key, value, timeout=DEFAULT_TIMEOUT, version=None): def set(self, key, value, timeout=DEFAULT_TIMEOUT, version=None):
key = self.make_and_validate_key(key, version=version) key = self.make_and_validate_key(key, version=version)
if not self._cache.set(key, value, self.get_backend_timeout(timeout)): if not self._cache.set(key, value, self.get_backend_timeout(timeout)):
# make sure the key doesn't keep its old value in case of failure to set (memcached's 1MB limit) # Make sure the key doesn't keep its old value in case of failure
# to set (memcached's 1MB limit).
self._cache.delete(key) self._cache.delete(key)
def touch(self, key, timeout=DEFAULT_TIMEOUT, version=None): def touch(self, key, timeout=DEFAULT_TIMEOUT, version=None):

View File

@ -60,8 +60,8 @@ def check_csrf_failure_view(app_configs, **kwargs):
inspect.signature(view).bind(None, reason=None) inspect.signature(view).bind(None, reason=None)
except TypeError: except TypeError:
msg = ( msg = (
"The CSRF failure view '%s' does not take the correct number of arguments." "The CSRF failure view '%s' does not take the correct number of "
% settings.CSRF_FAILURE_VIEW "arguments." % settings.CSRF_FAILURE_VIEW
) )
errors.append(Error(msg, id="security.E101")) errors.append(Error(msg, id="security.E101"))
return errors return errors

View File

@ -6,7 +6,7 @@ Cookbook [1] (licensed under the Python Software License) and a ctypes port by
Anatoly Techtonik for Roundup [2] (license [3]). Anatoly Techtonik for Roundup [2] (license [3]).
[1] https://code.activestate.com/recipes/65203/ [1] https://code.activestate.com/recipes/65203/
[2] https://sourceforge.net/p/roundup/code/ci/default/tree/roundup/backends/portalocker.py [2] https://sourceforge.net/p/roundup/code/ci/default/tree/roundup/backends/portalocker.py # NOQA
[3] https://sourceforge.net/p/roundup/code/ci/default/tree/COPYING.txt [3] https://sourceforge.net/p/roundup/code/ci/default/tree/COPYING.txt
Example Usage:: Example Usage::

View File

@ -104,7 +104,8 @@ class Storage:
truncation = len(name) - max_length truncation = len(name) - max_length
if truncation > 0: if truncation > 0:
file_root = file_root[:-truncation] file_root = file_root[:-truncation]
# Entire file_root was truncated in attempt to find an available filename. # Entire file_root was truncated in attempt to find an
# available filename.
if not file_root: if not file_root:
raise SuspiciousFileOperation( raise SuspiciousFileOperation(
'Storage can not find an available filename for "%s". ' 'Storage can not find an available filename for "%s". '

View File

@ -242,7 +242,10 @@ def load_handler(path, *args, **kwargs):
E.g.:: E.g.::
>>> from django.http import HttpRequest >>> from django.http import HttpRequest
>>> request = HttpRequest() >>> request = HttpRequest()
>>> load_handler('django.core.files.uploadhandler.TemporaryFileUploadHandler', request) >>> load_handler(
... 'django.core.files.uploadhandler.TemporaryFileUploadHandler',
... request,
... )
<TemporaryFileUploadHandler object at 0x...> <TemporaryFileUploadHandler object at 0x...>
""" """
return import_string(path)(*args, **kwargs) return import_string(path)(*args, **kwargs)

View File

@ -208,7 +208,8 @@ class BaseHandler:
if hasattr(response, "render") and callable(response.render): if hasattr(response, "render") and callable(response.render):
for middleware_method in self._template_response_middleware: for middleware_method in self._template_response_middleware:
response = middleware_method(request, response) response = middleware_method(request, response)
# Complain if the template response middleware returned None (a common error). # Complain if the template response middleware returned None
# (a common error).
self.check_response( self.check_response(
response, response,
middleware_method, middleware_method,

View File

@ -308,7 +308,10 @@ class BaseCommand:
default=1, default=1,
type=int, type=int,
choices=[0, 1, 2, 3], choices=[0, 1, 2, 3],
help="Verbosity level; 0=minimal output, 1=normal output, 2=verbose output, 3=very verbose output", help=(
"Verbosity level; 0=minimal output, 1=normal output, 2=verbose output, "
"3=very verbose output"
),
) )
self.add_base_argument( self.add_base_argument(
parser, parser,
@ -322,7 +325,10 @@ class BaseCommand:
self.add_base_argument( self.add_base_argument(
parser, parser,
"--pythonpath", "--pythonpath",
help='A directory to add to the Python path, e.g. "/home/djangoprojects/myproject".', help=(
"A directory to add to the Python path, e.g. "
'"/home/djangoprojects/myproject".'
),
) )
self.add_base_argument( self.add_base_argument(
parser, parser,

View File

@ -173,8 +173,8 @@ class Command(BaseCommand):
# Check writability on first location # Check writability on first location
if i == 0 and not is_writable(mo_path): if i == 0 and not is_writable(mo_path):
self.stderr.write( self.stderr.write(
"The po files under %s are in a seemingly not writable location. " "The po files under %s are in a seemingly not writable "
"mo files will not be updated/created." % dirpath "location. mo files will not be updated/created." % dirpath
) )
self.has_errors = True self.has_errors = True
return return

View File

@ -22,7 +22,10 @@ class Command(BaseCommand):
"args", "args",
metavar="table_name", metavar="table_name",
nargs="*", nargs="*",
help="Optional table names. Otherwise, settings.CACHES is used to find cache tables.", help=(
"Optional table names. Otherwise, settings.CACHES is used to find "
"cache tables."
),
) )
parser.add_argument( parser.add_argument(
"--database", "--database",

View File

@ -16,7 +16,10 @@ class Command(BaseCommand):
parser.add_argument( parser.add_argument(
"--database", "--database",
default=DEFAULT_DB_ALIAS, default=DEFAULT_DB_ALIAS,
help='Nominates a database onto which to open a shell. Defaults to the "default" database.', help=(
"Nominates a database onto which to open a shell. Defaults to the "
'"default" database.'
),
) )
parameters = parser.add_argument_group("parameters", prefix_chars="--") parameters = parser.add_argument_group("parameters", prefix_chars="--")
parameters.add_argument("parameters", nargs="*") parameters.add_argument("parameters", nargs="*")

View File

@ -25,8 +25,8 @@ class Command(BaseCommand):
"--default", "--default",
metavar="MODULE", metavar="MODULE",
help=( help=(
"The settings module to compare the current settings against. Leave empty to " "The settings module to compare the current settings against. Leave "
"compare against Django's default settings." "empty to compare against Django's default settings."
), ),
) )
parser.add_argument( parser.add_argument(

View File

@ -38,7 +38,10 @@ class Command(BaseCommand):
"args", "args",
metavar="app_label[.ModelName]", metavar="app_label[.ModelName]",
nargs="*", nargs="*",
help="Restricts dumped data to the specified app_label or app_label.ModelName.", help=(
"Restricts dumped data to the specified app_label or "
"app_label.ModelName."
),
) )
parser.add_argument( parser.add_argument(
"--format", "--format",
@ -81,8 +84,11 @@ class Command(BaseCommand):
"--all", "--all",
action="store_true", action="store_true",
dest="use_base_manager", dest="use_base_manager",
help="Use Django's base manager to dump all models stored in the database, " help=(
"including those that would otherwise be filtered or modified by a custom manager.", "Use Django's base manager to dump all models stored in the database, "
"including those that would otherwise be filtered or modified by a "
"custom manager."
),
) )
parser.add_argument( parser.add_argument(
"--pks", "--pks",

View File

@ -82,7 +82,8 @@ Are you sure you want to do this?
% (connection.settings_dict["NAME"],) % (connection.settings_dict["NAME"],)
) from exc ) from exc
# Empty sql_list may signify an empty database and post_migrate would then crash # Empty sql_list may signify an empty database and post_migrate
# would then crash.
if sql_list and not inhibit_post_migrate: if sql_list and not inhibit_post_migrate:
# Emit the post migrate signal. This allows individual applications to # Emit the post migrate signal. This allows individual applications to
# respond as if the database had been migrated from scratch. # respond as if the database had been migrated from scratch.

View File

@ -7,7 +7,10 @@ from django.db.models.constants import LOOKUP_SEP
class Command(BaseCommand): class Command(BaseCommand):
help = "Introspects the database tables in the given database and outputs a Django model module." help = (
"Introspects the database tables in the given database and outputs a Django "
"model module."
)
requires_system_checks = [] requires_system_checks = []
stealth_options = ("table_name_filter",) stealth_options = ("table_name_filter",)
db_module = "django.db" db_module = "django.db"
@ -22,7 +25,10 @@ class Command(BaseCommand):
parser.add_argument( parser.add_argument(
"--database", "--database",
default=DEFAULT_DB_ALIAS, default=DEFAULT_DB_ALIAS,
help='Nominates a database to introspect. Defaults to using the "default" database.', help=(
'Nominates a database to introspect. Defaults to using the "default" '
"database."
),
) )
parser.add_argument( parser.add_argument(
"--include-partitions", "--include-partitions",
@ -41,7 +47,8 @@ class Command(BaseCommand):
self.stdout.write(line) self.stdout.write(line)
except NotImplementedError: except NotImplementedError:
raise CommandError( raise CommandError(
"Database inspection isn't supported for the currently selected database backend." "Database inspection isn't supported for the currently selected "
"database backend."
) )
def handle_inspection(self, options): def handle_inspection(self, options):
@ -57,12 +64,18 @@ class Command(BaseCommand):
yield "# You'll have to do the following manually to clean this up:" yield "# You'll have to do the following manually to clean this up:"
yield "# * Rearrange models' order" yield "# * Rearrange models' order"
yield "# * Make sure each model has one field with primary_key=True" yield "# * Make sure each model has one field with primary_key=True"
yield "# * Make sure each ForeignKey and OneToOneField has `on_delete` set to the desired behavior" yield (
"# * Make sure each ForeignKey and OneToOneField has `on_delete` set "
"to the desired behavior"
)
yield ( yield (
"# * Remove `managed = False` lines if you wish to allow " "# * Remove `managed = False` lines if you wish to allow "
"Django to create, modify, and delete the table" "Django to create, modify, and delete the table"
) )
yield "# Feel free to rename the models, but don't rename db_table values or field names." yield (
"# Feel free to rename the models, but don't rename db_table values or "
"field names."
)
yield "from %s import models" % self.db_module yield "from %s import models" % self.db_module
known_models = [] known_models = []
table_info = connection.introspection.get_table_list(cursor) table_info = connection.introspection.get_table_list(cursor)

View File

@ -55,7 +55,10 @@ class Command(BaseCommand):
parser.add_argument( parser.add_argument(
"--database", "--database",
default=DEFAULT_DB_ALIAS, default=DEFAULT_DB_ALIAS,
help='Nominates a specific database to load fixtures into. Defaults to the "default" database.', help=(
"Nominates a specific database to load fixtures into. Defaults to the "
'"default" database.'
),
) )
parser.add_argument( parser.add_argument(
"--app", "--app",
@ -75,7 +78,10 @@ class Command(BaseCommand):
"--exclude", "--exclude",
action="append", action="append",
default=[], default=[],
help="An app_label or app_label.ModelName to exclude. Can be used multiple times.", help=(
"An app_label or app_label.ModelName to exclude. Can be used multiple "
"times."
),
) )
parser.add_argument( parser.add_argument(
"--format", "--format",
@ -105,7 +111,8 @@ class Command(BaseCommand):
@cached_property @cached_property
def compression_formats(self): def compression_formats(self):
"""A dict mapping format names to (open function, mode arg) tuples.""" """A dict mapping format names to (open function, mode arg) tuples."""
# Forcing binary mode may be revisited after dropping Python 2 support (see #22399) # Forcing binary mode may be revisited after dropping Python 2 support
# (see #22399).
compression_formats = { compression_formats = {
None: (open, "rb"), None: (open, "rb"),
"gz": (gzip.GzipFile, "rb"), "gz": (gzip.GzipFile, "rb"),

View File

@ -203,11 +203,11 @@ def write_pot_file(potfile, msgs):
class Command(BaseCommand): class Command(BaseCommand):
help = ( help = (
"Runs over the entire source tree of the current directory and " "Runs over the entire source tree of the current directory and pulls out all "
"pulls out all strings marked for translation. It creates (or updates) a message " "strings marked for translation. It creates (or updates) a message file in the "
"file in the conf/locale (in the django tree) or locale (for projects and " "conf/locale (in the django tree) or locale (for projects and applications) "
"applications) directory.\n\nYou must run this command with one of either the " "directory.\n\nYou must run this command with one of either the --locale, "
"--locale, --exclude, or --all options." "--exclude, or --all options."
) )
translatable_file_class = TranslatableFile translatable_file_class = TranslatableFile
@ -226,8 +226,10 @@ class Command(BaseCommand):
"-l", "-l",
default=[], default=[],
action="append", action="append",
help="Creates or updates the message files for the given locale(s) (e.g. pt_BR). " help=(
"Can be used multiple times.", "Creates or updates the message files for the given locale(s) (e.g. "
"pt_BR). Can be used multiple times."
),
) )
parser.add_argument( parser.add_argument(
"--exclude", "--exclude",
@ -278,7 +280,10 @@ class Command(BaseCommand):
"--no-default-ignore", "--no-default-ignore",
action="store_false", action="store_false",
dest="use_default_ignore_patterns", dest="use_default_ignore_patterns",
help="Don't ignore the common glob-style patterns 'CVS', '.*', '*~' and '*.pyc'.", help=(
"Don't ignore the common glob-style patterns 'CVS', '.*', '*~' and "
"'*.pyc'."
),
) )
parser.add_argument( parser.add_argument(
"--no-wrap", "--no-wrap",

View File

@ -147,7 +147,8 @@ class Command(BaseCommand):
# hard if there are any and they don't want to merge # hard if there are any and they don't want to merge
conflicts = loader.detect_conflicts() conflicts = loader.detect_conflicts()
# If app_labels is specified, filter out conflicting migrations for unspecified apps # If app_labels is specified, filter out conflicting migrations for
# unspecified apps.
if app_labels: if app_labels:
conflicts = { conflicts = {
app_label: conflict app_label: conflict

View File

@ -47,7 +47,10 @@ class Command(BaseCommand):
parser.add_argument( parser.add_argument(
"--database", "--database",
default=DEFAULT_DB_ALIAS, default=DEFAULT_DB_ALIAS,
help='Nominates a database to synchronize. Defaults to the "default" database.', help=(
'Nominates a database to synchronize. Defaults to the "default" '
"database."
),
) )
parser.add_argument( parser.add_argument(
"--fake", "--fake",
@ -57,9 +60,12 @@ class Command(BaseCommand):
parser.add_argument( parser.add_argument(
"--fake-initial", "--fake-initial",
action="store_true", action="store_true",
help="Detect if tables already exist and fake-apply initial migrations if so. Make sure " help=(
"that the current database schema matches your initial migration before using this " "Detect if tables already exist and fake-apply initial migrations if "
"flag. Django will only check for an existing table name.", "so. Make sure that the current database schema matches your initial "
"migration before using this flag. Django will only check for an "
"existing table name."
),
) )
parser.add_argument( parser.add_argument(
"--plan", "--plan",
@ -313,7 +319,8 @@ class Command(BaseCommand):
if not plan: if not plan:
if self.verbosity >= 1: if self.verbosity >= 1:
self.stdout.write(" No migrations to apply.") self.stdout.write(" No migrations to apply.")
# If there's changes that aren't in migrations yet, tell them how to fix it. # If there's changes that aren't in migrations yet, tell them
# how to fix it.
autodetector = MigrationAutodetector( autodetector = MigrationAutodetector(
executor.loader.project_state(), executor.loader.project_state(),
ProjectState.from_apps(apps), ProjectState.from_apps(apps),

View File

@ -7,7 +7,10 @@ from django.utils import timezone
class Command(BaseCommand): class Command(BaseCommand):
help = "Sends a test email to the email addresses specified as arguments." help = "Sends a test email to the email addresses specified as arguments."
missing_args_message = "You must specify some email recipients, or pass the --managers or --admin options." missing_args_message = (
"You must specify some email recipients, or pass the --managers or --admin "
"options."
)
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument( parser.add_argument(

View File

@ -21,18 +21,27 @@ class Command(BaseCommand):
parser.add_argument( parser.add_argument(
"--no-startup", "--no-startup",
action="store_true", action="store_true",
help="When using plain Python, ignore the PYTHONSTARTUP environment variable and ~/.pythonrc.py script.", help=(
"When using plain Python, ignore the PYTHONSTARTUP environment "
"variable and ~/.pythonrc.py script."
),
) )
parser.add_argument( parser.add_argument(
"-i", "-i",
"--interface", "--interface",
choices=self.shells, choices=self.shells,
help='Specify an interactive interpreter interface. Available options: "ipython", "bpython", and "python"', help=(
"Specify an interactive interpreter interface. Available options: "
'"ipython", "bpython", and "python"'
),
) )
parser.add_argument( parser.add_argument(
"-c", "-c",
"--command", "--command",
help="Instead of opening an interactive shell, run a command as Django and exit.", help=(
"Instead of opening an interactive shell, run a command as Django and "
"exit."
),
) )
def ipython(self, options): def ipython(self, options):

View File

@ -45,9 +45,9 @@ class Command(BaseCommand):
dest="format", dest="format",
const="plan", const="plan",
help=( help=(
"Shows all migrations in the order they will be applied. " "Shows all migrations in the order they will be applied. With a "
"With a verbosity level of 2 or above all direct migration dependencies " "verbosity level of 2 or above all direct migration dependencies and "
"and reverse dependencies (run_before) will be included." "reverse dependencies (run_before) will be included."
), ),
) )

View File

@ -16,7 +16,10 @@ class Command(BaseCommand):
parser.add_argument( parser.add_argument(
"--database", "--database",
default=DEFAULT_DB_ALIAS, default=DEFAULT_DB_ALIAS,
help='Nominates a database to print the SQL for. Defaults to the "default" database.', help=(
'Nominates a database to print the SQL for. Defaults to the "default" '
"database."
),
) )
def handle(self, **options): def handle(self, **options):

View File

@ -19,7 +19,10 @@ class Command(BaseCommand):
parser.add_argument( parser.add_argument(
"--database", "--database",
default=DEFAULT_DB_ALIAS, default=DEFAULT_DB_ALIAS,
help='Nominates a database to create SQL for. Defaults to the "default" database.', help=(
'Nominates a database to create SQL for. Defaults to the "default" '
"database."
),
) )
parser.add_argument( parser.add_argument(
"--backwards", "--backwards",
@ -55,13 +58,13 @@ class Command(BaseCommand):
migration = loader.get_migration_by_prefix(app_label, migration_name) migration = loader.get_migration_by_prefix(app_label, migration_name)
except AmbiguityError: except AmbiguityError:
raise CommandError( raise CommandError(
"More than one migration matches '%s' in app '%s'. Please be more specific." "More than one migration matches '%s' in app '%s'. Please be more "
% (migration_name, app_label) "specific." % (migration_name, app_label)
) )
except KeyError: except KeyError:
raise CommandError( raise CommandError(
"Cannot find a migration matching '%s' from app '%s'. Is it in INSTALLED_APPS?" "Cannot find a migration matching '%s' from app '%s'. Is it in "
% (migration_name, app_label) "INSTALLED_APPS?" % (migration_name, app_label)
) )
target = (app_label, migration.name) target = (app_label, migration.name)

View File

@ -14,7 +14,10 @@ class Command(AppCommand):
parser.add_argument( parser.add_argument(
"--database", "--database",
default=DEFAULT_DB_ALIAS, default=DEFAULT_DB_ALIAS,
help='Nominates a database to print the SQL for. Defaults to the "default" database.', help=(
'Nominates a database to print the SQL for. Defaults to the "default" '
"database."
),
) )
def handle_app_config(self, app_config, **options): def handle_app_config(self, app_config, **options):

View File

@ -12,7 +12,10 @@ from django.utils.version import get_docs_version
class Command(BaseCommand): class Command(BaseCommand):
help = "Squashes an existing set of migrations (from first until specified) into a single new one." help = (
"Squashes an existing set of migrations (from first until specified) into a "
"single new one."
)
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument( parser.add_argument(
@ -22,7 +25,10 @@ class Command(BaseCommand):
parser.add_argument( parser.add_argument(
"start_migration_name", "start_migration_name",
nargs="?", nargs="?",
help="Migrations will be squashed starting from and including this migration.", help=(
"Migrations will be squashed starting from and including this "
"migration."
),
) )
parser.add_argument( parser.add_argument(
"migration_name", "migration_name",
@ -66,7 +72,8 @@ class Command(BaseCommand):
apps.get_app_config(app_label) apps.get_app_config(app_label)
except LookupError as err: except LookupError as err:
raise CommandError(str(err)) raise CommandError(str(err))
# Load the current graph state, check the app and migration they asked for exists # Load the current graph state, check the app and migration they asked
# for exists.
loader = MigrationLoader(connections[DEFAULT_DB_ALIAS]) loader = MigrationLoader(connections[DEFAULT_DB_ALIAS])
if app_label not in loader.migrated_apps: if app_label not in loader.migrated_apps:
raise CommandError( raise CommandError(
@ -135,10 +142,9 @@ class Command(BaseCommand):
for smigration in migrations_to_squash: for smigration in migrations_to_squash:
if smigration.replaces: if smigration.replaces:
raise CommandError( raise CommandError(
"You cannot squash squashed migrations! Please transition " "You cannot squash squashed migrations! Please transition it to a "
"it to a normal migration first: " "normal migration first: https://docs.djangoproject.com/en/%s/"
"https://docs.djangoproject.com/en/%s/topics/migrations/#squashing-migrations" "topics/migrations/#squashing-migrations" % get_docs_version()
% get_docs_version()
) )
operations.extend(smigration.operations) operations.extend(smigration.operations)
for dependency in smigration.dependencies: for dependency in smigration.dependencies:
@ -223,15 +229,18 @@ class Command(BaseCommand):
+ "\n" + "\n"
" You should commit this migration but leave the old ones in place;\n" " You should commit this migration but leave the old ones in place;\n"
" the new migration will be used for new installs. Once you are sure\n" " the new migration will be used for new installs. Once you are sure\n"
" all instances of the codebase have applied the migrations you squashed,\n" " all instances of the codebase have applied the migrations you "
"squashed,\n"
" you can delete them." " you can delete them."
) )
if writer.needs_manual_porting: if writer.needs_manual_porting:
self.stdout.write( self.stdout.write(
self.style.MIGRATE_HEADING("Manual porting required") + "\n" self.style.MIGRATE_HEADING("Manual porting required") + "\n"
" Your migrations contained functions that must be manually copied over,\n" " Your migrations contained functions that must be manually "
"copied over,\n"
" as we could not safely copy their implementation.\n" " as we could not safely copy their implementation.\n"
" See the comment at the top of the squashed migration for details." " See the comment at the top of the squashed migration for "
"details."
) )
def find_migration(self, loader, app_label, name): def find_migration(self, loader, app_label, name):

View File

@ -28,7 +28,10 @@ class Command(BaseCommand):
"args", "args",
metavar="test_label", metavar="test_label",
nargs="*", nargs="*",
help="Module paths to test; can be modulename, modulename.TestCase or modulename.TestCase.test_method", help=(
"Module paths to test; can be modulename, modulename.TestCase or "
"modulename.TestCase.test_method"
),
) )
parser.add_argument( parser.add_argument(
"--noinput", "--noinput",

View File

@ -174,8 +174,11 @@ class EmailValidator:
message = _("Enter a valid email address.") message = _("Enter a valid email address.")
code = "invalid" code = "invalid"
user_regex = _lazy_re_compile( user_regex = _lazy_re_compile(
r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*\Z" # dot-atom # dot-atom
r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"\Z)', # quoted-string r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*\Z"
# quoted-string
r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])'
r'*"\Z)',
re.IGNORECASE, re.IGNORECASE,
) )
domain_regex = _lazy_re_compile( domain_regex = _lazy_re_compile(
@ -257,7 +260,8 @@ slug_unicode_re = _lazy_re_compile(r"^[-\w]+\Z")
validate_unicode_slug = RegexValidator( validate_unicode_slug = RegexValidator(
slug_unicode_re, slug_unicode_re,
_( _(
"Enter a valid “slug” consisting of Unicode letters, numbers, underscores, or hyphens." "Enter a valid “slug” consisting of Unicode letters, numbers, underscores, or "
"hyphens."
), ),
"invalid", "invalid",
) )
@ -400,8 +404,10 @@ class MinValueValidator(BaseValidator):
@deconstructible @deconstructible
class MinLengthValidator(BaseValidator): class MinLengthValidator(BaseValidator):
message = ngettext_lazy( message = ngettext_lazy(
"Ensure this value has at least %(limit_value)d character (it has %(show_value)d).", "Ensure this value has at least %(limit_value)d character (it has "
"Ensure this value has at least %(limit_value)d characters (it has %(show_value)d).", "%(show_value)d).",
"Ensure this value has at least %(limit_value)d characters (it has "
"%(show_value)d).",
"limit_value", "limit_value",
) )
code = "min_length" code = "min_length"
@ -416,8 +422,10 @@ class MinLengthValidator(BaseValidator):
@deconstructible @deconstructible
class MaxLengthValidator(BaseValidator): class MaxLengthValidator(BaseValidator):
message = ngettext_lazy( message = ngettext_lazy(
"Ensure this value has at most %(limit_value)d character (it has %(show_value)d).", "Ensure this value has at most %(limit_value)d character (it has "
"Ensure this value has at most %(limit_value)d characters (it has %(show_value)d).", "%(show_value)d).",
"Ensure this value has at most %(limit_value)d characters (it has "
"%(show_value)d).",
"limit_value", "limit_value",
) )
code = "max_length" code = "max_length"
@ -449,8 +457,10 @@ class DecimalValidator:
"max", "max",
), ),
"max_whole_digits": ngettext_lazy( "max_whole_digits": ngettext_lazy(
"Ensure that there are no more than %(max)s digit before the decimal point.", "Ensure that there are no more than %(max)s digit before the decimal "
"Ensure that there are no more than %(max)s digits before the decimal point.", "point.",
"Ensure that there are no more than %(max)s digits before the decimal "
"point.",
"max", "max",
), ),
} }

View File

@ -190,19 +190,22 @@ class BaseDatabaseWrapper:
def get_connection_params(self): def get_connection_params(self):
"""Return a dict of parameters suitable for get_new_connection.""" """Return a dict of parameters suitable for get_new_connection."""
raise NotImplementedError( raise NotImplementedError(
"subclasses of BaseDatabaseWrapper may require a get_connection_params() method" "subclasses of BaseDatabaseWrapper may require a get_connection_params() "
"method"
) )
def get_new_connection(self, conn_params): def get_new_connection(self, conn_params):
"""Open a connection to the database.""" """Open a connection to the database."""
raise NotImplementedError( raise NotImplementedError(
"subclasses of BaseDatabaseWrapper may require a get_new_connection() method" "subclasses of BaseDatabaseWrapper may require a get_new_connection() "
"method"
) )
def init_connection_state(self): def init_connection_state(self):
"""Initialize the database connection settings.""" """Initialize the database connection settings."""
raise NotImplementedError( raise NotImplementedError(
"subclasses of BaseDatabaseWrapper may require an init_connection_state() method" "subclasses of BaseDatabaseWrapper may require an init_connection_state() "
"method"
) )
def create_cursor(self, name=None): def create_cursor(self, name=None):

View File

@ -63,7 +63,8 @@ class BaseDatabaseIntrospection:
views that exist in the database. views that exist in the database.
""" """
raise NotImplementedError( raise NotImplementedError(
"subclasses of BaseDatabaseIntrospection may require a get_table_list() method" "subclasses of BaseDatabaseIntrospection may require a get_table_list() "
"method"
) )
def get_table_description(self, cursor, table_name): def get_table_description(self, cursor, table_name):
@ -158,7 +159,8 @@ class BaseDatabaseIntrospection:
'name' key can be added if the backend supports named sequences. 'name' key can be added if the backend supports named sequences.
""" """
raise NotImplementedError( raise NotImplementedError(
"subclasses of BaseDatabaseIntrospection may require a get_sequences() method" "subclasses of BaseDatabaseIntrospection may require a get_sequences() "
"method"
) )
def get_relations(self, cursor, table_name): def get_relations(self, cursor, table_name):
@ -200,5 +202,6 @@ class BaseDatabaseIntrospection:
if they don't name constraints of a certain type (e.g. SQLite) if they don't name constraints of a certain type (e.g. SQLite)
""" """
raise NotImplementedError( raise NotImplementedError(
"subclasses of BaseDatabaseIntrospection may require a get_constraints() method" "subclasses of BaseDatabaseIntrospection may require a get_constraints() "
"method"
) )

View File

@ -106,7 +106,8 @@ class BaseDatabaseOperations:
extracts a value from the given date field field_name. extracts a value from the given date field field_name.
""" """
raise NotImplementedError( raise NotImplementedError(
"subclasses of BaseDatabaseOperations may require a date_extract_sql() method" "subclasses of BaseDatabaseOperations may require a date_extract_sql() "
"method"
) )
def date_trunc_sql(self, lookup_type, field_name, tzname=None): def date_trunc_sql(self, lookup_type, field_name, tzname=None):
@ -119,7 +120,8 @@ class BaseDatabaseOperations:
timezone. timezone.
""" """
raise NotImplementedError( raise NotImplementedError(
"subclasses of BaseDatabaseOperations may require a date_trunc_sql() method." "subclasses of BaseDatabaseOperations may require a date_trunc_sql() "
"method."
) )
def datetime_cast_date_sql(self, field_name, tzname): def datetime_cast_date_sql(self, field_name, tzname):
@ -136,7 +138,8 @@ class BaseDatabaseOperations:
Return the SQL to cast a datetime value to time value. Return the SQL to cast a datetime value to time value.
""" """
raise NotImplementedError( raise NotImplementedError(
"subclasses of BaseDatabaseOperations may require a datetime_cast_time_sql() method" "subclasses of BaseDatabaseOperations may require a "
"datetime_cast_time_sql() method"
) )
def datetime_extract_sql(self, lookup_type, field_name, tzname): def datetime_extract_sql(self, lookup_type, field_name, tzname):
@ -146,7 +149,8 @@ class BaseDatabaseOperations:
datetime field field_name. datetime field field_name.
""" """
raise NotImplementedError( raise NotImplementedError(
"subclasses of BaseDatabaseOperations may require a datetime_extract_sql() method" "subclasses of BaseDatabaseOperations may require a datetime_extract_sql() "
"method"
) )
def datetime_trunc_sql(self, lookup_type, field_name, tzname): def datetime_trunc_sql(self, lookup_type, field_name, tzname):
@ -156,7 +160,8 @@ class BaseDatabaseOperations:
field_name to a datetime object with only the given specificity. field_name to a datetime object with only the given specificity.
""" """
raise NotImplementedError( raise NotImplementedError(
"subclasses of BaseDatabaseOperations may require a datetime_trunc_sql() method" "subclasses of BaseDatabaseOperations may require a datetime_trunc_sql() "
"method"
) )
def time_trunc_sql(self, lookup_type, field_name, tzname=None): def time_trunc_sql(self, lookup_type, field_name, tzname=None):
@ -727,9 +732,9 @@ class BaseDatabaseOperations:
def window_frame_range_start_end(self, start=None, end=None): def window_frame_range_start_end(self, start=None, end=None):
start_, end_ = self.window_frame_rows_start_end(start, end) start_, end_ = self.window_frame_rows_start_end(start, end)
if ( features = self.connection.features
self.connection.features.only_supports_unbounded_with_preceding_and_following if features.only_supports_unbounded_with_preceding_and_following and (
and ((start and start < 0) or (end and end > 0)) (start and start < 0) or (end and end > 0)
): ):
raise NotSupportedError( raise NotSupportedError(
"%s only supports UNBOUNDED together with PRECEDING and " "%s only supports UNBOUNDED together with PRECEDING and "

View File

@ -104,7 +104,10 @@ class BaseDatabaseSchemaEditor:
sql_create_check = "ALTER TABLE %(table)s ADD CONSTRAINT %(name)s CHECK (%(check)s)" sql_create_check = "ALTER TABLE %(table)s ADD CONSTRAINT %(name)s CHECK (%(check)s)"
sql_delete_check = sql_delete_constraint sql_delete_check = sql_delete_constraint
sql_create_unique = "ALTER TABLE %(table)s ADD CONSTRAINT %(name)s UNIQUE (%(columns)s)%(deferrable)s" sql_create_unique = (
"ALTER TABLE %(table)s ADD CONSTRAINT %(name)s "
"UNIQUE (%(columns)s)%(deferrable)s"
)
sql_delete_unique = sql_delete_constraint sql_delete_unique = sql_delete_constraint
sql_create_fk = ( sql_create_fk = (
@ -115,8 +118,14 @@ class BaseDatabaseSchemaEditor:
sql_create_column_inline_fk = None sql_create_column_inline_fk = None
sql_delete_fk = sql_delete_constraint sql_delete_fk = sql_delete_constraint
sql_create_index = "CREATE INDEX %(name)s ON %(table)s (%(columns)s)%(include)s%(extra)s%(condition)s" sql_create_index = (
sql_create_unique_index = "CREATE UNIQUE INDEX %(name)s ON %(table)s (%(columns)s)%(include)s%(condition)s" "CREATE INDEX %(name)s ON %(table)s "
"(%(columns)s)%(include)s%(extra)s%(condition)s"
)
sql_create_unique_index = (
"CREATE UNIQUE INDEX %(name)s ON %(table)s "
"(%(columns)s)%(include)s%(condition)s"
)
sql_delete_index = "DROP INDEX %(name)s" sql_delete_index = "DROP INDEX %(name)s"
sql_create_pk = ( sql_create_pk = (
@ -418,10 +427,12 @@ class BaseDatabaseSchemaEditor:
the given `model`. the given `model`.
""" """
sql, params = self.table_sql(model) sql, params = self.table_sql(model)
# Prevent using [] as params, in the case a literal '%' is used in the definition # Prevent using [] as params, in the case a literal '%' is used in the
# definition.
self.execute(sql, params or None) self.execute(sql, params or None)
# Add any field index and index_together's (deferred as SQLite _remake_table needs it) # Add any field index and index_together's (deferred as SQLite
# _remake_table needs it).
self.deferred_sql.extend(self._model_indexes_sql(model)) self.deferred_sql.extend(self._model_indexes_sql(model))
# Make M2M tables # Make M2M tables
@ -1190,8 +1201,9 @@ class BaseDatabaseSchemaEditor:
# Repoint the FK to the other side # Repoint the FK to the other side
self.alter_field( self.alter_field(
new_field.remote_field.through, new_field.remote_field.through,
# We need the field that points to the target model, so we can tell alter_field to change it - # The field that points to the target model is needed, so we can
# this is m2m_reverse_field_name() (as opposed to m2m_field_name, which points to our model) # tell alter_field to change it - this is m2m_reverse_field_name()
# (as opposed to m2m_field_name(), which points to our model).
old_field.remote_field.through._meta.get_field( old_field.remote_field.through._meta.get_field(
old_field.m2m_reverse_field_name() old_field.m2m_reverse_field_name()
), ),

View File

@ -349,9 +349,9 @@ class DatabaseWrapper(BaseDatabaseWrapper):
) )
for bad_row in cursor.fetchall(): for bad_row in cursor.fetchall():
raise IntegrityError( raise IntegrityError(
"The row in table '%s' with primary key '%s' has an invalid " "The row in table '%s' with primary key '%s' has an "
"foreign key: %s.%s contains a value '%s' that does not " "invalid foreign key: %s.%s contains a value '%s' that "
"have a corresponding value in %s.%s." "does not have a corresponding value in %s.%s."
% ( % (
table_name, table_name,
bad_row[0], bad_row[0],

View File

@ -69,8 +69,10 @@ class DatabaseFeatures(BaseDatabaseFeatures):
def django_test_skips(self): def django_test_skips(self):
skips = { skips = {
"This doesn't work on MySQL.": { "This doesn't work on MySQL.": {
"db_functions.comparison.test_greatest.GreatestTests.test_coalesce_workaround", "db_functions.comparison.test_greatest.GreatestTests."
"db_functions.comparison.test_least.LeastTests.test_coalesce_workaround", "test_coalesce_workaround",
"db_functions.comparison.test_least.LeastTests."
"test_coalesce_workaround",
}, },
"Running on MySQL requires utf8mb4 encoding (#18392).": { "Running on MySQL requires utf8mb4 encoding (#18392).": {
"model_fields.test_textfield.TextFieldTests.test_emoji", "model_fields.test_textfield.TextFieldTests.test_emoji",
@ -90,8 +92,10 @@ class DatabaseFeatures(BaseDatabaseFeatures):
{ {
"GROUP BY optimization does not work properly when " "GROUP BY optimization does not work properly when "
"ONLY_FULL_GROUP_BY mode is enabled on MySQL, see #31331.": { "ONLY_FULL_GROUP_BY mode is enabled on MySQL, see #31331.": {
"aggregation.tests.AggregateTestCase.test_aggregation_subquery_annotation_multivalued", "aggregation.tests.AggregateTestCase."
"annotations.tests.NonAggregateAnnotationTestCase.test_annotation_aggregate_with_m2o", "test_aggregation_subquery_annotation_multivalued",
"annotations.tests.NonAggregateAnnotationTestCase."
"test_annotation_aggregate_with_m2o",
}, },
} }
) )
@ -100,13 +104,19 @@ class DatabaseFeatures(BaseDatabaseFeatures):
): ):
skips.update( skips.update(
{ {
"Casting to datetime/time is not supported by MySQL < 8.0. (#30224)": { "Casting to datetime/time is not supported by MySQL < 8.0. "
"aggregation.tests.AggregateTestCase.test_aggregation_default_using_time_from_python", "(#30224)": {
"aggregation.tests.AggregateTestCase.test_aggregation_default_using_datetime_from_python", "aggregation.tests.AggregateTestCase."
"test_aggregation_default_using_time_from_python",
"aggregation.tests.AggregateTestCase."
"test_aggregation_default_using_datetime_from_python",
}, },
"MySQL < 8.0 returns string type instead of datetime/time. (#30224)": { "MySQL < 8.0 returns string type instead of datetime/time. "
"aggregation.tests.AggregateTestCase.test_aggregation_default_using_time_from_database", "(#30224)": {
"aggregation.tests.AggregateTestCase.test_aggregation_default_using_datetime_from_database", "aggregation.tests.AggregateTestCase."
"test_aggregation_default_using_time_from_database",
"aggregation.tests.AggregateTestCase."
"test_aggregation_default_using_datetime_from_database",
}, },
} }
) )
@ -118,7 +128,8 @@ class DatabaseFeatures(BaseDatabaseFeatures):
skips.update( skips.update(
{ {
"https://jira.mariadb.org/browse/MDEV-19598": { "https://jira.mariadb.org/browse/MDEV-19598": {
"schema.tests.SchemaTests.test_alter_not_unique_field_to_primary_key", "schema.tests.SchemaTests."
"test_alter_not_unique_field_to_primary_key",
}, },
} }
) )
@ -130,7 +141,8 @@ class DatabaseFeatures(BaseDatabaseFeatures):
skips.update( skips.update(
{ {
"https://jira.mariadb.org/browse/MDEV-22775": { "https://jira.mariadb.org/browse/MDEV-22775": {
"schema.tests.SchemaTests.test_alter_pk_with_self_referential_field", "schema.tests.SchemaTests."
"test_alter_pk_with_self_referential_field",
}, },
} }
) )

View File

@ -92,7 +92,8 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
FROM information_schema.check_constraints AS c FROM information_schema.check_constraints AS c
WHERE WHERE
c.table_name = %s AND c.table_name = %s AND
LOWER(c.check_clause) = 'json_valid(`' + LOWER(c.constraint_name) + '`)' AND LOWER(c.check_clause) =
'json_valid(`' + LOWER(c.constraint_name) + '`)' AND
c.constraint_schema = DATABASE() c.constraint_schema = DATABASE()
""", """,
[table_name], [table_name],

View File

@ -69,7 +69,8 @@ class DatabaseOperations(BaseDatabaseOperations):
return "CAST(DATE_FORMAT(%s, '%s') AS DATE)" % (field_name, format_str) return "CAST(DATE_FORMAT(%s, '%s') AS DATE)" % (field_name, format_str)
elif lookup_type == "quarter": elif lookup_type == "quarter":
return ( return (
"MAKEDATE(YEAR(%s), 1) + INTERVAL QUARTER(%s) QUARTER - INTERVAL 1 QUARTER" "MAKEDATE(YEAR(%s), 1) + "
"INTERVAL QUARTER(%s) QUARTER - INTERVAL 1 QUARTER"
% (field_name, field_name) % (field_name, field_name)
) )
elif lookup_type == "week": elif lookup_type == "week":
@ -266,7 +267,8 @@ class DatabaseOperations(BaseDatabaseOperations):
value = timezone.make_naive(value, self.connection.timezone) value = timezone.make_naive(value, self.connection.timezone)
else: else:
raise ValueError( raise ValueError(
"MySQL backend does not support timezone-aware datetimes when USE_TZ is False." "MySQL backend does not support timezone-aware datetimes when "
"USE_TZ is False."
) )
return str(value) return str(value)
@ -347,7 +349,10 @@ class DatabaseOperations(BaseDatabaseOperations):
if self.connection.mysql_is_mariadb: if self.connection.mysql_is_mariadb:
# MariaDB includes the microsecond component in TIME_TO_SEC as # MariaDB includes the microsecond component in TIME_TO_SEC as
# a decimal. MySQL returns an integer without microseconds. # a decimal. MySQL returns an integer without microseconds.
return "CAST((TIME_TO_SEC(%(lhs)s) - TIME_TO_SEC(%(rhs)s)) * 1000000 AS SIGNED)" % { return (
"CAST((TIME_TO_SEC(%(lhs)s) - TIME_TO_SEC(%(rhs)s)) "
"* 1000000 AS SIGNED)"
) % {
"lhs": lhs_sql, "lhs": lhs_sql,
"rhs": rhs_sql, "rhs": rhs_sql,
}, ( }, (

View File

@ -22,7 +22,8 @@ class DatabaseValidation(BaseDatabaseValidation):
"%s, such as data truncation upon insertion, by " "%s, such as data truncation upon insertion, by "
"escalating warnings into errors. It is strongly " "escalating warnings into errors. It is strongly "
"recommended you activate it. See: " "recommended you activate it. See: "
"https://docs.djangoproject.com/en/%s/ref/databases/#mysql-sql-mode" "https://docs.djangoproject.com/en/%s/ref/databases/"
"#mysql-sql-mode"
% ( % (
self.connection.display_name, self.connection.display_name,
self.connection.display_name, self.connection.display_name,

View File

@ -158,16 +158,31 @@ class DatabaseWrapper(BaseDatabaseWrapper):
_standard_operators = { _standard_operators = {
"exact": "= %s", "exact": "= %s",
"iexact": "= UPPER(%s)", "iexact": "= UPPER(%s)",
"contains": "LIKE TRANSLATE(%s USING NCHAR_CS) ESCAPE TRANSLATE('\\' USING NCHAR_CS)", "contains": (
"icontains": "LIKE UPPER(TRANSLATE(%s USING NCHAR_CS)) ESCAPE TRANSLATE('\\' USING NCHAR_CS)", "LIKE TRANSLATE(%s USING NCHAR_CS) ESCAPE TRANSLATE('\\' USING NCHAR_CS)"
),
"icontains": (
"LIKE UPPER(TRANSLATE(%s USING NCHAR_CS)) "
"ESCAPE TRANSLATE('\\' USING NCHAR_CS)"
),
"gt": "> %s", "gt": "> %s",
"gte": ">= %s", "gte": ">= %s",
"lt": "< %s", "lt": "< %s",
"lte": "<= %s", "lte": "<= %s",
"startswith": "LIKE TRANSLATE(%s USING NCHAR_CS) ESCAPE TRANSLATE('\\' USING NCHAR_CS)", "startswith": (
"endswith": "LIKE TRANSLATE(%s USING NCHAR_CS) ESCAPE TRANSLATE('\\' USING NCHAR_CS)", "LIKE TRANSLATE(%s USING NCHAR_CS) ESCAPE TRANSLATE('\\' USING NCHAR_CS)"
"istartswith": "LIKE UPPER(TRANSLATE(%s USING NCHAR_CS)) ESCAPE TRANSLATE('\\' USING NCHAR_CS)", ),
"iendswith": "LIKE UPPER(TRANSLATE(%s USING NCHAR_CS)) ESCAPE TRANSLATE('\\' USING NCHAR_CS)", "endswith": (
"LIKE TRANSLATE(%s USING NCHAR_CS) ESCAPE TRANSLATE('\\' USING NCHAR_CS)"
),
"istartswith": (
"LIKE UPPER(TRANSLATE(%s USING NCHAR_CS)) "
"ESCAPE TRANSLATE('\\' USING NCHAR_CS)"
),
"iendswith": (
"LIKE UPPER(TRANSLATE(%s USING NCHAR_CS)) "
"ESCAPE TRANSLATE('\\' USING NCHAR_CS)"
),
} }
_likec_operators = { _likec_operators = {

View File

@ -61,7 +61,8 @@ class DatabaseCreation(BaseDatabaseCreation):
cursor, parameters, verbosity, autoclobber cursor, parameters, verbosity, autoclobber
) )
else: else:
# Ran into a database error that isn't about leftover objects in the tablespace # Ran into a database error that isn't about
# leftover objects in the tablespace.
self.log( self.log(
"Got an error destroying the old test database: %s" "Got an error destroying the old test database: %s"
% e % e
@ -117,7 +118,8 @@ class DatabaseCreation(BaseDatabaseCreation):
else: else:
self.log("Tests cancelled.") self.log("Tests cancelled.")
sys.exit(1) sys.exit(1)
self._maindb_connection.close() # done with main user -- test user and tablespaces created # Done with main user -- test user and tablespaces created.
self._maindb_connection.close()
self._switch_to_test_user(parameters) self._switch_to_test_user(parameters)
return self.connection.settings_dict["NAME"] return self.connection.settings_dict["NAME"]
@ -160,8 +162,8 @@ class DatabaseCreation(BaseDatabaseCreation):
# There are objects in the test tablespace which prevent dropping it # There are objects in the test tablespace which prevent dropping it
# The easy fix is to drop the test user -- but are we allowed to do so? # The easy fix is to drop the test user -- but are we allowed to do so?
self.log( self.log(
"There are objects in the old test database which prevent its destruction.\n" "There are objects in the old test database which prevent its destruction."
"If they belong to the test user, deleting the user will allow the test " "\nIf they belong to the test user, deleting the user will allow the test "
"database to be recreated.\n" "database to be recreated.\n"
"Otherwise, you will need to find and remove each of these objects, " "Otherwise, you will need to find and remove each of these objects, "
"or use a different tablespace.\n" "or use a different tablespace.\n"
@ -301,8 +303,10 @@ class DatabaseCreation(BaseDatabaseCreation):
if verbosity >= 2: if verbosity >= 2:
self.log("_execute_test_db_destruction(): dbname=%s" % parameters["user"]) self.log("_execute_test_db_destruction(): dbname=%s" % parameters["user"])
statements = [ statements = [
"DROP TABLESPACE %(tblspace)s INCLUDING CONTENTS AND DATAFILES CASCADE CONSTRAINTS", "DROP TABLESPACE %(tblspace)s "
"DROP TABLESPACE %(tblspace_temp)s INCLUDING CONTENTS AND DATAFILES CASCADE CONSTRAINTS", "INCLUDING CONTENTS AND DATAFILES CASCADE CONSTRAINTS",
"DROP TABLESPACE %(tblspace_temp)s "
"INCLUDING CONTENTS AND DATAFILES CASCADE CONSTRAINTS",
] ]
self._execute_statements(cursor, statements, parameters, verbosity) self._execute_statements(cursor, statements, parameters, verbosity)

View File

@ -31,7 +31,8 @@ class DatabaseFeatures(BaseDatabaseFeatures):
requires_literal_defaults = True requires_literal_defaults = True
closed_cursor_error_class = InterfaceError closed_cursor_error_class = InterfaceError
bare_select_suffix = " FROM DUAL" bare_select_suffix = " FROM DUAL"
# select for update with limit can be achieved on Oracle, but not with the current backend. # Select for update with limit can be achieved on Oracle, but not with the
# current backend.
supports_select_for_update_with_limit = False supports_select_for_update_with_limit = False
supports_temporal_subtraction = True supports_temporal_subtraction = True
# Oracle doesn't ignore quoted identifiers case but the current backend # Oracle doesn't ignore quoted identifiers case but the current backend
@ -79,13 +80,16 @@ class DatabaseFeatures(BaseDatabaseFeatures):
}, },
"Oracle doesn't correctly calculate ISO 8601 week numbering before " "Oracle doesn't correctly calculate ISO 8601 week numbering before "
"1583 (the Gregorian calendar was introduced in 1582).": { "1583 (the Gregorian calendar was introduced in 1582).": {
"db_functions.datetime.test_extract_trunc.DateFunctionTests.test_trunc_week_before_1000", "db_functions.datetime.test_extract_trunc.DateFunctionTests."
"db_functions.datetime.test_extract_trunc.DateFunctionWithTimeZoneTests.test_trunc_week_before_1000", "test_trunc_week_before_1000",
"db_functions.datetime.test_extract_trunc.DateFunctionWithTimeZoneTests."
"test_trunc_week_before_1000",
}, },
"Oracle doesn't support bitwise XOR.": { "Oracle doesn't support bitwise XOR.": {
"expressions.tests.ExpressionOperatorTests.test_lefthand_bitwise_xor", "expressions.tests.ExpressionOperatorTests.test_lefthand_bitwise_xor",
"expressions.tests.ExpressionOperatorTests.test_lefthand_bitwise_xor_null", "expressions.tests.ExpressionOperatorTests.test_lefthand_bitwise_xor_null",
"expressions.tests.ExpressionOperatorTests.test_lefthand_bitwise_xor_right_null", "expressions.tests.ExpressionOperatorTests."
"test_lefthand_bitwise_xor_right_null",
}, },
"Oracle requires ORDER BY in row_number, ANSI:SQL doesn't.": { "Oracle requires ORDER BY in row_number, ANSI:SQL doesn't.": {
"expressions_window.tests.WindowFunctionTests.test_row_number_no_ordering", "expressions_window.tests.WindowFunctionTests.test_row_number_no_ordering",
@ -97,7 +101,8 @@ class DatabaseFeatures(BaseDatabaseFeatures):
django_test_expected_failures = { django_test_expected_failures = {
# A bug in Django/cx_Oracle with respect to string handling (#23843). # A bug in Django/cx_Oracle with respect to string handling (#23843).
"annotations.tests.NonAggregateAnnotationTestCase.test_custom_functions", "annotations.tests.NonAggregateAnnotationTestCase.test_custom_functions",
"annotations.tests.NonAggregateAnnotationTestCase.test_custom_functions_can_ref_other_functions", "annotations.tests.NonAggregateAnnotationTestCase."
"test_custom_functions_can_ref_other_functions",
} }
@cached_property @cached_property

View File

@ -147,7 +147,14 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
is_autofield, is_autofield,
is_json, is_json,
) )
for column, default, collation, internal_size, is_autofield, is_json in cursor.fetchall() for (
column,
default,
collation,
internal_size,
is_autofield,
is_json,
) in cursor.fetchall()
} }
self.cache_bust_counter += 1 self.cache_bust_counter += 1
cursor.execute( cursor.execute(
@ -271,7 +278,8 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
""" """
SELECT SELECT
user_constraints.constraint_name, user_constraints.constraint_name,
LISTAGG(LOWER(cols.column_name), ',') WITHIN GROUP (ORDER BY cols.position), LISTAGG(LOWER(cols.column_name), ',')
WITHIN GROUP (ORDER BY cols.position),
CASE user_constraints.constraint_type CASE user_constraints.constraint_type
WHEN 'P' THEN 1 WHEN 'P' THEN 1
ELSE 0 ELSE 0
@ -287,7 +295,8 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
FROM FROM
user_constraints user_constraints
LEFT OUTER JOIN LEFT OUTER JOIN
user_cons_columns cols ON user_constraints.constraint_name = cols.constraint_name user_cons_columns cols
ON user_constraints.constraint_name = cols.constraint_name
WHERE WHERE
user_constraints.constraint_type = ANY('P', 'U', 'C') user_constraints.constraint_type = ANY('P', 'U', 'C')
AND user_constraints.table_name = UPPER(%s) AND user_constraints.table_name = UPPER(%s)
@ -310,15 +319,18 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
""" """
SELECT SELECT
cons.constraint_name, cons.constraint_name,
LISTAGG(LOWER(cols.column_name), ',') WITHIN GROUP (ORDER BY cols.position), LISTAGG(LOWER(cols.column_name), ',')
WITHIN GROUP (ORDER BY cols.position),
LOWER(rcols.table_name), LOWER(rcols.table_name),
LOWER(rcols.column_name) LOWER(rcols.column_name)
FROM FROM
user_constraints cons user_constraints cons
INNER JOIN INNER JOIN
user_cons_columns rcols ON rcols.constraint_name = cons.r_constraint_name AND rcols.position = 1 user_cons_columns rcols
ON rcols.constraint_name = cons.r_constraint_name AND rcols.position = 1
LEFT OUTER JOIN LEFT OUTER JOIN
user_cons_columns cols ON cons.constraint_name = cols.constraint_name user_cons_columns cols
ON cons.constraint_name = cols.constraint_name
WHERE WHERE
cons.constraint_type = 'R' AND cons.constraint_type = 'R' AND
cons.table_name = UPPER(%s) cons.table_name = UPPER(%s)
@ -343,7 +355,8 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
ind.index_name, ind.index_name,
LOWER(ind.index_type), LOWER(ind.index_type),
LOWER(ind.uniqueness), LOWER(ind.uniqueness),
LISTAGG(LOWER(cols.column_name), ',') WITHIN GROUP (ORDER BY cols.column_position), LISTAGG(LOWER(cols.column_name), ',')
WITHIN GROUP (ORDER BY cols.column_position),
LISTAGG(cols.descend, ',') WITHIN GROUP (ORDER BY cols.column_position) LISTAGG(cols.descend, ',') WITHIN GROUP (ORDER BY cols.column_position)
FROM FROM
user_ind_columns cols, user_indexes ind user_ind_columns cols, user_indexes ind

View File

@ -399,12 +399,15 @@ END;
user_tables user_tables
JOIN JOIN
user_constraints cons user_constraints cons
ON (user_tables.table_name = cons.table_name AND cons.constraint_type = ANY('P', 'U')) ON (user_tables.table_name = cons.table_name
AND cons.constraint_type = ANY('P', 'U'))
LEFT JOIN LEFT JOIN
user_constraints rcons user_constraints rcons
ON (user_tables.table_name = rcons.table_name AND rcons.constraint_type = 'R') ON (user_tables.table_name = rcons.table_name
AND rcons.constraint_type = 'R')
START WITH user_tables.table_name = UPPER(%s) START WITH user_tables.table_name = UPPER(%s)
CONNECT BY NOCYCLE PRIOR cons.constraint_name = rcons.r_constraint_name CONNECT BY
NOCYCLE PRIOR cons.constraint_name = rcons.r_constraint_name
GROUP BY GROUP BY
user_tables.table_name, rcons.constraint_name user_tables.table_name, rcons.constraint_name
HAVING user_tables.table_name != UPPER(%s) HAVING user_tables.table_name != UPPER(%s)
@ -583,7 +586,8 @@ END;
value = timezone.make_naive(value, self.connection.timezone) value = timezone.make_naive(value, self.connection.timezone)
else: else:
raise ValueError( raise ValueError(
"Oracle backend does not support timezone-aware datetimes when USE_TZ is False." "Oracle backend does not support timezone-aware datetimes when "
"USE_TZ is False."
) )
return Oracle_datetime.from_datetime(value) return Oracle_datetime.from_datetime(value)

View File

@ -132,10 +132,8 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
new_value = "TO_TIMESTAMP(%s, 'YYYY-MM-DD HH24:MI:SS.FF')" % new_value new_value = "TO_TIMESTAMP(%s, 'YYYY-MM-DD HH24:MI:SS.FF')" % new_value
elif new_internal_type == "TimeField": elif new_internal_type == "TimeField":
# TimeField are stored as TIMESTAMP with a 1900-01-01 date part. # TimeField are stored as TIMESTAMP with a 1900-01-01 date part.
new_value = ( new_value = "CONCAT('1900-01-01 ', %s)" % new_value
"TO_TIMESTAMP(CONCAT('1900-01-01 ', %s), 'YYYY-MM-DD HH24:MI:SS.FF')" new_value = "TO_TIMESTAMP(%s, 'YYYY-MM-DD HH24:MI:SS.FF')" % new_value
% new_value
)
# Transfer values across # Transfer values across
self.execute( self.execute(
"UPDATE %s set %s=%s" "UPDATE %s set %s=%s"

View File

@ -67,7 +67,8 @@ class DatabaseFeatures(BaseDatabaseFeatures):
django_test_skips = { django_test_skips = {
"opclasses are PostgreSQL only.": { "opclasses are PostgreSQL only.": {
"indexes.tests.SchemaIndexesNotPostgreSQLTests.test_create_index_ignores_opclasses", "indexes.tests.SchemaIndexesNotPostgreSQLTests."
"test_create_index_ignores_opclasses",
}, },
} }

View File

@ -50,8 +50,13 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
"""Return a list of table and view names in the current database.""" """Return a list of table and view names in the current database."""
cursor.execute( cursor.execute(
""" """
SELECT c.relname, SELECT
CASE WHEN c.relispartition THEN 'p' WHEN c.relkind IN ('m', 'v') THEN 'v' ELSE 't' END c.relname,
CASE
WHEN c.relispartition THEN 'p'
WHEN c.relkind IN ('m', 'v') THEN 'v'
ELSE 't'
END
FROM pg_catalog.pg_class c FROM pg_catalog.pg_class c
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind IN ('f', 'm', 'p', 'r', 'v') WHERE c.relkind IN ('f', 'm', 'p', 'r', 'v')
@ -116,9 +121,15 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
SELECT s.relname as sequence_name, col.attname SELECT s.relname as sequence_name, col.attname
FROM pg_class s FROM pg_class s
JOIN pg_namespace sn ON sn.oid = s.relnamespace JOIN pg_namespace sn ON sn.oid = s.relnamespace
JOIN pg_depend d ON d.refobjid = s.oid AND d.refclassid = 'pg_class'::regclass JOIN
JOIN pg_attrdef ad ON ad.oid = d.objid AND d.classid = 'pg_attrdef'::regclass pg_depend d ON d.refobjid = s.oid
JOIN pg_attribute col ON col.attrelid = ad.adrelid AND col.attnum = ad.adnum AND d.refclassid = 'pg_class'::regclass
JOIN
pg_attrdef ad ON ad.oid = d.objid
AND d.classid = 'pg_attrdef'::regclass
JOIN
pg_attribute col ON col.attrelid = ad.adrelid
AND col.attnum = ad.adnum
JOIN pg_class tbl ON tbl.oid = ad.adrelid JOIN pg_class tbl ON tbl.oid = ad.adrelid
WHERE s.relkind = 'S' WHERE s.relkind = 'S'
AND d.deptype in ('a', 'n') AND d.deptype in ('a', 'n')
@ -143,8 +154,10 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
FROM pg_constraint con FROM pg_constraint con
LEFT JOIN pg_class c1 ON con.conrelid = c1.oid LEFT JOIN pg_class c1 ON con.conrelid = c1.oid
LEFT JOIN pg_class c2 ON con.confrelid = c2.oid LEFT JOIN pg_class c2 ON con.confrelid = c2.oid
LEFT JOIN pg_attribute a1 ON c1.oid = a1.attrelid AND a1.attnum = con.conkey[1] LEFT JOIN
LEFT JOIN pg_attribute a2 ON c2.oid = a2.attrelid AND a2.attnum = con.confkey[1] pg_attribute a1 ON c1.oid = a1.attrelid AND a1.attnum = con.conkey[1]
LEFT JOIN
pg_attribute a2 ON c2.oid = a2.attrelid AND a2.attnum = con.confkey[1]
WHERE WHERE
c1.relname = %s AND c1.relname = %s AND
con.contype = 'f' AND con.contype = 'f' AND
@ -203,8 +216,14 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
cursor.execute( cursor.execute(
""" """
SELECT SELECT
indexname, array_agg(attname ORDER BY arridx), indisunique, indisprimary, indexname,
array_agg(ordering ORDER BY arridx), amname, exprdef, s2.attoptions array_agg(attname ORDER BY arridx),
indisunique,
indisprimary,
array_agg(ordering ORDER BY arridx),
amname,
exprdef,
s2.attoptions
FROM ( FROM (
SELECT SELECT
c2.relname as indexname, idx.*, attr.attname, am.amname, c2.relname as indexname, idx.*, attr.attname, am.amname,
@ -221,12 +240,16 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
c2.reloptions as attoptions c2.reloptions as attoptions
FROM ( FROM (
SELECT * SELECT *
FROM pg_index i, unnest(i.indkey, i.indoption) WITH ORDINALITY koi(key, option, arridx) FROM
pg_index i,
unnest(i.indkey, i.indoption)
WITH ORDINALITY koi(key, option, arridx)
) idx ) idx
LEFT JOIN pg_class c ON idx.indrelid = c.oid LEFT JOIN pg_class c ON idx.indrelid = c.oid
LEFT JOIN pg_class c2 ON idx.indexrelid = c2.oid LEFT JOIN pg_class c2 ON idx.indexrelid = c2.oid
LEFT JOIN pg_am am ON c2.relam = am.oid LEFT JOIN pg_am am ON c2.relam = am.oid
LEFT JOIN pg_attribute attr ON attr.attrelid = c.oid AND attr.attnum = idx.key LEFT JOIN
pg_attribute attr ON attr.attrelid = c.oid AND attr.attnum = idx.key
WHERE c.relname = %s AND pg_catalog.pg_table_is_visible(c.oid) WHERE c.relname = %s AND pg_catalog.pg_table_is_visible(c.oid)
) s2 ) s2
GROUP BY indexname, indisunique, indisprimary, amname, exprdef, attoptions; GROUP BY indexname, indisunique, indisprimary, amname, exprdef, attoptions;

View File

@ -187,11 +187,12 @@ class DatabaseOperations(BaseDatabaseOperations):
output = [] output = []
qn = self.quote_name qn = self.quote_name
for model in model_list: for model in model_list:
# Use `coalesce` to set the sequence for each model to the max pk value if there are records, # Use `coalesce` to set the sequence for each model to the max pk
# or 1 if there are none. Set the `is_called` property (the third argument to `setval`) to true # value if there are records, or 1 if there are none. Set the
# if there are records (as the max pk value is already in use), otherwise set it to false. # `is_called` property (the third argument to `setval`) to true if
# Use pg_get_serial_sequence to get the underlying sequence name from the table name # there are records (as the max pk value is already in use),
# and column name (available since PostgreSQL 8) # otherwise set it to false. Use pg_get_serial_sequence to get the
# underlying sequence name from the table name and column name.
for f in model._meta.local_fields: for f in model._meta.local_fields:
if isinstance(f, models.AutoField): if isinstance(f, models.AutoField):
@ -209,7 +210,9 @@ class DatabaseOperations(BaseDatabaseOperations):
style.SQL_TABLE(qn(model._meta.db_table)), style.SQL_TABLE(qn(model._meta.db_table)),
) )
) )
break # Only one AutoField is allowed per model, so don't bother continuing. # Only one AutoField is allowed per model, so don't bother
# continuing.
break
return output return output
def prep_for_iexact_query(self, x): def prep_for_iexact_query(self, x):

View File

@ -33,8 +33,10 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
) )
# Setting the constraint to IMMEDIATE runs any deferred checks to allow # Setting the constraint to IMMEDIATE runs any deferred checks to allow
# dropping it in the same transaction. # dropping it in the same transaction.
sql_delete_fk = "SET CONSTRAINTS %(name)s IMMEDIATE; ALTER TABLE %(table)s DROP CONSTRAINT %(name)s" sql_delete_fk = (
"SET CONSTRAINTS %(name)s IMMEDIATE; "
"ALTER TABLE %(table)s DROP CONSTRAINT %(name)s"
)
sql_delete_procedure = "DROP FUNCTION %(procedure)s(%(param_types)s)" sql_delete_procedure = "DROP FUNCTION %(procedure)s(%(param_types)s)"
def quote_value(self, value): def quote_value(self, value):

View File

@ -209,9 +209,15 @@ def _sqlite_datetime_trunc(lookup_type, dt, tzname, conn_tzname):
elif lookup_type == "hour": elif lookup_type == "hour":
return f"{dt.year:04d}-{dt.month:02d}-{dt.day:02d} {dt.hour:02d}:00:00" return f"{dt.year:04d}-{dt.month:02d}-{dt.day:02d} {dt.hour:02d}:00:00"
elif lookup_type == "minute": elif lookup_type == "minute":
return f"{dt.year:04d}-{dt.month:02d}-{dt.day:02d} {dt.hour:02d}:{dt.minute:02d}:00" return (
f"{dt.year:04d}-{dt.month:02d}-{dt.day:02d} "
f"{dt.hour:02d}:{dt.minute:02d}:00"
)
elif lookup_type == "second": elif lookup_type == "second":
return f"{dt.year:04d}-{dt.month:02d}-{dt.day:02d} {dt.hour:02d}:{dt.minute:02d}:{dt.second:02d}" return (
f"{dt.year:04d}-{dt.month:02d}-{dt.day:02d} "
f"{dt.hour:02d}:{dt.minute:02d}:{dt.second:02d}"
)
raise ValueError(f"Unsupported lookup type: {lookup_type!r}") raise ValueError(f"Unsupported lookup type: {lookup_type!r}")

View File

@ -57,26 +57,34 @@ class DatabaseFeatures(BaseDatabaseFeatures):
def django_test_skips(self): def django_test_skips(self):
skips = { skips = {
"SQLite stores values rounded to 15 significant digits.": { "SQLite stores values rounded to 15 significant digits.": {
"model_fields.test_decimalfield.DecimalFieldTests.test_fetch_from_db_without_float_rounding", "model_fields.test_decimalfield.DecimalFieldTests."
"test_fetch_from_db_without_float_rounding",
}, },
"SQLite naively remakes the table on field alteration.": { "SQLite naively remakes the table on field alteration.": {
"schema.tests.SchemaTests.test_unique_no_unnecessary_fk_drops", "schema.tests.SchemaTests.test_unique_no_unnecessary_fk_drops",
"schema.tests.SchemaTests.test_unique_and_reverse_m2m", "schema.tests.SchemaTests.test_unique_and_reverse_m2m",
"schema.tests.SchemaTests.test_alter_field_default_doesnt_perform_queries", "schema.tests.SchemaTests."
"schema.tests.SchemaTests.test_rename_column_renames_deferred_sql_references", "test_alter_field_default_doesnt_perform_queries",
"schema.tests.SchemaTests."
"test_rename_column_renames_deferred_sql_references",
}, },
"SQLite doesn't support negative precision for ROUND().": { "SQLite doesn't support negative precision for ROUND().": {
"db_functions.math.test_round.RoundTests.test_null_with_negative_precision", "db_functions.math.test_round.RoundTests."
"db_functions.math.test_round.RoundTests.test_decimal_with_negative_precision", "test_null_with_negative_precision",
"db_functions.math.test_round.RoundTests.test_float_with_negative_precision", "db_functions.math.test_round.RoundTests."
"db_functions.math.test_round.RoundTests.test_integer_with_negative_precision", "test_decimal_with_negative_precision",
"db_functions.math.test_round.RoundTests."
"test_float_with_negative_precision",
"db_functions.math.test_round.RoundTests."
"test_integer_with_negative_precision",
}, },
} }
if Database.sqlite_version_info < (3, 27): if Database.sqlite_version_info < (3, 27):
skips.update( skips.update(
{ {
"Nondeterministic failure on SQLite < 3.27.": { "Nondeterministic failure on SQLite < 3.27.": {
"expressions_window.tests.WindowFunctionTests.test_subquery_row_range_rank", "expressions_window.tests.WindowFunctionTests."
"test_subquery_row_range_rank",
}, },
} }
) )
@ -85,8 +93,10 @@ class DatabaseFeatures(BaseDatabaseFeatures):
{ {
"the sqlite backend's close() method is a no-op when using an " "the sqlite backend's close() method is a no-op when using an "
"in-memory database": { "in-memory database": {
"servers.test_liveserverthread.LiveServerThreadTest.test_closes_connections", "servers.test_liveserverthread.LiveServerThreadTest."
"servers.tests.LiveServerTestCloseConnectionTest.test_closes_connections", "test_closes_connections",
"servers.tests.LiveServerTestCloseConnectionTest."
"test_closes_connections",
}, },
} }
) )

View File

@ -146,7 +146,14 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
) )
return { return {
column_name: (ref_column_name, ref_table_name) column_name: (ref_column_name, ref_table_name)
for _, _, ref_table_name, column_name, ref_column_name, *_ in cursor.fetchall() for (
_,
_,
ref_table_name,
column_name,
ref_column_name,
*_,
) in cursor.fetchall()
} }
def get_primary_key_column(self, cursor, table_name): def get_primary_key_column(self, cursor, table_name):

View File

@ -168,7 +168,9 @@ class DatabaseOperations(BaseDatabaseOperations):
def last_executed_query(self, cursor, sql, params): def last_executed_query(self, cursor, sql, params):
# Python substitutes parameters in Modules/_sqlite/cursor.c with: # Python substitutes parameters in Modules/_sqlite/cursor.c with:
# pysqlite_statement_bind_parameters(self->statement, parameters, allow_8bit_chars); # pysqlite_statement_bind_parameters(
# self->statement, parameters, allow_8bit_chars
# );
# Unfortunately there is no way to reach self->statement from Python, # Unfortunately there is no way to reach self->statement from Python,
# so we quote and substitute parameters manually. # so we quote and substitute parameters manually.
if params: if params:
@ -271,7 +273,8 @@ class DatabaseOperations(BaseDatabaseOperations):
value = timezone.make_naive(value, self.connection.timezone) value = timezone.make_naive(value, self.connection.timezone)
else: else:
raise ValueError( raise ValueError(
"SQLite backend does not support timezone-aware datetimes when USE_TZ is False." "SQLite backend does not support timezone-aware datetimes when "
"USE_TZ is False."
) )
return str(value) return str(value)

View File

@ -468,12 +468,15 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
old_field.remote_field.through._meta.db_table old_field.remote_field.through._meta.db_table
== new_field.remote_field.through._meta.db_table == new_field.remote_field.through._meta.db_table
): ):
# The field name didn't change, but some options did; we have to propagate this altering. # The field name didn't change, but some options did, so we have to
# propagate this altering.
self._remake_table( self._remake_table(
old_field.remote_field.through, old_field.remote_field.through,
alter_field=( alter_field=(
# We need the field that points to the target model, so we can tell alter_field to change it - # The field that points to the target model is needed, so
# this is m2m_reverse_field_name() (as opposed to m2m_field_name, which points to our model) # we can tell alter_field to change it - this is
# m2m_reverse_field_name() (as opposed to m2m_field_name(),
# which points to our model).
old_field.remote_field.through._meta.get_field( old_field.remote_field.through._meta.get_field(
old_field.m2m_reverse_field_name() old_field.m2m_reverse_field_name()
), ),

Some files were not shown because too many files have changed in this diff Show More