Files

214 lines
6.9 KiB
Python

import io
import os.path
from six.moves.urllib.request import urlopen
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
from psycopg2 import OperationalError
except ImportError:
class OperationalError(Exception):
pass
try:
from pandas import read_sql_table
except ImportError:
PANDAS_NEW_SQL_API = False
else:
PANDAS_NEW_SQL_API = True
def download_nybb():
""" Returns the path to the NYC boroughs file. Downloads if necessary. """
# Data from http://www.nyc.gov/html/dcp/download/bytes/nybb_14aav.zip
# saved as geopandas/examples/nybb_14aav.zip.
filename = 'nybb_14aav.zip'
full_path_name = os.path.join('examples', filename)
if not os.path.exists(full_path_name):
with io.open(full_path_name, 'wb') as f:
response = urlopen('http://www.nyc.gov/html/dcp/download/bytes/{0}'.format(filename))
f.write(response.read())
return full_path_name
def validate_boro_df(test, df):
""" Tests a GeoDataFrame that has been read in from the nybb dataset."""
test.assertTrue(isinstance(df, GeoDataFrame))
# Make sure all the columns are there and the geometries
# were properly loaded as MultiPolygons
test.assertEqual(len(df), 5)
columns = ('borocode', 'boroname', 'shape_leng', 'shape_area')
for col in columns:
test.assertTrue(col in df.columns, 'Column {0} missing'.format(col))
test.assertTrue(all(df.geometry.type == 'MultiPolygon'))
def connect(dbname):
try:
con = psycopg2.connect(dbname=dbname)
except (NameError, OperationalError):
return None
return con
def create_db(df):
"""
Create a nybb table in the test_geopandas PostGIS database.
Returns a boolean indicating whether the database table was successfully
created
"""
# Try to create the database, skip the db tests if something goes
# wrong
# If you'd like these tests to run, create a database called
# 'test_geopandas' and enable postgis in it:
# > createdb test_geopandas
# > psql -c "CREATE EXTENSION postgis" -d test_geopandas
con = connect('test_geopandas')
if con is None:
return False
try:
cursor = con.cursor()
cursor.execute("DROP TABLE IF EXISTS nybb;")
sql = """CREATE TABLE nybb (
geom geometry,
borocode integer,
boroname varchar(40),
shape_leng float,
shape_area float
);"""
cursor.execute(sql)
for i, row in df.iterrows():
sql = """INSERT INTO nybb VALUES (
ST_GeometryFromText(%s), %s, %s, %s, %s
);"""
cursor.execute(sql, (row['geometry'].wkt,
row['BoroCode'],
row['BoroName'],
row['Shape_Leng'],
row['Shape_Area']))
finally:
cursor.close()
con.commit()
con.close()
return True
def assert_seq_equal(left, right):
"""Poor man's version of assert_almost_equal which isn't working with Shapely
objects right now"""
assert len(left) == len(right), "Mismatched lengths: %d != %d" % (len(left), len(right))
for elem_left, elem_right in zip(left, right):
assert elem_left == elem_right, "%r != %r" % (left, right)
def geom_equals(this, that):
"""Test for geometric equality. Empty geometries are considered equal.
Parameters
----------
this, that : arrays of Geo objects (or anything that has an `is_empty`
attribute)
"""
return (this.geom_equals(that) | (this.is_empty & that.is_empty)).all()
def geom_almost_equals(this, that):
"""Test for 'almost' geometric equality. Empty geometries considered equal.
Parameters
----------
this, that : arrays of Geo objects (or anything that has an `is_empty`
property)
"""
return (this.geom_almost_equals(that) |
(this.is_empty & that.is_empty)).all()
# TODO: Remove me when standardizing on pandas 0.13, which already includes
# this test util.
def assert_isinstance(obj, klass_or_tuple):
assert isinstance(obj, klass_or_tuple), "type: %r != %r" % (
type(obj).__name__,
getattr(klass_or_tuple, '__name__',
klass_or_tuple))
def assert_geoseries_equal(left, right, check_dtype=False,
check_index_type=False,
check_series_type=True,
check_less_precise=False,
check_geom_type=False,
check_crs=True):
"""Test util for checking that two GeoSeries are equal.
Parameters
----------
left, right : two GeoSeries
check_dtype : bool, default False
if True, check geo dtype [only included so it's a drop-in replacement
for assert_series_equal]
check_index_type : bool, default False
check that index types are equal
check_series_type : bool, default True
check that both are same type (*and* are GeoSeries). If False,
will attempt to convert both into GeoSeries.
check_less_precise : bool, default False
if True, use geom_almost_equals. if False, use geom_equals.
check_geom_type : bool, default False
if True, check that all the geom types are equal.
check_crs: bool, default True
if check_series_type is True, then also check that the
crs matches
"""
assert len(left) == len(right), "%d != %d" % (len(left), len(right))
if check_index_type:
assert_isinstance(left.index, type(right.index))
if check_dtype:
assert left.dtype == right.dtype, "dtype: %s != %s" % (left.dtype,
right.dtype)
if check_series_type:
assert isinstance(left, GeoSeries)
assert_isinstance(left, type(right))
if check_crs:
assert(left.crs == right.crs)
else:
if not isinstance(left, GeoSeries):
left = GeoSeries(left)
if not isinstance(right, GeoSeries):
right = GeoSeries(right, index=left.index)
assert left.index.equals(right.index), "index: %s != %s" % (left.index,
right.index)
if check_geom_type:
assert (left.type == right.type).all(), "type: %s != %s" % (left.type,
right.type)
if check_less_precise:
assert geom_almost_equals(left, right)
else:
assert geom_equals(left, right)