#!/usr/bin/env python import os from nose.tools import eq_, raises import mapnik from .utilities import execution_path, run_all def setup(): # All of the paths used are relative, if we run the tests # from another directory we need to chdir() os.chdir(execution_path('.')) def teardown(): index = '../data/sqlite/world.sqlite.index' if os.path.exists(index): os.unlink(index) if 'sqlite' in mapnik.DatasourceCache.plugin_names(): def test_attachdb_with_relative_file(): # The point table and index is in the qgis_spatiallite.sqlite # database. If either is not found, then this fails ds = mapnik.SQLite(file='../data/sqlite/world.sqlite', table='point', attachdb='scratch@qgis_spatiallite.sqlite' ) fs = ds.featureset() feature = fs.next() eq_(feature['pkuid'], 1) test_attachdb_with_relative_file.requires_data = True def test_attachdb_with_multiple_files(): ds = mapnik.SQLite(file='../data/sqlite/world.sqlite', table='attachedtest', attachdb='scratch1@:memory:,scratch2@:memory:', initdb=''' create table scratch1.attachedtest (the_geom); create virtual table scratch2.idx_attachedtest_the_geom using rtree(pkid,xmin,xmax,ymin,ymax); insert into scratch2.idx_attachedtest_the_geom values (1,-7799225.5,-7778571.0,1393264.125,1417719.375); ''' ) fs = ds.featureset() feature = None try: feature = fs.next() except StopIteration: pass # the above should not throw but will result in no features eq_(feature, None) test_attachdb_with_multiple_files.requires_data = True def test_attachdb_with_absolute_file(): # The point table and index is in the qgis_spatiallite.sqlite # database. If either is not found, then this fails ds = mapnik.SQLite(file=os.getcwd() + '/../data/sqlite/world.sqlite', table='point', attachdb='scratch@qgis_spatiallite.sqlite' ) fs = ds.featureset() feature = fs.next() eq_(feature['pkuid'], 1) test_attachdb_with_absolute_file.requires_data = True def test_attachdb_with_index(): ds = mapnik.SQLite(file='../data/sqlite/world.sqlite', table='attachedtest', attachdb='scratch@:memory:', initdb=''' create table scratch.attachedtest (the_geom); create virtual table scratch.idx_attachedtest_the_geom using rtree(pkid,xmin,xmax,ymin,ymax); insert into scratch.idx_attachedtest_the_geom values (1,-7799225.5,-7778571.0,1393264.125,1417719.375); ''' ) fs = ds.featureset() feature = None try: feature = fs.next() except StopIteration: pass eq_(feature, None) test_attachdb_with_index.requires_data = True def test_attachdb_with_explicit_index(): ds = mapnik.SQLite(file='../data/sqlite/world.sqlite', table='attachedtest', index_table='myindex', attachdb='scratch@:memory:', initdb=''' create table scratch.attachedtest (the_geom); create virtual table scratch.myindex using rtree(pkid,xmin,xmax,ymin,ymax); insert into scratch.myindex values (1,-7799225.5,-7778571.0,1393264.125,1417719.375); ''' ) fs = ds.featureset() feature = None try: feature = fs.next() except StopIteration: pass eq_(feature, None) test_attachdb_with_explicit_index.requires_data = True def test_attachdb_with_sql_join(): ds = mapnik.SQLite(file='../data/sqlite/world.sqlite', table='(select * from world_merc INNER JOIN business on world_merc.iso3 = business.ISO3 limit 100)', attachdb='busines@business.sqlite' ) eq_(len(ds.fields()), 29) eq_(ds.fields(), ['OGC_FID', 'fips', 'iso2', 'iso3', 'un', 'name', 'area', 'pop2005', 'region', 'subregion', 'lon', 'lat', 'ISO3:1', '1995', '1996', '1997', '1998', '1999', '2000', '2001', '2002', '2003', '2004', '2005', '2006', '2007', '2008', '2009', '2010']) eq_(ds.field_types(), ['int', 'str', 'str', 'str', 'int', 'str', 'int', 'int', 'int', 'int', 'float', 'float', 'str', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int']) fs = ds.featureset() feature = fs.next() eq_(feature.id(), 1) expected = { 1995: 0, 1996: 0, 1997: 0, 1998: 0, 1999: 0, 2000: 0, 2001: 0, 2002: 0, 2003: 0, 2004: 0, 2005: 0, 2006: 0, 2007: 0, 2008: 0, 2009: 0, 2010: 0, # this appears to be sqlites way of # automatically handling clashing column names 'ISO3:1': 'ATG', 'OGC_FID': 1, 'area': 44, 'fips': u'AC', 'iso2': u'AG', 'iso3': u'ATG', 'lat': 17.078, 'lon': -61.783, 'name': u'Antigua and Barbuda', 'pop2005': 83039, 'region': 19, 'subregion': 29, 'un': 28 } for k, v in expected.items(): try: eq_(feature[str(k)], v) except: #import pdb;pdb.set_trace() print('invalid key/v %s/%s for: %s' % (k, v, feature)) test_attachdb_with_sql_join.requires_data = True def test_attachdb_with_sql_join_count(): ds = mapnik.SQLite(file='../data/sqlite/world.sqlite', table='(select * from world_merc INNER JOIN business on world_merc.iso3 = business.ISO3 limit 100)', attachdb='busines@business.sqlite' ) eq_(len(ds.fields()), 29) eq_(ds.fields(), ['OGC_FID', 'fips', 'iso2', 'iso3', 'un', 'name', 'area', 'pop2005', 'region', 'subregion', 'lon', 'lat', 'ISO3:1', '1995', '1996', '1997', '1998', '1999', '2000', '2001', '2002', '2003', '2004', '2005', '2006', '2007', '2008', '2009', '2010']) eq_(ds.field_types(), ['int', 'str', 'str', 'str', 'int', 'str', 'int', 'int', 'int', 'int', 'float', 'float', 'str', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int']) eq_(len(list(ds.all_features())), 100) test_attachdb_with_sql_join_count.requires_data = True def test_attachdb_with_sql_join_count2(): ''' sqlite3 world.sqlite attach database 'business.sqlite' as business; select count(*) from world_merc INNER JOIN business on world_merc.iso3 = business.ISO3; ''' ds = mapnik.SQLite(file='../data/sqlite/world.sqlite', table='(select * from world_merc INNER JOIN business on world_merc.iso3 = business.ISO3)', attachdb='busines@business.sqlite' ) eq_(len(ds.fields()), 29) eq_(ds.fields(), ['OGC_FID', 'fips', 'iso2', 'iso3', 'un', 'name', 'area', 'pop2005', 'region', 'subregion', 'lon', 'lat', 'ISO3:1', '1995', '1996', '1997', '1998', '1999', '2000', '2001', '2002', '2003', '2004', '2005', '2006', '2007', '2008', '2009', '2010']) eq_(ds.field_types(), ['int', 'str', 'str', 'str', 'int', 'str', 'int', 'int', 'int', 'int', 'float', 'float', 'str', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int']) eq_(len(list(ds.all_features())), 192) test_attachdb_with_sql_join_count2.requires_data = True def test_attachdb_with_sql_join_count3(): ''' select count(*) from (select * from world_merc where 1=1) as world_merc INNER JOIN business on world_merc.iso3 = business.ISO3; ''' ds = mapnik.SQLite(file='../data/sqlite/world.sqlite', table='(select * from (select * from world_merc where !intersects!) as world_merc INNER JOIN business on world_merc.iso3 = business.ISO3)', attachdb='busines@business.sqlite' ) eq_(len(ds.fields()), 29) eq_(ds.fields(), ['OGC_FID', 'fips', 'iso2', 'iso3', 'un', 'name', 'area', 'pop2005', 'region', 'subregion', 'lon', 'lat', 'ISO3:1', '1995', '1996', '1997', '1998', '1999', '2000', '2001', '2002', '2003', '2004', '2005', '2006', '2007', '2008', '2009', '2010']) eq_(ds.field_types(), ['int', 'str', 'str', 'str', 'int', 'str', 'int', 'int', 'int', 'int', 'float', 'float', 'str', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int']) eq_(len(list(ds.all_features())), 192) test_attachdb_with_sql_join_count3.requires_data = True def test_attachdb_with_sql_join_count4(): ''' select count(*) from (select * from world_merc where 1=1) as world_merc INNER JOIN business on world_merc.iso3 = business.ISO3; ''' ds = mapnik.SQLite(file='../data/sqlite/world.sqlite', table='(select * from (select * from world_merc where !intersects! limit 1) as world_merc INNER JOIN business on world_merc.iso3 = business.ISO3)', attachdb='busines@business.sqlite' ) eq_(len(ds.fields()), 29) eq_(ds.fields(), ['OGC_FID', 'fips', 'iso2', 'iso3', 'un', 'name', 'area', 'pop2005', 'region', 'subregion', 'lon', 'lat', 'ISO3:1', '1995', '1996', '1997', '1998', '1999', '2000', '2001', '2002', '2003', '2004', '2005', '2006', '2007', '2008', '2009', '2010']) eq_(ds.field_types(), ['int', 'str', 'str', 'str', 'int', 'str', 'int', 'int', 'int', 'int', 'float', 'float', 'str', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int', 'int']) eq_(len(list(ds.all_features())), 1) test_attachdb_with_sql_join_count4.requires_data = True def test_attachdb_with_sql_join_count5(): ''' select count(*) from (select * from world_merc where 1=1) as world_merc INNER JOIN business on world_merc.iso3 = business.ISO3; ''' ds = mapnik.SQLite(file='../data/sqlite/world.sqlite', table='(select * from (select * from world_merc where !intersects! and 1=2) as world_merc INNER JOIN business on world_merc.iso3 = business.ISO3)', attachdb='busines@business.sqlite' ) # nothing is able to join to business so we don't pick up business # schema eq_(len(ds.fields()), 12) eq_(ds.fields(), ['OGC_FID', 'fips', 'iso2', 'iso3', 'un', 'name', 'area', 'pop2005', 'region', 'subregion', 'lon', 'lat']) eq_(ds.field_types(), ['int', 'str', 'str', 'str', 'int', 'str', 'int', 'int', 'int', 'int', 'float', 'float']) eq_(len(list(ds.all_features())), 0) test_attachdb_with_sql_join_count5.requires_data = True def test_subqueries(): ds = mapnik.SQLite(file='../data/sqlite/world.sqlite', table='world_merc', ) fs = ds.featureset() feature = fs.next() eq_(feature['OGC_FID'], 1) eq_(feature['fips'], u'AC') eq_(feature['iso2'], u'AG') eq_(feature['iso3'], u'ATG') eq_(feature['un'], 28) eq_(feature['name'], u'Antigua and Barbuda') eq_(feature['area'], 44) eq_(feature['pop2005'], 83039) eq_(feature['region'], 19) eq_(feature['subregion'], 29) eq_(feature['lon'], -61.783) eq_(feature['lat'], 17.078) ds = mapnik.SQLite(file='../data/sqlite/world.sqlite', table='(select * from world_merc)', ) fs = ds.featureset() feature = fs.next() eq_(feature['OGC_FID'], 1) eq_(feature['fips'], u'AC') eq_(feature['iso2'], u'AG') eq_(feature['iso3'], u'ATG') eq_(feature['un'], 28) eq_(feature['name'], u'Antigua and Barbuda') eq_(feature['area'], 44) eq_(feature['pop2005'], 83039) eq_(feature['region'], 19) eq_(feature['subregion'], 29) eq_(feature['lon'], -61.783) eq_(feature['lat'], 17.078) ds = mapnik.SQLite(file='../data/sqlite/world.sqlite', table='(select OGC_FID,GEOMETRY from world_merc)', ) fs = ds.featureset() feature = fs.next() eq_(feature['OGC_FID'], 1) eq_(len(feature), 1) ds = mapnik.SQLite(file='../data/sqlite/world.sqlite', table='(select GEOMETRY,OGC_FID,fips from world_merc)', ) fs = ds.featureset() feature = fs.next() eq_(feature['OGC_FID'], 1) eq_(feature['fips'], u'AC') # same as above, except with alias like postgres requires # TODO - should we try to make this work? # ds = mapnik.SQLite(file='../data/sqlite/world.sqlite', # table='(select GEOMETRY,rowid as aliased_id,fips from world_merc) as table', # key_field='aliased_id' # ) #fs = ds.featureset() #feature = fs.next() # eq_(feature['aliased_id'],1) # eq_(feature['fips'],u'AC') ds = mapnik.SQLite(file='../data/sqlite/world.sqlite', table='(select GEOMETRY,OGC_FID,OGC_FID as rowid,fips from world_merc)', ) fs = ds.featureset() feature = fs.next() eq_(feature['rowid'], 1) eq_(feature['fips'], u'AC') test_subqueries.requires_data = True def test_empty_db(): ds = mapnik.SQLite(file='../data/sqlite/empty.db', table='empty', ) fs = ds.featureset() feature = None try: feature = fs.next() except StopIteration: pass eq_(feature, None) test_empty_db.requires_data = True @raises(RuntimeError) def test_that_nonexistant_query_field_throws(**kwargs): ds = mapnik.SQLite(file='../data/sqlite/empty.db', table='empty', ) eq_(len(ds.fields()), 25) eq_(ds.fields(), ['OGC_FID', 'scalerank', 'labelrank', 'featurecla', 'sovereignt', 'sov_a3', 'adm0_dif', 'level', 'type', 'admin', 'adm0_a3', 'geou_dif', 'name', 'abbrev', 'postal', 'name_forma', 'terr_', 'name_sort', 'map_color', 'pop_est', 'gdp_md_est', 'fips_10_', 'iso_a2', 'iso_a3', 'iso_n3']) eq_(ds.field_types(), ['int', 'int', 'int', 'str', 'str', 'str', 'float', 'float', 'str', 'str', 'str', 'float', 'str', 'str', 'str', 'str', 'str', 'str', 'float', 'float', 'float', 'float', 'str', 'str', 'float']) query = mapnik.Query(ds.envelope()) for fld in ds.fields(): query.add_property_name(fld) # also add an invalid one, triggering throw query.add_property_name('bogus') ds.features(query) test_that_nonexistant_query_field_throws.requires_data = True def test_intersects_token1(): ds = mapnik.SQLite(file='../data/sqlite/empty.db', table='(select * from empty where !intersects!)', ) fs = ds.featureset() feature = None try: feature = fs.next() except StopIteration: pass eq_(feature, None) test_intersects_token1.requires_data = True def test_intersects_token2(): ds = mapnik.SQLite(file='../data/sqlite/empty.db', table='(select * from empty where "a"!="b" and !intersects!)', ) fs = ds.featureset() feature = None try: feature = fs.next() except StopIteration: pass eq_(feature, None) test_intersects_token2.requires_data = True def test_intersects_token3(): ds = mapnik.SQLite(file='../data/sqlite/empty.db', table='(select * from empty where "a"!="b" and !intersects!)', ) fs = ds.featureset() feature = None try: feature = fs.next() except StopIteration: pass eq_(feature, None) test_intersects_token3.requires_data = True # https://github.com/mapnik/mapnik/issues/1537 # this works because key_field is manually set def test_db_with_one_text_column(): # form up an in-memory test db wkb = '010100000000000000000000000000000000000000' ds = mapnik.SQLite(file=':memory:', table='test1', initdb=''' create table test1 (alias TEXT,geometry BLOB); insert into test1 values ("test",x'%s'); ''' % wkb, extent='-180,-60,180,60', use_spatial_index=False, key_field='alias' ) eq_(len(ds.fields()), 1) eq_(ds.fields(), ['alias']) eq_(ds.field_types(), ['str']) fs = list(ds.all_features()) eq_(len(fs), 1) feat = fs[0] eq_(feat.id(), 0) # should be 1? eq_(feat['alias'], 'test') eq_(feat.geometry.to_wkt(), 'POINT(0 0)') def test_db_with_one_untyped_column(): # form up an in-memory test db wkb = '010100000000000000000000000000000000000000' ds = mapnik.SQLite(file=':memory:', table='test1', initdb=''' create table test1 (geometry BLOB, untyped); insert into test1 values (x'%s', 'untyped'); ''' % wkb, extent='-180,-60,180,60', use_spatial_index=False, key_field='rowid' ) # ensure the untyped column is found eq_(len(ds.fields()), 2) eq_(ds.fields(), ['rowid', 'untyped']) eq_(ds.field_types(), ['int', 'str']) def test_db_with_one_untyped_column_using_subquery(): # form up an in-memory test db wkb = '010100000000000000000000000000000000000000' ds = mapnik.SQLite(file=':memory:', table='(SELECT rowid, geometry, untyped FROM test1)', initdb=''' create table test1 (geometry BLOB, untyped); insert into test1 values (x'%s', 'untyped'); ''' % wkb, extent='-180,-60,180,60', use_spatial_index=False, key_field='rowid' ) # ensure the untyped column is found eq_(len(ds.fields()), 3) eq_(ds.fields(), ['rowid', 'untyped', 'rowid']) eq_(ds.field_types(), ['int', 'str', 'int']) def test_that_64bit_int_fields_work(): ds = mapnik.SQLite(file='../data/sqlite/64bit_int.sqlite', table='int_table', use_spatial_index=False ) eq_(len(ds.fields()), 3) eq_(ds.fields(), ['OGC_FID', 'id', 'bigint']) eq_(ds.field_types(), ['int', 'int', 'int']) fs = ds.featureset() feat = fs.next() eq_(feat.id(), 1) eq_(feat['OGC_FID'], 1) eq_(feat['bigint'], 2147483648) feat = fs.next() eq_(feat.id(), 2) eq_(feat['OGC_FID'], 2) eq_(feat['bigint'], 922337203685477580) test_that_64bit_int_fields_work.requires_data = True def test_null_id_field(): # silence null key warning: # https://github.com/mapnik/mapnik/issues/1889 default_logging_severity = mapnik.logger.get_severity() mapnik.logger.set_severity(getattr(mapnik.severity_type, "None")) # form up an in-memory test db wkb = '010100000000000000000000000000000000000000' # note: the osm_id should be declared INTEGER PRIMARY KEY # but in this case we intentionally do not make this a valid pkey # otherwise sqlite would turn the null into a valid, serial id ds = mapnik.SQLite(file=':memory:', table='test1', initdb=''' create table test1 (osm_id INTEGER,geometry BLOB); insert into test1 values (null,x'%s'); ''' % wkb, extent='-180,-60,180,60', use_spatial_index=False, key_field='osm_id' ) fs = ds.featureset() feature = None try: feature = fs.next() except StopIteration: pass eq_(feature, None) mapnik.logger.set_severity(default_logging_severity) if __name__ == "__main__": setup() result = run_all(eval(x) for x in dir() if x.startswith("test_")) teardown() exit(result)