gla-data 0.2.1__tar.gz → 0.3.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.
Files changed (74) hide show
  1. gla_data-0.3.0/PKG-INFO +165 -0
  2. gla_data-0.3.0/README.md +139 -0
  3. {gla_data-0.2.1 → gla_data-0.3.0}/pyproject.toml +36 -3
  4. gla_data-0.3.0/src/gla_data/__init__.py +60 -0
  5. gla_data-0.2.1/src/gla_data/addressbase.py → gla_data-0.3.0/src/gla_data/_addressbase.py +17 -98
  6. gla_data-0.3.0/src/gla_data/_aerial_imagery.py +161 -0
  7. gla_data-0.3.0/src/gla_data/_bbox.py +59 -0
  8. {gla_data-0.2.1 → gla_data-0.3.0}/src/gla_data/_cache.py +1 -1
  9. {gla_data-0.2.1 → gla_data-0.3.0}/src/gla_data/_lbsm.py +12 -42
  10. gla_data-0.3.0/src/gla_data/_london.py +54 -0
  11. {gla_data-0.2.1 → gla_data-0.3.0}/src/gla_data/_ons.py +15 -5
  12. gla_data-0.3.0/src/gla_data/_postgres.py +416 -0
  13. gla_data-0.3.0/src/gla_data/_s3.py +268 -0
  14. {gla_data-0.2.1 → gla_data-0.3.0}/src/gla_data/_schemas.py +21 -50
  15. gla_data-0.3.0/src/gla_data/_tree_canopy.py +296 -0
  16. gla_data-0.3.0/src/gla_data/addressbase.py +129 -0
  17. gla_data-0.3.0/src/gla_data/addressbase_ngd.py +305 -0
  18. gla_data-0.3.0/src/gla_data/aerial_imagery.py +375 -0
  19. {gla_data-0.2.1 → gla_data-0.3.0}/src/gla_data/catalogue.py +36 -4
  20. {gla_data-0.2.1 → gla_data-0.3.0}/src/gla_data/census.py +1 -2
  21. gla_data-0.3.0/src/gla_data/cli.py +211 -0
  22. gla_data-0.3.0/src/gla_data/config.py +180 -0
  23. gla_data-0.3.0/src/gla_data/explore.py +139 -0
  24. gla_data-0.3.0/src/gla_data/front_gardens.py +77 -0
  25. {gla_data-0.2.1 → gla_data-0.3.0}/src/gla_data/lbsm.py +5 -4
  26. gla_data-0.3.0/src/gla_data/mastermap.py +208 -0
  27. {gla_data-0.2.1 → gla_data-0.3.0}/src/gla_data/transforms.py +83 -48
  28. gla_data-0.3.0/src/gla_data/tree_canopy.py +209 -0
  29. {gla_data-0.2.1 → gla_data-0.3.0}/tests/test_addressbase.py +40 -6
  30. gla_data-0.3.0/tests/test_addressbase_ngd.py +248 -0
  31. gla_data-0.3.0/tests/test_aerial_imagery.py +355 -0
  32. {gla_data-0.2.1 → gla_data-0.3.0}/tests/test_aggregate.py +34 -0
  33. {gla_data-0.2.1 → gla_data-0.3.0}/tests/test_boundaries.py +1 -3
  34. {gla_data-0.2.1 → gla_data-0.3.0}/tests/test_catalogue.py +1 -1
  35. gla_data-0.3.0/tests/test_cli.py +101 -0
  36. gla_data-0.3.0/tests/test_config.py +87 -0
  37. gla_data-0.3.0/tests/test_conventions.py +206 -0
  38. {gla_data-0.2.1 → gla_data-0.3.0}/tests/test_crosswalk.py +32 -0
  39. gla_data-0.3.0/tests/test_explore.py +93 -0
  40. gla_data-0.3.0/tests/test_front_gardens.py +63 -0
  41. gla_data-0.3.0/tests/test_london.py +26 -0
  42. gla_data-0.3.0/tests/test_mastermap.py +279 -0
  43. gla_data-0.3.0/tests/test_postgres.py +282 -0
  44. gla_data-0.3.0/tests/test_s3.py +254 -0
  45. gla_data-0.3.0/tests/test_tree_canopy.py +361 -0
  46. gla_data-0.2.1/.copier-answers.yml +0 -13
  47. gla_data-0.2.1/.env.example +0 -43
  48. gla_data-0.2.1/.github/workflows/ci.yml +0 -35
  49. gla_data-0.2.1/.github/workflows/publish.yml +0 -43
  50. gla_data-0.2.1/PKG-INFO +0 -111
  51. gla_data-0.2.1/README.md +0 -93
  52. gla_data-0.2.1/notebooks/addressbase_postgres_setup.ipynb +0 -182
  53. gla_data-0.2.1/pixi.lock +0 -12984
  54. gla_data-0.2.1/pixi.toml +0 -41
  55. gla_data-0.2.1/src/gla_data/__init__.py +0 -22
  56. gla_data-0.2.1/src/gla_data/_postgres.py +0 -141
  57. gla_data-0.2.1/src/gla_data/cli.py +0 -59
  58. gla_data-0.2.1/src/gla_data/config.py +0 -62
  59. gla_data-0.2.1/tests/test_cli.py +0 -17
  60. gla_data-0.2.1/tests/test_postgres.py +0 -143
  61. gla_data-0.2.1/uv.lock +0 -763
  62. {gla_data-0.2.1 → gla_data-0.3.0}/.gitignore +0 -0
  63. {gla_data-0.2.1 → gla_data-0.3.0}/src/gla_data/_arcgis.py +0 -0
  64. {gla_data-0.2.1 → gla_data-0.3.0}/src/gla_data/_londondatastore.py +0 -0
  65. {gla_data-0.2.1 → gla_data-0.3.0}/src/gla_data/_ukds.py +0 -0
  66. {gla_data-0.2.1 → gla_data-0.3.0}/src/gla_data/geography.py +0 -0
  67. {gla_data-0.2.1 → gla_data-0.3.0}/src/gla_data/py.typed +0 -0
  68. {gla_data-0.2.1 → gla_data-0.3.0}/tests/__init__.py +0 -0
  69. {gla_data-0.2.1 → gla_data-0.3.0}/tests/conftest.py +0 -0
  70. {gla_data-0.2.1 → gla_data-0.3.0}/tests/test_census_dwellings.py +0 -0
  71. {gla_data-0.2.1 → gla_data-0.3.0}/tests/test_geography_lookup.py +0 -0
  72. {gla_data-0.2.1 → gla_data-0.3.0}/tests/test_gis_layer.py +0 -0
  73. {gla_data-0.2.1 → gla_data-0.3.0}/tests/test_lbsm.py +0 -0
  74. {gla_data-0.2.1 → gla_data-0.3.0}/tests/test_londondatastore.py +0 -0
@@ -0,0 +1,165 @@
1
+ Metadata-Version: 2.5
2
+ Name: gla-data
3
+ Version: 0.3.0
4
+ Summary: Shared tools for loading, transforming, and visualising the GLA datasets used in City Data analysis.
5
+ Author-email: Conor Dempsey <conor.dempsey@london.gov.uk>
6
+ License: MIT
7
+ Requires-Python: >=3.12
8
+ Requires-Dist: beautifulsoup4>=4.12
9
+ Requires-Dist: boto3>=1.35
10
+ Requires-Dist: botocore>=1.35
11
+ Requires-Dist: filelock>=3.12
12
+ Requires-Dist: geopandas>=1.0
13
+ Requires-Dist: numpy>=1.26
14
+ Requires-Dist: pandas>=2.2
15
+ Requires-Dist: pandera>=0.32.1
16
+ Requires-Dist: pyarrow>=24.0.0
17
+ Requires-Dist: pydantic-settings
18
+ Requires-Dist: pydantic>=2.0
19
+ Requires-Dist: python-dotenv
20
+ Requires-Dist: requests>=2.32
21
+ Requires-Dist: rich>=13.0
22
+ Requires-Dist: shapely>=2.0
23
+ Requires-Dist: sqlalchemy>=2.0
24
+ Requires-Dist: typer>=0.26.8
25
+ Description-Content-Type: text/markdown
26
+
27
+ # gla-data
28
+
29
+ Shared tools for loading, transforming, and visualising the GLA datasets used in City Data analysis.
30
+
31
+ ## Installation
32
+
33
+ ### CLI
34
+
35
+ To install `gla-data` globally so the `gla-data` CLI is available anywhere in your terminal:
36
+
37
+ ```bash
38
+ uv tool install gla-data
39
+ ```
40
+
41
+ This requires [uv](https://docs.astral.sh/uv/) to be installed.
42
+
43
+ ### pip
44
+
45
+ ```bash
46
+ pip install gla-data
47
+ ```
48
+
49
+ ### pixi
50
+
51
+ ```bash
52
+ pixi add gla-data
53
+ ```
54
+
55
+ Pixi pulls geospatial dependencies (geopandas, pyproj, etc.) from conda-forge, which provides reliable pre-built binaries across all platforms and Python versions.
56
+
57
+ ## Usage
58
+
59
+ ### Python API
60
+
61
+ ```python
62
+ import gla_data
63
+
64
+ # Load 2021 LSOA boundaries for London
65
+ lsoa_gdf = gla_data.load_boundaries(geography='lsoa', year=2021)
66
+
67
+ # Load census dwelling counts
68
+ dwellings_2021 = gla_data.load_census_dwellings(year=2021)
69
+ dwellings_2011 = gla_data.load_census_dwellings(year=2011)
70
+
71
+ # Crosswalk 2011 dwelling counts onto 2021 LSOA boundaries
72
+ dwellings_2011_xw = gla_data.crosswalk(
73
+ dwellings_2011,
74
+ from_year=2011,
75
+ to_year=2021,
76
+ value_cols=['dwellings_total'],
77
+ )
78
+
79
+ # Load an OA → LSOA geography lookup
80
+ lookup = gla_data.load_geography_lookup(year=2021, smallest_geography='oa')
81
+
82
+ # Aggregate OA-level data up to LSOA level
83
+ lsoa_totals = gla_data.aggregate(
84
+ df,
85
+ from_geography='oa',
86
+ to_geography='lsoa',
87
+ value_cols=['count'],
88
+ year=2021,
89
+ )
90
+
91
+ # OS MasterMap buildings, with heights, in one 1km grid square plus a 100m
92
+ # margin (GLA only; needs the database settings below)
93
+ buildings = gla_data.load_mastermap_topography(
94
+ bbox=(530000, 180000, 531000, 181000),
95
+ buffer_m=100,
96
+ descriptive_group='Building',
97
+ )
98
+
99
+ # GLA tree canopy in the same square plus a 100m margin. The first call
100
+ # downloads the data (about 270MB) and builds a local file from it, which
101
+ # takes several minutes; later calls read that file.
102
+ canopy = gla_data.load_tree_canopy(
103
+ bbox=(530000, 180000, 531000, 181000),
104
+ buffer_m=100,
105
+ )
106
+ ```
107
+
108
+ ### CLI
109
+
110
+ The package installs a `gla-data` command. Run `catalogue` to list all available datasets:
111
+
112
+ ```bash
113
+ gla-data catalogue
114
+ ```
115
+
116
+ This prints a table of every dataset, the function used to load it, a description, and its access tier (`public`, `registered`, `licensed` or `internal`; see Configuration for the last three).
117
+
118
+ ## Configuration
119
+
120
+ Public datasets need no setup. Datasets held inside the GLA (the GIS team's Postgres database and S3 buckets) need settings that are not included in this package: connection details, table names and bucket names. GLA staff can get the values from the City Intelligence Data Science team.
121
+
122
+ ### Where to put settings
123
+
124
+ Every setting is named `GLA_DATA_<NAME>` and can be set in any of these places. Higher in the list wins:
125
+
126
+ 1. An environment variable, e.g. `GLA_DATA_BLUESKY_IMAGERY_BUCKET`.
127
+ 2. A `.env` file in the folder you run your code from (a project's own settings).
128
+ 3. Your user-level settings file, `~/.config/gla-data/.env` (on Windows, `C:\Users\<you>\.config\gla-data\.env`). Use this for settings shared by all your projects, such as database connections and bucket names. Set `GLA_DATA_USER_ENV_FILE` to use a different path.
129
+
130
+ A settings file holds one setting per line:
131
+
132
+ ```
133
+ GLA_DATA_BLUESKY_IMAGERY_BUCKET=<bucket name>
134
+ ```
135
+
136
+ A misspelt `GLA_DATA_` setting in a settings file raises an error rather than being ignored. Other keys in a project's `.env` are left alone.
137
+
138
+ ### Settings for GLA-internal datasets
139
+
140
+ | Setting | Needed for |
141
+ |---|---|
142
+ | `GLA_DATA_GIS_DB_HOST`, `_PORT`, `_NAME`, `_USER`, `_PASSWORD` | Anything from the GIS team's Postgres database (`source="postgres"`, `load_gis_layer`, `load_front_gardens`, `load_mastermap_topography`, `gla-data db ...`). Use a read-only login. |
143
+ | `GLA_DATA_GIS_DB_SCHEMA` | Optional: the AddressBase schema, if not the default search path. |
144
+ | `GLA_DATA_ADDRESSBASE_BLPU_TABLE`, `_CLASSIFICATION_TABLE` | `load_addressbase(source="postgres")`, if the tables are not named `blpu` / `classification`. |
145
+ | `GLA_DATA_GISAPDATA_<LAYER>_TABLE` | Each `gisapdata` layer used by `load_boundaries(source="postgres")`, `load_gis_layer` and `load_front_gardens`. |
146
+ | `GLA_DATA_GISAPDATA_MASTERMAP_TOPO_2024_TABLE` | `load_mastermap_topography` (2024 snapshot). |
147
+ | `GLA_DATA_BLUESKY_IMAGERY_BUCKET` | Bluesky aerial imagery (`build_imagery_tile_index`, `download_imagery_tiles`). |
148
+ | `GLA_DATA_BLUESKY_IMAGERY_DIR` | Optional: folder for the imagery tile index and downloads (default `data/bluesky_imagery`). Tiles are 256MB each. |
149
+ | `GLA_DATA_AWS_PROFILE`, `GLA_DATA_AWS_REGION` | Optional: pin the AWS profile or region used for S3. |
150
+ | `GLA_DATA_TREE_CANOPY_DIR` | Optional: folder for the tree canopy download and the GeoPackage built from it (default `data/tree_canopy`). Point every project at the same folder so the data is downloaded once. |
151
+
152
+ AWS credentials are never set here. gla-data uses the standard AWS sources: an AWS profile (`~/.aws`), `AWS_*` environment variables, or the machine's own role on GLA cloud machines. Keep database passwords in your user-level file, never in a project's repository.
153
+
154
+ ## Development
155
+
156
+ ```bash
157
+ git clone <repo-url>
158
+ cd gla-data
159
+ pixi install
160
+
161
+ pixi run test # run tests
162
+ pixi run lint # check code style
163
+ pixi run format # auto-format
164
+ pixi run typecheck # type checking
165
+ ```
@@ -0,0 +1,139 @@
1
+ # gla-data
2
+
3
+ Shared tools for loading, transforming, and visualising the GLA datasets used in City Data analysis.
4
+
5
+ ## Installation
6
+
7
+ ### CLI
8
+
9
+ To install `gla-data` globally so the `gla-data` CLI is available anywhere in your terminal:
10
+
11
+ ```bash
12
+ uv tool install gla-data
13
+ ```
14
+
15
+ This requires [uv](https://docs.astral.sh/uv/) to be installed.
16
+
17
+ ### pip
18
+
19
+ ```bash
20
+ pip install gla-data
21
+ ```
22
+
23
+ ### pixi
24
+
25
+ ```bash
26
+ pixi add gla-data
27
+ ```
28
+
29
+ Pixi pulls geospatial dependencies (geopandas, pyproj, etc.) from conda-forge, which provides reliable pre-built binaries across all platforms and Python versions.
30
+
31
+ ## Usage
32
+
33
+ ### Python API
34
+
35
+ ```python
36
+ import gla_data
37
+
38
+ # Load 2021 LSOA boundaries for London
39
+ lsoa_gdf = gla_data.load_boundaries(geography='lsoa', year=2021)
40
+
41
+ # Load census dwelling counts
42
+ dwellings_2021 = gla_data.load_census_dwellings(year=2021)
43
+ dwellings_2011 = gla_data.load_census_dwellings(year=2011)
44
+
45
+ # Crosswalk 2011 dwelling counts onto 2021 LSOA boundaries
46
+ dwellings_2011_xw = gla_data.crosswalk(
47
+ dwellings_2011,
48
+ from_year=2011,
49
+ to_year=2021,
50
+ value_cols=['dwellings_total'],
51
+ )
52
+
53
+ # Load an OA → LSOA geography lookup
54
+ lookup = gla_data.load_geography_lookup(year=2021, smallest_geography='oa')
55
+
56
+ # Aggregate OA-level data up to LSOA level
57
+ lsoa_totals = gla_data.aggregate(
58
+ df,
59
+ from_geography='oa',
60
+ to_geography='lsoa',
61
+ value_cols=['count'],
62
+ year=2021,
63
+ )
64
+
65
+ # OS MasterMap buildings, with heights, in one 1km grid square plus a 100m
66
+ # margin (GLA only; needs the database settings below)
67
+ buildings = gla_data.load_mastermap_topography(
68
+ bbox=(530000, 180000, 531000, 181000),
69
+ buffer_m=100,
70
+ descriptive_group='Building',
71
+ )
72
+
73
+ # GLA tree canopy in the same square plus a 100m margin. The first call
74
+ # downloads the data (about 270MB) and builds a local file from it, which
75
+ # takes several minutes; later calls read that file.
76
+ canopy = gla_data.load_tree_canopy(
77
+ bbox=(530000, 180000, 531000, 181000),
78
+ buffer_m=100,
79
+ )
80
+ ```
81
+
82
+ ### CLI
83
+
84
+ The package installs a `gla-data` command. Run `catalogue` to list all available datasets:
85
+
86
+ ```bash
87
+ gla-data catalogue
88
+ ```
89
+
90
+ This prints a table of every dataset, the function used to load it, a description, and its access tier (`public`, `registered`, `licensed` or `internal`; see Configuration for the last three).
91
+
92
+ ## Configuration
93
+
94
+ Public datasets need no setup. Datasets held inside the GLA (the GIS team's Postgres database and S3 buckets) need settings that are not included in this package: connection details, table names and bucket names. GLA staff can get the values from the City Intelligence Data Science team.
95
+
96
+ ### Where to put settings
97
+
98
+ Every setting is named `GLA_DATA_<NAME>` and can be set in any of these places. Higher in the list wins:
99
+
100
+ 1. An environment variable, e.g. `GLA_DATA_BLUESKY_IMAGERY_BUCKET`.
101
+ 2. A `.env` file in the folder you run your code from (a project's own settings).
102
+ 3. Your user-level settings file, `~/.config/gla-data/.env` (on Windows, `C:\Users\<you>\.config\gla-data\.env`). Use this for settings shared by all your projects, such as database connections and bucket names. Set `GLA_DATA_USER_ENV_FILE` to use a different path.
103
+
104
+ A settings file holds one setting per line:
105
+
106
+ ```
107
+ GLA_DATA_BLUESKY_IMAGERY_BUCKET=<bucket name>
108
+ ```
109
+
110
+ A misspelt `GLA_DATA_` setting in a settings file raises an error rather than being ignored. Other keys in a project's `.env` are left alone.
111
+
112
+ ### Settings for GLA-internal datasets
113
+
114
+ | Setting | Needed for |
115
+ |---|---|
116
+ | `GLA_DATA_GIS_DB_HOST`, `_PORT`, `_NAME`, `_USER`, `_PASSWORD` | Anything from the GIS team's Postgres database (`source="postgres"`, `load_gis_layer`, `load_front_gardens`, `load_mastermap_topography`, `gla-data db ...`). Use a read-only login. |
117
+ | `GLA_DATA_GIS_DB_SCHEMA` | Optional: the AddressBase schema, if not the default search path. |
118
+ | `GLA_DATA_ADDRESSBASE_BLPU_TABLE`, `_CLASSIFICATION_TABLE` | `load_addressbase(source="postgres")`, if the tables are not named `blpu` / `classification`. |
119
+ | `GLA_DATA_GISAPDATA_<LAYER>_TABLE` | Each `gisapdata` layer used by `load_boundaries(source="postgres")`, `load_gis_layer` and `load_front_gardens`. |
120
+ | `GLA_DATA_GISAPDATA_MASTERMAP_TOPO_2024_TABLE` | `load_mastermap_topography` (2024 snapshot). |
121
+ | `GLA_DATA_BLUESKY_IMAGERY_BUCKET` | Bluesky aerial imagery (`build_imagery_tile_index`, `download_imagery_tiles`). |
122
+ | `GLA_DATA_BLUESKY_IMAGERY_DIR` | Optional: folder for the imagery tile index and downloads (default `data/bluesky_imagery`). Tiles are 256MB each. |
123
+ | `GLA_DATA_AWS_PROFILE`, `GLA_DATA_AWS_REGION` | Optional: pin the AWS profile or region used for S3. |
124
+ | `GLA_DATA_TREE_CANOPY_DIR` | Optional: folder for the tree canopy download and the GeoPackage built from it (default `data/tree_canopy`). Point every project at the same folder so the data is downloaded once. |
125
+
126
+ AWS credentials are never set here. gla-data uses the standard AWS sources: an AWS profile (`~/.aws`), `AWS_*` environment variables, or the machine's own role on GLA cloud machines. Keep database passwords in your user-level file, never in a project's repository.
127
+
128
+ ## Development
129
+
130
+ ```bash
131
+ git clone <repo-url>
132
+ cd gla-data
133
+ pixi install
134
+
135
+ pixi run test # run tests
136
+ pixi run lint # check code style
137
+ pixi run format # auto-format
138
+ pixi run typecheck # type checking
139
+ ```
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "gla-data"
3
- version = "0.2.1"
3
+ version = "0.3.0"
4
4
  description = "Shared tools for loading, transforming, and visualising the GLA datasets used in City Data analysis."
5
5
  readme = "README.md"
6
6
  license = { text = "MIT" }
@@ -10,12 +10,20 @@ dependencies = [
10
10
  "pandas>=2.2",
11
11
  "geopandas>=1.0",
12
12
  "requests>=2.32",
13
+ "pydantic>=2.0",
13
14
  "pydantic-settings",
15
+ "python-dotenv",
16
+ "shapely>=2.0",
14
17
  "pyarrow>=24.0.0",
15
18
  "typer>=0.26.8",
19
+ "rich>=13.0",
16
20
  "pandera>=0.32.1",
17
21
  "sqlalchemy>=2.0",
18
22
  "beautifulsoup4>=4.12",
23
+ "boto3>=1.35",
24
+ "botocore>=1.35",
25
+ "filelock>=3.12",
26
+ "numpy>=1.26",
19
27
  # Postgres driver (psycopg2) is a conda-only dep here (see pixi.toml) to
20
28
  # avoid pip/conda installing it twice in the pixi env, matching how
21
29
  # openpyxl (needed by census.py) is handled — a plain `pip install
@@ -30,6 +38,16 @@ gla-data = "gla_data.cli:main"
30
38
  requires = ["hatchling"]
31
39
  build-backend = "hatchling.build"
32
40
 
41
+ # The package is published on public PyPI while the repo is private, so the
42
+ # source distribution lists exactly what ships (pyproject.toml is always
43
+ # included). Everything else stays out: internal docs (DESIGN.md, docs/),
44
+ # notebooks, CI workflows, .env.example, Claude files, lock files.
45
+ [tool.hatch.build.targets.sdist]
46
+ only-include = ["src", "tests", "README.md"]
47
+
48
+ [tool.hatch.build.targets.wheel]
49
+ packages = ["src/gla_data"]
50
+
33
51
  [tool.pytest.ini_options]
34
52
  testpaths = ["tests"]
35
53
  addopts = "-v --tb=short"
@@ -43,7 +61,22 @@ source = ["src"]
43
61
 
44
62
 
45
63
  [tool.ruff.lint]
46
- select = ["E", "F", "I", "UP", "B"]
64
+ # T20: no print() in library code; BLE: no blind `except Exception`;
65
+ # C90: cyclomatic complexity limit (see mccabe below); D: numpy-style
66
+ # docstrings (this package's standard, decided 2026-10-19).
67
+ select = ["E", "F", "I", "UP", "B", "T20", "BLE", "C90", "D"]
68
+
69
+ [tool.ruff.lint.pydocstyle]
70
+ convention = "numpy"
71
+
72
+ [tool.ruff.lint.mccabe]
73
+ max-complexity = 10
74
+
75
+ [tool.ruff.lint.per-file-ignores]
76
+ "tests/**" = ["T20", "D"]
77
+
78
+ [tool.deptry]
79
+ known_first_party = ["gla_data"]
47
80
 
48
81
  [tool.mypy]
49
82
  strict = true
@@ -56,7 +89,7 @@ disallow_untyped_defs = false
56
89
  disallow_incomplete_defs = false
57
90
 
58
91
  [tool.bumpversion]
59
- current_version = "0.2.1"
92
+ current_version = "0.3.0"
60
93
  commit = true
61
94
  tag = true
62
95
 
@@ -0,0 +1,60 @@
1
+ """Shared tools for loading and transforming GLA datasets.
2
+
3
+ Every public function is importable from the top level, e.g.
4
+ ``gla_data.load_boundaries``; ``gla_data.catalogue()`` lists the datasets.
5
+ """
6
+
7
+ from importlib.metadata import version
8
+
9
+ from gla_data.addressbase import (
10
+ assign_area_code,
11
+ build_uprn_net_change_from_ngd,
12
+ compute_uprn_net_change,
13
+ load_addressbase,
14
+ load_ngd_addressbase,
15
+ )
16
+ from gla_data.aerial_imagery import (
17
+ build_imagery_tile_index,
18
+ download_imagery_tiles,
19
+ get_imagery_tile_path,
20
+ load_imagery_tile_index,
21
+ remove_imagery_tiles,
22
+ )
23
+ from gla_data.catalogue import catalogue
24
+ from gla_data.census import load_census_dwellings
25
+ from gla_data.explore import describe_table, list_schemas, list_tables
26
+ from gla_data.front_gardens import load_front_gardens
27
+ from gla_data.geography import load_boundaries, load_geography_lookup, load_gis_layer
28
+ from gla_data.lbsm import load_lbsm
29
+ from gla_data.mastermap import load_mastermap_topography
30
+ from gla_data.transforms import aggregate, crosswalk
31
+ from gla_data.tree_canopy import download_tree_canopy, load_tree_canopy
32
+
33
+ __version__ = version("gla-data")
34
+ __all__ = [
35
+ "load_boundaries",
36
+ "load_geography_lookup",
37
+ "load_gis_layer",
38
+ "load_census_dwellings",
39
+ "crosswalk",
40
+ "aggregate",
41
+ "catalogue",
42
+ "load_addressbase",
43
+ "compute_uprn_net_change",
44
+ "load_ngd_addressbase",
45
+ "assign_area_code",
46
+ "build_uprn_net_change_from_ngd",
47
+ "load_lbsm",
48
+ "list_schemas",
49
+ "list_tables",
50
+ "describe_table",
51
+ "load_front_gardens",
52
+ "build_imagery_tile_index",
53
+ "load_imagery_tile_index",
54
+ "download_imagery_tiles",
55
+ "get_imagery_tile_path",
56
+ "remove_imagery_tiles",
57
+ "load_mastermap_topography",
58
+ "load_tree_canopy",
59
+ "download_tree_canopy",
60
+ ]
@@ -1,44 +1,31 @@
1
- """OS AddressBase Premium: residential UPRN net change by area and financial year.
2
-
3
- AddressBase Premium is a ``licensed`` dataset (see DESIGN.md's data access tiers) —
4
- ``load_addressbase`` is the raw loader, not yet implemented pending GLA's S3
5
- location for the extract. ``compute_uprn_net_change`` is a pure transform that
6
- works on any already-loaded BLPU-shaped DataFrame, so it is fully testable today
7
- against synthetic fixtures without AddressBase access itself, and composes with
8
- ``load_addressbase``'s output once that lands.
9
-
10
- Ported from an exploratory notebook (external reference, not part of this
11
- package) that produced this same net-change-by-OA-by-financial-year table for
12
- the housing_projections project. That notebook's first approach computed a
13
- *cumulative* running UPRN count per area and diffed it year-over-year — wrong
14
- wherever the underlying data was processed in row-chunks rather than as one
15
- geographically complete set, since a chunk boundary could split one area's
16
- history across chunks. The event-based approach here (sum +1/-1 events within
17
- each financial year directly, no cumulative step) sidesteps that failure mode
18
- structurally: call ``compute_uprn_net_change`` once per geographic scope (e.g.
19
- once per borough, not on arbitrary row partitions of a larger file) and there is
20
- no cross-call state for a chunk boundary to corrupt.
21
- """
1
+ """Shared AddressBase logic used by both routes (Premium in Postgres, NGD).
22
2
 
23
- from typing import Literal
3
+ The residential classification rules, the financial-year convention and the
4
+ net-change transform. Public names are re-exported from ``addressbase``.
5
+ """
24
6
 
25
- import geopandas as gpd
26
7
  import pandas as pd
27
8
 
28
- from gla_data import _postgres
29
9
  from gla_data._schemas import addressbase_net_change_schema
30
- from gla_data.config import settings
31
10
 
32
- # AddressBase Premium classification scheme: residential codes start with 'R'.
33
- # RC01 (residential car park) and RG* (garage) are excluded — not living space.
11
+ # AddressBase classification scheme (shared by AddressBase Premium and NGD):
12
+ # residential codes start with 'R'. RC01 (residential car park) and RG*
13
+ # (garage) are excluded — not living space.
34
14
  _RESIDENTIAL_PREFIX = "R"
35
15
  _EXCLUDED_PREFIXES = ("RC01", "RG")
36
16
 
37
- # AddressBase Premium coverage is unreliable before this financial year in past
38
- # uses of this data (the source notebook dropped 2007/2008 for the same reason).
17
+ # AddressBase coverage is unreliable before this financial year in past uses
18
+ # of this data (the source notebook dropped 2007/2008 for the same reason).
39
19
  _MIN_FINANCIAL_YEAR = 2009
40
20
 
41
21
 
22
+ def _is_residential_classification(code: pd.Series) -> pd.Series:
23
+ """Boolean mask: residential classification code, excluding car parks/garages."""
24
+ is_residential = code.str.startswith(_RESIDENTIAL_PREFIX)
25
+ is_excluded = code.str.startswith(_EXCLUDED_PREFIXES)
26
+ return is_residential & ~is_excluded
27
+
28
+
42
29
  def _filter_residential_uprns(classification: pd.DataFrame) -> pd.Series:
43
30
  """Return the deduplicated set of residential UPRNs.
44
31
 
@@ -59,9 +46,7 @@ def _filter_residential_uprns(classification: pd.DataFrame) -> pd.Series:
59
46
  with multiple qualifying classification rows.
60
47
  """
61
48
  code = classification["classification_code"]
62
- is_residential = code.str.startswith(_RESIDENTIAL_PREFIX)
63
- is_excluded = code.str.startswith(_EXCLUDED_PREFIXES)
64
- residential = classification.loc[is_residential & ~is_excluded, "uprn"]
49
+ residential = classification.loc[_is_residential_classification(code), "uprn"]
65
50
  return residential.drop_duplicates()
66
51
 
67
52
 
@@ -176,69 +161,3 @@ def compute_uprn_net_change(
176
161
 
177
162
  addressbase_net_change_schema(area_col).validate(result)
178
163
  return result
179
-
180
-
181
- def load_addressbase(
182
- source: Literal["postgres", "s3", "local"] = "postgres",
183
- table: str | None = None,
184
- ) -> gpd.GeoDataFrame | pd.DataFrame:
185
- """Load raw AddressBase Premium records for London.
186
-
187
- GLA's AddressBase Premium extract lives in Postgres/PostGIS, so
188
- ``source="postgres"`` is implemented; ``"s3"`` and ``"local"`` are not,
189
- yet.
190
-
191
- **This currently returns the raw configured table as-is** — no column
192
- renaming, residential filtering, or schema validation. The real
193
- table/column names are still being confirmed against the live database
194
- (see ``notebooks/addressbase_postgres_setup.ipynb``, which reflects the
195
- schema and exports it for that purpose). Once confirmed, this will be
196
- tightened to return a validated, BLPU-shaped GeoDataFrame ready to pass
197
- directly into ``compute_uprn_net_change``.
198
-
199
- Parameters
200
- ----------
201
- source:
202
- ``"postgres"`` (implemented, default), ``"s3"`` or ``"local"``
203
- (not yet implemented).
204
- table:
205
- Postgres table to read. Defaults to the configured
206
- ``GLA_DATA_ADDRESSBASE_BLPU_TABLE`` (see ``.env.example``).
207
- Only used when ``source="postgres"``.
208
-
209
- Returns
210
- -------
211
- gpd.GeoDataFrame or pd.DataFrame
212
- Whatever is in the configured table, unmodified. GeoDataFrame if a
213
- geometry column is present, otherwise a plain DataFrame.
214
-
215
- Raises
216
- ------
217
- NotImplementedError
218
- For ``source="s3"`` or ``source="local"``.
219
- EnvironmentError
220
- For ``source="postgres"``, if required
221
- ``GLA_DATA_GIS_DB_*`` settings are missing — see
222
- ``.env.example``.
223
- ValueError
224
- For an unrecognised ``source``.
225
-
226
- Access tier: ``licensed`` (OS AddressBase Premium via GLA's own licence).
227
- """
228
- if source == "postgres":
229
- engine = _postgres.get_engine()
230
- table = table or settings.addressbase_blpu_table
231
- return _postgres.read_table(engine, table, schema=settings.gis_db_schema)
232
- if source == "s3":
233
- raise NotImplementedError(
234
- "load_addressbase(source='s3') is not yet implemented — GLA's "
235
- "AddressBase Premium extract currently lives in Postgres, not "
236
- "S3. Use source='postgres' instead."
237
- )
238
- if source == "local":
239
- raise NotImplementedError(
240
- "load_addressbase(source='local') is not yet implemented."
241
- )
242
- raise ValueError(
243
- f"source={source!r} is not supported. Choose from: 'postgres', 's3', 'local'."
244
- )