bcdata 0.13.0__tar.gz → 0.14.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {bcdata-0.13.0/src/bcdata.egg-info → bcdata-0.14.0}/PKG-INFO +16 -11
- {bcdata-0.13.0 → bcdata-0.14.0}/README.md +15 -10
- {bcdata-0.13.0 → bcdata-0.14.0}/src/bcdata/__init__.py +1 -3
- {bcdata-0.13.0 → bcdata-0.14.0}/src/bcdata/bc2pg.py +6 -13
- {bcdata-0.13.0 → bcdata-0.14.0}/src/bcdata/cli.py +60 -40
- {bcdata-0.13.0 → bcdata-0.14.0}/src/bcdata/wfs.py +86 -176
- {bcdata-0.13.0 → bcdata-0.14.0/src/bcdata.egg-info}/PKG-INFO +16 -11
- {bcdata-0.13.0 → bcdata-0.14.0}/tests/test_cli.py +9 -0
- {bcdata-0.13.0 → bcdata-0.14.0}/tests/test_wfs.py +1 -26
- {bcdata-0.13.0 → bcdata-0.14.0}/LICENSE.txt +0 -0
- {bcdata-0.13.0 → bcdata-0.14.0}/pyproject.toml +0 -0
- {bcdata-0.13.0 → bcdata-0.14.0}/setup.cfg +0 -0
- {bcdata-0.13.0 → bcdata-0.14.0}/src/bcdata/bcdc.py +0 -0
- {bcdata-0.13.0 → bcdata-0.14.0}/src/bcdata/database.py +0 -0
- {bcdata-0.13.0 → bcdata-0.14.0}/src/bcdata/wcs.py +0 -0
- {bcdata-0.13.0 → bcdata-0.14.0}/src/bcdata.egg-info/SOURCES.txt +0 -0
- {bcdata-0.13.0 → bcdata-0.14.0}/src/bcdata.egg-info/dependency_links.txt +0 -0
- {bcdata-0.13.0 → bcdata-0.14.0}/src/bcdata.egg-info/entry_points.txt +0 -0
- {bcdata-0.13.0 → bcdata-0.14.0}/src/bcdata.egg-info/requires.txt +0 -0
- {bcdata-0.13.0 → bcdata-0.14.0}/src/bcdata.egg-info/top_level.txt +0 -0
- {bcdata-0.13.0 → bcdata-0.14.0}/tests/test_bc2pg.py +0 -0
- {bcdata-0.13.0 → bcdata-0.14.0}/tests/test_bcdc.py +0 -0
- {bcdata-0.13.0 → bcdata-0.14.0}/tests/test_wcs.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: bcdata
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.14.0
|
|
4
4
|
Summary: Download open data, monitor and report on changes
|
|
5
5
|
Author-email: Simon Norris <snorris@hillcrestgeo.ca>
|
|
6
6
|
Project-URL: Homepage, https://github.com/smnorris/bcdata
|
|
@@ -123,7 +123,8 @@ AERODROME_STATUS AIRCRAFT_ACCESS_IND AIRPORT_NAME
|
|
|
123
123
|
```
|
|
124
124
|
|
|
125
125
|
### CLI
|
|
126
|
-
|
|
126
|
+
|
|
127
|
+
Commands available via the bcdata command line interface are documented with the --help option
|
|
127
128
|
|
|
128
129
|
```
|
|
129
130
|
|
|
@@ -136,7 +137,7 @@ Options:
|
|
|
136
137
|
--help Show this message and exit.
|
|
137
138
|
|
|
138
139
|
Commands:
|
|
139
|
-
bc2pg
|
|
140
|
+
bc2pg Load a DataBC WFS layer to a postgres db
|
|
140
141
|
cat Write DataBC features to stdout as GeoJSON feature objects.
|
|
141
142
|
dem Dump BC DEM to TIFF
|
|
142
143
|
dump Write DataBC features to stdout as GeoJSON feature collection.
|
|
@@ -151,7 +152,7 @@ $ bcdata bc2pg --help
|
|
|
151
152
|
|
|
152
153
|
Usage: bcdata bc2pg [OPTIONS] DATASET
|
|
153
154
|
|
|
154
|
-
|
|
155
|
+
Load a DataBC WFS layer to a postgres db
|
|
155
156
|
|
|
156
157
|
$ bcdata bc2pg whse_imagery_and_base_maps.gsr_airports_svw
|
|
157
158
|
|
|
@@ -190,16 +191,18 @@ Usage: bcdata cat [OPTIONS] DATASET
|
|
|
190
191
|
|
|
191
192
|
Options:
|
|
192
193
|
--query TEXT A valid CQL or ECQL query
|
|
194
|
+
-c, --count INTEGER Number of features to request and dump
|
|
193
195
|
--bounds TEXT Bounds: "left bottom right top" or "[left,
|
|
194
196
|
bottom, right, top]". Coordinates are BC
|
|
195
197
|
Albers (default) or --bounds_crs
|
|
198
|
+
--bounds-crs, --bounds_crs TEXT
|
|
199
|
+
CRS of provided bounds
|
|
196
200
|
--indent INTEGER Indentation level for JSON output
|
|
197
201
|
--compact / --not-compact Use compact separators (',', ':').
|
|
198
202
|
--dst-crs, --dst_crs TEXT Destination CRS
|
|
199
203
|
-s, --sortby TEXT Name of sort field
|
|
200
|
-
--bounds-crs, --bounds_crs TEXT
|
|
201
|
-
CRS of provided bounds
|
|
202
204
|
-l, --lowercase Write column/properties names as lowercase
|
|
205
|
+
-m, --promote-to-multi Promote features to multipart
|
|
203
206
|
-v, --verbose Increase verbosity.
|
|
204
207
|
-q, --quiet Decrease verbosity.
|
|
205
208
|
--help Show this message and exit.
|
|
@@ -219,9 +222,8 @@ Options:
|
|
|
219
222
|
--bounds TEXT Bounds: "left bottom right top" or "[left,
|
|
220
223
|
bottom, right, top]". Coordinates are BC
|
|
221
224
|
Albers (default) or --bounds_crs [required]
|
|
222
|
-
--dst-crs
|
|
223
|
-
--bounds-crs
|
|
224
|
-
CRS of provided bounds
|
|
225
|
+
--dst-crs TEXT CRS of output file
|
|
226
|
+
--bounds-crs TEXT CRS of provided bounds
|
|
225
227
|
-r, --resolution INTEGER
|
|
226
228
|
-a, --align Align provided bounds to provincial standard
|
|
227
229
|
-i, --interpolation [nearest|bilinear|bicubic]
|
|
@@ -243,18 +245,20 @@ Usage: bcdata dump [OPTIONS] DATASET
|
|
|
243
245
|
$ bcdata dump bc-airports --query "AIRPORT_NAME='Victoria Harbour (Shoal Point) Heliport'"
|
|
244
246
|
$ bcdata dump bc-airports --bounds xmin ymin xmax ymax
|
|
245
247
|
|
|
246
|
-
It can also be combined to read bounds of a feature dataset using Fiona:
|
|
248
|
+
It can also be combined to read bounds of a feature dataset using Fiona:
|
|
247
249
|
$ bcdata dump bc-airports --bounds $(fio info aoi.shp --bounds)
|
|
248
250
|
|
|
249
251
|
Options:
|
|
250
252
|
--query TEXT A valid CQL or ECQL query
|
|
251
|
-
-
|
|
253
|
+
-c, --count INTEGER Number of features to request and dump
|
|
252
254
|
--bounds TEXT Bounds: "left bottom right top" or "[left,
|
|
253
255
|
bottom, right, top]". Coordinates are BC
|
|
254
256
|
Albers (default) or --bounds_crs
|
|
255
257
|
--bounds-crs, --bounds_crs TEXT
|
|
256
258
|
CRS of provided bounds
|
|
259
|
+
-s, --sortby TEXT Name of sort field
|
|
257
260
|
-l, --lowercase Write column/properties names as lowercase
|
|
261
|
+
-m, --promote-to-multi Promote features to multipart
|
|
258
262
|
-v, --verbose Increase verbosity.
|
|
259
263
|
-q, --quiet Decrease verbosity.
|
|
260
264
|
--help Show this message and exit.
|
|
@@ -291,6 +295,7 @@ Usage: bcdata list [OPTIONS]
|
|
|
291
295
|
List DataBC layers available via WFS
|
|
292
296
|
|
|
293
297
|
Options:
|
|
298
|
+
-r, --refresh Refresh the cached list
|
|
294
299
|
--help Show this message and exit.
|
|
295
300
|
```
|
|
296
301
|
|
|
@@ -91,7 +91,8 @@ AERODROME_STATUS AIRCRAFT_ACCESS_IND AIRPORT_NAME
|
|
|
91
91
|
```
|
|
92
92
|
|
|
93
93
|
### CLI
|
|
94
|
-
|
|
94
|
+
|
|
95
|
+
Commands available via the bcdata command line interface are documented with the --help option
|
|
95
96
|
|
|
96
97
|
```
|
|
97
98
|
|
|
@@ -104,7 +105,7 @@ Options:
|
|
|
104
105
|
--help Show this message and exit.
|
|
105
106
|
|
|
106
107
|
Commands:
|
|
107
|
-
bc2pg
|
|
108
|
+
bc2pg Load a DataBC WFS layer to a postgres db
|
|
108
109
|
cat Write DataBC features to stdout as GeoJSON feature objects.
|
|
109
110
|
dem Dump BC DEM to TIFF
|
|
110
111
|
dump Write DataBC features to stdout as GeoJSON feature collection.
|
|
@@ -119,7 +120,7 @@ $ bcdata bc2pg --help
|
|
|
119
120
|
|
|
120
121
|
Usage: bcdata bc2pg [OPTIONS] DATASET
|
|
121
122
|
|
|
122
|
-
|
|
123
|
+
Load a DataBC WFS layer to a postgres db
|
|
123
124
|
|
|
124
125
|
$ bcdata bc2pg whse_imagery_and_base_maps.gsr_airports_svw
|
|
125
126
|
|
|
@@ -158,16 +159,18 @@ Usage: bcdata cat [OPTIONS] DATASET
|
|
|
158
159
|
|
|
159
160
|
Options:
|
|
160
161
|
--query TEXT A valid CQL or ECQL query
|
|
162
|
+
-c, --count INTEGER Number of features to request and dump
|
|
161
163
|
--bounds TEXT Bounds: "left bottom right top" or "[left,
|
|
162
164
|
bottom, right, top]". Coordinates are BC
|
|
163
165
|
Albers (default) or --bounds_crs
|
|
166
|
+
--bounds-crs, --bounds_crs TEXT
|
|
167
|
+
CRS of provided bounds
|
|
164
168
|
--indent INTEGER Indentation level for JSON output
|
|
165
169
|
--compact / --not-compact Use compact separators (',', ':').
|
|
166
170
|
--dst-crs, --dst_crs TEXT Destination CRS
|
|
167
171
|
-s, --sortby TEXT Name of sort field
|
|
168
|
-
--bounds-crs, --bounds_crs TEXT
|
|
169
|
-
CRS of provided bounds
|
|
170
172
|
-l, --lowercase Write column/properties names as lowercase
|
|
173
|
+
-m, --promote-to-multi Promote features to multipart
|
|
171
174
|
-v, --verbose Increase verbosity.
|
|
172
175
|
-q, --quiet Decrease verbosity.
|
|
173
176
|
--help Show this message and exit.
|
|
@@ -187,9 +190,8 @@ Options:
|
|
|
187
190
|
--bounds TEXT Bounds: "left bottom right top" or "[left,
|
|
188
191
|
bottom, right, top]". Coordinates are BC
|
|
189
192
|
Albers (default) or --bounds_crs [required]
|
|
190
|
-
--dst-crs
|
|
191
|
-
--bounds-crs
|
|
192
|
-
CRS of provided bounds
|
|
193
|
+
--dst-crs TEXT CRS of output file
|
|
194
|
+
--bounds-crs TEXT CRS of provided bounds
|
|
193
195
|
-r, --resolution INTEGER
|
|
194
196
|
-a, --align Align provided bounds to provincial standard
|
|
195
197
|
-i, --interpolation [nearest|bilinear|bicubic]
|
|
@@ -211,18 +213,20 @@ Usage: bcdata dump [OPTIONS] DATASET
|
|
|
211
213
|
$ bcdata dump bc-airports --query "AIRPORT_NAME='Victoria Harbour (Shoal Point) Heliport'"
|
|
212
214
|
$ bcdata dump bc-airports --bounds xmin ymin xmax ymax
|
|
213
215
|
|
|
214
|
-
It can also be combined to read bounds of a feature dataset using Fiona:
|
|
216
|
+
It can also be combined to read bounds of a feature dataset using Fiona:
|
|
215
217
|
$ bcdata dump bc-airports --bounds $(fio info aoi.shp --bounds)
|
|
216
218
|
|
|
217
219
|
Options:
|
|
218
220
|
--query TEXT A valid CQL or ECQL query
|
|
219
|
-
-
|
|
221
|
+
-c, --count INTEGER Number of features to request and dump
|
|
220
222
|
--bounds TEXT Bounds: "left bottom right top" or "[left,
|
|
221
223
|
bottom, right, top]". Coordinates are BC
|
|
222
224
|
Albers (default) or --bounds_crs
|
|
223
225
|
--bounds-crs, --bounds_crs TEXT
|
|
224
226
|
CRS of provided bounds
|
|
227
|
+
-s, --sortby TEXT Name of sort field
|
|
225
228
|
-l, --lowercase Write column/properties names as lowercase
|
|
229
|
+
-m, --promote-to-multi Promote features to multipart
|
|
226
230
|
-v, --verbose Increase verbosity.
|
|
227
231
|
-q, --quiet Decrease verbosity.
|
|
228
232
|
--help Show this message and exit.
|
|
@@ -259,6 +263,7 @@ Usage: bcdata list [OPTIONS]
|
|
|
259
263
|
List DataBC layers available via WFS
|
|
260
264
|
|
|
261
265
|
Options:
|
|
266
|
+
-r, --refresh Refresh the cached list
|
|
262
267
|
--help Show this message and exit.
|
|
263
268
|
```
|
|
264
269
|
|
|
@@ -4,10 +4,8 @@ from .bc2pg import bc2pg as bc2pg
|
|
|
4
4
|
from .bcdc import get_table_definition as get_table_definition
|
|
5
5
|
from .bcdc import get_table_name as get_table_name
|
|
6
6
|
from .wcs import get_dem as get_dem
|
|
7
|
-
from .wfs import define_requests as define_requests
|
|
8
7
|
from .wfs import get_count as get_count
|
|
9
8
|
from .wfs import get_data as get_data
|
|
10
|
-
from .wfs import get_features as get_features
|
|
11
9
|
from .wfs import get_sortkey as get_sortkey
|
|
12
10
|
from .wfs import list_tables as list_tables
|
|
13
11
|
from .wfs import validate_name as validate_name
|
|
@@ -24,4 +22,4 @@ else:
|
|
|
24
22
|
raise Exception(f"Failed to download primary key database at {PRIMARY_KEY_DB_URL}")
|
|
25
23
|
primary_keys = {}
|
|
26
24
|
|
|
27
|
-
__version__ = "0.
|
|
25
|
+
__version__ = "0.14.0"
|
|
@@ -73,14 +73,8 @@ def bc2pg( # noqa: C901
|
|
|
73
73
|
WFS = BCWFS()
|
|
74
74
|
|
|
75
75
|
# define requests
|
|
76
|
-
urls =
|
|
77
|
-
dataset,
|
|
78
|
-
query=query,
|
|
79
|
-
bounds=bounds,
|
|
80
|
-
bounds_crs=bounds_crs,
|
|
81
|
-
count=count,
|
|
82
|
-
sortby=sortby,
|
|
83
|
-
crs="epsg:3005",
|
|
76
|
+
urls = WFS.define_requests(
|
|
77
|
+
dataset, query=query, bounds=bounds, bounds_crs=bounds_crs, count=count, sortby=sortby
|
|
84
78
|
)
|
|
85
79
|
|
|
86
80
|
df = None # just for tracking if first download is done by geometry type check
|
|
@@ -101,7 +95,7 @@ def bc2pg( # noqa: C901
|
|
|
101
95
|
|
|
102
96
|
# if geometry type is not provided, determine type by making the first request
|
|
103
97
|
if not geometry_type:
|
|
104
|
-
df = WFS.
|
|
98
|
+
df = WFS.request_features(url=urls[0], as_gdf=True, crs="epsg:3005", lowercase=True)
|
|
105
99
|
geometry_type = df.geom_type.unique()[0] # keep only the first type
|
|
106
100
|
if numpy.any(df.has_z.unique()[0]): # geopandas does not include Z in geom_type string
|
|
107
101
|
geometry_type = geometry_type + "Z"
|
|
@@ -110,9 +104,8 @@ def bc2pg( # noqa: C901
|
|
|
110
104
|
# (in case all entrys with geom are near the bottom)
|
|
111
105
|
if not geometry_type:
|
|
112
106
|
if not urls[-1] == urls[0]:
|
|
113
|
-
df_temp = WFS.
|
|
114
|
-
|
|
115
|
-
urls=[urls[-1]],
|
|
107
|
+
df_temp = WFS.request_features(
|
|
108
|
+
url=urls[-1],
|
|
116
109
|
as_gdf=True,
|
|
117
110
|
crs="epsg:3005",
|
|
118
111
|
lowercase=True,
|
|
@@ -165,7 +158,7 @@ def bc2pg( # noqa: C901
|
|
|
165
158
|
for n, url in enumerate(urls):
|
|
166
159
|
# if first url not downloaded above when checking geom type, do now
|
|
167
160
|
if df is None:
|
|
168
|
-
df = WFS.
|
|
161
|
+
df = WFS.request_features(url=url, as_gdf=True, crs="epsg:3005", lowercase=True)
|
|
169
162
|
# tidy the resulting dataframe
|
|
170
163
|
df = df.rename_geometry("geom")
|
|
171
164
|
# lowercasify
|
|
@@ -6,12 +6,6 @@ import sys
|
|
|
6
6
|
|
|
7
7
|
import click
|
|
8
8
|
from cligj import compact_opt, indent_opt, quiet_opt, verbose_opt
|
|
9
|
-
from shapely.geometry.linestring import LineString
|
|
10
|
-
from shapely.geometry.multilinestring import MultiLineString
|
|
11
|
-
from shapely.geometry.multipoint import MultiPoint
|
|
12
|
-
from shapely.geometry.multipolygon import MultiPolygon
|
|
13
|
-
from shapely.geometry.point import Point
|
|
14
|
-
from shapely.geometry.polygon import Polygon
|
|
15
9
|
|
|
16
10
|
import bcdata
|
|
17
11
|
from bcdata.database import Database
|
|
@@ -27,6 +21,7 @@ def configure_logging(verbosity):
|
|
|
27
21
|
def complete_dataset_names(ctx, param, incomplete):
|
|
28
22
|
return [k for k in bcdata.list_tables() if k.startswith(incomplete)]
|
|
29
23
|
|
|
24
|
+
|
|
30
25
|
# bounds handling direct from rasterio
|
|
31
26
|
# https://github.com/mapbox/rasterio/blob/master/rasterio/rio/options.py
|
|
32
27
|
# https://github.com/mapbox/rasterio/blob/master/rasterio/rio/clip.py
|
|
@@ -201,7 +196,13 @@ def dem(
|
|
|
201
196
|
"--query",
|
|
202
197
|
help="A valid CQL or ECQL query",
|
|
203
198
|
)
|
|
204
|
-
@click.option(
|
|
199
|
+
@click.option(
|
|
200
|
+
"--count",
|
|
201
|
+
"-c",
|
|
202
|
+
default=None,
|
|
203
|
+
type=int,
|
|
204
|
+
help="Number of features to request and dump",
|
|
205
|
+
)
|
|
205
206
|
@bounds_opt
|
|
206
207
|
@click.option(
|
|
207
208
|
"--bounds-crs",
|
|
@@ -209,17 +210,20 @@ def dem(
|
|
|
209
210
|
help="CRS of provided bounds",
|
|
210
211
|
default="EPSG:3005",
|
|
211
212
|
)
|
|
213
|
+
@click.option("--sortby", "-s", help="Name of sort field")
|
|
214
|
+
@lowercase_opt
|
|
212
215
|
@click.option(
|
|
213
|
-
"--
|
|
214
|
-
"-
|
|
215
|
-
help="
|
|
216
|
+
"--promote-to-multi",
|
|
217
|
+
"-m",
|
|
218
|
+
help="Promote features to multipart",
|
|
216
219
|
is_flag=True,
|
|
217
|
-
default=
|
|
220
|
+
default=False,
|
|
218
221
|
)
|
|
219
|
-
@lowercase_opt
|
|
220
222
|
@verbose_opt
|
|
221
223
|
@quiet_opt
|
|
222
|
-
def dump(
|
|
224
|
+
def dump(
|
|
225
|
+
dataset, query, count, bounds, bounds_crs, sortby, lowercase, promote_to_multi, verbose, quiet
|
|
226
|
+
):
|
|
223
227
|
"""Write DataBC features to stdout as GeoJSON feature collection.
|
|
224
228
|
|
|
225
229
|
\b
|
|
@@ -235,19 +239,19 @@ def dump(dataset, query, out_file, bounds, bounds_crs, no_clean, lowercase, verb
|
|
|
235
239
|
verbosity = verbose - quiet
|
|
236
240
|
configure_logging(verbosity)
|
|
237
241
|
table = bcdata.validate_name(dataset)
|
|
238
|
-
if no_clean:
|
|
239
|
-
clean = False
|
|
240
|
-
else:
|
|
241
|
-
clean = True
|
|
242
242
|
data = bcdata.get_data(
|
|
243
|
-
table,
|
|
243
|
+
table,
|
|
244
|
+
query=query,
|
|
245
|
+
count=count,
|
|
246
|
+
bounds=bounds,
|
|
247
|
+
bounds_crs=bounds_crs,
|
|
248
|
+
sortby=sortby,
|
|
249
|
+
lowercase=lowercase,
|
|
250
|
+
promote_to_multi=promote_to_multi,
|
|
251
|
+
as_gdf=False,
|
|
244
252
|
)
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
sink.write(json.dumps(data))
|
|
248
|
-
else:
|
|
249
|
-
sink = click.get_text_stream("stdout")
|
|
250
|
-
sink.write(json.dumps(data))
|
|
253
|
+
sink = click.get_text_stream("stdout")
|
|
254
|
+
sink.write(json.dumps(data))
|
|
251
255
|
|
|
252
256
|
|
|
253
257
|
@cli.command()
|
|
@@ -256,23 +260,38 @@ def dump(dataset, query, out_file, bounds, bounds_crs, no_clean, lowercase, verb
|
|
|
256
260
|
"--query",
|
|
257
261
|
help="A valid CQL or ECQL query",
|
|
258
262
|
)
|
|
263
|
+
@click.option(
|
|
264
|
+
"--count",
|
|
265
|
+
"-c",
|
|
266
|
+
default=None,
|
|
267
|
+
type=int,
|
|
268
|
+
help="Number of features to request and dump",
|
|
269
|
+
)
|
|
259
270
|
@bounds_opt
|
|
260
|
-
@indent_opt
|
|
261
|
-
@compact_opt
|
|
262
|
-
@dst_crs_opt
|
|
263
|
-
@click.option("--sortby", "-s", help="Name of sort field")
|
|
264
271
|
@click.option(
|
|
265
272
|
"--bounds-crs",
|
|
266
273
|
"--bounds_crs",
|
|
267
274
|
help="CRS of provided bounds",
|
|
268
275
|
default="EPSG:3005",
|
|
269
276
|
)
|
|
277
|
+
@indent_opt
|
|
278
|
+
@compact_opt
|
|
279
|
+
@dst_crs_opt
|
|
280
|
+
@click.option("--sortby", "-s", help="Name of sort field")
|
|
270
281
|
@lowercase_opt
|
|
282
|
+
@click.option(
|
|
283
|
+
"--promote-to-multi",
|
|
284
|
+
"-m",
|
|
285
|
+
help="Promote features to multipart",
|
|
286
|
+
is_flag=True,
|
|
287
|
+
default=False,
|
|
288
|
+
)
|
|
271
289
|
@verbose_opt
|
|
272
290
|
@quiet_opt
|
|
273
291
|
def cat(
|
|
274
292
|
dataset,
|
|
275
293
|
query,
|
|
294
|
+
count,
|
|
276
295
|
bounds,
|
|
277
296
|
bounds_crs,
|
|
278
297
|
indent,
|
|
@@ -280,6 +299,7 @@ def cat(
|
|
|
280
299
|
dst_crs,
|
|
281
300
|
sortby,
|
|
282
301
|
lowercase,
|
|
302
|
+
promote_to_multi,
|
|
283
303
|
verbose,
|
|
284
304
|
quiet,
|
|
285
305
|
):
|
|
@@ -295,23 +315,23 @@ def cat(
|
|
|
295
315
|
if compact:
|
|
296
316
|
dump_kwds["separators"] = (",", ":")
|
|
297
317
|
table = bcdata.validate_name(dataset)
|
|
298
|
-
|
|
318
|
+
WFS = bcdata.wfs.BCWFS()
|
|
319
|
+
for url in WFS.define_requests(
|
|
299
320
|
table,
|
|
300
321
|
query=query,
|
|
322
|
+
count=count,
|
|
301
323
|
bounds=bounds,
|
|
302
324
|
bounds_crs=bounds_crs,
|
|
303
|
-
sortby=sortby,
|
|
304
|
-
crs=dst_crs,
|
|
305
|
-
lowercase=lowercase,
|
|
306
325
|
):
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
326
|
+
featurecollection = WFS.request_features(
|
|
327
|
+
url=url,
|
|
328
|
+
as_gdf=False,
|
|
329
|
+
lowercase=lowercase,
|
|
330
|
+
crs=dst_crs,
|
|
331
|
+
promote_to_multi=promote_to_multi,
|
|
332
|
+
)
|
|
333
|
+
for feat in featurecollection["features"]:
|
|
334
|
+
click.echo(json.dumps(feat, **dump_kwds))
|
|
315
335
|
|
|
316
336
|
|
|
317
337
|
@cli.command()
|
|
@@ -10,6 +10,7 @@ from pathlib import Path
|
|
|
10
10
|
from urllib.parse import urlencode
|
|
11
11
|
|
|
12
12
|
import geopandas as gpd
|
|
13
|
+
import pandas as pd
|
|
13
14
|
import requests
|
|
14
15
|
import stamina
|
|
15
16
|
from owslib.feature import schema as wfs_schema
|
|
@@ -30,26 +31,22 @@ if not sys.warnoptions:
|
|
|
30
31
|
log = logging.getLogger(__name__)
|
|
31
32
|
|
|
32
33
|
|
|
33
|
-
def
|
|
34
|
-
"""
|
|
35
|
-
|
|
36
|
-
[
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
]
|
|
47
|
-
df.geometry = [
|
|
48
|
-
MultiPolygon([feature]) if isinstance(feature, Polygon) else feature
|
|
49
|
-
for feature in df.geometry
|
|
50
|
-
]
|
|
34
|
+
def promote_gdf_to_multi(df):
|
|
35
|
+
"""Promote all features to multipart"""
|
|
36
|
+
df.geometry = [
|
|
37
|
+
MultiPoint([feature]) if isinstance(feature, Point) else feature for feature in df.geometry
|
|
38
|
+
]
|
|
39
|
+
df.geometry = [
|
|
40
|
+
MultiLineString([feature]) if isinstance(feature, LineString) else feature
|
|
41
|
+
for feature in df.geometry
|
|
42
|
+
]
|
|
43
|
+
df.geometry = [
|
|
44
|
+
MultiPolygon([feature]) if isinstance(feature, Polygon) else feature
|
|
45
|
+
for feature in df.geometry
|
|
46
|
+
]
|
|
51
47
|
return df
|
|
52
48
|
|
|
49
|
+
|
|
53
50
|
class ServiceException(Exception):
|
|
54
51
|
pass
|
|
55
52
|
|
|
@@ -158,7 +155,7 @@ class BCWFS(object):
|
|
|
158
155
|
|
|
159
156
|
@stamina.retry(on=requests.HTTPError, timeout=60)
|
|
160
157
|
def _request_features(self, url, silent=False):
|
|
161
|
-
"""Submit a getfeature request to DataBC WFS and return
|
|
158
|
+
"""Submit a getfeature request to DataBC WFS and return feature collection"""
|
|
162
159
|
r = requests.get(url, headers=self.request_headers)
|
|
163
160
|
if not silent:
|
|
164
161
|
log.info(r.url)
|
|
@@ -176,6 +173,26 @@ class BCWFS(object):
|
|
|
176
173
|
r.raise_for_status()
|
|
177
174
|
return r.json()["features"]
|
|
178
175
|
|
|
176
|
+
@stamina.retry(on=requests.HTTPError, timeout=60)
|
|
177
|
+
def _request_featurecollection(self, url, silent=False):
|
|
178
|
+
"""Submit a getfeature request to DataBC WFS and return feature collection"""
|
|
179
|
+
r = requests.get(url, headers=self.request_headers)
|
|
180
|
+
if not silent:
|
|
181
|
+
log.info(r.url)
|
|
182
|
+
else:
|
|
183
|
+
log.debug(r.url)
|
|
184
|
+
if r.status_code in [400, 401, 404]:
|
|
185
|
+
log.error(f"HTTP error {r.status_code}")
|
|
186
|
+
log.error(f"Response headers: {r.headers}")
|
|
187
|
+
log.error(f"Response text: {r.text}")
|
|
188
|
+
raise ServiceException(r.text) # presumed request error
|
|
189
|
+
elif r.status_code in [500, 502, 503, 504]: # presumed serivce error, retry
|
|
190
|
+
log.warning(f"HTTP error: {r.status_code}")
|
|
191
|
+
log.warning(f"Response headers: {r.headers}")
|
|
192
|
+
log.warning(f"Response text: {r.text}")
|
|
193
|
+
r.raise_for_status()
|
|
194
|
+
return r.json()
|
|
195
|
+
|
|
179
196
|
def build_bounds_filter(self, query, bounds, bounds_crs, geom_column):
|
|
180
197
|
"""The bbox param shortcut is mutually exclusive with CQL_FILTER,
|
|
181
198
|
combine query and bounds into a single CQL_FILTER expression
|
|
@@ -274,7 +291,6 @@ class BCWFS(object):
|
|
|
274
291
|
self,
|
|
275
292
|
dataset,
|
|
276
293
|
query=None,
|
|
277
|
-
crs="epsg:4326",
|
|
278
294
|
bounds=None,
|
|
279
295
|
bounds_crs="EPSG:3005",
|
|
280
296
|
count=None,
|
|
@@ -342,7 +358,7 @@ class BCWFS(object):
|
|
|
342
358
|
"request": "GetFeature",
|
|
343
359
|
"typeName": table,
|
|
344
360
|
"outputFormat": "json",
|
|
345
|
-
"SRSNAME":
|
|
361
|
+
"SRSNAME": "EPSG:4326",
|
|
346
362
|
}
|
|
347
363
|
if sortby:
|
|
348
364
|
request["sortby"] = sortby.upper()
|
|
@@ -364,133 +380,79 @@ class BCWFS(object):
|
|
|
364
380
|
urls.append(self.wfs_url + "?" + urlencode(request, doseq=True))
|
|
365
381
|
return urls
|
|
366
382
|
|
|
367
|
-
def
|
|
368
|
-
self,
|
|
383
|
+
def request_features(
|
|
384
|
+
self,
|
|
385
|
+
url,
|
|
386
|
+
as_gdf=False,
|
|
387
|
+
crs="EPSG:4326",
|
|
388
|
+
lowercase=False,
|
|
389
|
+
promote_to_multi=False,
|
|
369
390
|
):
|
|
370
|
-
"""
|
|
371
|
-
#
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
# load to geodataframe, standardize data slightly
|
|
387
|
-
if len(outjson["features"]) > 0:
|
|
388
|
-
gdf = gpd.GeoDataFrame.from_features(outjson)
|
|
389
|
-
gdf.crs = crs
|
|
390
|
-
# minor data cleaning as default
|
|
391
|
-
if clean:
|
|
392
|
-
if gdf.geometry.name != "geometry":
|
|
393
|
-
gdf = gdf.rename_geometry("geometry")
|
|
394
|
-
gdf = ensure_single_geometry_type(gdf)
|
|
395
|
-
table_definition = bcdata.get_table_definition(dataset)
|
|
396
|
-
column_names = [
|
|
397
|
-
c["column_name"]
|
|
398
|
-
for c in table_definition["schema"]
|
|
399
|
-
if c["column_name"] not in ["FEATURE_AREA_SQM", "FEATURE_LENGTH_M"]
|
|
400
|
-
and c["data_type"] in ["NUMBER", "VARCHAR2", "DATE"]
|
|
401
|
-
]
|
|
402
|
-
if lowercase:
|
|
403
|
-
column_names = [c.lower() for c in column_names]
|
|
404
|
-
gdf = gdf[column_names + ["geometry"]]
|
|
391
|
+
"""Make a request to WFS and return data as a FeatureCollection or a GeoDataFrame"""
|
|
392
|
+
# get the data
|
|
393
|
+
featurecollection = self._request_featurecollection(url)
|
|
394
|
+
|
|
395
|
+
# load to gdf for reprojection/minor data cleaning
|
|
396
|
+
if len(featurecollection["features"]) > 0:
|
|
397
|
+
gdf = gpd.GeoDataFrame.from_features(featurecollection)
|
|
398
|
+
gdf = gdf.set_crs("EPSG:4326")
|
|
399
|
+
if crs != "EPSG:4326":
|
|
400
|
+
gdf = gdf.to_crs(crs)
|
|
401
|
+
if gdf.geometry.name != "geometry":
|
|
402
|
+
gdf = gdf.rename_geometry("geometry")
|
|
403
|
+
if lowercase:
|
|
404
|
+
gdf.columns = [c.lower() for c in gdf.columns]
|
|
405
|
+
if promote_to_multi:
|
|
406
|
+
gdf = promote_gdf_to_multi(gdf)
|
|
405
407
|
else:
|
|
406
408
|
gdf = gpd.GeoDataFrame()
|
|
407
409
|
|
|
408
410
|
if as_gdf:
|
|
409
411
|
return gdf
|
|
410
|
-
|
|
411
412
|
else:
|
|
412
413
|
return json.loads(gdf.to_json())
|
|
413
414
|
|
|
414
|
-
def get_data(
|
|
415
|
-
self,
|
|
416
|
-
dataset,
|
|
417
|
-
query=None,
|
|
418
|
-
crs="epsg:4326",
|
|
419
|
-
bounds=None,
|
|
420
|
-
bounds_crs="epsg:3005",
|
|
421
|
-
count=None,
|
|
422
|
-
sortby=None,
|
|
423
|
-
as_gdf=False,
|
|
424
|
-
lowercase=False,
|
|
425
|
-
clean=True
|
|
426
|
-
):
|
|
427
|
-
"""Request features from DataBC WFS and return GeoJSON featurecollection or geodataframe"""
|
|
428
|
-
dataset = self.validate_name(dataset)
|
|
429
|
-
urls = self.define_requests(
|
|
430
|
-
dataset,
|
|
431
|
-
query=query,
|
|
432
|
-
crs=crs,
|
|
433
|
-
bounds=bounds,
|
|
434
|
-
bounds_crs=bounds_crs,
|
|
435
|
-
count=count,
|
|
436
|
-
sortby=sortby,
|
|
437
|
-
)
|
|
438
|
-
return self.make_requests(dataset, urls, as_gdf=as_gdf, crs=crs, lowercase=lowercase, clean=clean)
|
|
439
|
-
|
|
440
|
-
def get_features(
|
|
441
|
-
self,
|
|
442
|
-
dataset,
|
|
443
|
-
query=None,
|
|
444
|
-
crs="epsg:4326",
|
|
445
|
-
bounds=None,
|
|
446
|
-
bounds_crs="epsg:3005",
|
|
447
|
-
count=None,
|
|
448
|
-
sortby=None,
|
|
449
|
-
lowercase=False,
|
|
450
|
-
check_count=True,
|
|
451
|
-
):
|
|
452
|
-
"""Yield features from DataBC WFS"""
|
|
453
|
-
urls = self.define_requests(
|
|
454
|
-
dataset,
|
|
455
|
-
query=query,
|
|
456
|
-
crs=crs,
|
|
457
|
-
bounds=bounds,
|
|
458
|
-
bounds_crs=bounds_crs,
|
|
459
|
-
count=count,
|
|
460
|
-
sortby=sortby,
|
|
461
|
-
check_count=check_count,
|
|
462
|
-
)
|
|
463
|
-
for url in urls:
|
|
464
|
-
for feature in self._request_features(url):
|
|
465
|
-
if lowercase:
|
|
466
|
-
feature["properties"] = {k.lower(): v for k, v in feature["properties"].items()}
|
|
467
|
-
yield feature
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
# abstract away the WFS object
|
|
471
|
-
|
|
472
415
|
|
|
473
|
-
def
|
|
416
|
+
def get_data(
|
|
474
417
|
dataset,
|
|
475
418
|
query=None,
|
|
476
419
|
crs="epsg:4326",
|
|
477
420
|
bounds=None,
|
|
478
|
-
bounds_crs="
|
|
421
|
+
bounds_crs="epsg:3005",
|
|
479
422
|
count=None,
|
|
480
423
|
sortby=None,
|
|
481
|
-
|
|
424
|
+
as_gdf=False,
|
|
425
|
+
lowercase=False,
|
|
426
|
+
promote_to_multi=False,
|
|
482
427
|
):
|
|
428
|
+
"""Request features from DataBC WFS, returning GeoJSON featurecollection or geodataframe"""
|
|
483
429
|
WFS = BCWFS()
|
|
484
|
-
|
|
485
|
-
|
|
430
|
+
table = WFS.validate_name(dataset)
|
|
431
|
+
urls = WFS.define_requests(
|
|
432
|
+
table,
|
|
486
433
|
query=query,
|
|
487
|
-
crs=crs,
|
|
488
434
|
bounds=bounds,
|
|
489
435
|
bounds_crs=bounds_crs,
|
|
490
436
|
count=count,
|
|
491
437
|
sortby=sortby,
|
|
492
|
-
check_count=check_count,
|
|
493
438
|
)
|
|
439
|
+
results = []
|
|
440
|
+
for url in urls:
|
|
441
|
+
results.append(
|
|
442
|
+
WFS.request_features(
|
|
443
|
+
url, crs=crs, as_gdf=True, lowercase=lowercase, promote_to_multi=promote_to_multi
|
|
444
|
+
)
|
|
445
|
+
)
|
|
446
|
+
if len(results) > 1:
|
|
447
|
+
gdf = pd.concat(results)
|
|
448
|
+
elif len(results) == 1:
|
|
449
|
+
gdf = results[0]
|
|
450
|
+
else:
|
|
451
|
+
gdf = gpd.GeoDataFrame()
|
|
452
|
+
if as_gdf:
|
|
453
|
+
return gdf
|
|
454
|
+
else:
|
|
455
|
+
return json.loads(gdf.to_json())
|
|
494
456
|
|
|
495
457
|
|
|
496
458
|
def get_count(dataset, query=None, bounds=None, bounds_crs="EPSG:3005"):
|
|
@@ -506,58 +468,6 @@ def get_count(dataset, query=None, bounds=None, bounds_crs="EPSG:3005"):
|
|
|
506
468
|
)
|
|
507
469
|
|
|
508
470
|
|
|
509
|
-
def get_data(
|
|
510
|
-
dataset,
|
|
511
|
-
query=None,
|
|
512
|
-
crs="epsg:4326",
|
|
513
|
-
bounds=None,
|
|
514
|
-
bounds_crs="epsg:3005",
|
|
515
|
-
count=None,
|
|
516
|
-
sortby=None,
|
|
517
|
-
as_gdf=False,
|
|
518
|
-
lowercase=False,
|
|
519
|
-
clean=True
|
|
520
|
-
):
|
|
521
|
-
WFS = BCWFS()
|
|
522
|
-
return WFS.get_data(
|
|
523
|
-
dataset,
|
|
524
|
-
query=query,
|
|
525
|
-
crs=crs,
|
|
526
|
-
bounds=bounds,
|
|
527
|
-
bounds_crs=bounds_crs,
|
|
528
|
-
count=count,
|
|
529
|
-
sortby=sortby,
|
|
530
|
-
as_gdf=as_gdf,
|
|
531
|
-
lowercase=lowercase,
|
|
532
|
-
clean=clean
|
|
533
|
-
)
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
def get_features(
|
|
537
|
-
dataset,
|
|
538
|
-
query=None,
|
|
539
|
-
crs="epsg:4326",
|
|
540
|
-
bounds=None,
|
|
541
|
-
bounds_crs="epsg:3005",
|
|
542
|
-
count=None,
|
|
543
|
-
sortby=None,
|
|
544
|
-
lowercase=False,
|
|
545
|
-
check_count=True,
|
|
546
|
-
):
|
|
547
|
-
WFS = BCWFS()
|
|
548
|
-
return WFS.get_features(
|
|
549
|
-
dataset,
|
|
550
|
-
query=query,
|
|
551
|
-
crs=crs,
|
|
552
|
-
bounds=bounds,
|
|
553
|
-
bounds_crs=bounds_crs,
|
|
554
|
-
count=count,
|
|
555
|
-
sortby=sortby,
|
|
556
|
-
lowercase=lowercase,
|
|
557
|
-
check_count=check_count,
|
|
558
|
-
)
|
|
559
|
-
|
|
560
|
-
|
|
561
471
|
def get_sortkey(dataset):
|
|
562
472
|
WFS = BCWFS()
|
|
563
473
|
table = WFS.validate_name(dataset)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: bcdata
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.14.0
|
|
4
4
|
Summary: Download open data, monitor and report on changes
|
|
5
5
|
Author-email: Simon Norris <snorris@hillcrestgeo.ca>
|
|
6
6
|
Project-URL: Homepage, https://github.com/smnorris/bcdata
|
|
@@ -123,7 +123,8 @@ AERODROME_STATUS AIRCRAFT_ACCESS_IND AIRPORT_NAME
|
|
|
123
123
|
```
|
|
124
124
|
|
|
125
125
|
### CLI
|
|
126
|
-
|
|
126
|
+
|
|
127
|
+
Commands available via the bcdata command line interface are documented with the --help option
|
|
127
128
|
|
|
128
129
|
```
|
|
129
130
|
|
|
@@ -136,7 +137,7 @@ Options:
|
|
|
136
137
|
--help Show this message and exit.
|
|
137
138
|
|
|
138
139
|
Commands:
|
|
139
|
-
bc2pg
|
|
140
|
+
bc2pg Load a DataBC WFS layer to a postgres db
|
|
140
141
|
cat Write DataBC features to stdout as GeoJSON feature objects.
|
|
141
142
|
dem Dump BC DEM to TIFF
|
|
142
143
|
dump Write DataBC features to stdout as GeoJSON feature collection.
|
|
@@ -151,7 +152,7 @@ $ bcdata bc2pg --help
|
|
|
151
152
|
|
|
152
153
|
Usage: bcdata bc2pg [OPTIONS] DATASET
|
|
153
154
|
|
|
154
|
-
|
|
155
|
+
Load a DataBC WFS layer to a postgres db
|
|
155
156
|
|
|
156
157
|
$ bcdata bc2pg whse_imagery_and_base_maps.gsr_airports_svw
|
|
157
158
|
|
|
@@ -190,16 +191,18 @@ Usage: bcdata cat [OPTIONS] DATASET
|
|
|
190
191
|
|
|
191
192
|
Options:
|
|
192
193
|
--query TEXT A valid CQL or ECQL query
|
|
194
|
+
-c, --count INTEGER Number of features to request and dump
|
|
193
195
|
--bounds TEXT Bounds: "left bottom right top" or "[left,
|
|
194
196
|
bottom, right, top]". Coordinates are BC
|
|
195
197
|
Albers (default) or --bounds_crs
|
|
198
|
+
--bounds-crs, --bounds_crs TEXT
|
|
199
|
+
CRS of provided bounds
|
|
196
200
|
--indent INTEGER Indentation level for JSON output
|
|
197
201
|
--compact / --not-compact Use compact separators (',', ':').
|
|
198
202
|
--dst-crs, --dst_crs TEXT Destination CRS
|
|
199
203
|
-s, --sortby TEXT Name of sort field
|
|
200
|
-
--bounds-crs, --bounds_crs TEXT
|
|
201
|
-
CRS of provided bounds
|
|
202
204
|
-l, --lowercase Write column/properties names as lowercase
|
|
205
|
+
-m, --promote-to-multi Promote features to multipart
|
|
203
206
|
-v, --verbose Increase verbosity.
|
|
204
207
|
-q, --quiet Decrease verbosity.
|
|
205
208
|
--help Show this message and exit.
|
|
@@ -219,9 +222,8 @@ Options:
|
|
|
219
222
|
--bounds TEXT Bounds: "left bottom right top" or "[left,
|
|
220
223
|
bottom, right, top]". Coordinates are BC
|
|
221
224
|
Albers (default) or --bounds_crs [required]
|
|
222
|
-
--dst-crs
|
|
223
|
-
--bounds-crs
|
|
224
|
-
CRS of provided bounds
|
|
225
|
+
--dst-crs TEXT CRS of output file
|
|
226
|
+
--bounds-crs TEXT CRS of provided bounds
|
|
225
227
|
-r, --resolution INTEGER
|
|
226
228
|
-a, --align Align provided bounds to provincial standard
|
|
227
229
|
-i, --interpolation [nearest|bilinear|bicubic]
|
|
@@ -243,18 +245,20 @@ Usage: bcdata dump [OPTIONS] DATASET
|
|
|
243
245
|
$ bcdata dump bc-airports --query "AIRPORT_NAME='Victoria Harbour (Shoal Point) Heliport'"
|
|
244
246
|
$ bcdata dump bc-airports --bounds xmin ymin xmax ymax
|
|
245
247
|
|
|
246
|
-
It can also be combined to read bounds of a feature dataset using Fiona:
|
|
248
|
+
It can also be combined to read bounds of a feature dataset using Fiona:
|
|
247
249
|
$ bcdata dump bc-airports --bounds $(fio info aoi.shp --bounds)
|
|
248
250
|
|
|
249
251
|
Options:
|
|
250
252
|
--query TEXT A valid CQL or ECQL query
|
|
251
|
-
-
|
|
253
|
+
-c, --count INTEGER Number of features to request and dump
|
|
252
254
|
--bounds TEXT Bounds: "left bottom right top" or "[left,
|
|
253
255
|
bottom, right, top]". Coordinates are BC
|
|
254
256
|
Albers (default) or --bounds_crs
|
|
255
257
|
--bounds-crs, --bounds_crs TEXT
|
|
256
258
|
CRS of provided bounds
|
|
259
|
+
-s, --sortby TEXT Name of sort field
|
|
257
260
|
-l, --lowercase Write column/properties names as lowercase
|
|
261
|
+
-m, --promote-to-multi Promote features to multipart
|
|
258
262
|
-v, --verbose Increase verbosity.
|
|
259
263
|
-q, --quiet Decrease verbosity.
|
|
260
264
|
--help Show this message and exit.
|
|
@@ -291,6 +295,7 @@ Usage: bcdata list [OPTIONS]
|
|
|
291
295
|
List DataBC layers available via WFS
|
|
292
296
|
|
|
293
297
|
Options:
|
|
298
|
+
-r, --refresh Refresh the cached list
|
|
294
299
|
--help Show this message and exit.
|
|
295
300
|
```
|
|
296
301
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import json
|
|
1
2
|
import os
|
|
2
3
|
|
|
3
4
|
from click.testing import CliRunner
|
|
@@ -73,6 +74,14 @@ def test_cat_bounds_ll():
|
|
|
73
74
|
assert len(result.output.split("\n")) == 4
|
|
74
75
|
|
|
75
76
|
|
|
77
|
+
def test_dump():
|
|
78
|
+
runner = CliRunner()
|
|
79
|
+
result = runner.invoke(cli, ["dump", AIRPORTS_TABLE, "--count", 1])
|
|
80
|
+
assert result.exit_code == 0
|
|
81
|
+
assert json.loads(result.output)["type"] == "FeatureCollection"
|
|
82
|
+
assert len(json.loads(result.output)["features"]) == 1
|
|
83
|
+
|
|
84
|
+
|
|
76
85
|
def test_bc2pg():
|
|
77
86
|
runner = CliRunner()
|
|
78
87
|
result = runner.invoke(cli, ["bc2pg", AIRPORTS_TABLE, "--db_url", DB_URL])
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import pytest
|
|
2
|
-
import json
|
|
3
2
|
import requests
|
|
4
3
|
import requests_mock
|
|
5
4
|
import stamina
|
|
@@ -94,14 +93,7 @@ def test_get_data_lowercase():
|
|
|
94
93
|
|
|
95
94
|
def test_get_data_crs():
|
|
96
95
|
data = bcdata.get_data(AIRPORTS_TABLE, crs="EPSG:3005")
|
|
97
|
-
assert
|
|
98
|
-
data["crs"]["properties"]["name"] == 'urn:ogc:def:crs:EPSG::3005'
|
|
99
|
-
)
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
def test_get_features():
|
|
103
|
-
data = [f for f in bcdata.get_features(AIRPORTS_TABLE)]
|
|
104
|
-
assert len(data) == 455
|
|
96
|
+
assert data["crs"]["properties"]["name"] == "urn:ogc:def:crs:EPSG::3005"
|
|
105
97
|
|
|
106
98
|
|
|
107
99
|
def test_get_data_count():
|
|
@@ -147,20 +139,3 @@ def test_cql_bounds_filter():
|
|
|
147
139
|
)
|
|
148
140
|
assert len(data["features"]) == 1
|
|
149
141
|
assert data["features"][0]["properties"]["AIRPORT_NAME"] == "Victoria International Airport"
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
def test_clean():
|
|
153
|
-
data = bcdata.get_data(
|
|
154
|
-
AIRPORTS_TABLE,
|
|
155
|
-
query="AIRPORT_NAME='Terrace (Northwest Regional) Airport'",
|
|
156
|
-
)
|
|
157
|
-
assert "SE_ANNO_CAD_DATA" not in data["features"][0]["properties"].keys()
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
def test_no_clean():
|
|
161
|
-
data = bcdata.get_data(
|
|
162
|
-
AIRPORTS_TABLE,
|
|
163
|
-
query="AIRPORT_NAME='Terrace (Northwest Regional) Airport'",
|
|
164
|
-
clean=False
|
|
165
|
-
)
|
|
166
|
-
assert "SE_ANNO_CAD_DATA" in data["features"][0]["properties"].keys()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|