[Python-modules-commits] [python-django-netfields] 02/06: Import python-django-netfields_0.7.2.orig.tar.gz
Michael Fladischer
fladi at moszumanska.debian.org
Mon Jun 19 13:29:59 UTC 2017
This is an automated email from the git hooks/post-receive script.
fladi pushed a commit to branch master
in repository python-django-netfields.
commit 6071f678c0745c7c14818eef8d7a43ee13949d8e
Author: Michael Fladischer <FladischerMichael at fladi.at>
Date: Mon Jun 19 15:04:20 2017 +0200
Import python-django-netfields_0.7.2.orig.tar.gz
---
CHANGELOG | 14 +++
PKG-INFO | 150 +++++++++++++++++++++++++
django_netfields.egg-info/PKG-INFO | 150 +++++++++++++++++++++++++
django_netfields.egg-info/SOURCES.txt | 31 +++++
django_netfields.egg-info/dependency_links.txt | 1 +
django_netfields.egg-info/not-zip-safe | 1 +
django_netfields.egg-info/requires.txt | 3 +
django_netfields.egg-info/top_level.txt | 2 +
netfields/apps.py | 2 +
netfields/fields.py | 25 ++++-
netfields/forms.py | 19 +++-
netfields/lookups.py | 26 +++--
netfields/managers.py | 8 +-
netfields/psycopg2_types.py | 2 +-
netfields/rest_framework.py | 4 +-
setup.cfg | 5 +
setup.py | 2 +-
test/models.py | 12 +-
test/tests/test_form_fields.py | 43 ++++++-
test/tests/test_rest_framework_fields.py | 27 +++--
test/tests/test_sql_fields.py | 42 ++++++-
tox.ini | 114 -------------------
22 files changed, 534 insertions(+), 149 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index 534c6c3..ae4d6a4 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,17 @@
+- 0.7.2
+ * Fix issue where prefetch_related returns empty querysets (Jay McEntire)
+ * Improve validation error messages to include the underlying error (Diego
+ Gaustein)
+ * Strip extraneous whitespace around form inputs
+
+- 0.7.1
+ * Fix issue with recent psycopg2 releases (Jonas Genannt)
+ * Add a lookup for exact CIDR prefix length (Joey Wilhelm)
+ * Use proper unicode type when casting ipaddress/ipnetwork objects for
+ queries
+ * Support array aggregation with netfields (orf)
+ * compatibility with template based widgets (Leo Honkanen)
+
- 0.7
* Added support for Django 1.10
* Added __overlaps lookup (Emre Hasegeli)
diff --git a/PKG-INFO b/PKG-INFO
new file mode 100644
index 0000000..7c2d33c
--- /dev/null
+++ b/PKG-INFO
@@ -0,0 +1,150 @@
+Metadata-Version: 1.1
+Name: django-netfields
+Version: 0.7.2
+Summary: Django PostgreSQL netfields implementation
+Home-page: https://github.com/jimfunk/django-postgresql-netfields
+Author: James Oakley
+Author-email: jfunk at funktronics.ca
+License: BSD
+Description: Django PostgreSQL Netfields
+ ===========================
+
+ .. image:: https://secure.travis-ci.org/jimfunk/django-postgresql-netfields.png
+
+ This project is an attempt at making proper PostgreSQL net related fields for
+ Django. In Django pre 1.4 the built in ``IPAddressField`` does not support IPv6
+ and uses an inefficient ``HOST()`` cast in all lookups. As of 1.4 you can use
+ ``GenericIPAddressField`` for IPv6, but the casting problem remains.
+
+ In addition to the basic ``IPAddressField`` replacement a ``CIDR`` and
+ a ``MACADDR`` field have been added. This library also provides a manager that
+ allows for advanced IP based lookup directly in the ORM.
+
+ In Python, the values of the IP address fields are represented as types from
+ the ipaddress_ module. In Python 2.x, a backport_ is used. The MAC address
+ field is represented as an EUI type from the netaddr_ module.
+
+ .. _ipaddress: https://docs.python.org/3/library/ipaddress.html
+ .. _backport: https://pypi.python.org/pypi/ipaddress/
+ .. _netaddr: http://pythonhosted.org/netaddr/
+
+ Dependencies
+ ------------
+
+ Current version of code is targeting Django >= 1.8 support, as this relies
+ heavily on ORM internals and supporting multiple versions is especially tricky.
+
+ Getting started
+ ---------------
+
+ Make sure ``netfields`` is in your ``PYTHONPATH`` and in ``INSTALLED_APPS``.
+
+ ``InetAddressField`` will store values in PostgreSQL as type ``INET``. In
+ Python, the value will be represented as an ``ipaddress.ip_interface`` object
+ representing an IP address and netmask/prefix length pair unless the
+ ``store_prefix_length`` argument is set to `False``, in which case the value
+ will be represented as an ``ipaddress.ip_address`` object.
+
+ from netfields import InetAddressField, NetManager
+
+ class Example(models.Model):
+ inet = InetAddressField()
+ # ...
+
+ objects = NetManager()
+
+ ``CidrAddressField`` will store values in PostgreSQL as type ``CIDR``. In
+ Python, the value will be represented as an ``ipaddress.ip_network`` object.
+
+ from netfields import CidrAddressField, NetManager
+
+ class Example(models.Model):
+ inet = CidrAddressField()
+ # ...
+
+ objects = NetManager()
+
+ ``MACAddressField`` will store values in PostgreSQL as type ``MACADDR``. In
+ Python, the value will be represented as a ``netaddr.EUI`` object. Note that
+ the default text representation of EUI objects is not the same as that of the
+ ``netaddr`` module. It is represented in a format that is more commonly used
+ in network utilities and by network administrators (``00:11:22:aa:bb:cc``).
+
+ from netfields import MACAddressField, NetManager
+
+ class Example(models.Model):
+ inet = MACAddressField()
+ # ...
+
+ For ``InetAddressField`` and ``CidrAddressField``, ``NetManager`` is required
+ for the extra lookups to be available. Lookups for ``INET`` and ``CIDR``
+ database types will be handled differently than when running vanilla Django.
+ All lookups are case-insensitive and text based lookups are avoided whenever
+ possible. In addition to Django's default lookup types the following have been
+ added:
+
+ ``__net_contained``
+ is contained within the given network
+
+ ``__net_contained_or_equal``
+ is contained within or equal to the given network
+
+ ``__net_contains``
+ contains the given address
+
+ ``__net_contains_or_equals``
+ contains or is equal to the given address/network
+
+ ``__net_overlaps``
+ contains or contained by the given address
+
+ ``__family``
+ matches the given address family
+
+ These correspond with the operators and functions from
+ http://www.postgresql.org/docs/9.4/interactive/functions-net.html
+
+ ``CidrAddressField`` includes two extra lookups:
+
+ ``__max_prefixlen``
+ Maximum value (inclusive) for ``CIDR`` prefix, does not distinguish between IPv4 and IPv6
+
+ ``__min_prefixlen``
+ Minimum value (inclusive) for ``CIDR`` prefix, does not distinguish between IPv4 and IPv6
+
+ Related Django bugs
+ -------------------
+
+ * 11442_ - Postgresql backend casts inet types to text, breaks IP operations and IPv6 lookups.
+ * 811_ - IPv6 address field support.
+
+ https://docs.djangoproject.com/en/dev/releases/1.4/#extended-ipv6-support is also relevant
+
+ .. _11442: http://code.djangoproject.com/ticket/11442
+ .. _811: http://code.djangoproject.com/ticket/811
+
+
+ Similar projects
+ ----------------
+
+ https://bitbucket.org/onelson/django-ipyfield tries to solve some of the same
+ issues as this library. However, instead of supporting just postgres via the proper
+ fields types the ipyfield currently uses a ``VARCHAR(39)`` as a fake unsigned 64 bit
+ number in its implementation.
+
+ History
+ -------
+
+ Main repo was originaly kept https://github.com/adamcik/django-postgresql-netfields
+ Late April 2013 the project was moved to https://github.com/jimfunk/django-postgresql-netfields
+ to pass the torch on to someone who actually uses this code actively :-)
+
+Platform: UNKNOWN
+Classifier: Development Status :: 4 - Beta
+Classifier: Environment :: Web Environment
+Classifier: Framework :: Django
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: BSD License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python
+Classifier: Topic :: Utilities
diff --git a/django_netfields.egg-info/PKG-INFO b/django_netfields.egg-info/PKG-INFO
new file mode 100644
index 0000000..7c2d33c
--- /dev/null
+++ b/django_netfields.egg-info/PKG-INFO
@@ -0,0 +1,150 @@
+Metadata-Version: 1.1
+Name: django-netfields
+Version: 0.7.2
+Summary: Django PostgreSQL netfields implementation
+Home-page: https://github.com/jimfunk/django-postgresql-netfields
+Author: James Oakley
+Author-email: jfunk at funktronics.ca
+License: BSD
+Description: Django PostgreSQL Netfields
+ ===========================
+
+ .. image:: https://secure.travis-ci.org/jimfunk/django-postgresql-netfields.png
+
+ This project is an attempt at making proper PostgreSQL net related fields for
+ Django. In Django pre 1.4 the built in ``IPAddressField`` does not support IPv6
+ and uses an inefficient ``HOST()`` cast in all lookups. As of 1.4 you can use
+ ``GenericIPAddressField`` for IPv6, but the casting problem remains.
+
+ In addition to the basic ``IPAddressField`` replacement a ``CIDR`` and
+ a ``MACADDR`` field have been added. This library also provides a manager that
+ allows for advanced IP based lookup directly in the ORM.
+
+ In Python, the values of the IP address fields are represented as types from
+ the ipaddress_ module. In Python 2.x, a backport_ is used. The MAC address
+ field is represented as an EUI type from the netaddr_ module.
+
+ .. _ipaddress: https://docs.python.org/3/library/ipaddress.html
+ .. _backport: https://pypi.python.org/pypi/ipaddress/
+ .. _netaddr: http://pythonhosted.org/netaddr/
+
+ Dependencies
+ ------------
+
+ Current version of code is targeting Django >= 1.8 support, as this relies
+ heavily on ORM internals and supporting multiple versions is especially tricky.
+
+ Getting started
+ ---------------
+
+ Make sure ``netfields`` is in your ``PYTHONPATH`` and in ``INSTALLED_APPS``.
+
+ ``InetAddressField`` will store values in PostgreSQL as type ``INET``. In
+ Python, the value will be represented as an ``ipaddress.ip_interface`` object
+ representing an IP address and netmask/prefix length pair unless the
+ ``store_prefix_length`` argument is set to `False``, in which case the value
+ will be represented as an ``ipaddress.ip_address`` object.
+
+ from netfields import InetAddressField, NetManager
+
+ class Example(models.Model):
+ inet = InetAddressField()
+ # ...
+
+ objects = NetManager()
+
+ ``CidrAddressField`` will store values in PostgreSQL as type ``CIDR``. In
+ Python, the value will be represented as an ``ipaddress.ip_network`` object.
+
+ from netfields import CidrAddressField, NetManager
+
+ class Example(models.Model):
+ inet = CidrAddressField()
+ # ...
+
+ objects = NetManager()
+
+ ``MACAddressField`` will store values in PostgreSQL as type ``MACADDR``. In
+ Python, the value will be represented as a ``netaddr.EUI`` object. Note that
+ the default text representation of EUI objects is not the same as that of the
+ ``netaddr`` module. It is represented in a format that is more commonly used
+ in network utilities and by network administrators (``00:11:22:aa:bb:cc``).
+
+ from netfields import MACAddressField, NetManager
+
+ class Example(models.Model):
+ inet = MACAddressField()
+ # ...
+
+ For ``InetAddressField`` and ``CidrAddressField``, ``NetManager`` is required
+ for the extra lookups to be available. Lookups for ``INET`` and ``CIDR``
+ database types will be handled differently than when running vanilla Django.
+ All lookups are case-insensitive and text based lookups are avoided whenever
+ possible. In addition to Django's default lookup types the following have been
+ added:
+
+ ``__net_contained``
+ is contained within the given network
+
+ ``__net_contained_or_equal``
+ is contained within or equal to the given network
+
+ ``__net_contains``
+ contains the given address
+
+ ``__net_contains_or_equals``
+ contains or is equal to the given address/network
+
+ ``__net_overlaps``
+ contains or contained by the given address
+
+ ``__family``
+ matches the given address family
+
+ These correspond with the operators and functions from
+ http://www.postgresql.org/docs/9.4/interactive/functions-net.html
+
+ ``CidrAddressField`` includes two extra lookups:
+
+ ``__max_prefixlen``
+ Maximum value (inclusive) for ``CIDR`` prefix, does not distinguish between IPv4 and IPv6
+
+ ``__min_prefixlen``
+ Minimum value (inclusive) for ``CIDR`` prefix, does not distinguish between IPv4 and IPv6
+
+ Related Django bugs
+ -------------------
+
+ * 11442_ - Postgresql backend casts inet types to text, breaks IP operations and IPv6 lookups.
+ * 811_ - IPv6 address field support.
+
+ https://docs.djangoproject.com/en/dev/releases/1.4/#extended-ipv6-support is also relevant
+
+ .. _11442: http://code.djangoproject.com/ticket/11442
+ .. _811: http://code.djangoproject.com/ticket/811
+
+
+ Similar projects
+ ----------------
+
+ https://bitbucket.org/onelson/django-ipyfield tries to solve some of the same
+ issues as this library. However, instead of supporting just postgres via the proper
+ fields types the ipyfield currently uses a ``VARCHAR(39)`` as a fake unsigned 64 bit
+ number in its implementation.
+
+ History
+ -------
+
+ Main repo was originaly kept https://github.com/adamcik/django-postgresql-netfields
+ Late April 2013 the project was moved to https://github.com/jimfunk/django-postgresql-netfields
+ to pass the torch on to someone who actually uses this code actively :-)
+
+Platform: UNKNOWN
+Classifier: Development Status :: 4 - Beta
+Classifier: Environment :: Web Environment
+Classifier: Framework :: Django
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: BSD License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python
+Classifier: Topic :: Utilities
diff --git a/django_netfields.egg-info/SOURCES.txt b/django_netfields.egg-info/SOURCES.txt
new file mode 100644
index 0000000..10338b8
--- /dev/null
+++ b/django_netfields.egg-info/SOURCES.txt
@@ -0,0 +1,31 @@
+AUTHORS
+CHANGELOG
+LICENSE
+MANIFEST.in
+README.rst
+manage.py
+requirements.txt
+setup.py
+testsettings.py
+django_netfields.egg-info/PKG-INFO
+django_netfields.egg-info/SOURCES.txt
+django_netfields.egg-info/dependency_links.txt
+django_netfields.egg-info/not-zip-safe
+django_netfields.egg-info/requires.txt
+django_netfields.egg-info/top_level.txt
+netfields/__init__.py
+netfields/apps.py
+netfields/fields.py
+netfields/forms.py
+netfields/lookups.py
+netfields/mac.py
+netfields/managers.py
+netfields/models.py
+netfields/psycopg2_types.py
+netfields/rest_framework.py
+test/__init__.py
+test/models.py
+test/tests/__init__.py
+test/tests/test_form_fields.py
+test/tests/test_rest_framework_fields.py
+test/tests/test_sql_fields.py
\ No newline at end of file
diff --git a/django_netfields.egg-info/dependency_links.txt b/django_netfields.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/django_netfields.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/django_netfields.egg-info/not-zip-safe b/django_netfields.egg-info/not-zip-safe
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/django_netfields.egg-info/not-zip-safe
@@ -0,0 +1 @@
+
diff --git a/django_netfields.egg-info/requires.txt b/django_netfields.egg-info/requires.txt
new file mode 100644
index 0000000..0585d81
--- /dev/null
+++ b/django_netfields.egg-info/requires.txt
@@ -0,0 +1,3 @@
+netaddr
+django>=1.8
+ipaddress
diff --git a/django_netfields.egg-info/top_level.txt b/django_netfields.egg-info/top_level.txt
new file mode 100644
index 0000000..1a72369
--- /dev/null
+++ b/django_netfields.egg-info/top_level.txt
@@ -0,0 +1,2 @@
+netfields
+test
diff --git a/netfields/apps.py b/netfields/apps.py
index 286abe5..ab2729c 100644
--- a/netfields/apps.py
+++ b/netfields/apps.py
@@ -18,6 +18,7 @@ from netfields.lookups import (
NetContains,
NetContainsOrEquals,
NetOverlaps,
+ Prefixlen,
Regex,
StartsWith,
)
@@ -51,6 +52,7 @@ class NetfieldsConfig(AppConfig):
CidrAddressField.register_lookup(Family)
CidrAddressField.register_lookup(MaxPrefixlen)
CidrAddressField.register_lookup(MinPrefixlen)
+ CidrAddressField.register_lookup(Prefixlen)
InetAddressField.register_lookup(EndsWith)
InetAddressField.register_lookup(IEndsWith)
diff --git a/netfields/fields.py b/netfields/fields.py
index 4312503..2f908c9 100644
--- a/netfields/fields.py
+++ b/netfields/fields.py
@@ -19,6 +19,9 @@ class _NetAddressField(models.Field):
super(_NetAddressField, self).__init__(*args, **kwargs)
def from_db_value(self, value, expression, connection, context):
+ if isinstance(value, list):
+ # Aggregation detected, return a list of values
+ return [self.to_python(v) for v in value if v is not None]
return self.to_python(value)
def to_python(self, value):
@@ -53,8 +56,15 @@ class _NetAddressField(models.Field):
return str(self.to_python(value))
def get_db_prep_value(self, value, connection, prepared=False):
- if not value:
- return None
+ # Django <= 1.8, ArrayField does not pass model to the base_field so we have to check for existance
+ model = getattr(self, 'model', None)
+ if model is None or model._meta.get_field(self.name).get_internal_type() == 'ArrayField':
+ is_array_field = True
+ else:
+ is_array_field = False
+
+ if prepared is False and is_array_field is False:
+ return self.get_prep_value(value)
return Inet(self.get_prep_value(value))
@@ -150,8 +160,15 @@ class MACAddressField(models.Field):
return text_type(self.to_python(value))
def get_db_prep_value(self, value, connection, prepared=False):
- if not value:
- return None
+ # Django <= 1.8, ArrayField does not pass model to the base_field so we have to check for existance
+ model = getattr(self, 'model', None)
+ if model is None or model._meta.get_field(self.name).get_internal_type() == 'ArrayField':
+ is_array_field = True
+ else:
+ is_array_field = False
+
+ if prepared is False and is_array_field is False:
+ return self.get_prep_value(value)
return Macaddr(self.get_prep_value(value))
diff --git a/netfields/forms.py b/netfields/forms.py
index d19eeb9..b2510c3 100644
--- a/netfields/forms.py
+++ b/netfields/forms.py
@@ -5,6 +5,7 @@ from django import forms
import django
from django.forms.utils import flatatt
from django.utils.safestring import mark_safe
+from django.utils.six import text_type
from django.core.exceptions import ValidationError
from netfields.mac import mac_unix_common
@@ -17,7 +18,14 @@ class NetInput(forms.Widget):
# Default forms.Widget compares value != '' which breaks IP...
if value is None:
value = ''
- final_attrs = self.build_attrs(attrs, type=self.input_type, name=name)
+ if attrs is None:
+ attrs = {}
+ base_attrs = {
+ "type": self.input_type,
+ "name": name
+ }
+ base_attrs.update(attrs)
+ final_attrs = self.build_attrs(base_attrs)
if value:
final_attrs['value'] = value
return mark_safe(u'<input%s />' % flatatt(final_attrs))
@@ -39,6 +47,9 @@ class InetAddressFormField(forms.Field):
if isinstance(value, _IPAddressBase):
return value
+ if isinstance(value, text_type):
+ value = value.strip()
+
try:
return ip_interface(value)
except ValueError as e:
@@ -61,6 +72,9 @@ class CidrAddressFormField(forms.Field):
if isinstance(value, _BaseNetwork):
network = value
+ if isinstance(value, text_type):
+ value = value.strip()
+
try:
network = ip_network(value)
except ValueError as e:
@@ -84,6 +98,9 @@ class MACAddressFormField(forms.Field):
if isinstance(value, EUI):
return value
+ if isinstance(value, text_type):
+ value = value.strip()
+
try:
return EUI(value, dialect=mac_unix_common)
except (AddrFormatError, TypeError):
diff --git a/netfields/lookups.py b/netfields/lookups.py
index ea33afd..ebbcd62 100644
--- a/netfields/lookups.py
+++ b/netfields/lookups.py
@@ -135,6 +135,15 @@ class Family(Transform):
class _PrefixlenMixin(object):
+ format_string = None
+
+ def as_sql(self, qn, connection):
+ assert self.format_string is not None, "Prefixlen lookups must specify a format_string"
+ lhs, lhs_params = self.process_lhs(qn, connection)
+ rhs, rhs_params = self.process_rhs(qn, connection)
+ params = lhs_params + rhs_params
+ return self.format_string % (lhs, rhs), params
+
def process_lhs(self, qn, connection, lhs=None):
lhs = lhs or self.lhs
lhs_string, lhs_params = qn.compile(lhs)
@@ -147,19 +156,14 @@ class _PrefixlenMixin(object):
class MaxPrefixlen(_PrefixlenMixin, Lookup):
lookup_name = 'max_prefixlen'
-
- def as_sql(self, qn, connection):
- lhs, lhs_params = self.process_lhs(qn, connection)
- rhs, rhs_params = self.process_rhs(qn, connection)
- params = lhs_params + rhs_params
- return '%s <= %s' % (lhs, rhs), params
+ format_string = '%s <= %s'
class MinPrefixlen(_PrefixlenMixin, Lookup):
lookup_name = 'min_prefixlen'
+ format_string = '%s >= %s'
- def as_sql(self, qn, connection):
- lhs, lhs_params = self.process_lhs(qn, connection)
- rhs, rhs_params = self.process_rhs(qn, connection)
- params = lhs_params + rhs_params
- return '%s >= %s' % (lhs, rhs), params
+
+class Prefixlen(_PrefixlenMixin, Lookup):
+ lookup_name = 'prefixlen'
+ format_string = '%s = %s'
diff --git a/netfields/managers.py b/netfields/managers.py
index 6be708d..657e9e2 100644
--- a/netfields/managers.py
+++ b/netfields/managers.py
@@ -7,6 +7,12 @@ from django.db.backends.postgresql_psycopg2.base import DatabaseWrapper
from django.db.models import sql, query
from django.db.models.fields import DateTimeField
+try:
+ str_type = unicode
+except NameError:
+ str_type = str
+
+
NET_OPERATORS = DatabaseWrapper.operators.copy()
for operator in ['contains', 'startswith', 'endswith']:
@@ -79,5 +85,5 @@ class NetManager(models.Manager):
if isinstance(val, _BaseNetwork):
# Django will attempt to consume the _BaseNetwork iterator, which
# will convert it to a list of every address in the network
- kwargs[key] = str(val)
+ kwargs[key] = str_type(val)
return super(NetManager, self).filter(*args, **kwargs)
diff --git a/netfields/psycopg2_types.py b/netfields/psycopg2_types.py
index e5bdf90..b4be11c 100644
--- a/netfields/psycopg2_types.py
+++ b/netfields/psycopg2_types.py
@@ -10,7 +10,7 @@ class Macaddr(Inet):
obj = psycopg2.extensions.adapt(self.addr)
if hasattr(obj, 'prepare'):
obj.prepare(self._conn)
- return obj.getquoted() + psycopg2.extensions.b("::macaddr")
+ return obj.getquoted() + b"::macaddr"
# Register array types for CIDR and MACADDR (Django already registers INET)
diff --git a/netfields/rest_framework.py b/netfields/rest_framework.py
index 6223c6b..d5aa0c3 100644
--- a/netfields/rest_framework.py
+++ b/netfields/rest_framework.py
@@ -16,8 +16,8 @@ class NetfieldsField(serializers.CharField):
"""
try:
self.netfields_type(value).to_python(value)
- except DjangoValidationError:
- raise serializers.ValidationError("Invalid {} address.".format(self.address_type))
+ except DjangoValidationError as e:
+ raise serializers.ValidationError("Invalid {} address: {}".format(self.address_type, e.message))
class InetAddressField(NetfieldsField):
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..861a9f5
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,5 @@
+[egg_info]
+tag_build =
+tag_date = 0
+tag_svn_revision = 0
+
diff --git a/setup.py b/setup.py
index 8912b7a..70bc3b0 100755
--- a/setup.py
+++ b/setup.py
@@ -22,7 +22,7 @@ if sys.version_info.major == 2:
setup(
name='django-netfields',
- version='0.7',
+ version='0.7.2',
license='BSD',
description='Django PostgreSQL netfields implementation',
long_description=get_long_description(),
diff --git a/test/models.py b/test/models.py
index e82d10b..4381e1f 100644
--- a/test/models.py
+++ b/test/models.py
@@ -1,5 +1,5 @@
from django.contrib.postgres.fields import ArrayField
-from django.db.models import Model
+from django.db.models import Model, ForeignKey
from netfields import InetAddressField, CidrAddressField, MACAddressField, \
NetManager
@@ -88,3 +88,13 @@ class MACArrayTestModel(Model):
class Meta:
db_table = 'macarray'
+
+
+class AggregateTestModel(Model):
+ pass
+
+
+class AggregateTestChildModel(Model):
+ parent = ForeignKey('AggregateTestModel', related_name='children')
+ network = CidrAddressField()
+ inet = InetAddressField()
diff --git a/test/tests/test_form_fields.py b/test/tests/test_form_fields.py
index ede8dbe..209de14 100644
--- a/test/tests/test_form_fields.py
+++ b/test/tests/test_form_fields.py
@@ -34,6 +34,11 @@ class TestInetAddressFormField(TestCase):
form = self.form_class({'field': '10.0.0.1.2'})
self.assertFalse(form.is_valid())
+ def test_form_ipv4_strip(self):
+ form = self.form_class({'field': ' 10.0.0.1 '})
+ self.assertTrue(form.is_valid())
+ self.assertEqual(form.cleaned_data['field'], ip_interface('10.0.0.1'))
+
def test_form_ipv4_change(self):
instance = InetTestModel.objects.create(field='10.1.2.3/24')
form = self.form_class({'field': '10.1.2.4/24'}, instance=instance)
@@ -42,7 +47,7 @@ class TestInetAddressFormField(TestCase):
instance = InetTestModel.objects.get(pk=instance.pk)
self.assertEqual(instance.field, ip_interface('10.1.2.4/24'))
- def test_form_ipv6(self):
+ def test_form_ipv6_valid(self):
form = self.form_class({'field': '2001:0:1::2'})
self.assertTrue(form.is_valid())
self.assertEqual(form.cleaned_data['field'], ip_interface('2001:0:1::2'))
@@ -51,6 +56,11 @@ class TestInetAddressFormField(TestCase):
form = self.form_class({'field': '2001:0::1::2'})
self.assertFalse(form.is_valid())
+ def test_form_ipv6_strip(self):
+ form = self.form_class({'field': ' 2001:0:1::2 '})
+ self.assertTrue(form.is_valid())
+ self.assertEqual(form.cleaned_data['field'], ip_interface('2001:0:1::2'))
+
def test_form_ipv6_change(self):
instance = InetTestModel.objects.create(field='2001:0:1::2/64')
form = self.form_class({'field': '2001:0:1::3/64'}, instance=instance)
@@ -79,6 +89,12 @@ class TestNoPrefixInetAddressFormField(TestCase):
form = self.form_class({'field': '10.0.0.1.2'})
self.assertFalse(form.is_valid())
+ def test_form_ipv4_strip(self):
+ form = self.form_class({'field': ' 10.0.0.1 '})
+ self.assertTrue(form.is_valid())
+ # Form always passes ip_interface. Model field will return the requested type
+ self.assertEqual(form.cleaned_data['field'], ip_interface('10.0.0.1'))
+
def test_form_ipv4_change(self):
instance = NoPrefixInetTestModel.objects.create(field='10.1.2.3/24')
form = self.form_class({'field': '10.1.2.4/24'}, instance=instance)
@@ -87,7 +103,7 @@ class TestNoPrefixInetAddressFormField(TestCase):
instance = NoPrefixInetTestModel.objects.get(pk=instance.pk)
self.assertEqual(instance.field, ip_address('10.1.2.4'))
- def test_form_ipv6(self):
+ def test_form_ipv6_valid(self):
form = self.form_class({'field': '2001:0:1::2'})
self.assertTrue(form.is_valid())
# Form always passes ip_interface. Model field will return the requested type
@@ -97,6 +113,12 @@ class TestNoPrefixInetAddressFormField(TestCase):
form = self.form_class({'field': '2001:0::1::2'})
self.assertFalse(form.is_valid())
+ def test_form_ipv6_strip(self):
+ form = self.form_class({'field': ' 2001:0:1::2 '})
+ self.assertTrue(form.is_valid())
+ # Form always passes ip_interface. Model field will return the requested type
+ self.assertEqual(form.cleaned_data['field'], ip_interface('2001:0:1::2'))
+
def test_form_ipv6_change(self):
instance = NoPrefixInetTestModel.objects.create(field='2001:0:1::2/64')
form = self.form_class({'field': '2001:0:1::3/64'}, instance=instance)
@@ -134,11 +156,16 @@ class TestCidrAddressFormField(TestCase):
form = self.form_class({'field': '10.0.0.1.2/32'})
self.assertFalse(form.is_valid())
+ def test_form_ipv4_strip(self):
+ form = self.form_class({'field': ' 10.0.1.0/24 '})
+ self.assertTrue(form.is_valid())
+ self.assertEqual(form.cleaned_data['field'], ip_network('10.0.1.0/24'))
+
def test_form_ipv4_bits_to_right_of_mask(self):
form = self.form_class({'field': '10.0.0.1.2/24'})
self.assertFalse(form.is_valid())
- def test_form_ipv6(self):
+ def test_form_ipv6_valid(self):
form = self.form_class({'field': '2001:0:1::/64'})
self.assertTrue(form.is_valid())
self.assertEqual(form.cleaned_data['field'], ip_network('2001:0:1::/64'))
@@ -147,6 +174,11 @@ class TestCidrAddressFormField(TestCase):
form = self.form_class({'field': '2001:0::1::2/128'})
self.assertFalse(form.is_valid())
+ def test_form_ipv6_strip(self):
+ form = self.form_class({'field': ' 2001:0:1::/64 '})
+ self.assertTrue(form.is_valid())
+ self.assertEqual(form.cleaned_data['field'], ip_network('2001:0:1::/64'))
+
def test_form_ipv6_bits_to_right_of_mask(self):
form = self.form_class({'field': '2001:0::1::2/64'})
self.assertFalse(form.is_valid())
@@ -207,6 +239,11 @@ class TestMacAddressFormField(TestCase):
self.assertTrue(form.is_valid())
self.assertEqual(form.cleaned_data['field'], self.mac)
+ def test_strip(self):
+ form = MacAddressTestModelForm({'field': ' 00:aa:2b:c3:dd:44 '})
+ self.assertTrue(form.is_valid())
+ self.assertEqual(form.cleaned_data['field'], self.mac)
+
def test_invalid(self):
form = MacAddressTestModelForm({'field': 'notvalid'})
self.assertFalse(form.is_valid())
diff --git a/test/tests/test_rest_framework_fields.py b/test/tests/test_rest_framework_fields.py
index 093d37f..126065e 100644
--- a/test/tests/test_rest_framework_fields.py
+++ b/test/tests/test_rest_framework_fields.py
@@ -1,4 +1,4 @@
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
from rest_framework import serializers
@@ -12,30 +12,36 @@ class FieldsTestCase(unittest.TestCase):
class TestSerializer(serializers.Serializer):
ip = fields.InetAddressField()
- serializer = TestSerializer(data={'ip': '10.0.0.'})
+ address = '10.0.0.'
+ serializer = TestSerializer(data={'ip': address})
with self.assertRaises(serializers.ValidationError) as e:
serializer.is_valid(raise_exception=True)
- self.assertEqual(e.exception.detail['ip'], ['Invalid IP address.'])
+ self.assertEqual(e.exception.detail['ip'],
+ ["Invalid IP address: %r does not appear to be an IPv4 or IPv6 interface" % address])
+
def test_validation_cidr_field(self):
class TestSerializer(serializers.Serializer):
cidr = fields.CidrAddressField()
- serializer = TestSerializer(data={'cidr': '10.0.0.'})
+ address = '10.0.0.'
+ serializer = TestSerializer(data={'cidr': address})
with self.assertRaises(serializers.ValidationError) as e:
serializer.is_valid(raise_exception=True)
- self.assertEqual(e.exception.detail['cidr'], ['Invalid CIDR address.'])
+ self.assertEqual(e.exception.detail['cidr'],
+ ["Invalid CIDR address: %r does not appear to be an IPv4 or IPv6 network" % address])
def test_validation_mac_field(self):
class TestSerializer(serializers.Serializer):
mac = fields.MACAddressField()
- serializer = TestSerializer(data={'mac': 'de:'})
+ address = 'de:'
+ serializer = TestSerializer(data={'mac': address})
with self.assertRaises(serializers.ValidationError) as e:
serializer.is_valid(raise_exception=True)
- self.assertEqual(e.exception.detail['mac'], ['Invalid MAC address.'])
+ self.assertEqual(e.exception.detail['mac'], ["Invalid MAC address: failed to detect EUI version: %r" % address])
def test_validation_additional_validators(self):
def validate(value):
@@ -44,7 +50,10 @@ class FieldsTestCase(unittest.TestCase):
class TestSerializer(serializers.Serializer):
ip = fields.InetAddressField(validators=[validate])
- serializer = TestSerializer(data={'ip': 'de:'})
+ address = 'de:'
+ serializer = TestSerializer(data={'ip': address})
with self.assertRaises(serializers.ValidationError) as e:
serializer.is_valid(raise_exception=True)
- self.assertItemsEqual(e.exception.detail['ip'], ['Invalid IP address.', 'Invalid.'])
+ self.assertItemsEqual(e.exception.detail['ip'],
+ ["Invalid IP address: %r does not appear to be an IPv4 or IPv6 interface" % address,
+ 'Invalid.'])
diff --git a/test/tests/test_sql_fields.py b/test/tests/test_sql_fields.py
index a75c0ce..8b74363 100644
--- a/test/tests/test_sql_fields.py
+++ b/test/tests/test_sql_fields.py
@@ -32,7 +32,9 @@ from test.models import (
UniqueCidrTestModel,
NoPrefixInetTestModel,
MACArrayTestModel,
- MACTestModel
+ MACTestModel,
+ AggregateTestModel,
+ AggregateTestChildModel
)
@@ -227,6 +229,9 @@ class BaseInetFieldTestCase(BaseInetTestCase):
def test_query_filter_ipaddress(self):
self.model.objects.filter(field=ip_interface('1.2.3.4'))
+ def test_query_filter_contains_ipnetwork(self):
+ self.model.objects.filter(field__net_contains=ip_network(u'2001::0/16'))
+
class BaseCidrFieldTestCase(BaseInetTestCase):
value1 = '10.0.0.1/32'
@@ -299,6 +304,12 @@ class BaseCidrFieldTestCase(BaseInetTestCase):
self.select + 'WHERE masklen("table"."field") >= %s'
)
+ def test_prefixlen(self):
+ self.assertSqlEquals(
+ self.qs.filter(field__prefixlen='16'),
+ self.select + 'WHERE masklen("table"."field") = %s'
+ )
+
class TestInetField(BaseInetFieldTestCase, TestCase):
def setUp(self):
@@ -566,3 +577,32 @@ class TestMACAddressFieldArray(TestCase):
instance = MACArrayTestModel.objects.get(id=instance.id)
self.assertEqual(instance.field, [EUI('00:aa:2b:c3:dd:44')])
self.assertIsInstance(instance.field[0], EUI)
+
+
+class TestAggegate(TestCase):
+ @skipIf(VERSION < (1, 9), 'Postgres aggregates not supported in Django < 1.9')
+ def test_aggregate_inet(self):
+ from django.contrib.postgres.aggregates import ArrayAgg
+ inet = IPv4Interface('10.20.30.20/32')
+ network = IPv4Network('10.10.10.10/32')
+
+ parent = AggregateTestModel.objects.create()
+ inet_qs = AggregateTestModel.objects.annotate(agg_inet=ArrayAgg('children__inet'))
+
+ self.assertEqual(inet_qs[0].agg_inet, [])
+
+ AggregateTestChildModel.objects.create(parent=parent, network=network, inet=inet)
+ self.assertEqual(inet_qs[0].agg_inet, [inet])
+
+ @skipIf(VERSION < (1, 9), 'Postgres aggregates not supported in Django < 1.9')
+ def test_aggregate_network(self):
+ from django.contrib.postgres.aggregates import ArrayAgg
+ inet = IPv4Interface('10.20.30.20/32')
+ network = IPv4Network('10.10.10.10/32')
+
+ parent = AggregateTestModel.objects.create()
+ network_qs = AggregateTestModel.objects.annotate(agg_network=ArrayAgg('children__network'))
+
+ self.assertEqual(network_qs[0].agg_network, [])
+ AggregateTestChildModel.objects.create(parent=parent, network=network, inet=inet)
+ self.assertEqual(network_qs[0].agg_network, [network])
diff --git a/tox.ini b/tox.ini
deleted file mode 100644
index 2426078..0000000
--- a/tox.ini
+++ /dev/null
@@ -1,114 +0,0 @@
-[tox]
-envlist=
- py27-django18,
- py33-django18,
- py34-django18,
- py35-django18,
- py27-django19,
- py34-django19,
- py35-django19,
- py27-django110,
- py34-django110,
- py35-django110,
-
-
-
-[testenv]
-commands=
- python manage.py test {posargs}
-
-# Build configurations...
-
-[testenv:py27-django18]
-basepython=python2.7
-deps=
- django>=1.8,<1.9
- ipaddress
- netaddr
- psycopg2
- djangorestframework
- unittest2
-
-[testenv:py33-django18]
-basepython=python3.3
-deps=
- django>=1.8,<1.9
... 79 lines suppressed ...
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-django-netfields.git
More information about the Python-modules-commits
mailing list