bcdata 0.10.2__tar.gz → 0.10.4__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.
Files changed (27) hide show
  1. {bcdata-0.10.2 → bcdata-0.10.4}/CHANGES.txt +10 -0
  2. {bcdata-0.10.2/bcdata.egg-info → bcdata-0.10.4}/PKG-INFO +23 -18
  3. {bcdata-0.10.2 → bcdata-0.10.4}/README.md +22 -17
  4. {bcdata-0.10.2 → bcdata-0.10.4}/bcdata/__init__.py +1 -1
  5. {bcdata-0.10.2 → bcdata-0.10.4}/bcdata/bc2pg.py +8 -17
  6. {bcdata-0.10.2 → bcdata-0.10.4}/bcdata/bcdc.py +34 -20
  7. {bcdata-0.10.2 → bcdata-0.10.4}/bcdata/cli.py +16 -2
  8. {bcdata-0.10.2 → bcdata-0.10.4}/bcdata/database.py +18 -0
  9. {bcdata-0.10.2 → bcdata-0.10.4/bcdata.egg-info}/PKG-INFO +23 -18
  10. {bcdata-0.10.2 → bcdata-0.10.4}/tests/test_bc2pg.py +22 -0
  11. {bcdata-0.10.2 → bcdata-0.10.4}/tests/test_bcdc.py +18 -0
  12. {bcdata-0.10.2 → bcdata-0.10.4}/LICENSE.txt +0 -0
  13. {bcdata-0.10.2 → bcdata-0.10.4}/bcdata/wcs.py +0 -0
  14. {bcdata-0.10.2 → bcdata-0.10.4}/bcdata/wfs.py +0 -0
  15. {bcdata-0.10.2 → bcdata-0.10.4}/bcdata.egg-info/SOURCES.txt +0 -0
  16. {bcdata-0.10.2 → bcdata-0.10.4}/bcdata.egg-info/dependency_links.txt +0 -0
  17. {bcdata-0.10.2 → bcdata-0.10.4}/bcdata.egg-info/entry_points.txt +0 -0
  18. {bcdata-0.10.2 → bcdata-0.10.4}/bcdata.egg-info/not-zip-safe +0 -0
  19. {bcdata-0.10.2 → bcdata-0.10.4}/bcdata.egg-info/requires.txt +0 -0
  20. {bcdata-0.10.2 → bcdata-0.10.4}/bcdata.egg-info/top_level.txt +0 -0
  21. {bcdata-0.10.2 → bcdata-0.10.4}/pyproject.toml +0 -0
  22. {bcdata-0.10.2 → bcdata-0.10.4}/requirements.txt +0 -0
  23. {bcdata-0.10.2 → bcdata-0.10.4}/setup.cfg +0 -0
  24. {bcdata-0.10.2 → bcdata-0.10.4}/setup.py +0 -0
  25. {bcdata-0.10.2 → bcdata-0.10.4}/tests/test_cli.py +0 -0
  26. {bcdata-0.10.2 → bcdata-0.10.4}/tests/test_wcs.py +0 -0
  27. {bcdata-0.10.2 → bcdata-0.10.4}/tests/test_wfs.py +0 -0
@@ -1,6 +1,16 @@
1
1
  Changes
2
2
  =======
3
3
 
4
+ 0.10.4 (2024-06-28)
5
+ ------------------
6
+ - bc2pg - enable --no_timestamp on --refresh
7
+
8
+ 0.10.3 (2024-06-28)
9
+ ------------------
10
+ - bc2pg - fix logging error on data refresh (#184)
11
+ - fix failures on specific tables due to API quirks (#179/#181)
12
+ - bc2pg - add missing --bounds option (#173)
13
+
4
14
  0.10.2 (2024-03-01)
5
15
  ------------------
6
16
  - improve connection management for better stability (#171)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: bcdata
3
- Version: 0.10.2
3
+ Version: 0.10.4
4
4
  Summary: Python tools for quick access to DataBC geo-data available via WFS
5
5
  Home-page: https://github.com/smnorris/bcdata
6
6
  Author: Simon Norris
@@ -153,25 +153,30 @@ Usage: bcdata bc2pg [OPTIONS] DATASET
153
153
 
154
154
  Download a DataBC WFS layer to postgres
155
155
 
156
- $ bcdata bc2pg bc-airports --db_url postgresql://postgres:postgres@localhost:5432/postgis
156
+ $ bcdata bc2pg whse_imagery_and_base_maps.gsr_airports_svw
157
157
 
158
158
  Options:
159
- -db, --db_url TEXT Target database url, defaults to $DATABASE_URL
160
- environment variable if set
161
- --table TEXT Destination table name
162
- --schema TEXT Destination schema name
163
- --geometry_type TEXT Spatial type of geometry column
164
- --query TEXT A valid CQL or ECQL query
165
- -c, --count INTEGER Total number of features to load
166
- -k, --primary_key TEXT Primary key of dataset
167
- -s, --sortby TEXT Name of sort field
168
- -e, --schema_only Create empty table from catalogue schema
169
- -a, --append Append to existing table
170
- -r, --refresh Truncate from existing table before load
171
- -t, --no_timestamp Do not log download to bcdata.log
172
- -v, --verbose Increase verbosity.
173
- -q, --quiet Decrease verbosity.
174
- --help Show this message and exit.
159
+ -db, --db_url TEXT Target database url, defaults to
160
+ $DATABASE_URL environment variable if set
161
+ --table TEXT Destination table name
162
+ --schema TEXT Destination schema name
163
+ --geometry_type TEXT Spatial type of geometry column
164
+ --query TEXT A valid CQL or ECQL query
165
+ --bounds TEXT Bounds: "left bottom right top" or "[left,
166
+ bottom, right, top]". Coordinates are BC
167
+ Albers (default) or --bounds_crs
168
+ --bounds-crs, --bounds_crs TEXT
169
+ CRS of provided bounds
170
+ -c, --count INTEGER Total number of features to load
171
+ -k, --primary_key TEXT Primary key of dataset
172
+ -s, --sortby TEXT Name of sort field
173
+ -e, --schema_only Create empty table from catalogue schema
174
+ -a, --append Append to existing table
175
+ -r, --refresh Truncate from existing table before load
176
+ -t, --no_timestamp Do not log download to bcdata.log
177
+ -v, --verbose Increase verbosity.
178
+ -q, --quiet Decrease verbosity.
179
+ --help Show this message and exit.
175
180
  ```
176
181
 
177
182
  #### cat
@@ -119,25 +119,30 @@ Usage: bcdata bc2pg [OPTIONS] DATASET
119
119
 
120
120
  Download a DataBC WFS layer to postgres
121
121
 
122
- $ bcdata bc2pg bc-airports --db_url postgresql://postgres:postgres@localhost:5432/postgis
122
+ $ bcdata bc2pg whse_imagery_and_base_maps.gsr_airports_svw
123
123
 
124
124
  Options:
125
- -db, --db_url TEXT Target database url, defaults to $DATABASE_URL
126
- environment variable if set
127
- --table TEXT Destination table name
128
- --schema TEXT Destination schema name
129
- --geometry_type TEXT Spatial type of geometry column
130
- --query TEXT A valid CQL or ECQL query
131
- -c, --count INTEGER Total number of features to load
132
- -k, --primary_key TEXT Primary key of dataset
133
- -s, --sortby TEXT Name of sort field
134
- -e, --schema_only Create empty table from catalogue schema
135
- -a, --append Append to existing table
136
- -r, --refresh Truncate from existing table before load
137
- -t, --no_timestamp Do not log download to bcdata.log
138
- -v, --verbose Increase verbosity.
139
- -q, --quiet Decrease verbosity.
140
- --help Show this message and exit.
125
+ -db, --db_url TEXT Target database url, defaults to
126
+ $DATABASE_URL environment variable if set
127
+ --table TEXT Destination table name
128
+ --schema TEXT Destination schema name
129
+ --geometry_type TEXT Spatial type of geometry column
130
+ --query TEXT A valid CQL or ECQL query
131
+ --bounds TEXT Bounds: "left bottom right top" or "[left,
132
+ bottom, right, top]". Coordinates are BC
133
+ Albers (default) or --bounds_crs
134
+ --bounds-crs, --bounds_crs TEXT
135
+ CRS of provided bounds
136
+ -c, --count INTEGER Total number of features to load
137
+ -k, --primary_key TEXT Primary key of dataset
138
+ -s, --sortby TEXT Name of sort field
139
+ -e, --schema_only Create empty table from catalogue schema
140
+ -a, --append Append to existing table
141
+ -r, --refresh Truncate from existing table before load
142
+ -t, --no_timestamp Do not log download to bcdata.log
143
+ -v, --verbose Increase verbosity.
144
+ -q, --quiet Decrease verbosity.
145
+ --help Show this message and exit.
141
146
  ```
142
147
 
143
148
  #### cat
@@ -15,4 +15,4 @@ PRIMARY_KEY_DB_URL = (
15
15
  "https://raw.githubusercontent.com/smnorris/bcdata/main/data/primary_keys.json"
16
16
  )
17
17
 
18
- __version__ = "0.10.2"
18
+ __version__ = "0.10.4"
@@ -54,12 +54,15 @@ def bc2pg( # noqa: C901
54
54
  schema=None,
55
55
  geometry_type=None,
56
56
  query=None,
57
+ bounds=None,
58
+ bounds_crs=None,
57
59
  count=None,
58
60
  sortby=None,
59
61
  primary_key=None,
60
62
  timestamp=True,
61
63
  schema_only=False,
62
64
  append=False,
65
+ refresh=False,
63
66
  ):
64
67
  """Request table definition from bcdc and replicate in postgres"""
65
68
  if schema_only and append:
@@ -82,6 +85,8 @@ def bc2pg( # noqa: C901
82
85
  urls = bcdata.define_requests(
83
86
  dataset,
84
87
  query=query,
88
+ bounds=bounds,
89
+ bounds_crs=bounds_crs,
85
90
  count=count,
86
91
  sortby=sortby,
87
92
  crs="epsg:3005",
@@ -224,22 +229,8 @@ def bc2pg( # noqa: C901
224
229
  df = None
225
230
 
226
231
  # once load complete, note date/time of load completion in bcdata.log
227
- if timestamp:
228
- log.info("Logging download date to bcdata.log")
229
- db.execute(
230
- """CREATE SCHEMA IF NOT EXISTS bcdata;
231
- CREATE TABLE IF NOT EXISTS bcdata.log (
232
- table_name text PRIMARY KEY,
233
- latest_download timestamp WITH TIME ZONE
234
- );
235
- """
236
- )
237
- db.execute(
238
- """INSERT INTO bcdata.log (table_name, latest_download)
239
- SELECT %s as table_name, NOW() as latest_download
240
- ON CONFLICT (table_name) DO UPDATE SET latest_download = NOW();
241
- """,
242
- (schema_name + "." + table_name,),
243
- )
232
+ # do not log refreshes here, they called by cli once loaded to target table
233
+ if timestamp and not refresh:
234
+ db.log(schema_name, table_name)
244
235
 
245
236
  return schema_name + "." + table_name
@@ -66,7 +66,7 @@ def get_table_name(package):
66
66
  return layer_names[0]
67
67
 
68
68
 
69
- def get_table_definition(table_name):
69
+ def get_table_definition(table_name): # noqa: C901
70
70
  """
71
71
  Given a table/object name, search BCDC for the first package/resource with a matching "object_name",
72
72
  returns dict: {"comments": <>, "notes": <>, "schema": {<schema dict>} }
@@ -92,9 +92,8 @@ def get_table_definition(table_name):
92
92
  notes = result["notes"]
93
93
  # iterate through resources associated with each package
94
94
  for resource in result["resources"]:
95
- # wms format resource
95
+ # where to find schema details depends on format type
96
96
  if resource["format"] == "wms":
97
- # if wms, check for table name match in this location
98
97
  if urlparse(resource["url"]).path.split("/")[3] == table_name:
99
98
  if "object_table_comments" in resource.keys():
100
99
  table_comments = resource["object_table_comments"]
@@ -105,29 +104,44 @@ def get_table_definition(table_name):
105
104
  table_details = resource["details"]
106
105
  matches.append((notes, table_comments, table_details))
107
106
  log.debug(resource)
107
+ # oracle sde format type
108
+ if resource["format"] == "oracle_sde":
109
+ if resource["object_name"] == table_name:
110
+ if "object_table_comments" in resource.keys():
111
+ table_comments = resource["object_table_comments"]
112
+ else:
113
+ table_comments = None
114
+ # only add to matches if schema details found
115
+ if "details" in resource.keys() and resource["details"] != "":
116
+ table_details = resource["details"]
117
+ matches.append((notes, table_comments, table_details))
118
+ log.debug(resource)
108
119
 
109
120
  # multiple format resource
110
121
  elif resource["format"] == "multiple":
111
122
  # if multiple format, check for table name match in this location
112
- if resource[
113
- "preview_info"
114
- ]: # first check that the key is not empty
115
- if (
116
- json.loads(resource["preview_info"])["layer_name"]
117
- == table_name
118
- ):
119
- if "object_table_comments" in resource.keys():
120
- table_comments = resource["object_table_comments"]
121
- else:
122
- table_comments = None
123
- # only add to matches if schema details found
123
+ if resource["preview_info"]:
124
+ # check that layer_name key is present
125
+ if "layer_name" in json.loads(resource["preview_info"]):
126
+ # then check if it matches the table name
124
127
  if (
125
- "details" in resource.keys()
126
- and resource["details"] != ""
128
+ json.loads(resource["preview_info"])["layer_name"]
129
+ == table_name
127
130
  ):
128
- table_details = resource["details"]
129
- matches.append((notes, table_comments, table_details))
130
- log.debug(resource)
131
+ if "object_table_comments" in resource.keys():
132
+ table_comments = resource["object_table_comments"]
133
+ else:
134
+ table_comments = None
135
+ # only add to matches if schema details found
136
+ if (
137
+ "details" in resource.keys()
138
+ and resource["details"] != ""
139
+ ):
140
+ table_details = resource["details"]
141
+ matches.append(
142
+ (notes, table_comments, table_details)
143
+ )
144
+ log.debug(resource)
131
145
 
132
146
  # uniquify the result
133
147
  if len(matches) > 0:
@@ -320,6 +320,13 @@ def clear_cache(verbose, quiet):
320
320
  "--query",
321
321
  help="A valid CQL or ECQL query",
322
322
  )
323
+ @bounds_opt
324
+ @click.option(
325
+ "--bounds-crs",
326
+ "--bounds_crs",
327
+ help="CRS of provided bounds",
328
+ default="EPSG:3005",
329
+ )
323
330
  @click.option(
324
331
  "--count",
325
332
  "-c",
@@ -362,6 +369,8 @@ def bc2pg(
362
369
  schema,
363
370
  geometry_type,
364
371
  query,
372
+ bounds,
373
+ bounds_crs,
365
374
  count,
366
375
  primary_key,
367
376
  sortby,
@@ -372,10 +381,10 @@ def bc2pg(
372
381
  verbose,
373
382
  quiet,
374
383
  ):
375
- """Download a DataBC WFS layer to postgres
384
+ """Load a DataBC WFS layer to a postgres db
376
385
 
377
386
  \b
378
- $ bcdata bc2pg bc-airports --db_url postgresql://postgres:postgres@localhost:5432/postgis
387
+ $ bcdata bc2pg whse_imagery_and_base_maps.gsr_airports_svw
379
388
  """
380
389
  # for this command, default to INFO level logging
381
390
  verbosity = verbose - quiet
@@ -411,6 +420,8 @@ def bc2pg(
411
420
  table=table,
412
421
  schema=schema,
413
422
  query=query,
423
+ bounds=bounds,
424
+ bounds_crs=bounds_crs,
414
425
  geometry_type=geometry_type,
415
426
  count=count,
416
427
  primary_key=primary_key,
@@ -418,6 +429,7 @@ def bc2pg(
418
429
  timestamp=timestamp,
419
430
  schema_only=schema_only,
420
431
  append=append,
432
+ refresh=refresh,
421
433
  )
422
434
 
423
435
  # if refreshing, flush from temp bcdata schema to target schema
@@ -426,6 +438,8 @@ def bc2pg(
426
438
  s, table = out_table.split(".")
427
439
  db.refresh(schema_target, table)
428
440
  out_table = schema_target + "." + table
441
+ if timestamp:
442
+ db.log(schema_target, table)
429
443
 
430
444
  # do not notify of data load completion when no data load has occured
431
445
  if not schema_only:
@@ -212,3 +212,21 @@ class Database(object):
212
212
  metadata_obj = MetaData(schema=schema)
213
213
  table = Table(table, metadata_obj, schema=schema, autoload_with=self.engine)
214
214
  return list(table.columns.keys())
215
+
216
+ def log(self, schema_name, table_name):
217
+ log.info("Logging download date to bcdata.log")
218
+ self.execute(
219
+ """CREATE SCHEMA IF NOT EXISTS bcdata;
220
+ CREATE TABLE IF NOT EXISTS bcdata.log (
221
+ table_name text PRIMARY KEY,
222
+ latest_download timestamp WITH TIME ZONE
223
+ );
224
+ """
225
+ )
226
+ self.execute(
227
+ """INSERT INTO bcdata.log (table_name, latest_download)
228
+ SELECT %s as table_name, NOW() as latest_download
229
+ ON CONFLICT (table_name) DO UPDATE SET latest_download = NOW();
230
+ """,
231
+ (schema_name + "." + table_name,),
232
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: bcdata
3
- Version: 0.10.2
3
+ Version: 0.10.4
4
4
  Summary: Python tools for quick access to DataBC geo-data available via WFS
5
5
  Home-page: https://github.com/smnorris/bcdata
6
6
  Author: Simon Norris
@@ -153,25 +153,30 @@ Usage: bcdata bc2pg [OPTIONS] DATASET
153
153
 
154
154
  Download a DataBC WFS layer to postgres
155
155
 
156
- $ bcdata bc2pg bc-airports --db_url postgresql://postgres:postgres@localhost:5432/postgis
156
+ $ bcdata bc2pg whse_imagery_and_base_maps.gsr_airports_svw
157
157
 
158
158
  Options:
159
- -db, --db_url TEXT Target database url, defaults to $DATABASE_URL
160
- environment variable if set
161
- --table TEXT Destination table name
162
- --schema TEXT Destination schema name
163
- --geometry_type TEXT Spatial type of geometry column
164
- --query TEXT A valid CQL or ECQL query
165
- -c, --count INTEGER Total number of features to load
166
- -k, --primary_key TEXT Primary key of dataset
167
- -s, --sortby TEXT Name of sort field
168
- -e, --schema_only Create empty table from catalogue schema
169
- -a, --append Append to existing table
170
- -r, --refresh Truncate from existing table before load
171
- -t, --no_timestamp Do not log download to bcdata.log
172
- -v, --verbose Increase verbosity.
173
- -q, --quiet Decrease verbosity.
174
- --help Show this message and exit.
159
+ -db, --db_url TEXT Target database url, defaults to
160
+ $DATABASE_URL environment variable if set
161
+ --table TEXT Destination table name
162
+ --schema TEXT Destination schema name
163
+ --geometry_type TEXT Spatial type of geometry column
164
+ --query TEXT A valid CQL or ECQL query
165
+ --bounds TEXT Bounds: "left bottom right top" or "[left,
166
+ bottom, right, top]". Coordinates are BC
167
+ Albers (default) or --bounds_crs
168
+ --bounds-crs, --bounds_crs TEXT
169
+ CRS of provided bounds
170
+ -c, --count INTEGER Total number of features to load
171
+ -k, --primary_key TEXT Primary key of dataset
172
+ -s, --sortby TEXT Name of sort field
173
+ -e, --schema_only Create empty table from catalogue schema
174
+ -a, --append Append to existing table
175
+ -r, --refresh Truncate from existing table before load
176
+ -t, --no_timestamp Do not log download to bcdata.log
177
+ -v, --verbose Increase verbosity.
178
+ -q, --quiet Decrease verbosity.
179
+ --help Show this message and exit.
175
180
  ```
176
181
 
177
182
  #### cat
@@ -38,6 +38,28 @@ def test_bc2pg_count():
38
38
  DB_CONNECTION.execute("drop table " + AIRPORTS_TABLE)
39
39
 
40
40
 
41
+ def test_bc2pg_bounds():
42
+ bcdata.bc2pg(AIRPORTS_TABLE, DB_URL, bounds=[1188000, 377051, 1207437, 390361])
43
+ assert AIRPORTS_TABLE in DB_CONNECTION.tables
44
+ r = DB_CONNECTION.query(
45
+ "select airport_name from whse_imagery_and_base_maps.gsr_airports_svw"
46
+ )
47
+ assert len(r) == 8
48
+ DB_CONNECTION.execute("drop table " + AIRPORTS_TABLE)
49
+
50
+
51
+ def test_bc2pg_bounds_count():
52
+ bcdata.bc2pg(
53
+ AIRPORTS_TABLE, DB_URL, bounds=[1188000, 377051, 1207437, 390361], count=6
54
+ )
55
+ assert AIRPORTS_TABLE in DB_CONNECTION.tables
56
+ r = DB_CONNECTION.query(
57
+ "select airport_name from whse_imagery_and_base_maps.gsr_airports_svw"
58
+ )
59
+ assert len(r) == 6
60
+ DB_CONNECTION.execute("drop table " + AIRPORTS_TABLE)
61
+
62
+
41
63
  def test_bc2pg_table():
42
64
  bcdata.bc2pg(AIRPORTS_TABLE, DB_URL, table="testtable")
43
65
  assert "whse_imagery_and_base_maps.testtable" in DB_CONNECTION.tables
@@ -49,3 +49,21 @@ def test_get_table_definition_format_multi_nopreview():
49
49
  assert table_definition["description"]
50
50
  assert table_definition["comments"]
51
51
  assert table_definition["schema"]
52
+
53
+
54
+ def test_get_table_definition_format_multi_nolayer():
55
+ table_definition = bcdc.get_table_definition(
56
+ "WHSE_HUMAN_CULTURAL_ECONOMIC.HIST_HISTORIC_ENVIRONMENTS_SP"
57
+ )
58
+ assert table_definition["description"]
59
+ assert table_definition["comments"]
60
+ assert table_definition["schema"]
61
+
62
+
63
+ def test_get_table_definition_format_oracle_sde():
64
+ table_definition = bcdc.get_table_definition(
65
+ "WHSE_LAND_USE_PLANNING.RMP_LANDSCAPE_RSRV_DESIGN_SP"
66
+ )
67
+ assert table_definition["description"]
68
+ assert table_definition["comments"]
69
+ assert table_definition["schema"]
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