Skip to content

Commit

Permalink
add support for django.contrib.postgres.fields and also UUIDField
Browse files Browse the repository at this point in the history
NOTE: merged with modifications:
	- resolved conflicts
	- updated where test files are on disk

Original PR: pylint-dev#84
  • Loading branch information
Villiers Strauss authored and atodorov committed Jan 18, 2018
1 parent 4241d9d commit e5767ed
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 2 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ env:
- DJANGO="2.0,<3.0"

install:
- pip install coverage coveralls djangorestframework
- pip install coverage coveralls djangorestframework psycopg2
- pip install "Django>=$DJANGO"
- pip install git+https://github.com/landscapeio/pylint-plugin-utils.git@master
script:
Expand Down
13 changes: 12 additions & 1 deletion pylint_django/transforms/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@
_INT_FIELDS = ('IntegerField', 'SmallIntegerField', 'BigIntegerField',
'PositiveIntegerField', 'PositiveSmallIntegerField')
_BOOL_FIELDS = ('BooleanField', 'NullBooleanField')
_RANGE_FIELDS = ('RangeField', 'IntegerRangeField', 'BigIntegerRangeField',
'FloatRangeField', 'DateTimeRangeField', 'DateRangeField')


def is_model_field(cls):
return cls.qname().startswith('django.db.models.fields')
return cls.qname().startswith('django.db.models.fields') or \
cls.qname().startswith('django.contrib.postgres.fields')


def is_form_field(cls):
Expand Down Expand Up @@ -47,10 +50,18 @@ def apply_type_shim(cls, context=None): # noqa
base_nodes = MANAGER.ast_from_module_name('datetime').lookup('date')
elif cls.name == 'DurationField':
base_nodes = MANAGER.ast_from_module_name('datetime').lookup('timedelta')
elif cls.name == 'UUIDField':
base_nodes = MANAGER.ast_from_module_name('uuid').lookup('UUID')
elif cls.name == 'ManyToManyField':
base_nodes = MANAGER.ast_from_module_name('django.db.models.query').lookup('QuerySet')
elif cls.name in ('ImageField', 'FileField'):
base_nodes = MANAGER.ast_from_module_name('django.core.files.base').lookup('File')
elif cls.name == 'ArrayField':
base_nodes = scoped_nodes.builtin_lookup('list')
elif cls.name in ('HStoreField', 'JSONField'):
base_nodes = scoped_nodes.builtin_lookup('dict')
elif cls.name in _RANGE_FIELDS:
base_nodes = MANAGER.ast_from_module_name('psycopg2._range').lookup('Range')
else:
return iter([cls])

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from django.contrib.postgres import fields as django_fields
from psycopg2 import extras


# --------
# lists

class ArrayField(list, django_fields.ArrayField):
pass


# --------
# dicts

class HStoreField(dict, django_fields.HStoreField):
pass


class JSONField(dict, django_fields.JSONField):
pass


# --------
# ranges

class RangeField(extras.Range, django_fields.RangeField):
pass


class IntegerRangeField(extras.NumericRange, django_fields.IntegerRangeField):
pass


class BigIntegerRangeField(extras.NumericRange, django_fields.BigIntegerRangeField):
pass


class FloatRangeField(extras.NumericRange, django_fields.FloatRangeField):
pass


class DateTimeRangeField(extras.DateTimeTZRange, django_fields.DateRangeField):
pass


class DateRangeField(extras.DateRange, django_fields.DateRangeField):
pass
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.db.models import fields as django_fields
import datetime
from decimal import Decimal
from uuid import UUID


# --------
Expand Down Expand Up @@ -125,3 +126,7 @@ class GenericIPAddressField(str, django_fields.GenericIPAddressField):

class IPAddressField(str, django_fields.IPAddressField):
pass


class UUIDField(UUID, django_fields.UUIDField):
pass
Empty file added test/__init__.py
Empty file.
52 changes: 52 additions & 0 deletions test/input/external_psycopg2_noerror_postgres_fields.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"""
Checks that Pylint does not complain Postgres model fields.
"""
# pylint: disable=C0111,W5101
from __future__ import print_function

from django.contrib.postgres import fields
from django.db import models


class PostgresFieldsModel(models.Model):
arrayfield = fields.ArrayField(models.CharField())
hstorefield = fields.HStoreField()
jsonfield = fields.JSONField()
rangefield = fields.RangeField()
integerrangefield = fields.IntegerRangeField()
bigintegerrangefield = fields.BigIntegerRangeField()
floatrangefield = fields.FloatRangeField()
datetimerangefield = fields.DateTimeRangeField()
daterangefield = fields.DateRangeField()

def arrayfield_tests(self):
sorted_array = self.arrayfield.sort()
print(sorted_array)

def dictfield_tests(self):
print(self.hstorefield.keys())
print(self.hstorefield.values())
print(self.hstorefield.update({'foo': 'bar'}))

print(self.jsonfield.keys())
print(self.jsonfield.values())
print(self.jsonfield.update({'foo': 'bar'}))

def rangefield_tests(self):
print(self.rangefield.lower)
print(self.rangefield.upper)

print(self.integerrangefield.lower)
print(self.integerrangefield.upper)

print(self.bigintegerrangefield.lower)
print(self.bigintegerrangefield.upper)

print(self.floatrangefield.lower)
print(self.floatrangefield.upper)

print(self.datetimerangefield.lower)
print(self.datetimerangefield.upper)

print(self.daterangefield.lower)
print(self.daterangefield.upper)
2 changes: 2 additions & 0 deletions test/input/external_psycopg2_noerror_postgres_fields.rc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[testoptions]
requires = psycopg2
19 changes: 19 additions & 0 deletions test/input/func_noerror_uuid_field.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"""
Checks that Pylint does not complain about UUID fields.
"""
# pylint: disable=C0111,W5101
from __future__ import print_function
from django.db import models


class LotsOfFieldsModel(models.Model):
uuidfield = models.UUIDField()

def uuidfield_tests(self):
print(self.uuidfield.bytes)
print(self.uuidfield.bytes_le)
print(self.uuidfield.fields[2])
print(self.uuidfield.hex)
# print(self.uuidfield.int) # Don't know how to properly check this one
print(self.uuidfield.variant)
print(self.uuidfield.version)

0 comments on commit e5767ed

Please sign in to comment.