[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