Skip to content

Commit

Permalink
[qa] Added QA checks #230
Browse files Browse the repository at this point in the history
Closes #230
  • Loading branch information
devkapilbansal committed Aug 28, 2020
1 parent 44e471b commit 1814fc9
Show file tree
Hide file tree
Showing 30 changed files with 1,317 additions and 879 deletions.
4 changes: 3 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,16 @@ before_install:
- sudo add-apt-repository ppa:ubuntugis/ubuntugis-unstable -y
- sudo apt-get update -q
- sudo apt-get install binutils libproj-dev gdal-bin -y

- pip install -U pip setuptools wheel
- pip install -U -r requirements-test.txt
install:
- pip install tox
- pip install docutils pygments # for setup.py check -r -s

before_script:
- createdb django_restframework_gis
- psql -U postgres -d django_restframework_gis -c "CREATE EXTENSION postgis;"
- ./run-qa-checks

script:
- tox -e travis
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
THE SOFTWARE.
11 changes: 11 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,17 @@ To run tests in docker use
docker-compose build
docker-compose run --rm test
Running QA-checks
=================

You can run qa-checks by using

.. code-block:: shell
./run-qa-checks
In docker testing, QA checks are executed automatically.

Contributing
------------
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ services:
- ./tests:/project/tests
- ./README.rst:/project/README.rst
- ./setup.py:/project/setup.py
command: sh -c "pip install -e . && python ./tests/manage.py test tests/django_restframework_gis_tests"
command: sh -c "pip install -e . && python ./tests/manage.py test tests/django_restframework_gis_tests && ./run-qa-checks"

postgres:
image: mdillon/postgis:10-alpine
Expand Down
3 changes: 2 additions & 1 deletion requirements-test.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
psycopg2
coveralls
django-filter>=2.0
contexttimer
# QA checks
openwisp-utils[qa]~=0.6
23 changes: 13 additions & 10 deletions rest_framework_gis/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ def ready(self):
"""
from django.contrib.gis.db import models
from rest_framework.serializers import ModelSerializer

from .fields import GeometryField

try:
Expand All @@ -20,13 +21,15 @@ def ready(self):
field_mapping = ModelSerializer.serializer_field_mapping

# map GeoDjango fields to drf-gis GeometryField
field_mapping.update({
models.GeometryField: GeometryField,
models.PointField: GeometryField,
models.LineStringField: GeometryField,
models.PolygonField: GeometryField,
models.MultiPointField: GeometryField,
models.MultiLineStringField: GeometryField,
models.MultiPolygonField: GeometryField,
models.GeometryCollectionField: GeometryField
})
field_mapping.update(
{
models.GeometryField: GeometryField,
models.PointField: GeometryField,
models.LineStringField: GeometryField,
models.PolygonField: GeometryField,
models.MultiPointField: GeometryField,
models.MultiLineStringField: GeometryField,
models.MultiPolygonField: GeometryField,
models.GeometryCollectionField: GeometryField,
}
)
31 changes: 18 additions & 13 deletions rest_framework_gis/fields.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import json
from collections import OrderedDict

from django.contrib.gis.geos import GEOSGeometry, GEOSException
from django.contrib.gis.gdal import GDALException
from django.contrib.gis.geos import GEOSException, GEOSGeometry
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
from rest_framework.fields import Field, SerializerMethodField


__all__ = ['GeometryField', 'GeometrySerializerMethodField']


class GeometryField(Field):
"""
A field to handle GeoDjango Geometry fields
"""

type_name = 'GeometryField'

def __init__(self, precision=None, remove_duplicates=False, **kwargs):
Expand All @@ -31,21 +31,20 @@ def to_representation(self, value):
geojson = GeoJsonDict(value.geojson)
# in this case we're dealing with an empty point
else:
geojson = GeoJsonDict({
'type': value.geom_type,
'coordinates': []
})
geojson = GeoJsonDict({'type': value.geom_type, 'coordinates': []})
if geojson['type'] == 'GeometryCollection':
geometries = geojson.get('geometries')
else:
geometries = [geojson]
for geometry in geometries:
if self.precision is not None:
geometry['coordinates'] = self._recursive_round(
geometry['coordinates'], self.precision)
geometry['coordinates'], self.precision
)
if self.remove_dupes:
geometry['coordinates'] = self._rm_redundant_points(
geometry['coordinates'], geometry['type'])
geometry['coordinates'], geometry['type']
)
return geojson

def to_internal_value(self, value):
Expand All @@ -59,9 +58,15 @@ def to_internal_value(self, value):
try:
return GEOSGeometry(value)
except (GEOSException):
raise ValidationError(_('Invalid format: string or unicode input unrecognized as GeoJSON, WKT EWKT or HEXEWKB.'))
raise ValidationError(
_(
'Invalid format: string or unicode input unrecognized as GeoJSON, WKT EWKT or HEXEWKB.'
)
)
except (ValueError, TypeError, GDALException) as e:
raise ValidationError(_('Unable to convert to python object: {}'.format(str(e))))
raise ValidationError(
_('Unable to convert to python object: {}'.format(str(e)))
)

def validate_empty_values(self, data):
if data == '':
Expand All @@ -86,7 +91,7 @@ def _rm_redundant_points(self, geometry, geo_type):
determine structure of provided `geometry` argument
"""
if geo_type in ('MultiPoint', 'LineString'):
close = (geo_type == 'LineString')
close = geo_type == 'LineString'
output = []
for coord in geometry:
coord = tuple(coord)
Expand All @@ -96,8 +101,7 @@ def _rm_redundant_points(self, geometry, geo_type):
output.append(output[0])
return tuple(output)
if geo_type in ('MultiLineString', 'Polygon'):
return [
self._rm_redundant_points(c, 'LineString') for c in geometry]
return [self._rm_redundant_points(c, 'LineString') for c in geometry]
if geo_type == 'MultiPolygon':
return [self._rm_redundant_points(c, 'Polygon') for c in geometry]
return geometry
Expand All @@ -118,6 +122,7 @@ class GeoJsonDict(OrderedDict):
Used for serializing GIS values to GeoJSON values
TODO: remove this when support for python 2.6/2.7 will be dropped
"""

def __init__(self, *args, **kwargs):
"""
If a string is passed attempt to pass it through json.loads,
Expand Down
47 changes: 30 additions & 17 deletions rest_framework_gis/filters.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
from math import cos, pi

from django.db.models import Q
from django.core.exceptions import ImproperlyConfigured
from django.contrib.gis.db import models
from django.contrib.gis.geos import Polygon, Point
from django.contrib.gis import forms

from rest_framework.filters import BaseFilterBackend
from django.contrib.gis.db import models
from django.contrib.gis.geos import Point, Polygon
from django.core.exceptions import ImproperlyConfigured
from django.db.models import Q
from rest_framework.exceptions import ParseError
from rest_framework.filters import BaseFilterBackend

from .tilenames import tile_edges

Expand Down Expand Up @@ -45,7 +44,7 @@
'GeoFilterSet',
'TMSTileFilter',
'DistanceToPointFilter',
'DistanceToPointOrderingFilter'
'DistanceToPointOrderingFilter',
]


Expand All @@ -60,7 +59,9 @@ def get_filter_bbox(self, request):
try:
p1x, p1y, p2x, p2y = (float(n) for n in bbox_string.split(','))
except ValueError:
raise ParseError('Invalid bbox string supplied for parameter {0}'.format(self.bbox_param))
raise ParseError(
'Invalid bbox string supplied for parameter {0}'.format(self.bbox_param)
)

x = Polygon.from_bbox((p1x, p1y, p2x, p2y))
return x
Expand All @@ -80,6 +81,8 @@ def filter_queryset(self, request, queryset, view):
if not bbox:
return queryset
return queryset.filter(Q(**{'%s__%s' % (filter_field, geoDjango_filter): bbox}))


# backward compatibility
InBBOXFilter = InBBoxFilter

Expand All @@ -94,9 +97,7 @@ def __init__(self, *args, **kwargs):

class GeoFilterSet(django_filters.FilterSet):
GEOFILTER_FOR_DBFIELD_DEFAULTS = {
models.GeometryField: {
'filter_class': GeometryFilter
},
models.GeometryField: {'filter_class': GeometryFilter},
}

def __new__(cls, *args, **kwargs):
Expand All @@ -120,7 +121,9 @@ def get_filter_bbox(self, request):
try:
z, x, y = (int(n) for n in tile_string.split('/'))
except ValueError:
raise ParseError('Invalid tile string supplied for parameter {0}'.format(self.tile_param))
raise ParseError(
'Invalid tile string supplied for parameter {0}'.format(self.tile_param)
)

bbox = Polygon.from_bbox(tile_edges(x, y, z))
return bbox
Expand All @@ -138,7 +141,11 @@ def get_filter_point(self, request, **kwargs):
try:
(x, y) = (float(n) for n in point_string.split(','))
except ValueError:
raise ParseError('Invalid geometry string supplied for parameter {0}'.format(self.point_param))
raise ParseError(
'Invalid geometry string supplied for parameter {0}'.format(
self.point_param
)
)

p = Point(x, y, **kwargs)
return p
Expand Down Expand Up @@ -169,7 +176,7 @@ def dist_to_deg(self, distance, latitude):
rad2deg = 180 / pi
earthRadius = 6378160.0
latitudeCorrection = 0.5 * (1 + cos(lat * pi / 180))
return (distance / (earthRadius * latitudeCorrection) * rad2deg)
return distance / (earthRadius * latitudeCorrection) * rad2deg

def filter_queryset(self, request, queryset, view):
filter_field = getattr(view, 'distance_filter_field', None)
Expand All @@ -188,13 +195,19 @@ def filter_queryset(self, request, queryset, view):
try:
dist = float(dist_string)
except ValueError:
raise ParseError('Invalid distance string supplied for parameter {0}'.format(self.dist_param))
raise ParseError(
'Invalid distance string supplied for parameter {0}'.format(
self.dist_param
)
)

if (convert_distance_input):
if convert_distance_input:
# Warning: assumes that the point is (lon,lat)
dist = self.dist_to_deg(dist, point[1])

return queryset.filter(Q(**{'%s__%s' % (filter_field, geoDjango_filter): (point, dist)}))
return queryset.filter(
Q(**{'%s__%s' % (filter_field, geoDjango_filter): (point, dist)})
)


class DistanceToPointOrderingFilter(DistanceToPointFilter):
Expand Down
19 changes: 12 additions & 7 deletions rest_framework_gis/pagination.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,18 @@ class GeoJsonPagination(pagination.PageNumberPagination):
"""
A geoJSON implementation of a pagination serializer.
"""

page_size_query_param = 'page_size'

def get_paginated_response(self, data):
return Response(OrderedDict([
('type', 'FeatureCollection'),
('count', self.page.paginator.count),
('next', self.get_next_link()),
('previous', self.get_previous_link()),
('features', data['features'])
]))
return Response(
OrderedDict(
[
('type', 'FeatureCollection'),
('count', self.page.paginator.count),
('next', self.get_next_link()),
('previous', self.get_previous_link()),
('features', data['features']),
]
)
)
Loading

0 comments on commit 1814fc9

Please sign in to comment.