Commit 82ac3894 authored by Russell Keith-Magee's avatar Russell Keith-Magee
Browse files

Edited model and field checks for grammar and consistency.

parent bc4dc6e9
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -36,14 +36,14 @@ def check_model_signals(app_configs=None, **kwargs):
                        description = "An instance of the `%s` class" % receiver.__class__.__name__
                    errors.append(
                        Error(
                            "%s was connected to the `%s` signal "
                            "%s was connected to the '%s' signal "
                            "with a lazy reference to the '%s' sender, "
                            "which has not been installed." % (
                                description, name, '.'.join(reference)
                            ),
                            obj=receiver.__module__,
                            hint=None,
                            id='E014'
                            id='signals.E001'
                        )
                    )
    return errors
+55 −53
Original line number Diff line number Diff line
@@ -197,10 +197,10 @@ class Field(RegisterLookupMixin):
        if self.name.endswith('_'):
            return [
                checks.Error(
                    'Field names must not end with underscores.',
                    'Field names must not end with an underscore.',
                    hint=None,
                    obj=self,
                    id='E001',
                    id='fields.E001',
                )
            ]
        elif '__' in self.name:
@@ -209,16 +209,16 @@ class Field(RegisterLookupMixin):
                    'Field names must not contain "__".',
                    hint=None,
                    obj=self,
                    id='E052',
                    id='fields.E002',
                )
            ]
        elif self.name == 'pk':
            return [
                checks.Error(
                    'Cannot use "pk" as a field name since it is a reserved name.',
                    "'pk' is a reserved word that cannot be used as a field name.",
                    hint=None,
                    obj=self,
                    id='E051',
                    id='fields.E003',
                )
            ]
        else:
@@ -230,10 +230,10 @@ class Field(RegisterLookupMixin):
                    not is_iterable(self.choices)):
                return [
                    checks.Error(
                        '"choices" must be an iterable (e.g., a list or tuple).',
                        "'choices' must be an iterable (e.g., a list or tuple).",
                        hint=None,
                        obj=self,
                        id='E033',
                        id='fields.E004',
                    )
                ]
            elif any(isinstance(choice, six.string_types) or
@@ -241,13 +241,11 @@ class Field(RegisterLookupMixin):
                     for choice in self.choices):
                return [
                    checks.Error(
                        ('All "choices" elements must be a tuple of two '
                         'elements (the first one is the actual value '
                         'to be stored and the second element is '
                         'the human-readable name).'),
                        ("'choices' must be an iterable containing "
                         "(actual value, human readable name) tuples."),
                        hint=None,
                        obj=self,
                        id='E034',
                        id='fields.E005',
                    )
                ]
            else:
@@ -259,10 +257,10 @@ class Field(RegisterLookupMixin):
        if self.db_index not in (None, True, False):
            return [
                checks.Error(
                    '"db_index" must be either None, True or False.',
                    "'db_index' must be None, True or False.",
                    hint=None,
                    obj=self,
                    id='E035',
                    id='fields.E006',
                )
            ]
        else:
@@ -277,10 +275,10 @@ class Field(RegisterLookupMixin):
            return [
                checks.Error(
                    'Primary keys must not have null=True.',
                    hint=('Set null=False on the field or '
                    hint=('Set null=False on the field, or '
                          'remove primary_key=True argument.'),
                    obj=self,
                    id='E036',
                    id='fields.E007',
                )
            ]
        else:
@@ -864,10 +862,10 @@ class AutoField(Field):
        if not self.primary_key:
            return [
                checks.Error(
                    'The field must have primary_key=True, because it is an AutoField.',
                    'AutoFields must set primary_key=True.',
                    hint=None,
                    obj=self,
                    id='E048',
                    id='fields.E100',
                ),
            ]
        else:
@@ -940,10 +938,10 @@ class BooleanField(Field):
        if getattr(self, 'null', False):
            return [
                checks.Error(
                    'BooleanFields do not acceps null values.',
                    'BooleanFields do not accept null values.',
                    hint='Use a NullBooleanField instead.',
                    obj=self,
                    id='E037',
                    id='fields.E110',
                )
            ]
        else:
@@ -1020,19 +1018,19 @@ class CharField(Field):
        except TypeError:
            return [
                checks.Error(
                    'The field must have "max_length" attribute.',
                    "CharFields must define a 'max_length' attribute.",
                    hint=None,
                    obj=self,
                    id='E038',
                    id='fields.E120',
                )
            ]
        except ValueError:
            return [
                checks.Error(
                    '"max_length" must be a positive integer.',
                    "'max_length' must be a positive integer.",
                    hint=None,
                    obj=self,
                    id='E039',
                    id='fields.E121',
                )
            ]
        else:
@@ -1305,24 +1303,16 @@ class DecimalField(Field):

    def check(self, **kwargs):
        errors = super(DecimalField, self).check(**kwargs)
        errors.extend(self._check_decimal_places_and_max_digits(**kwargs))
        return errors

    def _check_decimal_places_and_max_digits(self, **kwargs):
        errors = self.__check_decimal_places()
        errors += self.__check_max_digits()
        if not errors and int(self.decimal_places) > int(self.max_digits):
            errors.append(
                checks.Error(
                    '"max_digits" must be greater or equal to "decimal_places".',
                    hint=None,
                    obj=self,
                    id='E040',
                )
            )
        digits_errors = self._check_decimal_places()
        digits_errors.extend(self._check_max_digits())
        if not digits_errors:
            errors.extend(self._check_decimal_places_and_max_digits(**kwargs))
        else:
            errors.extend(digits_errors)
        return errors

    def __check_decimal_places(self):
    def _check_decimal_places(self):
        try:
            decimal_places = int(self.decimal_places)
            if decimal_places < 0:
@@ -1330,25 +1320,25 @@ class DecimalField(Field):
        except TypeError:
            return [
                checks.Error(
                    'The field requires a "decimal_places" attribute.',
                    "DecimalFields must define a 'decimal_places' attribute.",
                    hint=None,
                    obj=self,
                    id='E041',
                    id='fields.E130',
                )
            ]
        except ValueError:
            return [
                checks.Error(
                    '"decimal_places" attribute must be a non-negative integer.',
                    "'decimal_places' must be a non-negative integer.",
                    hint=None,
                    obj=self,
                    id='E042',
                    id='fields.E131',
                )
            ]
        else:
            return []

    def __check_max_digits(self):
    def _check_max_digits(self):
        try:
            max_digits = int(self.max_digits)
            if max_digits <= 0:
@@ -1356,24 +1346,36 @@ class DecimalField(Field):
        except TypeError:
            return [
                checks.Error(
                    'The field requires a "max_digits" attribute.',
                    "DecimalFields must define a 'max_digits' attribute.",
                    hint=None,
                    obj=self,
                    id='E043',
                    id='fields.E132',
                )
            ]
        except ValueError:
            return [
                checks.Error(
                    '"max_digits" attribute must be a positive integer.',
                    "'max_digits' must be a positive integer.",
                    hint=None,
                    obj=self,
                    id='E044',
                    id='fields.E133',
                )
            ]
        else:
            return []

    def _check_decimal_places_and_max_digits(self, **kwargs):
        if int(self.decimal_places) > int(self.max_digits):
            return [
                checks.Error(
                    "'max_digits' must be greater or equal to 'decimal_places'.",
                    hint=None,
                    obj=self,
                    id='fields.E134',
                )
            ]
        return []

    def deconstruct(self):
        name, path, args, kwargs = super(DecimalField, self).deconstruct()
        if self.max_digits:
@@ -1481,10 +1483,10 @@ class FilePathField(Field):
        if not self.allow_files and not self.allow_folders:
            return [
                checks.Error(
                    'The field must have either "allow_files" or "allow_folders" set to True.',
                    "FilePathFields must have either 'allow_files' or 'allow_folders' set to True.",
                    hint=None,
                    obj=self,
                    id='E045',
                    id='fields.E140',
                )
            ]
        return []
@@ -1659,11 +1661,11 @@ class GenericIPAddressField(Field):
        if not getattr(self, 'null', False) and getattr(self, 'blank', False):
            return [
                checks.Error(
                    ('The field cannot accept blank values if null values '
                     'are not allowed, as blank values are stored as null.'),
                    ('GenericIPAddressFields cannot have blank=True if null=False, '
                     'as blank values are stored as nulls.'),
                    hint=None,
                    obj=self,
                    id='E046',
                    id='fields.E150',
                )
            ]
        return []
+6 −6
Original line number Diff line number Diff line
@@ -246,10 +246,10 @@ class FileField(Field):
        if self._unique_set_explicitly:
            return [
                checks.Error(
                    '"unique" is not a valid argument for %s.' % self.__class__.__name__,
                    "'unique' is not a valid argument for a %s." % self.__class__.__name__,
                    hint=None,
                    obj=self,
                    id='E049',
                    id='fields.E200',
                )
            ]
        else:
@@ -259,10 +259,10 @@ class FileField(Field):
        if self._primary_key_set_explicitly:
            return [
                checks.Error(
                    '"primary_key" is not a valid argument for %s.' % self.__class__.__name__,
                    "'primary_key' is not a valid argument for a %s." % self.__class__.__name__,
                    hint=None,
                    obj=self,
                    id='E050',
                    id='fields.E201',
                )
            ]
        else:
@@ -392,11 +392,11 @@ class ImageField(FileField):
        except ImproperlyConfigured:
            return [
                checks.Error(
                    'To use ImageFields, Pillow must be installed.',
                    'Cannot use ImageField because Pillow is not installed.',
                    hint=('Get Pillow at https://pypi.python.org/pypi/Pillow '
                          'or run command "pip install pillow".'),
                    obj=self,
                    id='E032',
                    id='fields.E210',
                )
            ]
        else:
+59 −65
Original line number Diff line number Diff line
@@ -108,13 +108,11 @@ class RelatedField(Field):
        if rel_is_missing and (rel_is_string or not self.rel.to._meta.swapped):
            return [
                checks.Error(
                    ('The field has a relation with model %s, which '
                     'has either not been installed or is abstract.') % model_name,
                    hint=('Ensure that you did not misspell the model name and '
                          'the model is not abstract. Does your INSTALLED_APPS '
                          'setting contain the app where %s is defined?') % model_name,
                    ("Field defines a relation with model '%s', which "
                     "is either not installed, or is abstract.") % model_name,
                    hint=None,
                    obj=self,
                    id='E030',
                    id='fields.E300',
                )
            ]
        return []
@@ -129,11 +127,11 @@ class RelatedField(Field):
            )
            return [
                checks.Error(
                    ('The field defines a relation with the model %s, '
                     'which has been swapped out.') % model,
                    hint='Update the relation to point at settings.%s' % self.rel.to._meta.swappable,
                    ("Field defines a relation with the model '%s', "
                     "which has been swapped out.") % model,
                    hint="Update the relation to point at 'settings.%s'." % self.rel.to._meta.swappable,
                    obj=self,
                    id='E029',
                    id='fields.E301',
                )
            ]
        return []
@@ -190,22 +188,22 @@ class RelatedField(Field):
            if clash_field.name == rel_name:
                errors.append(
                    checks.Error(
                        'Accessor for field %s clashes with field %s.' % (field_name, clash_name),
                        hint=('Rename field %s or add/change a related_name '
                              'argument to the definition for field %s.') % (clash_name, field_name),
                        "Reverse accessor for '%s' clashes with field name '%s'." % (field_name, clash_name),
                        hint=("Rename field '%s', or add/change a related_name "
                              "argument to the definition for field '%s'.") % (clash_name, field_name),
                        obj=self,
                        id='E014',
                        id='fields.E302',
                    )
                )

            if clash_field.name == rel_query_name:
                errors.append(
                    checks.Error(
                        'Reverse query name for field %s clashes with field %s.' % (field_name, clash_name),
                        hint=('Rename field %s or add/change a related_name '
                              'argument to the definition for field %s.') % (clash_name, field_name),
                        "Reverse query name for '%s' clashes with field name '%s'." % (field_name, clash_name),
                        hint=("Rename field '%s', or add/change a related_name "
                              "argument to the definition for field '%s'.") % (clash_name, field_name),
                        obj=self,
                        id='E015',
                        id='fields.E303',
                    )
                )

@@ -223,22 +221,22 @@ class RelatedField(Field):
            if clash_field.get_accessor_name() == rel_name:
                errors.append(
                    checks.Error(
                        'Clash between accessors for %s and %s.' % (field_name, clash_name),
                        hint=('Add or change a related_name argument '
                              'to the definition for %s or %s.') % (field_name, clash_name),
                        "Reverse accessor for '%s' clashes with reverse accessor for '%s'." % (field_name, clash_name),
                        hint=("Add or change a related_name argument "
                              "to the definition for '%s' or '%s'.") % (field_name, clash_name),
                        obj=self,
                        id='E016',
                        id='fields.E304',
                    )
                )

            if clash_field.get_accessor_name() == rel_query_name:
                errors.append(
                    checks.Error(
                        'Clash between reverse query names for %s and %s.' % (field_name, clash_name),
                        hint=('Add or change a related_name argument '
                              'to the definition for %s or %s.') % (field_name, clash_name),
                        "Reverse query name for '%s' clashes with reverse query name for '%s'." % (field_name, clash_name),
                        hint=("Add or change a related_name argument "
                              "to the definition for '%s' or '%s'.") % (field_name, clash_name),
                        obj=self,
                        id='E017',
                        id='fields.E305',
                    )
                )

@@ -1317,17 +1315,15 @@ class ForeignObject(RelatedField):
        has_unique_field = any(rel_field.unique
            for rel_field in self.foreign_related_fields)
        if not has_unique_field and len(self.foreign_related_fields) > 1:
            field_combination = ','.join(rel_field.name
            field_combination = ', '.join("'%s'" % rel_field.name
                for rel_field in self.foreign_related_fields)
            model_name = self.rel.to.__name__
            return [
                checks.Error(
                    ('No unique=True constraint '
                     'on field combination "%s" under model %s.') % (field_combination, model_name),
                    hint=('Set unique=True argument on any of the fields '
                          '"%s" under model %s.') % (field_combination, model_name),
                    "None of the fields %s on model '%s' have a unique=True constraint." % (field_combination, model_name),
                    hint=None,
                    obj=self,
                    id='E018',
                    id='fields.E310',
                )
            ]
        elif not has_unique_field:
@@ -1335,11 +1331,11 @@ class ForeignObject(RelatedField):
            model_name = self.rel.to.__name__
            return [
                checks.Error(
                    ('%s.%s must have unique=True '
                     'because it is referenced by a foreign key.') % (model_name, field_name),
                    ("'%s.%s' must set unique=True "
                     "because it is referenced by a foreign key.") % (model_name, field_name),
                    hint=None,
                    obj=self,
                    id='E019',
                    id='fields.E311',
                )
            ]
        else:
@@ -1605,19 +1601,19 @@ class ForeignKey(ForeignObject):
        if on_delete == SET_NULL and not self.null:
            return [
                checks.Error(
                    'The field specifies on_delete=SET_NULL, but cannot be null.',
                    hint='Set null=True argument on the field.',
                    'Field specifies on_delete=SET_NULL, but cannot be null.',
                    hint='Set null=True argument on the field, or change the on_delete rule.',
                    obj=self,
                    id='E020',
                    id='fields.E320',
                )
            ]
        elif on_delete == SET_DEFAULT and not self.has_default():
            return [
                checks.Error(
                    'The field specifies on_delete=SET_DEFAULT, but has no default value.',
                    hint=None,
                    'Field specifies on_delete=SET_DEFAULT, but has no default value.',
                    hint='Set a default value, or change the on_delete rule.',
                    obj=self,
                    id='E021',
                    id='fields.E321',
                )
            ]
        else:
@@ -1864,10 +1860,10 @@ class ManyToManyField(RelatedField):
        if self.unique:
            return [
                checks.Error(
                    'ManyToManyFields must not be unique.',
                    'ManyToManyFields cannot be unique.',
                    hint=None,
                    obj=self,
                    id='E022',
                    id='fields.E330',
                )
            ]
        return []
@@ -1879,13 +1875,11 @@ class ManyToManyField(RelatedField):
            # The relationship model is not installed.
            errors.append(
                checks.Error(
                    ('The field specifies a many-to-many relation through model '
                     '%s, which has not been installed.') % self.rel.through,
                    hint=('Ensure that you did not misspell the model name and '
                          'the model is not abstract. Does your INSTALLED_APPS '
                          'setting contain the app where %s is defined?') % self.rel.through,
                    ("Field specifies a many-to-many relation through model "
                     "'%s', which has not been installed.") % self.rel.through,
                    hint=None,
                    obj=self,
                    id='E023',
                    id='fields.E331',
                )
            )

@@ -1914,7 +1908,7 @@ class ManyToManyField(RelatedField):
                        'Many-to-many fields with intermediate tables must not be symmetrical.',
                        hint=None,
                        obj=self,
                        id='E024',
                        id='fields.E332',
                    )
                )

@@ -1926,12 +1920,12 @@ class ManyToManyField(RelatedField):
                if seen_self > 2:
                    errors.append(
                        checks.Error(
                            ('The model is used as an intermediary model by '
                             '%s, but it has more than two foreign keys '
                             'to %s, which is ambiguous and is not permitted.') % (self, from_model_name),
                            ("The model is used as an intermediate model by "
                             "'%s', but it has more than two foreign keys "
                             "to '%s', which is ambiguous.") % (self, from_model_name),
                            hint=None,
                            obj=self.rel.through,
                            id='E025',
                            id='fields.E333',
                        )
                    )

@@ -1945,41 +1939,41 @@ class ManyToManyField(RelatedField):
                if seen_from > 1:
                    errors.append(
                        checks.Error(
                            ('The model is used as an intermediary model by '
                             '%s, but it has more than one foreign key '
                             'to %s, which is ambiguous and is not permitted.') % (self, from_model_name),
                            ("The model is used as an intermediate model by "
                             "'%s', but it has more than one foreign key "
                             "from '%s', which is ambiguous.") % (self, from_model_name),
                            hint=('If you want to create a recursive relationship, '
                                  'use ForeignKey("self", symmetrical=False, '
                                  'through="%s").') % relationship_model_name,
                            obj=self,
                            id='E026',
                            id='fields.E334',
                        )
                    )

                if seen_to > 1:
                    errors.append(
                        checks.Error(
                            ('The model is used as an intermediary model by '
                             '%s, but it has more than one foreign key '
                             'to %s, which is ambiguous and is not permitted.') % (self, to_model_name),
                            ("The model is used as an intermediate model by "
                             "'%s', but it has more than one foreign key "
                             "to '%s', which is ambiguous.") % (self, to_model_name),
                            hint=('If you want to create a recursive '
                                  'relationship, use ForeignKey("self", '
                                  'symmetrical=False, through="%s").') % relationship_model_name,
                            obj=self,
                            id='E027',
                            id='fields.E335',
                        )
                    )

                if seen_from == 0 or seen_to == 0:
                    errors.append(
                        checks.Error(
                            ('The model is used as an intermediary model by '
                             '%s, but it misses a foreign key to %s or %s.') % (
                            ("The model is used as an intermediate model by "
                             "'%s', but it does not have a foreign key to '%s' or '%s'.") % (
                                self, from_model_name, to_model_name
                            ),
                            hint=None,
                            obj=self.rel.through,
                            id='E028',
                            id='fields.E336',
                        )
                    )
        return errors
+11 −13

File changed.

Preview size limit exceeded, changes collapsed.

Loading