YAML-driven ETL mappers for ForSITE soil database imports.
Project description
SOIL — Structured Observation Ingestion Library
Version: 0.1.0-a.2 (alpha) · Python: ≥ 3.10 · PyPI:
soil-etl
YAML-driven ETL package for importing Canadian forestry soil datasets into the ForSITE PostGIS database model, built on the OGC Observations, Measurements & Samples specification.
Acknowledgements
| Project Partners |
|---|
This project was developed through joint funding provided by Agriculture and Agri-Food Canada (AAFC) under
the CSBO program and Natural Resources Canada (NRCan) for
the ForSITE-Soil degradation project.
The code developed as part of this project includes contributions from:
Installation
pip install soil-etl
Or with Poetry:
poetry add soil-etl
Quick Start
YAML-only pipeline (recommended)
from pathlib import Path
from soil_etl.yaml_mapper import YamlDatasetMapper
mapper = YamlDatasetMapper(
config_path=Path("my_config.yaml"),
data_file_path=Path("data.xlsx"),
)
metrics = mapper.import_data(
database_connection_string="postgresql+psycopg2://user:password@host:5432/database",
)
print(metrics)
All new ETL pipelines must use YamlDatasetMapper. See AGENTS.md for full architecture guidance.
Canonical imports
from soil_etl.yaml_mapper import YamlDatasetMapper
from soil_etl.bindings import Binding, FromColumn
from soil_etl.db import ImportationInterface
Database Connection
Connection resolution priority (first non-null wins):
- Explicit
database_connection_stringargument toimport_data() DB_CONNenvironment variable- Hydra config directory (
database_config_path/CONFIG_PATHenv var)
# Option 1 — direct connection string
mapper.import_data(
database_connection_string="postgresql+psycopg2://user:password@host:5432/database",
database_engine_kwargs={"pool_size": 10, "pool_pre_ping": True},
)
# Option 2 — Hydra config files
mapper.import_data(
database_config_path="configs",
database_config_name="configs.yaml",
)
# Option 3 — environment variables
import os
os.environ["DB_CONN"] = "postgresql+psycopg2://user:password@host:5432/database"
mapper.import_data()
Environment variables recognized:
| Variable | Description |
|---|---|
DB_CONN |
Full SQLAlchemy connection string |
DB_USER |
Database username (used alongside Hydra config) |
DB_PASSWORD |
Database password (used alongside Hydra config) |
CONFIG_PATH |
Hydra config directory path |
IMPORT_BATCH_SIZE |
Override batch size for this run (positive integer) |
EXPORT_RETREATED_DATAFRAME |
Export transformed DataFrame to *_retreated.xlsx (1/true/yes) |
import_data() Signature
mapper.import_data(
error_file_path=Path("errors.xlsx"), # defaults to <dataset_title>_ERROR.xlsx
dry_run=False, # True: extract + validate only, no DB writes
database_connection_string="postgresql+...",
database_config_path="configs",
database_config_name="configs.yaml",
database_engine_kwargs={"pool_size": 10},
) -> ImportRunMetrics
Returns an ImportRunMetrics dataclass:
@dataclass(frozen=True)
class ImportRunMetrics:
rows_processed: int
error_rows: int
generic_results: int
horizon_results: int
feature_relationships: int
sample_information: int
batches: int
batch_size: int
dry_run: bool
extract_seconds: float
persist_seconds: float
total_seconds: float
YAML Configuration
The YAML config drives the entire mapping: Excel reading parameters, project metadata, feature of interest hierarchy, observations, and results.
Reference files (packaged):
| File | Purpose |
|---|---|
src/soil_etl/yaml_mapper/dummy_config_file.yaml |
Fully-documented boilerplate with all options |
src/soil_etl/yaml_mapper/template.yaml |
Real-world example with YAML anchors |
src/soil_etl/yaml_mapper/examples/on_master.yaml |
Province-specific example |
examples/configs/example_config.yaml |
Additional annotated example |
For full documentation of the YAML format, see docs/README_yaml_format_en.md.
Top-level sections
source: # Excel reading params (sheet_name, header, skiprows, null_values…)
export_retreated_dataframe: false
import_batch_size: 1000 # Rows per DB batch (default: 5000)
project: # Project metadata (strategy, name, abbrev, province, type…)
partners: # Partner organizations
stewards: # Data steward contacts
feature_relationships: # Optional parent-child FOI hierarchies
sample_information: # Optional sample metadata (type, depth, horizon, dimensions)
results: # Generic result bindings
horizon_results: # Horizon-specific results (includes hz_from, hz_to)
Python Subclass (advanced)
When YAML alone cannot express the required logic, subclass YamlDatasetMapper and override properties:
from pathlib import Path
from soil_etl.yaml_mapper import YamlDatasetMapper
from soil_etl.model_bindings import FeatureOfInterestBinding
class MyMapper(YamlDatasetMapper):
@property
def _feature_of_interest(self) -> FeatureOfInterestBinding:
# custom logic here
...
mapper = MyMapper(
config_path=Path("my_config.yaml"),
data_file_path=Path("data.xlsx"),
)
mapper.import_data(database_connection_string="postgresql+psycopg2://...")
See examples/subclass_runner.py for a complete example.
Development
pip install poetry
poetry install --with dev,test
poetry run pytest tests
Tests use testcontainers with postgis/postgis:17-3.4 — Docker must be running.
Linting & formatting
poetry run black src tests
poetry run ruff check src tests
poetry run isort src tests
Build & Publish
python -m build
twine check dist/*
twine upload dist/*
Links
- Repository: gitlab.com/nrcan-rncan-cfs-scf/lfc-cfl/soil-etl
- Issues: soil-etl/issues
- YAML format reference: docs/README_yaml_format_en.md
- Testing guide: docs/testing.md
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file soil_etl-0.1.0a5.tar.gz.
File metadata
- Download URL: soil_etl-0.1.0a5.tar.gz
- Upload date:
- Size: 102.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0fe07a92892c533211c0f3501041419cdaec6957d5aad97d0d124913407af759
|
|
| MD5 |
9239008712db5572cec1567a64ea04a1
|
|
| BLAKE2b-256 |
7fa1cc6bc071bc8e0f925cc67e8a172768f1aaa2e9bf01c241aaf36c38b1d24d
|
File details
Details for the file soil_etl-0.1.0a5-py3-none-any.whl.
File metadata
- Download URL: soil_etl-0.1.0a5-py3-none-any.whl
- Upload date:
- Size: 155.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3d47a507e29da4ba19dd35da0ea780e358e28054487326b81f78e23eab7f703b
|
|
| MD5 |
8658c41bcc2df0d3fda3c4abd9ecfe72
|
|
| BLAKE2b-256 |
d6e00571b7baedff94aa387e2515804cc26f04a0d90963bbf50cc9057ee633ea
|