dcp-tools 1.0.0a1__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 (35) hide show
  1. dcp_tools-1.0.0a1/LICENSE +21 -0
  2. dcp_tools-1.0.0a1/PKG-INFO +161 -0
  3. dcp_tools-1.0.0a1/README.md +132 -0
  4. dcp_tools-1.0.0a1/pyproject.toml +151 -0
  5. dcp_tools-1.0.0a1/src/dcp_tools/__init__.py +15 -0
  6. dcp_tools-1.0.0a1/src/dcp_tools/__main__.py +6 -0
  7. dcp_tools-1.0.0a1/src/dcp_tools/cli/__init__.py +5 -0
  8. dcp_tools-1.0.0a1/src/dcp_tools/cli/common.py +9 -0
  9. dcp_tools-1.0.0a1/src/dcp_tools/cli/csv2mcf.py +91 -0
  10. dcp_tools-1.0.0a1/src/dcp_tools/cli/data_load.py +35 -0
  11. dcp_tools-1.0.0a1/src/dcp_tools/cli/data_load_pipeline.py +47 -0
  12. dcp_tools-1.0.0a1/src/dcp_tools/cli/main.py +42 -0
  13. dcp_tools-1.0.0a1/src/dcp_tools/cli/upload.py +43 -0
  14. dcp_tools-1.0.0a1/src/dcp_tools/custom_data/__init__.py +5 -0
  15. dcp_tools-1.0.0a1/src/dcp_tools/custom_data/config_utils.py +188 -0
  16. dcp_tools-1.0.0a1/src/dcp_tools/custom_data/data_management.py +1548 -0
  17. dcp_tools-1.0.0a1/src/dcp_tools/custom_data/models/__init__.py +0 -0
  18. dcp_tools-1.0.0a1/src/dcp_tools/custom_data/models/common.py +249 -0
  19. dcp_tools-1.0.0a1/src/dcp_tools/custom_data/models/config_file.py +119 -0
  20. dcp_tools-1.0.0a1/src/dcp_tools/custom_data/models/data_files.py +191 -0
  21. dcp_tools-1.0.0a1/src/dcp_tools/custom_data/models/mcf.py +263 -0
  22. dcp_tools-1.0.0a1/src/dcp_tools/custom_data/models/schema_nodes.py +114 -0
  23. dcp_tools-1.0.0a1/src/dcp_tools/custom_data/models/sources.py +66 -0
  24. dcp_tools-1.0.0a1/src/dcp_tools/custom_data/models/stat_vars.py +111 -0
  25. dcp_tools-1.0.0a1/src/dcp_tools/custom_data/models/topics.py +33 -0
  26. dcp_tools-1.0.0a1/src/dcp_tools/custom_data/models/vertical_specs.py +30 -0
  27. dcp_tools-1.0.0a1/src/dcp_tools/custom_data/schema_tools.py +297 -0
  28. dcp_tools-1.0.0a1/src/dcp_tools/gcp_utilities/__init__.py +24 -0
  29. dcp_tools-1.0.0a1/src/dcp_tools/gcp_utilities/clients.py +23 -0
  30. dcp_tools-1.0.0a1/src/dcp_tools/gcp_utilities/jobs.py +31 -0
  31. dcp_tools-1.0.0a1/src/dcp_tools/gcp_utilities/pipeline.py +56 -0
  32. dcp_tools-1.0.0a1/src/dcp_tools/gcp_utilities/settings.py +95 -0
  33. dcp_tools-1.0.0a1/src/dcp_tools/gcp_utilities/storage.py +412 -0
  34. dcp_tools-1.0.0a1/src/dcp_tools/logger.py +25 -0
  35. dcp_tools-1.0.0a1/src/dcp_tools/py.typed +0 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 ONE Campaign
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,161 @@
1
+ Metadata-Version: 2.4
2
+ Name: dcp-tools
3
+ Version: 1.0.0a1
4
+ Summary: Tools to work with the Data Commons Platform.
5
+ Keywords: data-commons,datacommons,dcp,etl,statistics
6
+ Author: ONE Campaign, Luca Picci, Jorge Rivera
7
+ Author-email: Luca Picci <lpicci96@gmail.com>, Jorge Rivera <jorge.rivera@one.org>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Programming Language :: Python :: 3.14
15
+ Classifier: Topic :: Scientific/Engineering :: Information Analysis
16
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
17
+ Classifier: Typing :: Typed
18
+ Requires-Dist: pydantic>=2.11.3,<3.0.0
19
+ Requires-Dist: pandas>=2.2.3,<4.0.0
20
+ Requires-Dist: pydantic-settings>=2.9.1,<3.0.0
21
+ Requires-Dist: google-cloud-storage>=3.1.0,<4.0.0
22
+ Requires-Dist: datacommons-admin>=1.1.0
23
+ Requires-Python: >=3.13
24
+ Project-URL: homepage, https://docs.one.org/tools/dcp-tools/
25
+ Project-URL: documentation, https://docs.one.org/tools/dcp-tools/
26
+ Project-URL: repository, https://github.com/ONEcampaign/dcp-tools
27
+ Project-URL: issues, https://github.com/ONEcampaign/dcp-tools/issues
28
+ Description-Content-Type: text/markdown
29
+
30
+ # dcp-tools
31
+
32
+ __Manage and load data to Data Commons Platform instances__
33
+
34
+ [![PyPI](https://img.shields.io/pypi/v/dcp-tools.svg)](https://pypi.org/project/dcp-tools/)
35
+ [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/dcp-tools.svg)](https://pypi.org/project/dcp-tools/)
36
+ [![Docs](https://img.shields.io/badge/docs-dcp--tools-blue)](https://docs.one.org/tools/dcp-tools/)
37
+ [![Lint/format: Ruff](https://img.shields.io/badge/lint%2Fformat-ruff-46a758.svg)](https://github.com/astral-sh/ruff)
38
+
39
+ A [Data Commons Platform](https://docs.datacommons.org/custom_dc/custom_data.html) instance takes
40
+ your data as CSVs in a fixed variable-per-row shape, plus a `config.json` that maps each CSV's
41
+ columns onto the Data Commons schema. If you're defining your own statistical variables,
42
+ entities, or properties rather than reusing existing ones, you also need MCF (Meta Content
43
+ Framework) files describing them. `dcp-tools` builds and validates that bundle in Python (or from
44
+ the CLI) and uploads it to Cloud Storage to trigger the platform's ingestion job.
45
+
46
+ This package was published as `bblocks-datacommons-tools` until version 0.1.1, and imported as
47
+ `bblocks.datacommons_tools`. Installing the old distribution now pulls in `dcp-tools` and
48
+ redirects those imports with a `DeprecationWarning`, so existing code keeps working. Update
49
+ imports to `dcp_tools` when convenient.
50
+
51
+ ## Install
52
+
53
+ ```bash
54
+ pip install dcp-tools
55
+ ```
56
+
57
+ While `1.0.0` is still in alpha, this is a pre-release, so pip won't find it
58
+ unless you ask for pre-releases explicitly: `pip install --pre dcp-tools`.
59
+
60
+ Or from GitHub:
61
+
62
+ ```bash
63
+ pip install git+https://github.com/ONEcampaign/dcp-tools
64
+ ```
65
+
66
+ ## Quickstart
67
+
68
+ This builds a config and MCF for a source, a provenance, one input file, and one statistical
69
+ variable, then exports the bundle to disk.
70
+
71
+ ```python
72
+ from pathlib import Path
73
+
74
+ import pandas as pd
75
+ from dcp_tools import CustomDataManager
76
+
77
+ manager = CustomDataManager()
78
+ manager.add_source(dcid="ONEData", url="https://data.one.org")
79
+ manager.add_provenance(
80
+ dcid="ONEClimateFinance",
81
+ url="https://datacommons.one.org/data/climate-finance-files",
82
+ source="ONEData",
83
+ )
84
+
85
+ data = pd.DataFrame({
86
+ "country": ["Kenya", "Kenya", "Vietnam"],
87
+ "year": [2022, 2023, 2023],
88
+ "variable": ["climateFinanceProvidedCommitments"] * 3,
89
+ "value": [12.4, 15.1, 8.7],
90
+ })
91
+ manager.add_input_file(
92
+ file_name="climate_finance/one_cf_provider_commitments.csv",
93
+ provenance="ONEClimateFinance",
94
+ data=data,
95
+ column_mappings={
96
+ "observationAbout": "country",
97
+ "date": "year",
98
+ "variable": "variable",
99
+ "value": "value",
100
+ },
101
+ observation_properties={"unit": "USDollar"},
102
+ )
103
+
104
+ manager.add_variable_to_mcf(
105
+ dcid="climateFinanceProvidedCommitments",
106
+ name="Climate finance commitments (bilateral)",
107
+ description="Funding committed for climate adaptation and mitigation projects",
108
+ stat_type="dcid:measuredValue",
109
+ )
110
+
111
+ out_dir = Path("export/climate_finance")
112
+ out_dir.mkdir(parents=True, exist_ok=True)
113
+ manager.export_all(out_dir)
114
+ ```
115
+
116
+ `export_all` writes `config.json`, the CSV, and both MCF files under `out_dir`. Since we
117
+ never called `set_import_name`, `config.json` defaults `importName` to the export directory's
118
+ name, and column mappings and the provenance name are resolved to full dcids:
119
+
120
+ ```json
121
+ {
122
+ "importName": "climate_finance",
123
+ "inputFiles": [
124
+ {
125
+ "filename": "climate_finance/one_cf_provider_commitments.csv",
126
+ "provenance": "dcid:provenance/ONEClimateFinance",
127
+ "columnMappings": {
128
+ "dcid:variableMeasured": "variable",
129
+ "dcid:observationDate": "year",
130
+ "dcid:value": "value",
131
+ "dcid:observationAbout": "country"
132
+ },
133
+ "observationProperties": {"unit": "USDollar"},
134
+ "format": "variablePerRow"
135
+ }
136
+ ]
137
+ }
138
+ ```
139
+
140
+ ## Loading it
141
+
142
+ Once you have a bundle on disk, `dcp_tools.gcp_utilities` uploads it and triggers the load:
143
+
144
+ ```python
145
+ from dcp_tools.gcp_utilities import get_kg_settings, upload_to_cloud_storage, run_data_load
146
+
147
+ settings = get_kg_settings(source="env", env_file="customDC.env")
148
+ upload_to_cloud_storage(settings=settings, directory="export/climate_finance")
149
+ run_data_load(settings=settings)
150
+ ```
151
+
152
+ `run_data_load` triggers the DCP (Data Commons Platform) ingestion job, which ingests the new
153
+ data and serves it. There's no separate redeploy step to run. See the
154
+ [loading-data docs](https://docs.one.org/tools/dcp-tools/loading-data/) for the
155
+ full settings reference, and the `dcp-tools` CLI (`upload`, `dataload`, `pipeline`), which wraps
156
+ this same flow.
157
+
158
+ ## Contributing
159
+
160
+ Contributions are welcome! See [CONTRIBUTING](https://github.com/ONEcampaign/dcp-tools/blob/main/CONTRIBUTING.MD)
161
+ for how to get started, report bugs, and submit changes.
@@ -0,0 +1,132 @@
1
+ # dcp-tools
2
+
3
+ __Manage and load data to Data Commons Platform instances__
4
+
5
+ [![PyPI](https://img.shields.io/pypi/v/dcp-tools.svg)](https://pypi.org/project/dcp-tools/)
6
+ [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/dcp-tools.svg)](https://pypi.org/project/dcp-tools/)
7
+ [![Docs](https://img.shields.io/badge/docs-dcp--tools-blue)](https://docs.one.org/tools/dcp-tools/)
8
+ [![Lint/format: Ruff](https://img.shields.io/badge/lint%2Fformat-ruff-46a758.svg)](https://github.com/astral-sh/ruff)
9
+
10
+ A [Data Commons Platform](https://docs.datacommons.org/custom_dc/custom_data.html) instance takes
11
+ your data as CSVs in a fixed variable-per-row shape, plus a `config.json` that maps each CSV's
12
+ columns onto the Data Commons schema. If you're defining your own statistical variables,
13
+ entities, or properties rather than reusing existing ones, you also need MCF (Meta Content
14
+ Framework) files describing them. `dcp-tools` builds and validates that bundle in Python (or from
15
+ the CLI) and uploads it to Cloud Storage to trigger the platform's ingestion job.
16
+
17
+ This package was published as `bblocks-datacommons-tools` until version 0.1.1, and imported as
18
+ `bblocks.datacommons_tools`. Installing the old distribution now pulls in `dcp-tools` and
19
+ redirects those imports with a `DeprecationWarning`, so existing code keeps working. Update
20
+ imports to `dcp_tools` when convenient.
21
+
22
+ ## Install
23
+
24
+ ```bash
25
+ pip install dcp-tools
26
+ ```
27
+
28
+ While `1.0.0` is still in alpha, this is a pre-release, so pip won't find it
29
+ unless you ask for pre-releases explicitly: `pip install --pre dcp-tools`.
30
+
31
+ Or from GitHub:
32
+
33
+ ```bash
34
+ pip install git+https://github.com/ONEcampaign/dcp-tools
35
+ ```
36
+
37
+ ## Quickstart
38
+
39
+ This builds a config and MCF for a source, a provenance, one input file, and one statistical
40
+ variable, then exports the bundle to disk.
41
+
42
+ ```python
43
+ from pathlib import Path
44
+
45
+ import pandas as pd
46
+ from dcp_tools import CustomDataManager
47
+
48
+ manager = CustomDataManager()
49
+ manager.add_source(dcid="ONEData", url="https://data.one.org")
50
+ manager.add_provenance(
51
+ dcid="ONEClimateFinance",
52
+ url="https://datacommons.one.org/data/climate-finance-files",
53
+ source="ONEData",
54
+ )
55
+
56
+ data = pd.DataFrame({
57
+ "country": ["Kenya", "Kenya", "Vietnam"],
58
+ "year": [2022, 2023, 2023],
59
+ "variable": ["climateFinanceProvidedCommitments"] * 3,
60
+ "value": [12.4, 15.1, 8.7],
61
+ })
62
+ manager.add_input_file(
63
+ file_name="climate_finance/one_cf_provider_commitments.csv",
64
+ provenance="ONEClimateFinance",
65
+ data=data,
66
+ column_mappings={
67
+ "observationAbout": "country",
68
+ "date": "year",
69
+ "variable": "variable",
70
+ "value": "value",
71
+ },
72
+ observation_properties={"unit": "USDollar"},
73
+ )
74
+
75
+ manager.add_variable_to_mcf(
76
+ dcid="climateFinanceProvidedCommitments",
77
+ name="Climate finance commitments (bilateral)",
78
+ description="Funding committed for climate adaptation and mitigation projects",
79
+ stat_type="dcid:measuredValue",
80
+ )
81
+
82
+ out_dir = Path("export/climate_finance")
83
+ out_dir.mkdir(parents=True, exist_ok=True)
84
+ manager.export_all(out_dir)
85
+ ```
86
+
87
+ `export_all` writes `config.json`, the CSV, and both MCF files under `out_dir`. Since we
88
+ never called `set_import_name`, `config.json` defaults `importName` to the export directory's
89
+ name, and column mappings and the provenance name are resolved to full dcids:
90
+
91
+ ```json
92
+ {
93
+ "importName": "climate_finance",
94
+ "inputFiles": [
95
+ {
96
+ "filename": "climate_finance/one_cf_provider_commitments.csv",
97
+ "provenance": "dcid:provenance/ONEClimateFinance",
98
+ "columnMappings": {
99
+ "dcid:variableMeasured": "variable",
100
+ "dcid:observationDate": "year",
101
+ "dcid:value": "value",
102
+ "dcid:observationAbout": "country"
103
+ },
104
+ "observationProperties": {"unit": "USDollar"},
105
+ "format": "variablePerRow"
106
+ }
107
+ ]
108
+ }
109
+ ```
110
+
111
+ ## Loading it
112
+
113
+ Once you have a bundle on disk, `dcp_tools.gcp_utilities` uploads it and triggers the load:
114
+
115
+ ```python
116
+ from dcp_tools.gcp_utilities import get_kg_settings, upload_to_cloud_storage, run_data_load
117
+
118
+ settings = get_kg_settings(source="env", env_file="customDC.env")
119
+ upload_to_cloud_storage(settings=settings, directory="export/climate_finance")
120
+ run_data_load(settings=settings)
121
+ ```
122
+
123
+ `run_data_load` triggers the DCP (Data Commons Platform) ingestion job, which ingests the new
124
+ data and serves it. There's no separate redeploy step to run. See the
125
+ [loading-data docs](https://docs.one.org/tools/dcp-tools/loading-data/) for the
126
+ full settings reference, and the `dcp-tools` CLI (`upload`, `dataload`, `pipeline`), which wraps
127
+ this same flow.
128
+
129
+ ## Contributing
130
+
131
+ Contributions are welcome! See [CONTRIBUTING](https://github.com/ONEcampaign/dcp-tools/blob/main/CONTRIBUTING.MD)
132
+ for how to get started, report bugs, and submit changes.
@@ -0,0 +1,151 @@
1
+ [project]
2
+ name = "dcp-tools"
3
+ version = "1.0.0a1"
4
+ description = "Tools to work with the Data Commons Platform."
5
+ authors = [
6
+ { name = "ONE Campaign" },
7
+ { name = "Luca Picci", email = "lpicci96@gmail.com" },
8
+ { name = "Jorge Rivera", email = "jorge.rivera@one.org" },
9
+ ]
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ readme = "README.md"
13
+ requires-python = ">=3.13"
14
+ dependencies = [
15
+ "pydantic>=2.11.3,<3.0.0",
16
+ "pandas>=2.2.3,<4.0.0",
17
+ "pydantic-settings>=2.9.1,<3.0.0",
18
+ "google-cloud-storage>=3.1.0,<4.0.0",
19
+ "datacommons-admin>=1.1.0",
20
+ ]
21
+ keywords = ["data-commons", "datacommons", "dcp", "etl", "statistics"]
22
+ classifiers = [
23
+ "Development Status :: 4 - Beta",
24
+ "Intended Audience :: Developers",
25
+ "Operating System :: OS Independent",
26
+ "Programming Language :: Python :: 3.13",
27
+ "Programming Language :: Python :: 3.14",
28
+ "Topic :: Scientific/Engineering :: Information Analysis",
29
+ "Topic :: Software Development :: Libraries :: Python Modules",
30
+ "Typing :: Typed",
31
+ ]
32
+
33
+ [project.scripts]
34
+ dcp-tools = "dcp_tools.cli:main"
35
+
36
+ [project.urls]
37
+ homepage = "https://docs.one.org/tools/dcp-tools/"
38
+ documentation = "https://docs.one.org/tools/dcp-tools/"
39
+ repository = "https://github.com/ONEcampaign/dcp-tools"
40
+ issues = "https://github.com/ONEcampaign/dcp-tools/issues"
41
+
42
+ [dependency-groups]
43
+ dev = [
44
+ "pytest>=8.0.0",
45
+ "pytest-cov>=4.1.0",
46
+ "ty>=0.0.33",
47
+ "ruff>=0.8.0",
48
+ "pre-commit>=3.0.0",
49
+ "mkdocs-material>=9.6.14,<10.0.0",
50
+ ]
51
+
52
+ [build-system]
53
+ requires = ["uv_build>=0.11.8,<0.12"]
54
+ build-backend = "uv_build"
55
+
56
+ [tool.ruff]
57
+ line-length = 88
58
+ target-version = "py313"
59
+ extend-include = ["*.ipynb"]
60
+
61
+ exclude = [
62
+ ".git",
63
+ ".venv",
64
+ "venv",
65
+ "__pycache__",
66
+ "build",
67
+ "dist",
68
+ "*.egg-info",
69
+ ".pytest_cache",
70
+ "htmlcov",
71
+ ]
72
+
73
+ [tool.ruff.lint]
74
+ # "N" (pep8-naming) is intentionally omitted: the public API mirrors the Data
75
+ # Commons config.json schema, which is camelCase (e.g. ``importName``,
76
+ # ``set_includeInputSubdirs``). Those names are a serialization contract, not a
77
+ # style choice, so the naming rules would fight the domain.
78
+ select = [
79
+ "E", "W", "F", # pycodestyle, pyflakes
80
+ "I", # isort
81
+ "UP", # pyupgrade
82
+ "B", # bugbear
83
+ "C4", # comprehensions
84
+ "SIM", # simplify
85
+ "PL", # pylint
86
+ "RUF", # ruff-specific
87
+ "ERA", # eradicate (commented-out code)
88
+ "PERF", # perflint
89
+ "ANN", # flake8-annotations (require type hints on public APIs)
90
+ ]
91
+
92
+ ignore = [
93
+ "E501", # Line length (formatter handles)
94
+ "PLR0913", # Too many arguments
95
+ "PLR0912", # Too many branches
96
+ "PLR0914", # Too many locals
97
+ "PLR0915", # Too many statements
98
+ "PLR2004", # Magic values
99
+ "ANN401", # Allow `Any` in typed signatures
100
+ ]
101
+
102
+ # Allow autofix for all enabled rules
103
+ fixable = ["ALL"]
104
+ unfixable = []
105
+
106
+ [tool.ruff.lint.per-file-ignores]
107
+ # Tests don't need annotations or pylint-complexity gates.
108
+ "tests/**/*.py" = ["ANN", "PLR2004"]
109
+ # Notebooks: don't require annotations; allow REPL-style patterns.
110
+ "**/*.ipynb" = ["ANN", "F401", "F811", "E402"]
111
+
112
+ [tool.ruff.lint.pydocstyle]
113
+ convention = "google"
114
+
115
+ [tool.ruff.format]
116
+ quote-style = "double"
117
+ indent-style = "space"
118
+ skip-magic-trailing-comma = false
119
+ line-ending = "auto"
120
+
121
+ [tool.ty.environment]
122
+ python-version = "3.13"
123
+
124
+ [tool.ty.src]
125
+ include = ["src/dcp_tools"]
126
+
127
+ [tool.pytest.ini_options]
128
+ testpaths = ["tests"]
129
+ python_files = ["test_*.py"]
130
+ addopts = "-v --cov=src/dcp_tools --cov-report=term"
131
+
132
+ [tool.coverage.run]
133
+ source = ["src"]
134
+ branch = true
135
+ omit = [
136
+ "*/tests/*",
137
+ "*/__pycache__/*",
138
+ ]
139
+
140
+ [tool.coverage.report]
141
+ exclude_lines = [
142
+ "pragma: no cover",
143
+ "def __repr__",
144
+ "def __str__",
145
+ "raise AssertionError",
146
+ "raise NotImplementedError",
147
+ "if __name__ == .__main__.:",
148
+ "if TYPE_CHECKING:",
149
+ ]
150
+ show_missing = true
151
+ precision = 2
@@ -0,0 +1,15 @@
1
+ from importlib.metadata import version
2
+
3
+ from .custom_data.config_utils import merge_configs_from_directory
4
+ from .custom_data.data_management import CustomDataManager
5
+ from .custom_data.schema_tools import csv_metadata_to_mcf_file, csv_metadata_to_nodes
6
+
7
+ __version__ = version("dcp-tools")
8
+
9
+
10
+ __all__ = [
11
+ "CustomDataManager",
12
+ "csv_metadata_to_mcf_file",
13
+ "csv_metadata_to_nodes",
14
+ "merge_configs_from_directory",
15
+ ]
@@ -0,0 +1,6 @@
1
+ """Enable ``python -m dcp_tools``."""
2
+
3
+ from dcp_tools.cli.main import main
4
+
5
+ if __name__ == "__main__":
6
+ raise SystemExit(main())
@@ -0,0 +1,5 @@
1
+ """Command line interface for ``dcp_tools`` package."""
2
+
3
+ from dcp_tools.cli.main import main
4
+
5
+ __all__ = ["main"]
@@ -0,0 +1,9 @@
1
+ import argparse
2
+
3
+ from dcp_tools.gcp_utilities import KGSettings, get_kg_settings
4
+
5
+
6
+ def load_settings_from_args(args: argparse.Namespace) -> KGSettings:
7
+ if args.settings_file:
8
+ return get_kg_settings(source="json", file=args.settings_file)
9
+ return get_kg_settings(env_file=args.env_file)
@@ -0,0 +1,91 @@
1
+ """CSV to MCF command implementation."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ from pathlib import Path
7
+
8
+ from dcp_tools.custom_data.schema_tools import (
9
+ NodeTypes,
10
+ csv_metadata_to_mcf_file,
11
+ )
12
+
13
+ __all__ = ["add_parser", "run"]
14
+
15
+
16
+ def _kv_pair(value: str) -> tuple[str, str]:
17
+ """Parse a KEY=VALUE string into a tuple."""
18
+ if "=" not in value:
19
+ raise ValueError(f"Invalid key-value pair: {value}")
20
+ key, val = value.split("=", 1)
21
+ return key.strip(), val.strip()
22
+
23
+
24
+ def add_parser(subparsers: argparse._SubParsersAction) -> None:
25
+ """Register the ``csv2mcf`` subcommand with the CLI parser."""
26
+ parser = subparsers.add_parser(
27
+ "csv2mcf", help="Convert a CSV of Node metadata to an MCF file"
28
+ )
29
+
30
+ parser.add_argument("csv", type=Path, help="Path to the input CSV file")
31
+ parser.add_argument("mcf", type=Path, help="Path to write the generated MCF")
32
+
33
+ parser.add_argument(
34
+ "--node-type",
35
+ choices=[node_type.value for node_type in NodeTypes],
36
+ default="Node",
37
+ help="Type of node to create (default: %(default)s)",
38
+ )
39
+
40
+ parser.add_argument(
41
+ "--column-mapping",
42
+ metavar="CSV_COL=MCF_PROP",
43
+ type=_kv_pair,
44
+ action="append",
45
+ help=(
46
+ "Map CSV column names to MCF properties. "
47
+ "May be used multiple times, eg: "
48
+ "--column-mapping description=searchDescription --column-mapping indicator=Node"
49
+ ),
50
+ )
51
+
52
+ parser.add_argument(
53
+ "--csv-option",
54
+ metavar="KEY=VALUE",
55
+ type=_kv_pair,
56
+ action="append",
57
+ help=(
58
+ "Extra keyword arguments forwarded to pandas.read_csv, "
59
+ 'e.g. --csv-option delimiter=";" --csv-option encoding=UTF-8'
60
+ ),
61
+ )
62
+
63
+ parser.add_argument(
64
+ "--ignore-column",
65
+ metavar="COLUMN",
66
+ action="append",
67
+ help="Name of a CSV column to ignore. May be specified multiple times.",
68
+ )
69
+
70
+ parser.add_argument(
71
+ "--append", action="store_true", help="Append to the output file if it exists."
72
+ )
73
+
74
+ parser.set_defaults(func=run)
75
+
76
+
77
+ def run(args: argparse.Namespace) -> int:
78
+ """Execute the ``csv2mcf`` command."""
79
+ column_mapping = dict(args.column_mapping) if args.column_mapping else None
80
+ csv_options = dict(args.csv_option) if args.csv_option else None
81
+
82
+ csv_metadata_to_mcf_file(
83
+ csv_path=args.csv,
84
+ mcf_path=args.mcf,
85
+ node_type=args.node_type,
86
+ column_to_property_mapping=column_mapping,
87
+ csv_options=csv_options,
88
+ ignore_columns=args.ignore_column,
89
+ overwrite=not args.append,
90
+ )
91
+ return 0
@@ -0,0 +1,35 @@
1
+ """Run the data load job via CLI."""
2
+
3
+ import argparse
4
+ from pathlib import Path
5
+
6
+ from dcp_tools.cli.common import load_settings_from_args
7
+ from dcp_tools.gcp_utilities.pipeline import run_data_load
8
+
9
+ __all__ = ["add_parser", "run"]
10
+
11
+
12
+ def add_parser(subparsers: argparse._SubParsersAction) -> None:
13
+ """Register the ``dataload`` subcommand."""
14
+ parser = subparsers.add_parser(
15
+ "dataload", help="Run the Knowledge Graph data load job"
16
+ )
17
+ parser.add_argument(
18
+ "--settings-file", type=Path, help="Path to the KG settings JSON file"
19
+ )
20
+ parser.add_argument(
21
+ "--env-file", type=Path, help="Optional .env file containing KG settings"
22
+ )
23
+ parser.add_argument(
24
+ "--imports",
25
+ type=str,
26
+ help="Comma-separated list of imports to load, defaults to all imports",
27
+ )
28
+ parser.set_defaults(func=run)
29
+
30
+
31
+ def run(args: argparse.Namespace) -> int:
32
+ """Execute the ``dataload`` command."""
33
+ settings = load_settings_from_args(args)
34
+ run_data_load(settings=settings, imports=args.imports)
35
+ return 0
@@ -0,0 +1,47 @@
1
+ """Run the full Knowledge Graph pipeline via CLI."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ from pathlib import Path
7
+
8
+ from dcp_tools.cli.common import load_settings_from_args
9
+ from dcp_tools.gcp_utilities.pipeline import (
10
+ run_data_load,
11
+ upload_to_cloud_storage,
12
+ )
13
+
14
+ __all__ = ["add_parser", "run"]
15
+
16
+
17
+ def add_parser(subparsers: argparse._SubParsersAction) -> None:
18
+ """Register the ``pipeline`` subcommand."""
19
+ parser = subparsers.add_parser(
20
+ "pipeline", help="Run the full Knowledge Graph loading pipeline"
21
+ )
22
+ parser.add_argument(
23
+ "--settings-file", type=Path, help="Path to the KG settings JSON file"
24
+ )
25
+ parser.add_argument(
26
+ "--env-file", type=Path, help="Optional .env file containing KG settings"
27
+ )
28
+ parser.add_argument(
29
+ "--directory",
30
+ type=Path,
31
+ help="Local directory to upload. Defaults to settings.LOCAL_PATH",
32
+ )
33
+ parser.add_argument(
34
+ "--sync",
35
+ action="store_true",
36
+ default=False,
37
+ help="Delete remote blobs that no longer have a local counterpart after uploading",
38
+ )
39
+ parser.set_defaults(func=run)
40
+
41
+
42
+ def run(args: argparse.Namespace) -> int:
43
+ """Execute the ``pipeline`` command."""
44
+ settings = load_settings_from_args(args)
45
+ upload_to_cloud_storage(settings=settings, directory=args.directory, sync=args.sync)
46
+ run_data_load(settings=settings)
47
+ return 0