diff --git a/.requirements-2.6.txt b/.requirements-2.6.txt new file mode 100644 index 0000000..062b6c5 --- /dev/null +++ b/.requirements-2.6.txt @@ -0,0 +1,2 @@ +unittest2 +ordereddict diff --git a/.travis.yml b/.travis.yml index cfafb8e..0fee17f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,8 @@ language: python python: - - "2.7" + - 2.6 + - 2.7 env: - PANDAS_VERSION=v0.12.0 @@ -18,6 +19,7 @@ before_install: install: - pip install -r requirements.txt --use-mirrors - pip install -r requirements.test.txt --use-mirrors + - if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then pip install -r .requirements-2.6.txt --use-mirrors; fi - git clone git://github.com/pydata/pandas.git - cd pandas - git checkout $PANDAS_VERSION diff --git a/doc/source/install.rst b/doc/source/install.rst index 2f02df8..1091d16 100644 --- a/doc/source/install.rst +++ b/doc/source/install.rst @@ -12,6 +12,9 @@ should work as well. Dependencies ------------ +Requires Python version 2.6 or 2.7 (Python 3.x support is planned +soon). + - `numpy`_ - `pandas`_ - `shapely`_ diff --git a/geopandas/geodataframe.py b/geopandas/geodataframe.py index cd9c475..7380f63 100644 --- a/geopandas/geodataframe.py +++ b/geopandas/geodataframe.py @@ -1,4 +1,8 @@ -from collections import OrderedDict +try: + from collections import OrderedDict +except ImportError: + # Python 2.6 + from ordereddict import OrderedDict import json import os import sys @@ -211,8 +215,8 @@ class GeoDataFrame(DataFrame): return { 'id': str(i), 'type': 'Feature', - 'properties': { - k: v for k, v in row.iteritems() if k != 'geometry'}, + 'properties': + dict((k, v) for k, v in row.iteritems() if k != 'geometry'), 'geometry': mapping(row['geometry']) } return json.dumps( @@ -247,8 +251,8 @@ class GeoDataFrame(DataFrame): return { 'id': str(i), 'type': 'Feature', - 'properties': { - k: v for k, v in row.iteritems() if k != 'geometry'}, + 'properties': + dict((k, v) for k, v in row.iteritems() if k != 'geometry'), 'geometry': mapping(row['geometry']) } properties = OrderedDict([(col, convert_type(_type)) for col, _type diff --git a/geopandas/geoseries.py b/geopandas/geoseries.py index 42b6ecb..92305c8 100644 --- a/geopandas/geoseries.py +++ b/geopandas/geoseries.py @@ -89,7 +89,7 @@ class GeoSeries(Series): """Operation that returns a GeoSeries""" if isinstance(other, GeoSeries): if self.crs != other.crs: - warn('GeoSeries crs mismatch: {} and {}'.format(self.crs, other.crs)) + warn('GeoSeries crs mismatch: {0} and {1}'.format(self.crs, other.crs)) this, other = self.align(other) return GeoSeries([getattr(s[0], op)(s[1]) for s in zip(this, other)], index=this.index, crs=self.crs) diff --git a/tests/test_geocode.py b/tests/test_geocode.py index a94d6bf..8b91cb1 100644 --- a/tests/test_geocode.py +++ b/tests/test_geocode.py @@ -1,5 +1,3 @@ -import unittest - import fiona import pandas as pd from shapely.geometry import Point @@ -7,6 +5,8 @@ import geopandas as gpd import nose from geopandas.geocode import geocode, _prepare_geocode_result +from .util import unittest + def _skip_if_no_geopy(): try: @@ -59,4 +59,5 @@ class TestGeocode(unittest.TestCase): self.assert_(pd.np.isnan(row['address'])) def test_bad_provider(self): - self.assertRaises(ValueError, geocode, ['cambridge, ma'], 'badprovider') + with self.assertRaises(ValueError): + geocode(['cambridge, ma'], 'badprovider') diff --git a/tests/test_geodataframe.py b/tests/test_geodataframe.py index c3ab1c9..fb833bb 100644 --- a/tests/test_geodataframe.py +++ b/tests/test_geodataframe.py @@ -1,4 +1,3 @@ -import unittest import json import os import tempfile @@ -8,9 +7,9 @@ import numpy as np import pandas as pd from shapely.geometry import Point, Polygon - from geopandas import GeoDataFrame, read_file, GeoSeries -import tests.util as tu +from .util import unittest, download_nybb, assert_geoseries_equal, connect, \ + create_db, validate_boro_df class TestDataFrame(unittest.TestCase): @@ -18,7 +17,7 @@ class TestDataFrame(unittest.TestCase): def setUp(self): N = 10 - nybb_filename = tu.download_nybb() + nybb_filename = download_nybb() self.df = read_file('/nybb_13a/nybb.shp', vfs='zip://' + nybb_filename) self.tempdir = tempfile.mkdtemp() @@ -41,7 +40,7 @@ class TestDataFrame(unittest.TestCase): "location": [Point(x, y) for x, y in zip(range(5), range(5))]} df = GeoDataFrame(data, crs=self.crs, geometry='location') locs = GeoSeries(data['location'], crs=self.crs) - tu.assert_geoseries_equal(df.geometry, locs) + assert_geoseries_equal(df.geometry, locs) self.assert_('geometry' not in df) self.assertEqual(df.geometry.name, 'location') # internal implementation detail @@ -55,13 +54,13 @@ class TestDataFrame(unittest.TestCase): self.assertEqual(df2.geometry.crs, 'dummy_crs') # reset so it outputs okay df2.crs = df.crs - tu.assert_geoseries_equal(df2.geometry, GeoSeries(geom2, crs=df2.crs)) + assert_geoseries_equal(df2.geometry, GeoSeries(geom2, crs=df2.crs)) # for right now, non-geometry comes back as series - tu.assert_geoseries_equal(df2['location'], df['location'], + assert_geoseries_equal(df2['location'], df['location'], check_series_type=False, check_dtype=False) def test_geometry_property(self): - tu.assert_geoseries_equal(self.df.geometry, self.df['geometry'], + assert_geoseries_equal(self.df.geometry, self.df['geometry'], check_dtype=True, check_index_type=True) df = self.df.copy() @@ -70,8 +69,8 @@ class TestDataFrame(unittest.TestCase): df.geometry = new_geom new_geom = GeoSeries(new_geom, index=df.index, crs=df.crs) - tu.assert_geoseries_equal(df.geometry, new_geom) - tu.assert_geoseries_equal(df['geometry'], new_geom) + assert_geoseries_equal(df.geometry, new_geom) + assert_geoseries_equal(df['geometry'], new_geom) # new crs gs = GeoSeries(new_geom, crs="epsg:26018") @@ -79,39 +78,30 @@ class TestDataFrame(unittest.TestCase): self.assertEqual(df.crs, "epsg:26018") def test_geometry_property_errors(self): - # TODO: Much cleaner if we use pandas test options (since assertRaises - # contextmanager and friends not available in 2.6), but need 0.13 for - # that. - def _should_raise_att_error(): + with self.assertRaises(AttributeError): df = self.df.copy() del df['geometry'] df.geometry - self.assertRaises(AttributeError, _should_raise_att_error) # list-like error - def _should_raise_value_error_on_set_with_col(): + with self.assertRaises(ValueError): df = self.df2.copy() df.geometry = 'value1' - self.assertRaises(ValueError, _should_raise_value_error_on_set_with_col) # list-like error - def _should_raise_value_error_with_string(): + with self.assertRaises(ValueError): df = self.df.copy() df.geometry = 'apple' - self.assertRaises(ValueError, _should_raise_value_error_with_string) - def _should_raise_key_error(): + with self.assertRaises(KeyError): df = self.df.copy() del df['geometry'] df['geometry'] - self.assertRaises(KeyError, _should_raise_key_error) # ndim error - def _setting_with_df_should_raise_value_error(): + with self.assertRaises(ValueError): df = self.df.copy() df.geometry = df - self.assertRaises(ValueError, - _setting_with_df_should_raise_value_error) def test_set_geometry(self): geom = GeoSeries([Point(x,y) for x,y in zip(range(5), range(5))]) @@ -119,15 +109,16 @@ class TestDataFrame(unittest.TestCase): df2 = self.df.set_geometry(geom) self.assert_(self.df is not df2) - tu.assert_geoseries_equal(df2.geometry, geom) - tu.assert_geoseries_equal(self.df.geometry, original_geom) - tu.assert_geoseries_equal(self.df['geometry'], self.df.geometry) + assert_geoseries_equal(df2.geometry, geom) + assert_geoseries_equal(self.df.geometry, original_geom) + assert_geoseries_equal(self.df['geometry'], self.df.geometry) # unknown column - self.assertRaises(ValueError, self.df.set_geometry, - 'nonexistent-column') + with self.assertRaises(ValueError): + self.df.set_geometry('nonexistent-column') + # ndim error - self.assertRaises(ValueError, self.df.set_geometry, - self.df) + with self.assertRaises(ValueError): + self.df.set_geometry(self.df) # new crs - setting should default to GeoSeries' crs gs = GeoSeries(geom, crs="epsg:26018") @@ -152,19 +143,19 @@ class TestDataFrame(unittest.TestCase): # Drop is false by default self.assert_('simplified_geometry' in df2) - tu.assert_geoseries_equal(df2.geometry, g_simplified) + assert_geoseries_equal(df2.geometry, g_simplified) # If True, drops column and renames to geometry df3 = self.df.set_geometry('simplified_geometry', drop=True) self.assert_('simplified_geometry' not in df3) - tu.assert_geoseries_equal(df3.geometry, g_simplified) + assert_geoseries_equal(df3.geometry, g_simplified) def test_set_geometry_inplace(self): geom = [Point(x,y) for x,y in zip(range(5), range(5))] ret = self.df.set_geometry(geom, inplace=True) self.assert_(ret is None) geom = GeoSeries(geom, index=self.df.index, crs=self.df.crs) - tu.assert_geoseries_equal(self.df.geometry, geom) + assert_geoseries_equal(self.df.geometry, geom) def test_to_json(self): text = self.df.to_json() @@ -266,8 +257,8 @@ class TestDataFrame(unittest.TestCase): self.assertTrue(all(df2['geometry'].almost_equals(utm['geometry'], decimal=2))) def test_from_postgis_default(self): - con = tu.connect('test_geopandas') - if con is None or not tu.create_db(self.df): + con = connect('test_geopandas') + if con is None or not create_db(self.df): raise unittest.case.SkipTest() try: @@ -276,11 +267,11 @@ class TestDataFrame(unittest.TestCase): finally: con.close() - tu.validate_boro_df(self, df) + validate_boro_df(self, df) def test_from_postgis_custom_geom_col(self): - con = tu.connect('test_geopandas') - if con is None or not tu.create_db(self.df): + con = connect('test_geopandas') + if con is None or not create_db(self.df): raise unittest.case.SkipTest() try: @@ -292,21 +283,21 @@ class TestDataFrame(unittest.TestCase): finally: con.close() - tu.validate_boro_df(self, df) + validate_boro_df(self, df) def test_dataframe_to_geodataframe(self): df = pd.DataFrame({"A": range(len(self.df)), "location": list(self.df.geometry)}, index=self.df.index) gf = df.set_geometry('location', crs=self.df.crs) - tu.assert_isinstance(df, pd.DataFrame) - tu.assert_isinstance(gf, GeoDataFrame) - tu.assert_geoseries_equal(gf.geometry, self.df.geometry) + self.assertIsInstance(df, pd.DataFrame) + self.assertIsInstance(gf, GeoDataFrame) + assert_geoseries_equal(gf.geometry, self.df.geometry) self.assertEqual(gf.geometry.name, 'location') self.assert_('geometry' not in gf) gf2 = df.set_geometry('location', crs=self.df.crs, drop=True) - tu.assert_isinstance(df, pd.DataFrame) - tu.assert_isinstance(gf2, GeoDataFrame) + self.assertIsInstance(df, pd.DataFrame) + self.assertIsInstance(gf2, GeoDataFrame) self.assertEqual(gf2.geometry.name, 'geometry') self.assert_('geometry' in gf2) self.assert_('location' not in gf2) @@ -317,5 +308,5 @@ class TestDataFrame(unittest.TestCase): self.assertEqual(gf.ix[0, "A"], 0) self.assertEqual(gf2.ix[0, "A"], 0) - self.assertRaises(ValueError, df.set_geometry, 'location', - inplace=True) + with self.assertRaises(ValueError): + df.set_geometry('location', inplace=True) diff --git a/tests/test_geoseries.py b/tests/test_geoseries.py index 2e86dcd..3bc5345 100644 --- a/tests/test_geoseries.py +++ b/tests/test_geoseries.py @@ -1,15 +1,13 @@ import os import shutil import tempfile -import unittest import numpy as np from numpy.testing import assert_array_equal from pandas import Series from shapely.geometry import Polygon, Point, LineString from shapely.geometry.base import BaseGeometry from geopandas import GeoSeries -from pandas import Series -from tests.util import geom_equals, geom_almost_equals +from .util import unittest, geom_equals, geom_almost_equals class TestSeries(unittest.TestCase): diff --git a/tests/test_types.py b/tests/test_types.py index f92a88e..9baa8af 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -1,10 +1,9 @@ -import unittest - import numpy as np from shapely.geometry import Point from pandas import Series, DataFrame from geopandas import GeoSeries, GeoDataFrame +from .util import unittest OLD_PANDAS = issubclass(Series, np.ndarray) diff --git a/tests/util.py b/tests/util.py index e54fda1..8b390f7 100644 --- a/tests/util.py +++ b/tests/util.py @@ -3,6 +3,16 @@ import urllib2 from geopandas import GeoDataFrame, GeoSeries +# Compatibility layer for Python 2.6: try loading unittest2 +import sys +if sys.version_info[:2] == (2, 6): + try: + import unittest2 as unittest + except ImportError: + import unittest + +else: + import unittest try: import psycopg2 @@ -32,7 +42,7 @@ def validate_boro_df(test, df): test.assertEqual(len(df), 5) columns = ('borocode', 'boroname', 'shape_leng', 'shape_area') for col in columns: - test.assertTrue(col in df.columns, 'Column {} missing'.format(col)) + test.assertTrue(col in df.columns, 'Column {0} missing'.format(col)) test.assertTrue(all(df.geometry.type == 'MultiPolygon'))