Repository: smnorris/bcdata

Issue:
add option to lowercase all columns
Or just make it the default as with `bc2pg`. 

Discussion:

Patch:
diff --git a/CHANGES.txt b/CHANGES.txt
index 053d7e7..bf94931 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,6 +1,10 @@
 Changes
 =======
 
+0.7.7 (2023-04-13)
+------------------
+- add option to lowercasify properties keys / column names (#126)
+
 0.7.6 (2023-02-01)
 ------------------
 - better handling of connection errors (#118)
diff --git a/README.md b/README.md
index 78c18a9..da83092 100644
--- a/README.md
+++ b/README.md
@@ -153,6 +153,7 @@ Options:
   --bounds-crs, --bounds_crs TEXT
                                   CRS of provided bounds
   -w, --max_workers INTEGER       Max number of concurrent requests
+  -l, --lowercase                 Write column/properties names as lowercase
   -v, --verbose                   Increase verbosity.
   -q, --quiet                     Decrease verbosity.
   --help                          Show this message and exit.
@@ -196,7 +197,7 @@ Usage: bcdata dump [OPTIONS] DATASET
     $ bcdata dump bc-airports --query "AIRPORT_NAME='Victoria Harbour (Shoal Point) Heliport'"
     $ bcdata dump bc-airports --bounds xmin ymin xmax ymax
 
-   It can also be combined to read bounds of a feature dataset using Fiona: 
+   It can also be combined to read bounds of a feature dataset using Fiona:
    $ bcdata dump bc-airports --bounds $(fio info aoi.shp --bounds)
 
 Options:
@@ -207,6 +208,7 @@ Options:
                                   Albers (default) or --bounds_crs
   --bounds-crs, --bounds_crs TEXT
                                   CRS of provided bounds
+  -l, --lowercase                 Write column/properties names as lowercase
   -v, --verbose                   Increase verbosity.
   -q, --quiet                     Decrease verbosity.
   --help                          Show this message and exit.
diff --git a/bcdata/__init__.py b/bcdata/__init__.py
index 3379e13..c3a5a76 100644
--- a/bcdata/__init__.py
+++ b/bcdata/__init__.py
@@ -11,4 +11,4 @@ from .bc2pg import bc2pg
 from .wcs import get_dem
 
 
-__version__ = "0.7.6"
+__version__ = "0.7.7"
diff --git a/bcdata/cli.py b/bcdata/cli.py
index d0f4410..1a7d53c 100644
--- a/bcdata/cli.py
+++ b/bcdata/cli.py
@@ -72,6 +72,10 @@ dst_crs_opt = click.option(
     "--dst-crs", "--dst_crs", default="epsg:4326", help="Destination CRS"
 )
 
+lowercase_opt = click.option(
+    "--lowercase", "-l", is_flag=True, help="Write column/properties names as lowercase"
+)
+
 
 @click.group()
 @click.version_option(version=bcdata.__version__, message="%(version)s")
@@ -191,9 +195,10 @@ def dem(
     help="CRS of provided bounds",
     default="EPSG:3005",
 )
+@lowercase_opt
 @verbose_opt
 @quiet_opt
-def dump(dataset, query, out_file, bounds, bounds_crs, verbose, quiet):
+def dump(dataset, query, out_file, bounds, bounds_crs, lowercase, verbose, quiet):
     """Write DataBC features to stdout as GeoJSON feature collection.
 
     \b
@@ -209,7 +214,9 @@ def dump(dataset, query, out_file, bounds, bounds_crs, verbose, quiet):
     verbosity = verbose - quiet
     configure_logging(verbosity)
     table = bcdata.validate_name(dataset)
-    data = bcdata.get_data(table, query=query, bounds=bounds, bounds_crs=bounds_crs)
+    data = bcdata.get_data(
+        table, query=query, bounds=bounds, bounds_crs=bounds_crs, lowercase=lowercase
+    )
     if out_file:
         with open(out_file, "w") as sink:
             sink.write(json.dumps(data))
@@ -239,6 +246,7 @@ def dump(dataset, query, out_file, bounds, bounds_crs, verbose, quiet):
 @click.option(
     "--max_workers", "-w", default=2, help="Max number of concurrent requests"
 )
+@lowercase_opt
 @verbose_opt
 @quiet_opt
 def cat(
@@ -252,6 +260,7 @@ def cat(
     pagesize,
     sortby,
     max_workers,
+    lowercase,
     verbose,
     quiet,
 ):
@@ -276,6 +285,7 @@ def cat(
         crs=dst_crs,
         pagesize=pagesize,
         max_workers=max_workers,
+        lowercase=lowercase,
     ):
         click.echo(json.dumps(feat, **dump_kwds))
 
diff --git a/bcdata/wfs.py b/bcdata/wfs.py
index e0b5291..837ad98 100644
--- a/bcdata/wfs.py
+++ b/bcdata/wfs.py
@@ -219,6 +219,7 @@ def get_data(
     pagesize=10000,
     max_workers=2,
     as_gdf=False,
+    lowercase=False,
 ):
     """Get GeoJSON featurecollection (or geodataframe) from DataBC WFS"""
     urls = define_requests(
@@ -237,6 +238,12 @@ def get_data(
     outjson = dict(type="FeatureCollection", features=[])
     for result in results:
         outjson["features"] += result
+    # if specified, lowercasify all properties
+    if lowercase:
+        for feature in outjson["features"]:
+            feature["properties"] = {
+                k.lower(): v for k, v in feature["properties"].items()
+            }
     if not as_gdf:
         # If output crs is specified, include the crs object in the json
         # But as default, we prefer to default to 4326 and RFC7946 (no crs)
@@ -265,6 +272,7 @@ def get_features(
     sortby=None,
     pagesize=10000,
     max_workers=2,
+    lowercase=False,
 ):
     """Yield features from DataBC WFS"""
     urls = define_requests(
@@ -280,6 +288,10 @@ def get_features(
     with ThreadPoolExecutor(max_workers=max_workers) as executor:
         for result in executor.map(make_request, urls):
             for feature in result:
+                if lowercase:
+                    feature["properties"] = {
+                        k.lower(): v for k, v in feature["properties"].items()
+                    }
                 yield feature
 
 


Test patch:
diff --git a/tests/test_bcdata.py b/tests/test_bcdata.py
index 4a839df..a6ef968 100644
--- a/tests/test_bcdata.py
+++ b/tests/test_bcdata.py
@@ -57,6 +57,11 @@ def test_get_data_small():
     assert data["type"] == "FeatureCollection"
 
 
+def test_get_data_lowercase():
+    data = bcdata.get_data(AIRPORTS_TABLE, lowercase=True)
+    assert "airport_name" in data["features"][0]["properties"].keys()
+
+
 def test_get_data_crs():
     data = bcdata.get_data(AIRPORTS_TABLE, crs="EPSG:3005")
     assert (