Skip to content

Commit

Permalink
Merge pull request City-of-Helsinki#104 from amanpdyadav/geojson-impo…
Browse files Browse the repository at this point in the history
…rters

Geojson importers
  • Loading branch information
suutari-ai authored Dec 23, 2019
2 parents d185a67 + ebed786 commit 7475bd2
Show file tree
Hide file tree
Showing 11 changed files with 359 additions and 0 deletions.
7 changes: 7 additions & 0 deletions parkings/importers/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from .geojson_payment_zones import PaymentZoneImporter
from .geojson_permit_areas import PermitAreaImporter

__all__ = [
'PermitAreaImporter',
'PaymentZoneImporter',
]
20 changes: 20 additions & 0 deletions parkings/importers/geojson_importer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import abc
import json

from django.contrib.gis.geos import GEOSGeometry


class GeoJsonImporter(metaclass=abc.ABCMeta):

def read_and_parse(self, geojson_file_path):
with open(geojson_file_path, "rt") as file:
root = json.load(file)
for member in root['features']:
yield self._parse_member(member)

@abc.abstractmethod
def _parse_member(self, member):
pass

def get_polygons(self, geom):
return GEOSGeometry(json.dumps(geom))
48 changes: 48 additions & 0 deletions parkings/importers/geojson_payment_zones.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import logging
import os

from django.db import transaction

from parkings.models import PaymentZone

from .geojson_importer import GeoJsonImporter

logger = logging.getLogger(__name__)

mydir = os.path.dirname(__file__)


class PaymentZoneImporter(GeoJsonImporter):
"""
Imports paymentzones data
"""

def import_payment_zones(self, geojson_file_path):
payment_zone_dicts = self.read_and_parse(geojson_file_path)
count = self._save_payment_zones(payment_zone_dicts)
logger.info('Created or updated {} payment zones'.format(count))

@transaction.atomic
def _save_payment_zones(self, payment_zone_dicts):
logger.info('Saving payment zones.')
count = 0
payment_zone_ids = []
for payment_dict in payment_zone_dicts:
payment_zone, _ = PaymentZone.objects.update_or_create(
number=payment_dict['number'],
defaults=payment_dict)
payment_zone_ids.append(payment_zone.pk)
count += 1
PaymentZone.objects.exclude(pk__in=payment_zone_ids).delete()
return count

def _parse_member(self, member):
name = member['properties']['name']
number = member['properties']['number']
geom = self.get_polygons(member['geometry'])

return {
'name': name,
'number': number,
'geom': geom,
}
47 changes: 47 additions & 0 deletions parkings/importers/geojson_permit_areas.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import logging
import os

from django.db import transaction

from parkings.models import PermitArea

from .geojson_importer import GeoJsonImporter

logger = logging.getLogger(__name__)
mydir = os.path.dirname(__file__)


class PermitAreaImporter(GeoJsonImporter):
"""
Imports permit area data
"""

def import_permit_areas(self, geojson_file_path):
permit_area_dicts = self.read_and_parse(geojson_file_path)
count = self._save_permit_areas(permit_area_dicts)
logger.info('Created or updated {} permit areas'.format(count))

@transaction.atomic
def _save_permit_areas(self, permit_areas_dict):
logger.info('Saving permit areas.')
count = 0
permit_area_ids = []
for area_dict in permit_areas_dict:
permit_area, _ = PermitArea.objects.update_or_create(
identifier=area_dict['identifier'],
defaults=area_dict)
permit_area_ids.append(permit_area.pk)
count += 1
PermitArea.objects.exclude(pk__in=permit_area_ids).delete()
return count

def _parse_member(self, member):
identifier = member['properties']['identifier']
name = member['properties']['name']
geom = self.get_polygons(member['geometry'])

return {
'name': name,
'identifier': identifier,
'geom': geom,
}
14 changes: 14 additions & 0 deletions parkings/management/commands/import_geojson_payment_zones.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from django.core.management.base import BaseCommand

from parkings.importers import PaymentZoneImporter


class Command(BaseCommand):
help = 'Uses the PaymentZoneImporter to import payment zones.'

def add_arguments(self, parser):
parser.add_argument('geojson_file_path')

def handle(self, *args, **options):
file_path = options.get('geojson_file_path', None)
PaymentZoneImporter().import_payment_zones(file_path)
14 changes: 14 additions & 0 deletions parkings/management/commands/import_geojson_permit_areas.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from django.core.management.base import BaseCommand

from parkings.importers import PermitAreaImporter


class Command(BaseCommand):
help = 'Uses the PermitAreaImporter to create permit areas'

def add_arguments(self, parser):
parser.add_argument('geojson_file_path')

def handle(self, *args, **options):
file_path = options.get('geojson_file_path', None)
PermitAreaImporter().import_permit_areas(file_path)
90 changes: 90 additions & 0 deletions parkings/tests/geojson_payment_zones_importer_data.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
{
"type": "FeatureCollection",
"name": "maksut_wgs84",
"crs": {
"type": "name",
"properties": {
"name": "urn:ogc:def:crs:OGC:1.3:CRS84"
}
},
"features": [{
"type": "Feature",
"properties": {
"number": 0,
"name": "Zone 1"
},
"geometry": {
"type": "MultiPolygon",
"coordinates": [
[
[
[
-47.900390625,
-14.944784875088372
],
[
-51.591796875,
-19.91138351415555
],
[
-41.11083984375,
-21.309846141087192
],
[
-43.39599609375,
-15.390135715305204
],
[
-47.900390625,
-14.944784875088372
]
],
[
[
-46.6259765625,
-17.14079039331664
],
[
-47.548828125,
-16.804541076383455
],
[
-46.23046874999999,
-16.699340234594537
],
[
-45.3515625,
-19.31114335506464
],
[
-46.6259765625,
-17.14079039331664
]
],
[
[
-44.40673828125,
-18.375379094031825
],
[
-44.4287109375,
-20.097206227083888
],
[
-42.9345703125,
-18.979025953255267
],
[
-43.52783203125,
-17.602139123350838
],
[
-44.40673828125,
-18.375379094031825
]
]
]
]
}
}]
}
47 changes: 47 additions & 0 deletions parkings/tests/geojson_permit_areas_importer_data.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"type": "FeatureCollection",
"name": "asukaspysakointi_wgs84",
"crs": {
"type": "name",
"properties": {
"name": "urn:ogc:def:crs:OGC:1.3:CRS84"
}
},
"features": [{
"type": "Feature",
"properties": {
"identifier": 1,
"name": "Asukaspysäköintialue A"
},
"geometry": {
"type": "MultiPolygon",
"coordinates": [
[
[
[102.0, 2.0],
[103.0, 2.0],
[103.0, 3.0],
[102.0, 3.0],
[102.0, 2.0]
]
],
[
[
[100.0, 0.0],
[101.0, 0.0],
[101.0, 1.0],
[100.0, 1.0],
[100.0, 0.0]
],
[
[100.2, 0.2],
[100.8, 0.2],
[100.8, 0.8],
[100.2, 0.8],
[100.2, 0.2]
]
]
]
}
}]
}
27 changes: 27 additions & 0 deletions parkings/tests/test_geojson_importing_management_commands.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import os

import pytest
from django.core.management import call_command

from parkings.models import PaymentZone, PermitArea

from ..management.commands import (
import_geojson_payment_zones, import_geojson_permit_areas)

mydir = os.path.dirname(__file__)
permit_areas = os.path.join(mydir, 'geojson_permit_areas_importer_data.geojson')
payment_zones = os.path.join(mydir, 'geojson_payment_zones_importer_data.geojson')


@pytest.mark.django_db
def test_import_payment_zones():
call_command(import_geojson_payment_zones.Command(), payment_zones)

assert PaymentZone.objects.count() == 1


@pytest.mark.django_db
def test_permit_area_importer():
call_command(import_geojson_permit_areas.Command(), permit_areas)

assert PermitArea.objects.count() == 1
24 changes: 24 additions & 0 deletions parkings/tests/test_geojson_payment_zone_importer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import os

from parkings.importers import PaymentZoneImporter

mydir = os.path.dirname(__file__)


def test_payment_zone_importer():
filename = os.path.join(mydir, 'geojson_payment_zones_importer_data.geojson')
importer = PaymentZoneImporter()
data = importer.read_and_parse(filename)
payment_zone = next(iter(data))

assert payment_zone['name'] == "Zone 1"
assert payment_zone['number'] == 0
assert payment_zone['geom'].wkt == (
'MULTIPOLYGON (('
'(-47.900390625 -14.94478487508837, -51.591796875 -19.91138351415555, -41.11083984375'
' -21.30984614108719, -43.39599609375 -15.3901357153052, -47.900390625 -14.94478487508837), '
'(-46.6259765625 -17.14079039331664, -47.548828125 -16.80454107638345, -46.23046874999999'
' -16.69934023459454, -45.3515625 -19.31114335506464, -46.6259765625 -17.14079039331664), '
'(-44.40673828125 -18.37537909403182, -44.4287109375 -20.09720622708389, -42.9345703125'
' -18.97902595325527, -43.52783203125 -17.60213912335084, -44.40673828125 -18.37537909403182)))'
)
21 changes: 21 additions & 0 deletions parkings/tests/test_geojson_permit_area_importer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import os

from parkings.importers import PermitAreaImporter

mydir = os.path.dirname(__file__)


def test_permit_area_importer():
filename = os.path.join(mydir, 'geojson_permit_areas_importer_data.geojson')
importer = PermitAreaImporter()
data = importer.read_and_parse(filename)
permit_area = next(iter(data))

assert permit_area['name'] == 'Asukaspysäköintialue A'
assert permit_area['identifier'] == 1
assert permit_area['geom'].wkt == (
'MULTIPOLYGON (('
'(102 2, 103 2, 103 3, 102 3, 102 2)),'
' ((100 0, 101 0, 101 1, 100 1, 100 0),'
' (100.2 0.2, 100.8 0.2, 100.8 0.8, 100.2 0.8, 100.2 0.2)))'
)

0 comments on commit 7475bd2

Please sign in to comment.