[python-geojson] 01/04: Imported Upstream version 1.2.0
Johan Van de Wauw
johanvdw-guest at moszumanska.debian.org
Tue Jun 23 14:00:47 UTC 2015
This is an automated email from the git hooks/post-receive script.
johanvdw-guest pushed a commit to branch master
in repository python-geojson.
commit ee97e9d8ee9eee07d54e9cdf33040f456b027e96
Author: Johan Van de Wauw <johan.vandewauw at gmail.com>
Date: Tue Jun 23 15:52:43 2015 +0200
Imported Upstream version 1.2.0
---
.gitignore | 1 +
.travis.yml | 13 +++---
CHANGELOG.rst | 14 ++++++
README.rst | 30 ++++++++++---
geojson/__init__.py | 10 +++++
geojson/base.py | 77 +++++++++++++++++++++++--------
geojson/crs.py | 9 ++++
geojson/examples.py | 34 ++++++++++++--
geojson/factory.py | 6 +++
geojson/feature.py | 37 +++++++++++----
geojson/geometry.py | 23 +++++++---
geojson/mapping.py | 9 ++++
geojson/utils.py | 31 ++++++++++---
geojson/validation.py | 97 +++++++++++++++++++++++++++++++++++++++
setup.py | 13 ++----
tests/test_base.py | 15 +++++--
tests/test_coords.py | 8 ++--
tests/test_crs.py | 12 ++---
tests/test_features.py | 71 ++++++++++++++++++++++-------
tests/test_geo_interface.py | 27 ++++-------
tests/test_validation.py | 107 ++++++++++++++++++++++++++++++++++++++++++++
21 files changed, 536 insertions(+), 108 deletions(-)
diff --git a/.gitignore b/.gitignore
index 567609b..edd9d60 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
build/
+dist/
diff --git a/.travis.yml b/.travis.yml
index f9f06e7..151293a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,6 +1,5 @@
language: "python"
python:
- - "2.6"
- "2.7"
- "3.2"
- "3.3"
@@ -8,8 +7,12 @@ python:
- "pypy"
- "pypy3"
install:
- pip install coveralls
-script:
- coverage run --source=geojson setup.py test
+ - pip install flake8
+ - pip install codecov
+before_script:
+ flake8 .
+script:
+ - coverage run --branch --source=geojson setup.py test
+ - coverage xml
after_success:
- coveralls
+ - codecov
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 202de17..4f1b9b1 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -1,6 +1,20 @@
Changes
=======
+1.2.0 (2015-06-19)
+------------------
+
+- Utility function to validate GeoJSON objects
+
+ - https://github.com/frewsxcv/python-geojson/pull/56
+
+1.1.0 (2015-06-08)
+------------------
+
+- Stop outputting invalid GeoJSON value id=null on Features
+
+ - https://github.com/frewsxcv/python-geojson/pull/53
+
1.0.9 (2014-10-05)
------------------
diff --git a/README.rst b/README.rst
index e31128f..b08b9a0 100644
--- a/README.rst
+++ b/README.rst
@@ -1,10 +1,10 @@
python-geojson
==============
-.. image:: https://travis-ci.org/frewsxcv/python-geojson.png?branch=master
+.. image:: https://img.shields.io/travis/frewsxcv/python-geojson.svg
:target: https://travis-ci.org/frewsxcv/python-geojson
-.. image:: https://coveralls.io/repos/frewsxcv/python-geojson/badge.png
- :target: https://coveralls.io/r/frewsxcv/python-geojson
+.. image:: https://img.shields.io/codecov/c/github/frewsxcv/python-geojson.svg
+ :target: https://codecov.io/github/frewsxcv/python-geojson?branch=master
This library contains:
@@ -171,10 +171,10 @@ Feature
>>> my_point = Point((-3.68, 40.41))
>>> Feature(geometry=my_point) # doctest: +ELLIPSIS
- {"geometry": {"coordinates": [-3.68..., 40.4...], "type": "Point"}, "id": null, "properties": {}, "type": "Feature"}
+ {"geometry": {"coordinates": [-3.68..., 40.4...], "type": "Point"}, "properties": {}, "type": "Feature"}
>>> Feature(geometry=my_point, properties={"country": "Spain"}) # doctest: +ELLIPSIS
- {"geometry": {"coordinates": [-3.68..., 40.4...], "type": "Point"}, "id": null, "properties": {"country": "Spain"}, "type": "Feature"}
+ {"geometry": {"coordinates": [-3.68..., 40.4...], "type": "Point"}, "properties": {"country": "Spain"}, "type": "Feature"}
>>> Feature(geometry=my_point, id=27) # doctest: +ELLIPSIS
{"geometry": {"coordinates": [-3.68..., 40.4...], "type": "Point"}, "id": 27, "properties": {}, "type": "Feature"}
@@ -195,7 +195,7 @@ FeatureCollection
>>> my_other_feature = Feature(geometry=Point((-80.234, -22.532)))
>>> FeatureCollection([my_feature, my_other_feature]) # doctest: +ELLIPSIS
- {"features": [{"geometry": {"coordinates": [1.643..., -19.12...], "type": "Point"}, "id": null, "properties": {}, "type": "Feature"}, {"geometry": {"coordinates": [-80.23..., -22.53...], "type": "Point"}, "id": null, "properties": {}, "type": "Feature"}], "type": "FeatureCollection"}
+ {"features": [{"geometry": {"coordinates": [1.643..., -19.12...], "type": "Point"}, "properties": {}, "type": "Feature"}, {"geometry": {"coordinates": [-80.23..., -22.53...], "type": "Point"}, "properties": {}, "type": "Feature"}], "type": "FeatureCollection"}
Visualize the result of the example above `here <https://gist.github.com/frewsxcv/34513be6fb492771ef7b>`__. General information about FeatureCollection can be found in `Section 2.3`_ within `The GeoJSON Format Specification`_.
@@ -279,6 +279,21 @@ map_coords
>>> geojson.dumps(new_point, sort_keys=True) # doctest: +ELLIPSIS
'{"coordinates": [-57.905..., 18.62...], "type": "Point"}'
+validation
+~~~~~~~~~~
+:code:`geojson.is_valid` provides validation of GeoJSON objects.
+
+.. code:: python
+
+ >>> import geojson
+
+ >>> validation = geojson.is_valid(geojson.Point((-3.68,40.41,25.14)))
+ >>> validation['valid']
+ 'no'
+ >>> validation['message']
+ 'the "coordinates" member must be a single position'
+
+
Development
-----------
@@ -290,6 +305,9 @@ Credits
* Sean Gillies <sgillies at frii.com>
* Matthew Russell <matt at sanoodi.com>
* Corey Farwell <coreyf at rwell.org>
+* Blake Grotewold <hello at grotewold.me>
+* Zsolt Ero <zsolt.ero at gmail.com>
+* Sergey Romanov <xxsmotur at gmail.com>
.. _GeoJSON: http://geojson.org/
diff --git a/geojson/__init__.py b/geojson/__init__.py
index 4de7ca0..f46f5cc 100644
--- a/geojson/__init__.py
+++ b/geojson/__init__.py
@@ -5,3 +5,13 @@ from geojson.geometry import MultiLineString, MultiPoint, MultiPolygon
from geojson.geometry import GeometryCollection
from geojson.feature import Feature, FeatureCollection
from geojson.base import GeoJSON
+from geojson.validation import is_valid
+
+__all__ = ([dump, dumps, load, loads, GeoJSONEncoder] +
+ [coords, map_coords] +
+ [Point, LineString, Polygon] +
+ [MultiLineString, MultiPoint, MultiPolygon] +
+ [GeometryCollection] +
+ [Feature, FeatureCollection] +
+ [GeoJSON] +
+ [is_valid])
diff --git a/geojson/base.py b/geojson/base.py
index 1bd69dd..692141f 100644
--- a/geojson/base.py
+++ b/geojson/base.py
@@ -1,10 +1,24 @@
+from __future__ import unicode_literals
+
import geojson
from geojson.mapping import to_mapping
class GeoJSON(dict):
+ """
+ A class representing a GeoJSON object.
+ """
def __init__(self, iterable=(), **extra):
+ """
+ Initialises a GeoJSON object
+
+ :param iterable: iterable from which to draw the content of the GeoJSON
+ object.
+ :type iterable: dict, array, tuple
+ :return: a GeoJSON object
+ :rtype: GeoJSON
+ """
super(GeoJSON, self).__init__(iterable)
self["type"] = getattr(self, "type", type(self).__name__)
self.update(extra)
@@ -14,25 +28,38 @@ class GeoJSON(dict):
__str__ = __repr__
- def __setattr__(self, name, value):
- """
- Permit dictionary items to be set like object attributes
- """
- self[name] = value
-
def __getattr__(self, name):
"""
Permit dictionary items to be retrieved like object attributes
+
+ :param name: attribute name
+ :type name: str, int
+ :return: dictionary value
"""
try:
return self[name]
except KeyError:
raise AttributeError(name)
+ def __setattr__(self, name, value):
+ """
+ Permit dictionary items to be set like object attributes.
+
+ :param name: key of item to be set
+ :type name: str
+ :param value: value to set item to
+ """
+
+ self[name] = value
+
def __delattr__(self, name):
"""
Permit dictionary items to be deleted like object attributes
+
+ :param name: key of item to be deleted
+ :type name: str
"""
+
del self[name]
@property
@@ -43,8 +70,28 @@ class GeoJSON(dict):
@classmethod
def to_instance(cls, ob, default=None, strict=False):
"""Encode a GeoJSON dict into an GeoJSON object.
-
Assumes the caller knows that the dict should satisfy a GeoJSON type.
+
+ :param cls: Dict containing the elements to be encoded into a GeoJSON
+ object.
+ :type cls: dict
+ :param ob: GeoJSON object into which to encode the dict provided in
+ `cls`.
+ :type ob: GeoJSON
+ :param default: A default instance to append the content of the dict
+ to if none is provided.
+ :type default: GeoJSON
+ :param strict: Raise error if unable to coerce particular keys or
+ attributes to a valid GeoJSON structure.
+ :type strict: bool
+ :return: A GeoJSON object with the dict's elements as its constituents.
+ :rtype: GeoJSON
+ :raises TypeError: If the input dict contains items that are not valid
+ GeoJSON types.
+ :raises UnicodeEncodeError: If the input dict contains items of a type
+ that contain non-ASCII characters.
+ :raises AttributeError: If the input dict contains items that are not
+ valid GeoJSON types.
"""
if ob is None and default is not None:
instance = default()
@@ -54,21 +101,16 @@ class GeoJSON(dict):
mapping = to_mapping(ob)
d = {}
for k in mapping:
- try:
- str_key = str(k)
- except (UnicodeEncodeError):
- str_key = unicode(k)
- d[str_key] = mapping[k]
+ d[k] = mapping[k]
try:
type_ = d.pop("type")
try:
type_ = str(type_)
- except (UnicodeEncodeError):
+ except UnicodeEncodeError:
# If the type contains non-ascii characters, we can assume
# it's not a valid GeoJSON type
raise AttributeError(
- unicode("{0} is not a GeoJSON type").format(
- unicode(type_)))
+ "{0} is not a GeoJSON type").format(type_)
geojson_factory = getattr(geojson.factory, type_)
if not issubclass(geojson_factory, GeoJSON):
raise TypeError("""\
@@ -77,10 +119,9 @@ class GeoJSON(dict):
""" % (type_, geojson_factory, cls))
instance = geojson_factory(**d)
except (AttributeError, KeyError) as invalid:
- if not strict:
- instance = ob
- else:
+ if strict:
msg = "Cannot coerce %r into a valid GeoJSON structure: %s"
msg %= (ob, invalid)
raise ValueError(msg)
+ instance = ob
return instance
diff --git a/geojson/crs.py b/geojson/crs.py
index 792adec..41a60e2 100644
--- a/geojson/crs.py
+++ b/geojson/crs.py
@@ -2,6 +2,9 @@ from geojson.base import GeoJSON
class CoordinateReferenceSystem(GeoJSON):
+ """
+ Represents a CRS.
+ """
def __init__(self, properties=None, **extra):
super(CoordinateReferenceSystem, self).__init__(**extra)
@@ -9,6 +12,9 @@ class CoordinateReferenceSystem(GeoJSON):
class Named(CoordinateReferenceSystem):
+ """
+ Represents a named CRS.
+ """
def __init__(self, properties=None, **extra):
super(Named, self).__init__(properties=properties, **extra)
@@ -19,6 +25,9 @@ class Named(CoordinateReferenceSystem):
class Linked(CoordinateReferenceSystem):
+ """
+ Represents a linked CRS.
+ """
def __init__(self, properties=None, **extra):
super(Linked, self).__init__(properties=properties, **extra)
diff --git a/geojson/examples.py b/geojson/examples.py
index 81dd88d..2a75c72 100644
--- a/geojson/examples.py
+++ b/geojson/examples.py
@@ -7,7 +7,22 @@ class SimpleWebFeature(object):
def __init__(self, id=None, geometry=None, title=None, summary=None,
link=None):
- """Initialize."""
+ """
+ Initialises a SimpleWebFeature from the parameters provided.
+
+ :param id: Identifier assigned to the object.
+ :type id: int, str
+ :param geometry: The geometry on which the object is based.
+ :type geometry: Geometry
+ :param title: Name of the object
+ :type title: str
+ :param summary: Short summary associated with the object.
+ :type summary: str
+ :param link: Link associated with the object.
+ :type link: str
+ :return: A SimpleWebFeature object
+ :rtype: SimpleWebFeature
+ """
self.id = id
self.geometry = geometry
self.properties = {}
@@ -25,11 +40,24 @@ class SimpleWebFeature(object):
__geo_interface__ = property(as_dict)
+ """
+ Create an instance of SimpleWebFeature from a dict, o. If o does not
+ match a Python feature object, simply return o. This function serves as a
+ json decoder hook. See coding.load().
+ """
+
def createSimpleWebFeature(o):
- """Create an instance of SimpleWebFeature from a dict, o. If o does not
+ """
+ Create an instance of SimpleWebFeature from a dict, o. If o does not
match a Python feature object, simply return o. This function serves as a
- json decoder hook. See coding.load()."""
+ json decoder hook. See coding.load().
+
+ :param o: A dict to create the SimpleWebFeature from.
+ :type o: dict
+ :return: A SimpleWebFeature from the dict provided.
+ :rtype: SimpleWebFeature
+ """
try:
id = o['id']
g = o['geometry']
diff --git a/geojson/factory.py b/geojson/factory.py
index aa79dd9..bd0493e 100644
--- a/geojson/factory.py
+++ b/geojson/factory.py
@@ -5,5 +5,11 @@ from geojson.feature import Feature, FeatureCollection
from geojson.base import GeoJSON
from geojson.crs import Named, Linked
+__all__ = ([Point, LineString, Polygon] +
+ [MultiLineString, MultiPoint, MultiPolygon] +
+ [GeometryCollection] +
+ [Feature, FeatureCollection] +
+ [GeoJSON])
+
name = Named
link = Linked
diff --git a/geojson/feature.py b/geojson/feature.py
index 48db6c0..dc9625d 100644
--- a/geojson/feature.py
+++ b/geojson/feature.py
@@ -7,23 +7,42 @@ from geojson.base import GeoJSON
class Feature(GeoJSON):
-
- """A (WGS84) GIS Feature."""
+ """
+ Represents a WGS84 GIS feature.
+ """
def __init__(self, id=None, geometry=None, properties=None, **extra):
+ """
+ Initialises a Feature object with the given parameters.
+
+ :param id: Feature identifier, such as a sequential number.
+ :type id: str, int
+ :param geometry: Geometry corresponding to the feature.
+ :param properties: Dict containing properties of the feature.
+ :type properties: dict
+ :return: Feature object
+ :rtype: Feature
+ """
super(Feature, self).__init__(**extra)
- self["id"] = id
- if geometry:
- self["geometry"] = self.to_instance(geometry, strict=True)
- else:
- self["geometry"] = None
+ if id is not None:
+ self["id"] = id
+ self["geometry"] = (self.to_instance(geometry, strict=True)
+ if geometry else None)
self["properties"] = properties or {}
class FeatureCollection(GeoJSON):
-
- """A collection of Features."""
+ """
+ Represents a FeatureCollection, a set of multiple Feature objects.
+ """
def __init__(self, features, **extra):
+ """
+ Initialises a FeatureCollection object from the
+ :param features: List of features to constitute the FeatureCollection.
+ :type features: list
+ :return: FeatureCollection object
+ :rtype: FeatureCollection
+ """
super(FeatureCollection, self).__init__(**extra)
self["features"] = features
diff --git a/geojson/geometry.py b/geojson/geometry.py
index 22ea24a..30facc3 100644
--- a/geojson/geometry.py
+++ b/geojson/geometry.py
@@ -4,10 +4,20 @@ from geojson.base import GeoJSON
class Geometry(GeoJSON):
-
- """A (WGS84) GIS geometry."""
+ """
+ Represents an abstract base class for a WGS84 geometry.
+ """
def __init__(self, coordinates=None, crs=None, **extra):
+ """
+ Initialises a Geometry object.
+
+ :param coordinates: Coordinates of the Geometry object.
+ :type coordinates: tuple
+ :param crs: CRS
+ :type crs: CRS object
+ """
+
super(Geometry, self).__init__(**extra)
self["coordinates"] = coordinates or []
self.clean_coordinates(self["coordinates"])
@@ -24,8 +34,9 @@ class Geometry(GeoJSON):
class GeometryCollection(GeoJSON):
-
- """A collection of (WGS84) GIS geometries."""
+ """
+ Represents an abstract base class for collections of WGS84 geometries.
+ """
def __init__(self, geometries=None, **extra):
super(GeometryCollection, self).__init__(**extra)
@@ -59,4 +70,6 @@ class MultiPolygon(Geometry):
class Default(object):
- """GeoJSON default."""
+ """
+ GeoJSON default object.
+ """
diff --git a/geojson/mapping.py b/geojson/mapping.py
index fb24c33..efee073 100644
--- a/geojson/mapping.py
+++ b/geojson/mapping.py
@@ -14,10 +14,19 @@ GEO_INTERFACE_MARKER = "__geo_interface__"
def is_mapping(obj):
+ """
+ Checks if the object is an instance of MutableMapping.
+
+ :param obj: Object to be checked.
+ :return: Truth value of whether the object is an instance of
+ MutableMapping.
+ :rtype: bool
+ """
return isinstance(obj, MutableMapping)
def to_mapping(obj):
+
mapping = getattr(obj, GEO_INTERFACE_MARKER, None)
if mapping is not None:
diff --git a/geojson/utils.py b/geojson/utils.py
index 068b1c3..2639e45 100644
--- a/geojson/utils.py
+++ b/geojson/utils.py
@@ -1,7 +1,16 @@
"""Coordinate utility functions."""
+
def coords(obj):
- """Yield all coordinate coordinate tuples from a geometry or feature."""
+ """
+ Yields the coordinates from a Feature or Geometry.
+
+ :param obj: A geometry or feature to extract the coordinates from."
+ :type obj: Feature, Geometry
+ :return: A generator with coordinate tuples from the geometry or feature.
+ :rtype: generator
+ """
+
if isinstance(obj, (tuple, list)):
coordinates = obj
elif 'geometry' in obj:
@@ -15,8 +24,20 @@ def coords(obj):
for f in coords(e):
yield f
+
def map_coords(func, obj):
- """Return coordinates, mapped pair-wise using the provided function."""
+ """
+ Returns the coordinates from a Geometry after applying the provided
+ function to the tuples.
+
+ :param obj: A geometry or feature to extract the coordinates from.
+ :type obj: Point, LineString, MultiPoint, MultiLineString, Polygon,
+ MultiPolygon
+ :return: The result of applying the function to each coordinate array.
+ :rtype: list
+ :raises ValueError: if the provided object is not a Geometry.
+ """
+
if obj['type'] == 'Point':
coordinates = tuple(map(func, obj['coordinates']))
elif obj['type'] in ['LineString', 'MultiPoint']:
@@ -24,12 +45,12 @@ def map_coords(func, obj):
elif obj['type'] in ['MultiLineString', 'Polygon']:
coordinates = [[
tuple(map(func, c)) for c in curve]
- for curve in obj['coordinates']]
+ for curve in obj['coordinates']]
elif obj['type'] == 'MultiPolygon':
coordinates = [[[
tuple(map(func, c)) for c in curve]
- for curve in part]
- for part in obj['coordinates']]
+ for curve in part]
+ for part in obj['coordinates']]
else:
raise ValueError("Invalid geometry object %s" % repr(obj))
return {'type': obj['type'], 'coordinates': coordinates}
diff --git a/geojson/validation.py b/geojson/validation.py
new file mode 100644
index 0000000..25a4103
--- /dev/null
+++ b/geojson/validation.py
@@ -0,0 +1,97 @@
+import geojson
+
+
+def is_valid(obj):
+ """ IsValid provides validation for GeoJSON objects
+ All of error messages obtained from the offical site
+ http://geojson.org/geojson-spec.html
+
+ Args:
+ obj(geoJSON object): check validation
+
+ Returns:
+ dict of two paremeters 'valid' and 'message'.
+ In the case if geoJSON object is valid, returns
+ {valid: 'yes', message: ''}
+ If json objects is not valid, returns
+ {valid: 'no', message:'explanation, why this object is not valid'}
+
+ Example:
+ >> point = Point((10,20), (30,40))
+ >> IsValid(point)
+ >> {valid: 'yes', message: ''}
+ """
+
+ if not isinstance(obj, geojson.GeoJSON):
+ return output('this is not GeoJSON object')
+
+ if isinstance(obj, geojson.Point):
+ if len(obj['coordinates']) != 2:
+ return output('the "coordinates" member must be a single position')
+
+ if isinstance(obj, geojson.MultiPoint):
+ if checkListOfObjects(obj['coordinates'], lambda x: len(x) == 2):
+ return output(
+ 'the "coordinates" member must be an array of positions'
+ )
+
+ if isinstance(obj, geojson.LineString):
+ if len(obj['coordinates']) < 2:
+ return output('the "coordinates" member must be an array '
+ 'of two or more positions')
+
+ if isinstance(obj, geojson.MultiLineString):
+ coord = obj['coordinates']
+ if checkListOfObjects(coord, lambda x: len(x) >= 2):
+ return output('the "coordinates" member must be an array '
+ 'of LineString coordinate arrays')
+
+ if isinstance(obj, geojson.Polygon):
+ coord = obj['coordinates']
+ lengths = all([len(elem) >= 4 for elem in coord])
+ if lengths is False:
+ return output('LinearRing must contain with 4 or more positions')
+
+ isring = all([elem[0] == elem[-1] for elem in coord])
+ if isring is False:
+ return output('The first and last positions in LinearRing'
+ 'must be equivalent')
+
+ if isinstance(obj, geojson.MultiPolygon):
+ if checkListOfObjects(obj['coordinates'],
+ lambda x: len(x) >= 4 and x[0] == x[-1]):
+ return output('the "coordinates" member must be an array'
+ 'of Polygon coordinate arrays')
+
+ return output('')
+
+
+def checkListOfObjects(coord, pred):
+ """ This method provides checking list of geojson objects such Multipoint or
+ MultiLineString that each element of the list is valid geojson object.
+ This is helpful method for IsValid.
+
+ Args:
+ coord(list): List of coordinates
+ pred(function): Predicate to check validation of each
+ member in the coord
+
+ Returns:
+ True if list contains valid objects, False otherwise
+ """
+ return not isinstance(coord, list) or not all([pred(ls) for ls in coord])
+
+
+def output(message):
+ """ Output result for IsValid
+
+ Args:
+ message - If message is not empty,
+ object is not valid
+ """
+ result = {'valid': 'no', 'message': ''}
+ if message != '':
+ result['message'] = message
+ return result
+ result['valid'] = 'yes'
+ return result
diff --git a/setup.py b/setup.py
index 1ef9588..031562a 100644
--- a/setup.py
+++ b/setup.py
@@ -6,6 +6,7 @@ import sys
with io.open("README.rst") as readme_file:
readme_text = readme_file.read()
+
def test_suite():
import doctest
try:
@@ -19,21 +20,17 @@ def test_suite():
if sys.version_info[:2] not in [(2, 6), (2, 7)] and \
sys.version_info[:1] not in [(3, )]:
- sys.stderr.write("Sorry, only Python 2.6, 2.7, and 3.x are supported "
+ sys.stderr.write("Sorry, only Python 2.7, and 3.x are supported "
"at this time.\n")
exit(1)
-tests_require = []
-if sys.version_info[:2] == (2, 6):
- tests_require.append("unittest2")
-
# Get around this issue: http://bugs.python.org/issue15881
-# Appears to be a problem in older versions of Python 2.6 and 2.7
+# Appears to be a problem in older versions of Python 2.7
import multiprocessing # NOQA
setup(
name="geojson",
- version="1.0.9",
+ version="1.2.0",
description="Python bindings and utilities for GeoJSON",
license="BSD",
keywords="gis geography json",
@@ -48,7 +45,6 @@ setup(
package_data={"geojson": ["*.rst"]},
install_requires=["setuptools"],
test_suite="setup.test_suite",
- tests_require=tests_require,
classifiers=[
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
@@ -57,7 +53,6 @@ setup(
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 2",
- "Programming Language :: Python :: 2.6",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.2",
diff --git a/tests/test_base.py b/tests/test_base.py
index aabbfe7..a80355b 100644
--- a/tests/test_base.py
+++ b/tests/test_base.py
@@ -10,17 +10,26 @@ import geojson
class TypePropertyTestCase(unittest.TestCase):
def test_type_property(self):
- json_str = '{"type": "Feature", "geometry": null, "id": 1, "properties": {"type": "é"}}'
+ json_str = ('{"type": "Feature",'
+ ' "geometry": null,'
+ ' "id": 1,'
+ ' "properties": {"type": "é"}}')
geojson_obj = geojson.loads(json_str)
self.assertTrue(isinstance(geojson_obj, geojson.GeoJSON))
self.assertTrue("type" in geojson_obj.properties)
- json_str = '{"type": "Feature", "geometry": null, "id": 1, "properties": {"type": null}}'
+ json_str = ('{"type": "Feature",'
+ ' "geometry": null,'
+ ' "id": 1,'
+ ' "properties": {"type": null}}')
geojson_obj = geojson.loads(json_str)
self.assertTrue(isinstance(geojson_obj, geojson.GeoJSON))
self.assertTrue("type" in geojson_obj.properties)
- json_str = '{"type": "Feature", "geometry": null, "id": 1, "properties": {"type": "meow"}}'
+ json_str = ('{"type": "Feature",'
+ ' "geometry": null,'
+ ' "id": 1,'
+ ' "properties": {"type": "meow"}}')
geojson_obj = geojson.loads(json_str)
self.assertTrue(isinstance(geojson_obj, geojson.GeoJSON))
self.assertTrue("type" in geojson_obj.properties)
diff --git a/tests/test_coords.py b/tests/test_coords.py
index 5575158..3435786 100644
--- a/tests/test_coords.py
+++ b/tests/test_coords.py
@@ -20,7 +20,8 @@ class CoordsTestCase(unittest.TestCase):
def test_multipolygon(self):
g = geojson.MultiPolygon([
([(3.78, 9.28), (-130.91, 1.52), (35.12, 72.234), (3.78, 9.28)],),
- ([(23.18, -34.29), (-1.31, -4.61), (3.41, 77.91), (23.18, -34.29)],)])
+ ([(23.18, -34.29), (-1.31, -4.61),
+ (3.41, 77.91), (23.18, -34.29)],)])
itr = coords(g)
pairs = list(itr)
self.assertEqual(pairs[0], (3.78, 9.28))
@@ -41,7 +42,7 @@ class CoordsTestCase(unittest.TestCase):
def test_map_polygon(self):
g = geojson.Polygon([
- [(3.78, 9.28), (-130.91, 1.52), (35.12, 72.234), (3.78, 9.28)],])
+ [(3.78, 9.28), (-130.91, 1.52), (35.12, 72.234), (3.78, 9.28)], ])
result = map_coords(lambda x: x, g)
self.assertEqual(result['type'], 'Polygon')
self.assertEqual(result['coordinates'][0][0], (3.78, 9.28))
@@ -50,7 +51,8 @@ class CoordsTestCase(unittest.TestCase):
def test_map_multipolygon(self):
g = geojson.MultiPolygon([
([(3.78, 9.28), (-130.91, 1.52), (35.12, 72.234), (3.78, 9.28)],),
- ([(23.18, -34.29), (-1.31, -4.61), (3.41, 77.91), (23.18, -34.29)],)])
+ ([(23.18, -34.29), (-1.31, -4.61),
+ (3.41, 77.91), (23.18, -34.29)],)])
result = map_coords(lambda x: x, g)
self.assertEqual(result['type'], 'MultiPolygon')
self.assertEqual(result['coordinates'][0][0][0], (3.78, 9.28))
diff --git a/tests/test_crs.py b/tests/test_crs.py
index d6bcca5..cbcc106 100644
--- a/tests/test_crs.py
+++ b/tests/test_crs.py
@@ -7,24 +7,24 @@ class CRSTest(unittest.TestCase):
def setUp(self):
self.crs = geojson.crs.Named(
- properties = {
+ properties={
"name": "urn:ogc:def:crs:EPSG::3785",
}
)
def test_crs_repr(self):
actual = repr(self.crs)
- expected = '{"properties": {"name": "urn:ogc:def:crs:EPSG::3785"}, ' \
- '"type": "name"}'
+ expected = ('{"properties": {"name": "urn:ogc:def:crs:EPSG::3785"},'
+ ' "type": "name"}')
self.assertEqual(actual, expected)
def test_crs_encode(self):
actual = geojson.dumps(self.crs, sort_keys=True)
- expected = '{"properties": {"name": "urn:ogc:def:crs:EPSG::3785"}, ' \
- '"type": "name"}'
+ expected = ('{"properties": {"name": "urn:ogc:def:crs:EPSG::3785"},'
+ ' "type": "name"}')
self.assertEqual(actual, expected)
def test_crs_decode(self):
dumped = geojson.dumps(self.crs)
actual = geojson.loads(dumped)
- self.assertEqual(actual, self.crs)
\ No newline at end of file
+ self.assertEqual(actual, self.crs)
diff --git a/tests/test_features.py b/tests/test_features.py
index 4dbf51d..9f791fa 100644
--- a/tests/test_features.py
+++ b/tests/test_features.py
@@ -1,4 +1,4 @@
-from io import BytesIO
+from io import BytesIO # NOQA
import unittest
import geojson
@@ -10,18 +10,28 @@ class FeaturesTest(unittest.TestCase):
A dictionary can satisfy the protocol
"""
f = {
- 'type': 'Feature',
- 'id': '1',
- 'geometry': {'type': 'Point', 'coordinates': [53, -4]},
- 'properties': {'title': 'Dict 1'},
+ 'type': 'Feature',
+ 'id': '1',
+ 'geometry': {'type': 'Point', 'coordinates': [53, -4]},
+ 'properties': {'title': 'Dict 1'},
}
json = geojson.dumps(f, sort_keys=True)
- self.assertEqual(json, '{"geometry": {"coordinates": [53, -4], "type": "Point"}, "id": "1", "properties": {"title": "Dict 1"}, "type": "Feature"}')
+ self.assertEqual(json, '{"geometry":'
+ ' {"coordinates": [53, -4],'
+ ' "type": "Point"},'
+ ' "id": "1",'
+ ' "properties": {"title": "Dict 1"},'
+ ' "type": "Feature"}')
o = geojson.loads(json)
output = geojson.dumps(o, sort_keys=True)
- self.assertEqual(output, '{"geometry": {"coordinates": [53, -4], "type": "Point"}, "id": "1", "properties": {"title": "Dict 1"}, "type": "Feature"}')
+ self.assertEqual(output, '{"geometry":'
+ ' {"coordinates": [53, -4],'
+ ' "type": "Point"},'
+ ' "id": "1",'
+ ' "properties": {"title": "Dict 1"},'
+ ' "type": "Feature"}')
def test_unicode_properties(self):
with open("tests/data.geojson") as file_:
@@ -45,22 +55,40 @@ class FeaturesTest(unittest.TestCase):
self.assertEqual(feature.id, '1')
self.assertEqual(feature.properties['title'], 'Feature 1')
self.assertEqual(feature.properties['summary'], 'The first feature')
- self.assertEqual(feature.properties['link'], 'http://example.org/features/1')
- self.assertEqual(geojson.dumps(feature.geometry, sort_keys=True), '{"coordinates": [53, -4], "type": "Point"}')
+ self.assertEqual(feature.properties['link'],
+ 'http://example.org/features/1')
+ self.assertEqual(geojson.dumps(feature.geometry, sort_keys=True),
+ '{"coordinates": [53, -4], "type": "Point"}')
# Encoding
- self.assertEqual(geojson.dumps(feature, sort_keys=True), '{"geometry": {"coordinates": [53, -4], "type": "Point"}, "id": "1", "properties": {"link": "http://example.org/features/1", "summary": "The first feature", "title": "Feature 1"}, "type": "Feature"}')
+ json = ('{"geometry": {"coordinates": [53, -4],'
+ ' "type": "Point"},'
+ ' "id": "1",'
+ ' "properties":'
+ ' {"link": "http://example.org/features/1",'
+ ' "summary": "The first feature",'
+ ' "title": "Feature 1"},'
+ ' "type": "Feature"}')
+ self.assertEqual(geojson.dumps(feature, sort_keys=True), json)
# Decoding
factory = geojson.examples.createSimpleWebFeature
- json = '{"geometry": {"type": "Point", "coordinates": [53, -4]}, "id": "1", "properties": {"summary": "The first feature", "link": "http://example.org/features/1", "title": "Feature 1"}}'
+ json = ('{"geometry": {"type": "Point",'
+ ' "coordinates": [53, -4]},'
+ ' "id": "1",'
+ ' "properties": {"summary": "The first feature",'
+ ' "link": "http://example.org/features/1",'
+ ' "title": "Feature 1"}}')
feature = geojson.loads(json, object_hook=factory, encoding="utf-8")
- self.assertEqual(repr(type(feature)), "<class 'geojson.examples.SimpleWebFeature'>")
+ self.assertEqual(repr(type(feature)),
+ "<class 'geojson.examples.SimpleWebFeature'>")
self.assertEqual(feature.id, '1')
self.assertEqual(feature.properties['title'], 'Feature 1')
self.assertEqual(feature.properties['summary'], 'The first feature')
- self.assertEqual(feature.properties['link'], 'http://example.org/features/1')
- self.assertEqual(geojson.dumps(feature.geometry, sort_keys=True), '{"coordinates": [53, -4], "type": "Point"}')
+ self.assertEqual(feature.properties['link'],
+ 'http://example.org/features/1')
+ self.assertEqual(geojson.dumps(feature.geometry, sort_keys=True),
+ '{"coordinates": [53, -4], "type": "Point"}')
def test_geo_interface(self):
class Thingy(object):
@@ -72,8 +100,17 @@ class FeaturesTest(unittest.TestCase):
@property
def __geo_interface__(self):
- return {"id": self.id, "properties": {"title": self.title}, "geometry": {"type": "Point", "coordinates": (self.x, self.y)}}
+ return ({"id": self.id,
+ "properties": {"title": self.title},
+ "geometry": {"type": "Point",
+ "coordinates": (self.x, self.y)}})
ob = Thingy('1', 'thingy one', -106, 40)
- self.assertEqual(geojson.dumps(ob.__geo_interface__['geometry'], sort_keys=True), '{"coordinates": [-106, 40], "type": "Point"}')
- self.assertEqual(geojson.dumps(ob, sort_keys=True), '{"geometry": {"coordinates": [-106, 40], "type": "Point"}, "id": "1", "properties": {"title": "thingy one"}}')
+ self.assertEqual(geojson.dumps(ob.__geo_interface__['geometry'],
+ sort_keys=True),
+ '{"coordinates": [-106, 40], "type": "Point"}')
+ self.assertEqual(geojson.dumps(ob, sort_keys=True),
+ ('{"geometry": {"coordinates": [-106, 40],'
+ ' "type": "Point"},'
+ ' "id": "1",'
+ ' "properties": {"title": "thingy one"}}'))
diff --git a/tests/test_geo_interface.py b/tests/test_geo_interface.py
index 0eafe32..7e7cb54 100644
--- a/tests/test_geo_interface.py
+++ b/tests/test_geo_interface.py
@@ -46,7 +46,6 @@ class EncodingDecodingTest(unittest.TestCase):
'type': "Point",
'coordinates': self.latlng,
},
- 'id': None,
'type': "Feature",
'properties': {
'name': self.name,
@@ -72,28 +71,18 @@ class EncodingDecodingTest(unittest.TestCase):
self.restaurant1 = Restaurant1(self.name, self.latlng)
self.restaurant2 = Restaurant2(self.name, self.latlng)
- self.restaurant_str = (
- '{'
- '"coordinates": [-54, 4], '
- '"type": "Point"'
- '}'
- )
+ self.restaurant_str = ('{"coordinates": [-54, 4],'
+ ' "type": "Point"}')
self.restaurant_feature1 = RestaurantFeature1(self.name, self.latlng)
self.restaurant_feature2 = RestaurantFeature2(self.name, self.latlng)
- self.restaurant_feature_str = (
- '{'
- '"geometry": {'
- '"coordinates": [-54, 4], '
- '"type": "Point"'
- '}, '
- '"id": null, '
- '"properties": {"name": "In N Out Burger"}, '
- '"type": "Feature"'
- '}'
- )
-
+ self.restaurant_feature_str = ('{"geometry":'
+ ' {"coordinates": [-54, 4],'
+ ' "type": "Point"},'
+ ' "properties":'
+ ' {"name": "In N Out Burger"},'
+ ' "type": "Feature"}')
def test_encode(self):
"""
diff --git a/tests/test_validation.py b/tests/test_validation.py
new file mode 100644
index 0000000..4086d52
--- /dev/null
+++ b/tests/test_validation.py
@@ -0,0 +1,107 @@
+# -*- coding: utf-8 -*-
+"""
+Tests for geojson/validation
+"""
+
+import unittest
+
+import geojson
+
+is_valid = geojson.is_valid
+YES = 'yes'
+NO = 'no'
+
+
+class TestValidationGeoJSONObject(unittest.TestCase):
+
+ def test_invalid_jsonobject(self):
+ obj = [1, 2, 3]
+ self.assertEqual(is_valid(obj)['valid'], NO)
+
+ def test_valid_jsonobject(self):
+ point = geojson.Point((-10.52, 2.33))
+ self.assertEqual(is_valid(point)['valid'], YES)
+
+
+class TestValidationPoint(unittest.TestCase):
+
+ def test_invalid_point(self):
+ point = geojson.Point((10, 20, 30))
+ self.assertEqual(is_valid(point)['valid'], NO)
+
+ def test_valid_point(self):
+ point = geojson.Point((-3.68, 40.41))
+ self.assertEqual(is_valid(point)['valid'], YES)
+
+
+class TestValidationMultipoint(unittest.TestCase):
+
+ def test_invalid_multipoint(self):
+ mpoint = geojson.MultiPoint(
+ [(3.5887, 10.44558), (2.5555, 3.887), (2.44, 3.44, 2.555)])
+ self.assertEqual(is_valid(mpoint)['valid'], NO)
+
+ def test_valid_multipoint(self):
+ mpoint = geojson.MultiPoint([(10, 20), (30, 40)])
+ self.assertEqual(is_valid(mpoint)['valid'], YES)
+
+
+class TestValidationLineString(unittest.TestCase):
+
+ def test_invalid_linestring(self):
+ ls = geojson.LineString([(8.919, 44.4074)])
+ self.assertEqual(is_valid(ls)['valid'], NO)
+
+ def test_valid_linestring(self):
+ ls = geojson.LineString([(10, 5), (4, 3)])
+ self.assertEqual(is_valid(ls)['valid'], YES)
+
+
+class TestValidationMultiLineString(unittest.TestCase):
+
+ def test_invalid_multilinestring(self):
+ mls = geojson.MultiLineString([[(10, 5), (20, 1)], []])
+ self.assertEqual(is_valid(mls)['valid'], NO)
+
+ def test_valid_multilinestring(self):
+ ls1 = [(3.75, 9.25), (-130.95, 1.52)]
+ ls2 = [(23.15, -34.25), (-1.35, -4.65), (3.45, 77.95)]
+ mls = geojson.MultiLineString([ls1, ls2])
+ self.assertEqual(is_valid(mls)['valid'], YES)
+
+
+class TestValidationPolygon(unittest.TestCase):
+
+ def test_invalid_polygon(self):
+ poly1 = geojson.Polygon(
+ [[(2.38, 57.322), (23.194, -20.28), (-120.43, 19.15)]])
+ self.assertEqual(is_valid(poly1)['valid'], NO)
+ poly2 = geojson.Polygon(
+ [[(2.38, 57.322), (23.194, -20.28),
+ (-120.43, 19.15), (2.38, 57.323)]])
+ self.assertEqual(is_valid(poly2)['valid'], NO)
+
+ def test_valid_polygon(self):
+ poly = geojson.Polygon(
+ [[(2.38, 57.322), (23.194, -20.28),
+ (-120.43, 19.15), (2.38, 57.322)]])
+ self.assertEqual(is_valid(poly)['valid'], YES)
+
+
+class TestValidationMultiPolygon(unittest.TestCase):
+
+ def test_invalid_multipolygon(self):
+ poly1 = [(2.38, 57.322), (23.194, -20.28),
+ (-120.43, 19.15), (25.44, -17.91)]
+ poly2 = [(2.38, 57.322), (23.194, -20.28),
+ (-120.43, 19.15), (2.38, 57.322)]
+ multipoly = geojson.MultiPolygon([poly1, poly2])
+ self.assertEqual(is_valid(multipoly)['valid'], NO)
+
+ def test_valid_multipolygon(self):
+ poly1 = [(2.38, 57.322), (23.194, -20.28),
+ (-120.43, 19.15), (2.38, 57.322)]
+ poly2 = [(-5.34, 3.71), (28.74, 31.44), (28.55, 19.10), (-5.34, 3.71)]
+ poly3 = [(3.14, 23.17), (51.34, 27.14), (22, -18.11), (3.14, 23.17)]
+ multipoly = geojson.MultiPolygon([poly1, poly2, poly3])
+ self.assertEqual(is_valid(multipoly)['valid'], YES)
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/python-geojson.git
More information about the Pkg-grass-devel
mailing list