Skip to content

Commit e5767ed

Browse files
Villiers Straussatodorov
Villiers Strauss
authored andcommitted
add support for django.contrib.postgres.fields and also UUIDField
NOTE: merged with modifications: - resolved conflicts - updated where test files are on disk Original PR: pylint-dev#84
1 parent 4241d9d commit e5767ed

8 files changed

+138
-2
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ env:
88
- DJANGO="2.0,<3.0"
99

1010
install:
11-
- pip install coverage coveralls djangorestframework
11+
- pip install coverage coveralls djangorestframework psycopg2
1212
- pip install "Django>=$DJANGO"
1313
- pip install git+https://github.com/landscapeio/pylint-plugin-utils.git@master
1414
script:

pylint_django/transforms/fields.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,13 @@
99
_INT_FIELDS = ('IntegerField', 'SmallIntegerField', 'BigIntegerField',
1010
'PositiveIntegerField', 'PositiveSmallIntegerField')
1111
_BOOL_FIELDS = ('BooleanField', 'NullBooleanField')
12+
_RANGE_FIELDS = ('RangeField', 'IntegerRangeField', 'BigIntegerRangeField',
13+
'FloatRangeField', 'DateTimeRangeField', 'DateRangeField')
1214

1315

1416
def is_model_field(cls):
15-
return cls.qname().startswith('django.db.models.fields')
17+
return cls.qname().startswith('django.db.models.fields') or \
18+
cls.qname().startswith('django.contrib.postgres.fields')
1619

1720

1821
def is_form_field(cls):
@@ -47,10 +50,18 @@ def apply_type_shim(cls, context=None): # noqa
4750
base_nodes = MANAGER.ast_from_module_name('datetime').lookup('date')
4851
elif cls.name == 'DurationField':
4952
base_nodes = MANAGER.ast_from_module_name('datetime').lookup('timedelta')
53+
elif cls.name == 'UUIDField':
54+
base_nodes = MANAGER.ast_from_module_name('uuid').lookup('UUID')
5055
elif cls.name == 'ManyToManyField':
5156
base_nodes = MANAGER.ast_from_module_name('django.db.models.query').lookup('QuerySet')
5257
elif cls.name in ('ImageField', 'FileField'):
5358
base_nodes = MANAGER.ast_from_module_name('django.core.files.base').lookup('File')
59+
elif cls.name == 'ArrayField':
60+
base_nodes = scoped_nodes.builtin_lookup('list')
61+
elif cls.name in ('HStoreField', 'JSONField'):
62+
base_nodes = scoped_nodes.builtin_lookup('dict')
63+
elif cls.name in _RANGE_FIELDS:
64+
base_nodes = MANAGER.ast_from_module_name('psycopg2._range').lookup('Range')
5465
else:
5566
return iter([cls])
5667

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
from django.contrib.postgres import fields as django_fields
2+
from psycopg2 import extras
3+
4+
5+
# --------
6+
# lists
7+
8+
class ArrayField(list, django_fields.ArrayField):
9+
pass
10+
11+
12+
# --------
13+
# dicts
14+
15+
class HStoreField(dict, django_fields.HStoreField):
16+
pass
17+
18+
19+
class JSONField(dict, django_fields.JSONField):
20+
pass
21+
22+
23+
# --------
24+
# ranges
25+
26+
class RangeField(extras.Range, django_fields.RangeField):
27+
pass
28+
29+
30+
class IntegerRangeField(extras.NumericRange, django_fields.IntegerRangeField):
31+
pass
32+
33+
34+
class BigIntegerRangeField(extras.NumericRange, django_fields.BigIntegerRangeField):
35+
pass
36+
37+
38+
class FloatRangeField(extras.NumericRange, django_fields.FloatRangeField):
39+
pass
40+
41+
42+
class DateTimeRangeField(extras.DateTimeTZRange, django_fields.DateRangeField):
43+
pass
44+
45+
46+
class DateRangeField(extras.DateRange, django_fields.DateRangeField):
47+
pass

pylint_django/transforms/transforms/django_db_models_fields.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from django.db.models import fields as django_fields
22
import datetime
33
from decimal import Decimal
4+
from uuid import UUID
45

56

67
# --------
@@ -125,3 +126,7 @@ class GenericIPAddressField(str, django_fields.GenericIPAddressField):
125126

126127
class IPAddressField(str, django_fields.IPAddressField):
127128
pass
129+
130+
131+
class UUIDField(UUID, django_fields.UUIDField):
132+
pass

test/__init__.py

Whitespace-only changes.
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
"""
2+
Checks that Pylint does not complain Postgres model fields.
3+
"""
4+
# pylint: disable=C0111,W5101
5+
from __future__ import print_function
6+
7+
from django.contrib.postgres import fields
8+
from django.db import models
9+
10+
11+
class PostgresFieldsModel(models.Model):
12+
arrayfield = fields.ArrayField(models.CharField())
13+
hstorefield = fields.HStoreField()
14+
jsonfield = fields.JSONField()
15+
rangefield = fields.RangeField()
16+
integerrangefield = fields.IntegerRangeField()
17+
bigintegerrangefield = fields.BigIntegerRangeField()
18+
floatrangefield = fields.FloatRangeField()
19+
datetimerangefield = fields.DateTimeRangeField()
20+
daterangefield = fields.DateRangeField()
21+
22+
def arrayfield_tests(self):
23+
sorted_array = self.arrayfield.sort()
24+
print(sorted_array)
25+
26+
def dictfield_tests(self):
27+
print(self.hstorefield.keys())
28+
print(self.hstorefield.values())
29+
print(self.hstorefield.update({'foo': 'bar'}))
30+
31+
print(self.jsonfield.keys())
32+
print(self.jsonfield.values())
33+
print(self.jsonfield.update({'foo': 'bar'}))
34+
35+
def rangefield_tests(self):
36+
print(self.rangefield.lower)
37+
print(self.rangefield.upper)
38+
39+
print(self.integerrangefield.lower)
40+
print(self.integerrangefield.upper)
41+
42+
print(self.bigintegerrangefield.lower)
43+
print(self.bigintegerrangefield.upper)
44+
45+
print(self.floatrangefield.lower)
46+
print(self.floatrangefield.upper)
47+
48+
print(self.datetimerangefield.lower)
49+
print(self.datetimerangefield.upper)
50+
51+
print(self.daterangefield.lower)
52+
print(self.daterangefield.upper)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[testoptions]
2+
requires = psycopg2

test/input/func_noerror_uuid_field.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
"""
2+
Checks that Pylint does not complain about UUID fields.
3+
"""
4+
# pylint: disable=C0111,W5101
5+
from __future__ import print_function
6+
from django.db import models
7+
8+
9+
class LotsOfFieldsModel(models.Model):
10+
uuidfield = models.UUIDField()
11+
12+
def uuidfield_tests(self):
13+
print(self.uuidfield.bytes)
14+
print(self.uuidfield.bytes_le)
15+
print(self.uuidfield.fields[2])
16+
print(self.uuidfield.hex)
17+
# print(self.uuidfield.int) # Don't know how to properly check this one
18+
print(self.uuidfield.variant)
19+
print(self.uuidfield.version)

0 commit comments

Comments
 (0)