pax_global_header00006660000000000000000000000064126067624430014524gustar00rootroot0000000000000052 comment=be57103b9e020948d5209439ad411df8a07b9c75 python-geojson-1.3.1/000077500000000000000000000000001260676244300145115ustar00rootroot00000000000000python-geojson-1.3.1/.gitignore000066400000000000000000000000151260676244300164750ustar00rootroot00000000000000build/ dist/ python-geojson-1.3.1/.travis.yml000066400000000000000000000004611260676244300166230ustar00rootroot00000000000000language: "python" sudo: false python: - "2.7" - "3.3" - "3.4" - "3.5" - "pypy" - "pypy3" install: - pip install flake8 - pip install codecov before_script: flake8 . script: - coverage run --branch --source=geojson setup.py test - coverage xml after_success: - codecov python-geojson-1.3.1/CHANGELOG.rst000066400000000000000000000051501260676244300165330ustar00rootroot00000000000000Changes ======= 1.3.1 (2015-10-12) ------------------ - Fix validation bug for MultiPolygons - https://github.com/frewsxcv/python-geojson/pull/63 1.3.0 (2015-08-11) ------------------ - Add utility to generate geometries with random data - https://github.com/frewsxcv/python-geojson/pull/60 1.2.2 (2015-07-13) ------------------ - Fix tests by including test file into build - https://github.com/frewsxcv/python-geojson/issues/61 - Build universal wheels - https://packaging.python.org/en/latest/distributing.html#universal-wheels 1.2.1 (2015-06-25) ------------------ - Encode long types correctly with Python 2.x - https://github.com/frewsxcv/python-geojson/pull/57 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) ------------------ - Fix bug where unicode/non-string properties with a 'type' key cause a crash 1.0.8 (2014-09-30) ------------------ - Fix bug where unicode keys don't get decoded properly - Add coords and map_coords utilities 1.0.7 (2014-04-19) ------------------ - Compatibility with Python 3.4 - Remove nose dependency - Convert doctests to unittests - Run tests using runtests.sh 1.0.6 (2014-01-18) ------------------ - Update README.rst documentation (fix errors, add examples) - Allow simplejson to be used again 1.0.5 (2013-11-16) ------------------ - Remove warning about RSTs in test/ upon install 1.0.4 (2013-11-16) ------------------ - Flake8 everything - Transition all documentation to reStructuredText - Start using Travis CI - Support Python 3 - Fix broken testcase when run using Python 2.6 1.0.3 (2009-11-25) ------------------ - Fixed #186 - Internal code simplification 1.0.2 (2009-11-24) ------------------ - Use nose test framework instead of rolling our own. 1.0.1 (2008-12-19) ------------------ - Handle features with null geometries (#174). 1.0 (2008-08-01) ---------------- - Final 1.0 release. - Rename PyGFPEncoder to GeoJSONEncoder and expose it from the geojson module. 1.0rc1 (2008-07-11) ------------------- - Release candidate. 1.0b1 (2008-07-02) ------------------ - Rename encoding module to codec. 1.0a4 (2008-04-27) ------------------ - Get in step with GeoJSON draft version 6. - Made all code work with Python 2.4.3, 2.5.1, will test with all variations. (see tests/rundoctests.dist) - Made tests use ELLIPSIS to avoid output transmogification due to floating point representation. python-geojson-1.3.1/LICENSE.rst000066400000000000000000000027271260676244300163350ustar00rootroot00000000000000Copyright © 2014, contributors of python-geojson All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - Neither the name of the python-geojson nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS OF PYTHON-GEOJSON BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. python-geojson-1.3.1/MANIFEST.in000066400000000000000000000000731260676244300162470ustar00rootroot00000000000000include *.rst recursive-include tests *.txt *.py *.geojson python-geojson-1.3.1/README.rst000066400000000000000000000273451260676244300162130ustar00rootroot00000000000000python-geojson ============== .. image:: https://img.shields.io/travis/frewsxcv/python-geojson.svg :target: https://travis-ci.org/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: - Functions for encoding and decoding GeoJSON_ formatted data - Classes for all GeoJSON Objects - An implementation of the Python `__geo_interface__ Specification`_ **Table of Contents** .. contents:: :backlinks: none :local: Installation ------------ python-geojson is compatible with Python 2.6, 2.7, 3.2, 3.3, and 3.4. It is listed on `PyPi as 'geojson'`_. The recommended way to install is via pip_: .. code:: pip install geojson .. _PyPi as 'geojson': https://pypi.python.org/pypi/geojson/ .. _pip: http://www.pip-installer.org GeoJSON Objects --------------- This library implements all the `GeoJSON Objects`_ described in `The GeoJSON Format Specification`_. .. _GeoJSON Objects: http://www.geojson.org/geojson-spec.html#geojson-objects Point ~~~~~ .. code:: python >>> from geojson import Point >>> Point((-115.81, 37.24)) # doctest: +ELLIPSIS {"coordinates": [-115.8..., 37.2...], "type": "Point"} Visualize the result of the example above `here `__. General information about Point can be found in `Section 2.1.2`_ and `Appendix A: Point`_ within `The GeoJSON Format Specification`_. .. _Section 2.1.2: http://www.geojson.org/geojson-spec.html#point .. _Appendix A\: Point: http://www.geojson.org/geojson-spec.html#id2 MultiPoint ~~~~~~~~~~ .. code:: python >>> from geojson import MultiPoint >>> MultiPoint([(-155.52, 19.61), (-156.22, 20.74), (-157.97, 21.46)]) # doctest: +ELLIPSIS {"coordinates": [[-155.5..., 19.6...], [-156.2..., 20.7...], [-157.9..., 21.4...]], "type": "MultiPoint"} Visualize the result of the example above `here `__. General information about MultiPoint can be found in `Section 2.1.3`_ and `Appendix A: MultiPoint`_ within `The GeoJSON Format Specification`_. .. _Section 2.1.3: http://www.geojson.org/geojson-spec.html#multipoint .. _Appendix A\: MultiPoint: http://www.geojson.org/geojson-spec.html#id5 LineString ~~~~~~~~~~ .. code:: python >>> from geojson import LineString >>> LineString([(8.919, 44.4074), (8.923, 44.4075)]) # doctest: +ELLIPSIS {"coordinates": [[8.91..., 44.407...], [8.92..., 44.407...]], "type": "LineString"} Visualize the result of the example above `here `__. General information about LineString can be found in `Section 2.1.4`_ and `Appendix A: LineString`_ within `The GeoJSON Format Specification`_. .. _Section 2.1.4: http://www.geojson.org/geojson-spec.html#linestring .. _Appendix A\: LineString: http://www.geojson.org/geojson-spec.html#id3 MultiLineString ~~~~~~~~~~~~~~~ .. code:: python >>> from geojson import MultiLineString >>> MultiLineString([ ... [(3.75, 9.25), (-130.95, 1.52)], ... [(23.15, -34.25), (-1.35, -4.65), (3.45, 77.95)] ... ]) # doctest: +ELLIPSIS {"coordinates": [[[3.7..., 9.2...], [-130.9..., 1.52...]], [[23.1..., -34.2...], [-1.3..., -4.6...], [3.4..., 77.9...]]], "type": "MultiLineString"} Visualize the result of the example above `here `__. General information about MultiLineString can be found in `Section 2.1.5`_ and `Appendix A: MultiLineString`_ within `The GeoJSON Format Specification`_. .. _Section 2.1.5: http://www.geojson.org/geojson-spec.html#multilinestring .. _Appendix A\: MultiLineString: http://www.geojson.org/geojson-spec.html#id6 Polygon ~~~~~~~ .. code:: python >>> from geojson import Polygon >>> # no hole within polygon >>> Polygon([[(2.38, 57.322), (23.194, -20.28), (-120.43, 19.15), (2.38, 57.322)]]) # doctest: +ELLIPSIS {"coordinates": [[[2.3..., 57.32...], [23.19..., -20.2...], [-120.4..., 19.1...]]], "type": "Polygon"} >>> # hole within polygon >>> Polygon([ ... [(2.38, 57.322), (23.194, -20.28), (-120.43, 19.15), (2.38, 57.322)], ... [(-5.21, 23.51), (15.21, -10.81), (-20.51, 1.51), (-5.21, 23.51)] ... ]) # doctest: +ELLIPSIS {"coordinates": [[[2.3..., 57.32...], [23.19..., -20.2...], [-120.4..., 19.1...]], [[-5.2..., 23.5...], [15.2..., -10.8...], [-20.5..., 1.5...], [-5.2..., 23.5...]]], "type": "Polygon"} Visualize the results of the example above `here `__. General information about Polygon can be found in `Section 2.1.6`_ and `Appendix A: Polygon`_ within `The GeoJSON Format Specification`_. .. _Section 2.1.6: http://www.geojson.org/geojson-spec.html#polygon .. _Appendix A\: Polygon: http://www.geojson.org/geojson-spec.html#id4 MultiPolygon ~~~~~~~~~~~~ .. code:: python >>> from geojson import MultiPolygon >>> 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)],) ... ]) # doctest: +ELLIPSIS {"coordinates": [[[[3.7..., 9.2...], [-130.9..., 1.5...], [35.1..., 72.23...]]], [[[23.1..., -34.2...], [-1.3..., -4.6...], [3.4..., 77.9...]]]], "type": "MultiPolygon"} Visualize the result of the example above `here `__. General information about MultiPolygon can be found in `Section 2.1.7`_ and `Appendix A: MultiPolygon`_ within `The GeoJSON Format Specification`_. .. _Section 2.1.7: http://www.geojson.org/geojson-spec.html#multipolygon .. _Appendix A\: MultiPolygon: http://www.geojson.org/geojson-spec.html#id7 GeometryCollection ~~~~~~~~~~~~~~~~~~ .. code:: python >>> from geojson import GeometryCollection, Point, LineString >>> my_point = Point((23.532, -63.12)) >>> my_line = LineString([(-152.62, 51.21), (5.21, 10.69)]) >>> GeometryCollection([my_point, my_line]) # doctest: +ELLIPSIS {"geometries": [{"coordinates": [23.53..., -63.1...], "type": "Point"}, {"coordinates": [[-152.6..., 51.2...], [5.2..., 10.6...]], "type": "LineString"}], "type": "GeometryCollection"} Visualize the result of the example above `here `__. General information about GeometryCollection can be found in `Section 2.1.8`_ and `Appendix A: GeometryCollection`_ within `The GeoJSON Format Specification`_. .. _Section 2.1.8: http://www.geojson.org/geojson-spec.html#geometry-collection .. _Appendix A\: GeometryCollection: http://www.geojson.org/geojson-spec.html#geometrycollection Feature ~~~~~~~ .. code:: python >>> from geojson import Feature, Point >>> my_point = Point((-3.68, 40.41)) >>> Feature(geometry=my_point) # doctest: +ELLIPSIS {"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"}, "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"} Visualize the results of the examples above `here `__. General information about Feature can be found in `Section 2.2`_ within `The GeoJSON Format Specification`_. .. _Section 2.2: http://geojson.org/geojson-spec.html#feature-objects FeatureCollection ~~~~~~~~~~~~~~~~~ .. code:: python >>> from geojson import Feature, Point, FeatureCollection >>> my_feature = Feature(geometry=Point((1.6432, -19.123))) >>> 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"}, "properties": {}, "type": "Feature"}, {"geometry": {"coordinates": [-80.23..., -22.53...], "type": "Point"}, "properties": {}, "type": "Feature"}], "type": "FeatureCollection"} Visualize the result of the example above `here `__. General information about FeatureCollection can be found in `Section 2.3`_ within `The GeoJSON Format Specification`_. .. _Section 2.3: http://geojson.org/geojson-spec.html#feature-collection-objects GeoJSON encoding/decoding ------------------------- All of the GeoJSON Objects implemented in this library can be encoded and decoded into raw GeoJSON with the ``geojson.dump``, ``geojson.dumps``, ``geojson.load``, and ``geojson.loads`` functions. .. code:: python >>> import geojson >>> my_point = geojson.Point((43.24, -1.532)) >>> my_point # doctest: +ELLIPSIS {"coordinates": [43.2..., -1.53...], "type": "Point"} >>> dump = geojson.dumps(my_point, sort_keys=True) >>> dump # doctest: +ELLIPSIS '{"coordinates": [43.2..., -1.53...], "type": "Point"}' >>> geojson.loads(dump) # doctest: +ELLIPSIS {"coordinates": [43.2..., -1.53...], "type": "Point"} Custom classes ~~~~~~~~~~~~~~ This encoding/decoding functionality shown in the previous can be extended to custom classes using the interface described by the `__geo_interface__ Specification`_. .. code:: python >>> import geojson >>> class MyPoint(): ... def __init__(self, x, y): ... self.x = x ... self.y = y ... ... @property ... def __geo_interface__(self): ... return {'type': 'Point', 'coordinates': (self.x, self.y)} >>> point_instance = MyPoint(52.235, -19.234) >>> geojson.dumps(point_instance, sort_keys=True) # doctest: +ELLIPSIS '{"coordinates": [52.23..., -19.23...], "type": "Point"}' Helpful utilities ----------------- coords ~~~~~~ :code:`geojson.utils.coords` yields all coordinate tuples from a geometry or feature object. .. code:: python >>> import geojson >>> my_line = LineString([(-152.62, 51.21), (5.21, 10.69)]) >>> my_feature = geojson.Feature(geometry=my_line) >>> list(geojson.utils.coords(my_feature)) # doctest: +ELLIPSIS [(-152.62..., 51.21...), (5.21..., 10.69...)] map_coords ~~~~~~~~~~ :code:`geojson.utils.map_coords` maps a function over all coordinate tuples and returns a geometry of the same type. Useful for translating a geometry in space or flipping coordinate order. .. code:: python >>> import geojson >>> new_point = geojson.utils.map_coords(lambda x: x/2, geojson.Point((-115.81, 37.24))) >>> 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' generate_random ~~~~~~~~~~~~~~~ :code:`geojson.utils.generate_random` yields a geometry type with random data .. code:: python >>> import geojson >>> geojson.utils.generate_random("LineString") # doctest: +ELLIPSIS {"coordinates": [...], "type": "LineString"} Development ----------- To build this project, run :code:`python setup.py build`. To run the unit tests, run :code:`python setup.py test`. Credits ------- * Sean Gillies * Matthew Russell * Corey Farwell * Blake Grotewold * Zsolt Ero * Sergey Romanov .. _GeoJSON: http://geojson.org/ .. _The GeoJSON Format Specification: http://www.geojson.org/geojson-spec.html .. _\_\_geo\_interface\_\_ Specification: https://gist.github.com/sgillies/2217756 python-geojson-1.3.1/geojson/000077500000000000000000000000001260676244300161555ustar00rootroot00000000000000python-geojson-1.3.1/geojson/__init__.py000066400000000000000000000013271260676244300202710ustar00rootroot00000000000000from geojson.codec import dump, dumps, load, loads, GeoJSONEncoder from geojson.utils import coords, map_coords from geojson.geometry import Point, LineString, Polygon 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]) python-geojson-1.3.1/geojson/base.py000066400000000000000000000101431260676244300174400ustar00rootroot00000000000000from __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) def __repr__(self): return geojson.dumps(self, sort_keys=True) __str__ = __repr__ 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 def __geo_interface__(self): if self.type != "GeoJSON": return self @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() elif isinstance(ob, GeoJSON): instance = ob else: mapping = to_mapping(ob) d = {} for k in mapping: d[k] = mapping[k] try: type_ = d.pop("type") try: type_ = str(type_) except UnicodeEncodeError: # If the type contains non-ascii characters, we can assume # it's not a valid GeoJSON type raise AttributeError( "{0} is not a GeoJSON type").format(type_) geojson_factory = getattr(geojson.factory, type_) if not issubclass(geojson_factory, GeoJSON): raise TypeError("""\ Not a valid GeoJSON type: %r (geojson_factory: %r, cls: %r) """ % (type_, geojson_factory, cls)) instance = geojson_factory(**d) except (AttributeError, KeyError) as invalid: if strict: msg = "Cannot coerce %r into a valid GeoJSON structure: %s" msg %= (ob, invalid) raise ValueError(msg) instance = ob return instance python-geojson-1.3.1/geojson/codec.py000066400000000000000000000031551260676244300176100ustar00rootroot00000000000000try: import simplejson as json except ImportError: import json import geojson import geojson.factory from geojson.mapping import to_mapping class GeoJSONEncoder(json.JSONEncoder): def default(self, obj): return geojson.factory.GeoJSON.to_instance(obj) # Wrap the functions from json, providing encoder, decoders, and # object creation hooks. # Here the defaults are set to only permit valid JSON as per RFC 4267 def _enforce_strict_numbers(obj): if isinstance(obj, (int, float)): raise ValueError("Number %r is not JSON compliant" % obj) def dump(obj, fp, cls=GeoJSONEncoder, allow_nan=False, **kwargs): return json.dump(to_mapping(obj), fp, cls=cls, allow_nan=allow_nan, **kwargs) def dumps(obj, cls=GeoJSONEncoder, allow_nan=False, **kwargs): return json.dumps(to_mapping(obj), cls=cls, allow_nan=allow_nan, **kwargs) def load(fp, cls=json.JSONDecoder, parse_constant=_enforce_strict_numbers, object_hook=geojson.base.GeoJSON.to_instance, **kwargs): return json.load(fp, cls=cls, object_hook=object_hook, parse_constant=parse_constant, **kwargs) def loads(s, cls=json.JSONDecoder, parse_constant=_enforce_strict_numbers, object_hook=geojson.base.GeoJSON.to_instance, **kwargs): return json.loads(s, cls=cls, object_hook=object_hook, parse_constant=parse_constant, **kwargs) # Backwards compatibility PyGFPEncoder = GeoJSONEncoder python-geojson-1.3.1/geojson/crs.py000066400000000000000000000016141260676244300173200ustar00rootroot00000000000000from geojson.base import GeoJSON class CoordinateReferenceSystem(GeoJSON): """ Represents a CRS. """ def __init__(self, properties=None, **extra): super(CoordinateReferenceSystem, self).__init__(**extra) self["properties"] = properties or {} class Named(CoordinateReferenceSystem): """ Represents a named CRS. """ def __init__(self, properties=None, **extra): super(Named, self).__init__(properties=properties, **extra) self["type"] = "name" def __repr__(self): return super(Named, self).__repr__() class Linked(CoordinateReferenceSystem): """ Represents a linked CRS. """ def __init__(self, properties=None, **extra): super(Linked, self).__init__(properties=properties, **extra) self["type"] = "link" class Default(object): """GeoJSON default, long/lat WGS84, is not serialized.""" python-geojson-1.3.1/geojson/examples.py000066400000000000000000000043141260676244300203470ustar00rootroot00000000000000 class SimpleWebFeature(object): """ A simple, Atom-ish, single geometry (WGS84) GIS feature. """ def __init__(self, id=None, geometry=None, title=None, summary=None, link=None): """ 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 = {} self.properties['title'] = title self.properties['summary'] = summary self.properties['link'] = link def as_dict(self): return { "type": "Feature", "id": self.id, "properties": self.properties, "geometry": self.geometry } __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 match a Python feature object, simply return o. This function serves as a 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'] p = o['properties'] return SimpleWebFeature(str(id), { 'type': str(g.get('type')), 'coordinates': g.get('coordinates', [])}, title=p.get('title'), summary=p.get('summary'), link=str(p.get('link'))) except (KeyError, TypeError): pass return o python-geojson-1.3.1/geojson/factory.py000066400000000000000000000010171260676244300201750ustar00rootroot00000000000000from geojson.geometry import Point, LineString, Polygon 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.crs import Named, Linked __all__ = ([Point, LineString, Polygon] + [MultiLineString, MultiPoint, MultiPolygon] + [GeometryCollection] + [Feature, FeatureCollection] + [GeoJSON]) name = Named link = Linked python-geojson-1.3.1/geojson/feature.py000066400000000000000000000027111260676244300201630ustar00rootroot00000000000000""" SimpleWebFeature is a working example of a class that satisfies the Python geo interface. """ from geojson.base import GeoJSON class Feature(GeoJSON): """ 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) 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): """ 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 python-geojson-1.3.1/geojson/geometry.py000066400000000000000000000034301260676244300203620ustar00rootroot00000000000000import sys from decimal import Decimal from geojson.base import GeoJSON class Geometry(GeoJSON): """ Represents an abstract base class for a WGS84 geometry. """ if sys.version_info[0] == 3: # Python 3.x has no long type __JSON_compliant_types = (float, int, Decimal) else: __JSON_compliant_types = (float, int, Decimal, long) # noqa 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"]) if crs: self["crs"] = self.to_instance(crs, strict=True) @classmethod def clean_coordinates(cls, coords): for coord in coords: if isinstance(coord, (list, tuple)): cls.clean_coordinates(coord) elif not isinstance(coord, cls.__JSON_compliant_types): raise ValueError("%r is not JSON compliant number" % coord) class GeometryCollection(GeoJSON): """ Represents an abstract base class for collections of WGS84 geometries. """ def __init__(self, geometries=None, **extra): super(GeometryCollection, self).__init__(**extra) self["geometries"] = geometries or [] # Marker classes. class Point(Geometry): pass class MultiPoint(Geometry): pass class LineString(MultiPoint): pass class MultiLineString(Geometry): pass class Polygon(Geometry): pass class MultiPolygon(Geometry): pass class Default(object): """ GeoJSON default object. """ python-geojson-1.3.1/geojson/mapping.py000066400000000000000000000013771260676244300201720ustar00rootroot00000000000000from collections import MutableMapping try: import simplejson as json except ImportError: import json import geojson mapping_base = MutableMapping 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: return mapping if is_mapping(obj): return obj if isinstance(obj, geojson.GeoJSON): return dict(obj) return json.loads(json.dumps(obj)) python-geojson-1.3.1/geojson/utils.py000066400000000000000000000111061260676244300176660ustar00rootroot00000000000000"""Coordinate utility functions.""" def coords(obj): """ 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: coordinates = obj['geometry']['coordinates'] else: coordinates = obj.get('coordinates', obj) for e in coordinates: if isinstance(e, (float, int)): yield tuple(coordinates) break for f in coords(e): yield f def map_coords(func, obj): """ 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']: coordinates = [tuple(map(func, c)) for c in obj['coordinates']] elif obj['type'] in ['MultiLineString', 'Polygon']: coordinates = [[ tuple(map(func, c)) for c in curve] 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']] else: raise ValueError("Invalid geometry object %s" % repr(obj)) return {'type': obj['type'], 'coordinates': coordinates} def generate_random(featureType, numberVertices=3, boundingBox=[-180.0, -90.0, 180.0, 90.0]): """ Generates random geojson features depending on the parameters passed through. :param featureType: A geometry type :type string: Point, LineString, Polygon :param numberVertices: The number vertices that a linestring or polygon will have :type int: defaults to 3 :param boundingBox: A bounding box in which features will be restricted to :type list: defaults to the world - [-180.0, -90.0, 180.0, 90.0] :return: The resulting random geojson object or geometry collection. :rtype: object :raises ValueError: if there is no featureType provided. """ from geojson import Point, LineString, Polygon import random import math lonMin = boundingBox[0] lonMax = boundingBox[2] def randomLon(): return random.uniform(lonMin, lonMax) latMin = boundingBox[1] latMax = boundingBox[3] def randomLat(): return random.uniform(latMin, latMax) def createPoint(): return Point((randomLon(), randomLat())) def createLine(): coords = [] for i in range(0, numberVertices): coords.append((randomLon(), randomLat())) return LineString(coords) def createPoly(): aveRadius = 60 ctrX = 0.1 ctrY = 0.2 irregularity = clip(0.1, 0, 1) * 2 * math.pi / numberVertices spikeyness = clip(0.5, 0, 1) * aveRadius angleSteps = [] lower = (2 * math.pi / numberVertices) - irregularity upper = (2 * math.pi / numberVertices) + irregularity sum = 0 for i in range(numberVertices): tmp = random.uniform(lower, upper) angleSteps.append(tmp) sum = sum + tmp k = sum / (2 * math.pi) for i in range(numberVertices): angleSteps[i] = angleSteps[i] / k points = [] angle = random.uniform(0, 2 * math.pi) for i in range(numberVertices): r_i = clip(random.gauss(aveRadius, spikeyness), 0, 2 * aveRadius) x = ctrX + r_i * math.cos(angle) y = ctrY + r_i * math.sin(angle) points.append((int(x), int(y))) angle = angle + angleSteps[i] firstVal = points[0] points.append(firstVal) return Polygon([points]) def clip(x, min, max): if(min > max): return x elif(x < min): return min elif(x > max): return max else: return x if featureType == 'Point': return createPoint() if featureType == 'LineString': return createLine() if featureType == 'Polygon': return createPoly() python-geojson-1.3.1/geojson/validation.py000066400000000000000000000066351260676244300206730ustar00rootroot00000000000000import 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: is_polygon(x)): return output('the "coordinates" member must be an array' 'of Polygon coordinate arrays') return output('') def is_polygon(coords): lengths = all(len(elem) >= 4 for elem in coords) isring = all(elem[0] == elem[-1] for elem in coords) return lengths and isring 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 python-geojson-1.3.1/setup.cfg000066400000000000000000000000341260676244300163270ustar00rootroot00000000000000[bdist_wheel] universal = 1 python-geojson-1.3.1/setup.py000066400000000000000000000036601260676244300162300ustar00rootroot00000000000000import io from setuptools import setup import sys with io.open("README.rst") as readme_file: readme_text = readme_file.read() def test_suite(): import doctest try: import unittest2 as unittest except: import unittest suite = unittest.TestLoader().discover("tests") suite.addTest(doctest.DocFileSuite("README.rst")) return 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.7, and 3.x are supported " "at this time.\n") exit(1) # Get around this issue: http://bugs.python.org/issue15881 # Appears to be a problem in older versions of Python 2.7 import multiprocessing # NOQA setup( name="geojson", version="1.3.1", description="Python bindings and utilities for GeoJSON", license="BSD", keywords="gis geography json", author="Sean Gillies", author_email="sgillies@frii.com", maintainer="Corey Farwell", maintainer_email="coreyf@rwell.org", url="https://github.com/frewsxcv/python-geojson", long_description=readme_text, packages=["geojson"], package_dir={"geojson": "geojson"}, package_data={"geojson": ["*.rst"]}, install_requires=["setuptools"], test_suite="setup.test_suite", classifiers=[ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Intended Audience :: Science/Research", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Topic :: Scientific/Engineering :: GIS", ] ) python-geojson-1.3.1/tests/000077500000000000000000000000001260676244300156535ustar00rootroot00000000000000python-geojson-1.3.1/tests/__init__.py000066400000000000000000000006121260676244300177630ustar00rootroot00000000000000import doctest import glob import os optionflags = (doctest.REPORT_ONLY_FIRST_FAILURE | doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS) _basedir = os.path.dirname(__file__) paths = glob.glob("%s/*.txt" % _basedir) test_suite = doctest.DocFileSuite(*paths, **dict(module_relative=False, optionflags=optionflags)) python-geojson-1.3.1/tests/data.geojson000066400000000000000000000001311260676244300201450ustar00rootroot00000000000000{ "properties": { "Ã": "Ã" }, "type": "Feature", "geometry": null } python-geojson-1.3.1/tests/test_base.py000066400000000000000000000034101260676244300201740ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ Tests for geojson/base.py """ import unittest import geojson class TypePropertyTestCase(unittest.TestCase): def test_type_property(self): 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}}') 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"}}') geojson_obj = geojson.loads(json_str) self.assertTrue(isinstance(geojson_obj, geojson.GeoJSON)) self.assertTrue("type" in geojson_obj.properties) class OperatorOverloadingTestCase(unittest.TestCase): """ Tests for operator overloading """ def setUp(self): self.coords = (12, -5) self.point = geojson.Point(self.coords) def test_setattr(self): new_coords = (27, 42) self.point.coordinates = new_coords self.assertEqual(self.point['coordinates'], new_coords) def test_getattr(self): self.assertEqual(self.point['coordinates'], self.point.coordinates) def test_delattr(self): del self.point.coordinates self.assertFalse(hasattr(self.point, 'coordinates')) python-geojson-1.3.1/tests/test_coords.py000066400000000000000000000046111260676244300205570ustar00rootroot00000000000000import unittest import geojson from geojson.utils import coords, map_coords class CoordsTestCase(unittest.TestCase): def test_point(self): itr = coords(geojson.Point((-115.81, 37.24))) self.assertEqual(next(itr), (-115.81, 37.24)) def test_dict(self): itr = coords({'type': 'Point', 'coordinates': [-115.81, 37.24]}) self.assertEqual(next(itr), (-115.81, 37.24)) def test_point_feature(self): itr = coords(geojson.Feature(geometry=geojson.Point((-115.81, 37.24)))) self.assertEqual(next(itr), (-115.81, 37.24)) 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)],)]) itr = coords(g) pairs = list(itr) self.assertEqual(pairs[0], (3.78, 9.28)) self.assertEqual(pairs[-1], (23.18, -34.29)) def test_map_point(self): result = map_coords(lambda x: x, geojson.Point((-115.81, 37.24))) self.assertEqual(result['type'], 'Point') self.assertEqual(result['coordinates'], (-115.81, 37.24)) def test_map_linestring(self): g = geojson.LineString( [(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'], 'LineString') self.assertEqual(result['coordinates'][0], (3.78, 9.28)) self.assertEqual(result['coordinates'][-1], (3.78, 9.28)) def test_map_polygon(self): g = geojson.Polygon([ [(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)) self.assertEqual(result['coordinates'][0][-1], (3.78, 9.28)) 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)],)]) result = map_coords(lambda x: x, g) self.assertEqual(result['type'], 'MultiPolygon') self.assertEqual(result['coordinates'][0][0][0], (3.78, 9.28)) self.assertEqual(result['coordinates'][-1][-1][-1], (23.18, -34.29)) python-geojson-1.3.1/tests/test_crs.py000066400000000000000000000015311260676244300200530ustar00rootroot00000000000000import unittest import geojson class CRSTest(unittest.TestCase): def setUp(self): self.crs = geojson.crs.Named( 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"}') 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"}') self.assertEqual(actual, expected) def test_crs_decode(self): dumped = geojson.dumps(self.crs) actual = geojson.loads(dumped) self.assertEqual(actual, self.crs) python-geojson-1.3.1/tests/test_features.py000066400000000000000000000111741260676244300211060ustar00rootroot00000000000000from io import BytesIO # NOQA import unittest import geojson class FeaturesTest(unittest.TestCase): def test_protocol(self): """ A dictionary can satisfy the protocol """ f = { '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"}') 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"}') def test_unicode_properties(self): with open("tests/data.geojson") as file_: obj = geojson.load(file_) geojson.dumps(obj) def test_feature_class(self): """ Test the Feature class """ from geojson.examples import SimpleWebFeature feature = SimpleWebFeature( id='1', geometry={'type': 'Point', 'coordinates': [53, -4]}, title='Feature 1', summary='The first feature', link='http://example.org/features/1' ) # It satisfies the feature protocol 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"}') # Encoding 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"}}') feature = geojson.loads(json, object_hook=factory, encoding="utf-8") self.assertEqual(repr(type(feature)), "") 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"}') def test_geo_interface(self): class Thingy(object): def __init__(self, id, title, x, y): self.id = id self.title = title self.x = x self.y = y @property def __geo_interface__(self): 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"}}')) python-geojson-1.3.1/tests/test_geo_interface.py000066400000000000000000000107261260676244300220640ustar00rootroot00000000000000""" Encoding/decoding custom objects with __geo_interface__ """ import unittest import geojson class EncodingDecodingTest(unittest.TestCase): def setUp(self): class Restaurant(object): """ Basic Restaurant class """ def __init__(self, name, latlng): super(Restaurant, self).__init__() self.name = name self.latlng = latlng class Restaurant1(Restaurant): """ Extends Restaurant with __geo_interface__ returning dict """ @property def __geo_interface__(self): return {'type': "Point", 'coordinates': self.latlng} class Restaurant2(Restaurant): """ Extends Restaurant with __geo_interface__ returning another __geo_interface__ object """ @property def __geo_interface__(self): return geojson.Point(self.latlng) class RestaurantFeature1(Restaurant): """ Extends Restaurant with __geo_interface__ returning dict """ @property def __geo_interface__(self): return { 'geometry': { 'type': "Point", 'coordinates': self.latlng, }, 'type': "Feature", 'properties': { 'name': self.name, }, } class RestaurantFeature2(Restaurant): """ Extends Restaurant with __geo_interface__ returning another __geo_interface__ object """ @property def __geo_interface__(self): return geojson.Feature( geometry=geojson.Point(self.latlng), properties={'name': self.name}) self.name = "In N Out Burger" self.latlng = [-54, 4] self.restaurant_nogeo = Restaurant(self.name, self.latlng) self.restaurant1 = Restaurant1(self.name, self.latlng) self.restaurant2 = Restaurant2(self.name, self.latlng) 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"},' ' "properties":' ' {"name": "In N Out Burger"},' ' "type": "Feature"}') def test_encode(self): """ Ensure objects that implement __geo_interface__ can be encoded into GeoJSON strings """ actual = geojson.dumps(self.restaurant1, sort_keys=True) self.assertEqual(actual, self.restaurant_str) actual = geojson.dumps(self.restaurant2, sort_keys=True) self.assertEqual(actual, self.restaurant_str) # Classes that don't implement geo interface should raise TypeError self.assertRaises( TypeError, geojson.dumps, self.restaurant_nogeo, sort_keys=True) def test_encode_nested(self): """ Ensure nested objects that implement __geo_interface__ can be encoded into GeoJSON strings """ actual = geojson.dumps(self.restaurant_feature1, sort_keys=True) self.assertEqual(actual, self.restaurant_feature_str) actual = geojson.dumps(self.restaurant_feature2, sort_keys=True) self.assertEqual(actual, self.restaurant_feature_str) def test_decode(self): """ Ensure a GeoJSON string can be decoded into GeoJSON objects """ actual = geojson.loads(self.restaurant_str) expected = self.restaurant1.__geo_interface__ self.assertEqual(expected, actual) def test_decode_nested(self): """ Ensure a GeoJSON string can be decoded into nested GeoJSON objects """ actual = geojson.loads(self.restaurant_feature_str) expected = self.restaurant_feature1.__geo_interface__ self.assertEqual(expected, actual) nested = expected['geometry'] expected = self.restaurant1.__geo_interface__ self.assertEqual(nested, expected) python-geojson-1.3.1/tests/test_null_geometries.py000066400000000000000000000015141260676244300224620ustar00rootroot00000000000000import unittest import geojson class NullGeometriesTest(unittest.TestCase): def test_null_geometry_explicit(self): feature = geojson.Feature( id=12, geometry=None, properties={'foo': 'bar'} ) actual = geojson.dumps(feature, sort_keys=True) expected = ('{"geometry": null, "id": 12, "properties": {"foo": ' '"bar"}, "type": "Feature"}') self.assertEqual(actual, expected) def test_null_geometry_implicit(self): feature = geojson.Feature( id=12, properties={'foo': 'bar'} ) actual = geojson.dumps(feature, sort_keys=True) expected = ('{"geometry": null, "id": 12, "properties": {"foo": ' '"bar"}, "type": "Feature"}') self.assertEqual(actual, expected) python-geojson-1.3.1/tests/test_strict_json.py000066400000000000000000000030431260676244300216250ustar00rootroot00000000000000""" GeoJSON produces and consumes only strict JSON. NAN and Infinity are not permissible values according to the JSON specification. """ import unittest import geojson class StrictJsonTest(unittest.TestCase): def test_encode_nan(self): """ Ensure Error is raised when encoding nan """ unstrict = { "type": "Point", "coordinates": (float("nan"), 1.0), } self.assertRaises(ValueError, geojson.dumps, unstrict) def test_encode_inf(self): """ Ensure Error is raised when encoding inf or -inf """ unstrict = { "type": "Point", "coordinates": (float("inf"), 1.0), } self.assertRaises(ValueError, geojson.dumps, unstrict) unstrict = { "type": "Point", "coordinates": (float("-inf"), 1.0), } self.assertRaises(ValueError, geojson.dumps, unstrict) def test_decode_nan(self): """ Ensure Error is raised when decoding NaN """ unstrict = '{"type": "Point", "coordinates": [1.0, NaN]}' self.assertRaises(ValueError, geojson.loads, unstrict) def test_decode_inf(self): """ Ensure Error is raised when decoding Infinity or -Infinity """ unstrict = '{"type": "Point", "coordinates": [1.0, Infinity]}' self.assertRaises(ValueError, geojson.loads, unstrict) unstrict = '{"type": "Point", "coordinates": [1.0, -Infinity]}' self.assertRaises(ValueError, geojson.loads, unstrict) python-geojson-1.3.1/tests/test_validation.py000066400000000000000000000067211260676244300214240ustar00rootroot00000000000000# -*- 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)