dcp-tools 1.0.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 (36) hide show
  1. dcp_tools-1.0.0/LICENSE +21 -0
  2. dcp_tools-1.0.0/PKG-INFO +168 -0
  3. dcp_tools-1.0.0/README.md +139 -0
  4. dcp_tools-1.0.0/pyproject.toml +163 -0
  5. dcp_tools-1.0.0/pyproject.toml.orig +151 -0
  6. dcp_tools-1.0.0/src/dcp_tools/__init__.py +15 -0
  7. dcp_tools-1.0.0/src/dcp_tools/__main__.py +6 -0
  8. dcp_tools-1.0.0/src/dcp_tools/cli/__init__.py +5 -0
  9. dcp_tools-1.0.0/src/dcp_tools/cli/common.py +9 -0
  10. dcp_tools-1.0.0/src/dcp_tools/cli/csv2mcf.py +91 -0
  11. dcp_tools-1.0.0/src/dcp_tools/cli/ingest.py +35 -0
  12. dcp_tools-1.0.0/src/dcp_tools/cli/main.py +42 -0
  13. dcp_tools-1.0.0/src/dcp_tools/cli/pipeline.py +45 -0
  14. dcp_tools-1.0.0/src/dcp_tools/cli/upload.py +43 -0
  15. dcp_tools-1.0.0/src/dcp_tools/custom_data/__init__.py +5 -0
  16. dcp_tools-1.0.0/src/dcp_tools/custom_data/config_utils.py +188 -0
  17. dcp_tools-1.0.0/src/dcp_tools/custom_data/data_management.py +1696 -0
  18. dcp_tools-1.0.0/src/dcp_tools/custom_data/models/__init__.py +0 -0
  19. dcp_tools-1.0.0/src/dcp_tools/custom_data/models/common.py +249 -0
  20. dcp_tools-1.0.0/src/dcp_tools/custom_data/models/config_file.py +119 -0
  21. dcp_tools-1.0.0/src/dcp_tools/custom_data/models/data_files.py +220 -0
  22. dcp_tools-1.0.0/src/dcp_tools/custom_data/models/mcf.py +263 -0
  23. dcp_tools-1.0.0/src/dcp_tools/custom_data/models/schema_nodes.py +137 -0
  24. dcp_tools-1.0.0/src/dcp_tools/custom_data/models/sources.py +74 -0
  25. dcp_tools-1.0.0/src/dcp_tools/custom_data/models/stat_vars.py +113 -0
  26. dcp_tools-1.0.0/src/dcp_tools/custom_data/models/topics.py +33 -0
  27. dcp_tools-1.0.0/src/dcp_tools/custom_data/models/vertical_specs.py +30 -0
  28. dcp_tools-1.0.0/src/dcp_tools/custom_data/schema_tools.py +297 -0
  29. dcp_tools-1.0.0/src/dcp_tools/gcp_utilities/__init__.py +22 -0
  30. dcp_tools-1.0.0/src/dcp_tools/gcp_utilities/clients.py +23 -0
  31. dcp_tools-1.0.0/src/dcp_tools/gcp_utilities/ingestion.py +36 -0
  32. dcp_tools-1.0.0/src/dcp_tools/gcp_utilities/pipeline.py +45 -0
  33. dcp_tools-1.0.0/src/dcp_tools/gcp_utilities/settings.py +106 -0
  34. dcp_tools-1.0.0/src/dcp_tools/gcp_utilities/storage.py +412 -0
  35. dcp_tools-1.0.0/src/dcp_tools/logger.py +25 -0
  36. dcp_tools-1.0.0/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,168 @@
1
+ Metadata-Version: 2.4
2
+ Name: dcp-tools
3
+ Version: 1.0.0
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 :: 5 - Production/Stable
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.1
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 workflow.
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
+ Or from GitHub:
58
+
59
+ ```bash
60
+ pip install git+https://github.com/ONEcampaign/dcp-tools
61
+ ```
62
+
63
+ ## Quickstart
64
+
65
+ This builds a config and MCF for a source, a provenance, one input file, and one statistical
66
+ variable, then exports the bundle to disk.
67
+
68
+ ```python
69
+ from pathlib import Path
70
+
71
+ import pandas as pd
72
+ from dcp_tools import CustomDataManager
73
+
74
+ manager = CustomDataManager()
75
+ manager.add_source(dcid="ONEData", url="https://data.one.org")
76
+ manager.add_provenance(
77
+ dcid="ONEClimateFinance",
78
+ url="https://datacommons.one.org/data/climate-finance-files",
79
+ source="ONEData",
80
+ )
81
+
82
+ data = pd.DataFrame({
83
+ "country": ["Kenya", "Kenya", "Vietnam"],
84
+ "year": [2022, 2023, 2023],
85
+ "variable": ["climateFinanceProvidedCommitments"] * 3,
86
+ "value": [12.4, 15.1, 8.7],
87
+ })
88
+ manager.add_input_file(
89
+ file_name="climate_finance/one_cf_provider_commitments.csv",
90
+ provenance="ONEClimateFinance",
91
+ data=data,
92
+ column_mappings={
93
+ "observationAbout": "country",
94
+ "date": "year",
95
+ "variable": "variable",
96
+ "value": "value",
97
+ },
98
+ observation_properties={"unit": "USDollar"},
99
+ )
100
+
101
+ manager.add_variable_to_mcf(
102
+ dcid="climateFinanceProvidedCommitments",
103
+ name="Climate finance commitments (bilateral)",
104
+ description="Funding committed for climate adaptation and mitigation projects",
105
+ stat_type="dcid:measuredValue",
106
+ )
107
+
108
+ manager.add_mcf_file("*.mcf", provenance="ONEClimateFinance")
109
+
110
+ out_dir = Path("export/climate_finance")
111
+ out_dir.mkdir(parents=True, exist_ok=True)
112
+ manager.export_all(out_dir)
113
+ ```
114
+
115
+ `export_all` writes `config.json`, the CSV, and both MCF files under `out_dir`. Since we
116
+ never called `set_import_name`, `config.json` defaults `importName` to the export directory's
117
+ name, and column mappings and the provenance name are resolved to full dcids:
118
+
119
+ ```json
120
+ {
121
+ "importName": "climate_finance",
122
+ "inputFiles": [
123
+ {
124
+ "filename": "climate_finance/one_cf_provider_commitments.csv",
125
+ "provenance": "dcid:provenance/ONEClimateFinance",
126
+ "columnMappings": {
127
+ "dcid:variableMeasured": "variable",
128
+ "dcid:observationDate": "year",
129
+ "dcid:value": "value",
130
+ "dcid:observationAbout": "country"
131
+ },
132
+ "observationProperties": {"unit": "USDollar"},
133
+ "format": "variablePerRow"
134
+ },
135
+ {
136
+ "pattern": "*.mcf",
137
+ "provenance": "dcid:provenance/ONEClimateFinance"
138
+ }
139
+ ]
140
+ }
141
+ ```
142
+
143
+ ## Loading it
144
+
145
+ Once you have a bundle on disk, `dcp_tools.gcp_utilities` uploads it and triggers ingestion:
146
+
147
+ ```python
148
+ from dcp_tools.gcp_utilities import (
149
+ get_kg_settings,
150
+ run_ingestion_workflow,
151
+ upload_to_cloud_storage,
152
+ )
153
+
154
+ settings = get_kg_settings(source="env", env_file="customDC.env")
155
+ upload_to_cloud_storage(settings=settings, directory="export/climate_finance")
156
+ run_ingestion_workflow(settings=settings)
157
+ ```
158
+
159
+ `run_ingestion_workflow` triggers the DCP (Data Commons Platform) ingestion workflow, which
160
+ ingests the new data and serves it. There's no separate redeploy step to run. See the
161
+ [loading-data docs](https://docs.one.org/tools/dcp-tools/loading-data/) for the
162
+ full settings reference, and the `dcp-tools` CLI (`upload`, `ingest`, `pipeline`), which wraps
163
+ this same flow.
164
+
165
+ ## Contributing
166
+
167
+ Contributions are welcome! See [CONTRIBUTING](https://github.com/ONEcampaign/dcp-tools/blob/main/CONTRIBUTING.MD)
168
+ for how to get started, report bugs, and submit changes.
@@ -0,0 +1,139 @@
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 workflow.
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
+ Or from GitHub:
29
+
30
+ ```bash
31
+ pip install git+https://github.com/ONEcampaign/dcp-tools
32
+ ```
33
+
34
+ ## Quickstart
35
+
36
+ This builds a config and MCF for a source, a provenance, one input file, and one statistical
37
+ variable, then exports the bundle to disk.
38
+
39
+ ```python
40
+ from pathlib import Path
41
+
42
+ import pandas as pd
43
+ from dcp_tools import CustomDataManager
44
+
45
+ manager = CustomDataManager()
46
+ manager.add_source(dcid="ONEData", url="https://data.one.org")
47
+ manager.add_provenance(
48
+ dcid="ONEClimateFinance",
49
+ url="https://datacommons.one.org/data/climate-finance-files",
50
+ source="ONEData",
51
+ )
52
+
53
+ data = pd.DataFrame({
54
+ "country": ["Kenya", "Kenya", "Vietnam"],
55
+ "year": [2022, 2023, 2023],
56
+ "variable": ["climateFinanceProvidedCommitments"] * 3,
57
+ "value": [12.4, 15.1, 8.7],
58
+ })
59
+ manager.add_input_file(
60
+ file_name="climate_finance/one_cf_provider_commitments.csv",
61
+ provenance="ONEClimateFinance",
62
+ data=data,
63
+ column_mappings={
64
+ "observationAbout": "country",
65
+ "date": "year",
66
+ "variable": "variable",
67
+ "value": "value",
68
+ },
69
+ observation_properties={"unit": "USDollar"},
70
+ )
71
+
72
+ manager.add_variable_to_mcf(
73
+ dcid="climateFinanceProvidedCommitments",
74
+ name="Climate finance commitments (bilateral)",
75
+ description="Funding committed for climate adaptation and mitigation projects",
76
+ stat_type="dcid:measuredValue",
77
+ )
78
+
79
+ manager.add_mcf_file("*.mcf", provenance="ONEClimateFinance")
80
+
81
+ out_dir = Path("export/climate_finance")
82
+ out_dir.mkdir(parents=True, exist_ok=True)
83
+ manager.export_all(out_dir)
84
+ ```
85
+
86
+ `export_all` writes `config.json`, the CSV, and both MCF files under `out_dir`. Since we
87
+ never called `set_import_name`, `config.json` defaults `importName` to the export directory's
88
+ name, and column mappings and the provenance name are resolved to full dcids:
89
+
90
+ ```json
91
+ {
92
+ "importName": "climate_finance",
93
+ "inputFiles": [
94
+ {
95
+ "filename": "climate_finance/one_cf_provider_commitments.csv",
96
+ "provenance": "dcid:provenance/ONEClimateFinance",
97
+ "columnMappings": {
98
+ "dcid:variableMeasured": "variable",
99
+ "dcid:observationDate": "year",
100
+ "dcid:value": "value",
101
+ "dcid:observationAbout": "country"
102
+ },
103
+ "observationProperties": {"unit": "USDollar"},
104
+ "format": "variablePerRow"
105
+ },
106
+ {
107
+ "pattern": "*.mcf",
108
+ "provenance": "dcid:provenance/ONEClimateFinance"
109
+ }
110
+ ]
111
+ }
112
+ ```
113
+
114
+ ## Loading it
115
+
116
+ Once you have a bundle on disk, `dcp_tools.gcp_utilities` uploads it and triggers ingestion:
117
+
118
+ ```python
119
+ from dcp_tools.gcp_utilities import (
120
+ get_kg_settings,
121
+ run_ingestion_workflow,
122
+ upload_to_cloud_storage,
123
+ )
124
+
125
+ settings = get_kg_settings(source="env", env_file="customDC.env")
126
+ upload_to_cloud_storage(settings=settings, directory="export/climate_finance")
127
+ run_ingestion_workflow(settings=settings)
128
+ ```
129
+
130
+ `run_ingestion_workflow` triggers the DCP (Data Commons Platform) ingestion workflow, which
131
+ ingests the new data and serves it. There's no separate redeploy step to run. See the
132
+ [loading-data docs](https://docs.one.org/tools/dcp-tools/loading-data/) for the
133
+ full settings reference, and the `dcp-tools` CLI (`upload`, `ingest`, `pipeline`), which wraps
134
+ this same flow.
135
+
136
+ ## Contributing
137
+
138
+ Contributions are welcome! See [CONTRIBUTING](https://github.com/ONEcampaign/dcp-tools/blob/main/CONTRIBUTING.MD)
139
+ for how to get started, report bugs, and submit changes.
@@ -0,0 +1,163 @@
1
+ [project]
2
+ name = "dcp-tools"
3
+ version = "1.0.0"
4
+ description = "Tools to work with the Data Commons Platform."
5
+ license = "MIT"
6
+ license-files = ["LICENSE"]
7
+ readme = "README.md"
8
+ requires-python = ">=3.13"
9
+ dependencies = [
10
+ "pydantic>=2.11.3,<3.0.0",
11
+ "pandas>=2.2.3,<4.0.0",
12
+ "pydantic-settings>=2.9.1,<3.0.0",
13
+ "google-cloud-storage>=3.1.0,<4.0.0",
14
+ "datacommons-admin>=1.1.1",
15
+ ]
16
+ keywords = [
17
+ "data-commons",
18
+ "datacommons",
19
+ "dcp",
20
+ "etl",
21
+ "statistics",
22
+ ]
23
+ classifiers = [
24
+ "Development Status :: 5 - Production/Stable",
25
+ "Intended Audience :: Developers",
26
+ "Operating System :: OS Independent",
27
+ "Programming Language :: Python :: 3.13",
28
+ "Programming Language :: Python :: 3.14",
29
+ "Topic :: Scientific/Engineering :: Information Analysis",
30
+ "Topic :: Software Development :: Libraries :: Python Modules",
31
+ "Typing :: Typed",
32
+ ]
33
+
34
+ [[project.authors]]
35
+ name = "ONE Campaign"
36
+
37
+ [[project.authors]]
38
+ name = "Luca Picci"
39
+ email = "lpicci96@gmail.com"
40
+
41
+ [[project.authors]]
42
+ name = "Jorge Rivera"
43
+ email = "jorge.rivera@one.org"
44
+
45
+ [project.scripts]
46
+ dcp-tools = "dcp_tools.cli:main"
47
+
48
+ [project.urls]
49
+ homepage = "https://docs.one.org/tools/dcp-tools/"
50
+ documentation = "https://docs.one.org/tools/dcp-tools/"
51
+ repository = "https://github.com/ONEcampaign/dcp-tools"
52
+ issues = "https://github.com/ONEcampaign/dcp-tools/issues"
53
+
54
+ [dependency-groups]
55
+ dev = [
56
+ "pytest>=8.0.0",
57
+ "pytest-cov>=4.1.0",
58
+ "ty>=0.0.33",
59
+ "ruff>=0.8.0",
60
+ "pre-commit>=3.0.0",
61
+ "mkdocs-material>=9.6.14,<10.0.0",
62
+ ]
63
+
64
+ [build-system]
65
+ requires = ["uv_build>=0.11.8,<0.12"]
66
+ build-backend = "uv_build"
67
+
68
+ [tool.ruff]
69
+ line-length = 88
70
+ target-version = "py313"
71
+ extend-include = ["*.ipynb"]
72
+ exclude = [
73
+ ".git",
74
+ ".venv",
75
+ "venv",
76
+ "__pycache__",
77
+ "build",
78
+ "dist",
79
+ "*.egg-info",
80
+ ".pytest_cache",
81
+ "htmlcov",
82
+ ]
83
+
84
+ [tool.ruff.lint]
85
+ select = [
86
+ "E",
87
+ "W",
88
+ "F",
89
+ "I",
90
+ "UP",
91
+ "B",
92
+ "C4",
93
+ "SIM",
94
+ "PL",
95
+ "RUF",
96
+ "ERA",
97
+ "PERF",
98
+ "ANN",
99
+ ]
100
+ ignore = [
101
+ "E501",
102
+ "PLR0913",
103
+ "PLR0912",
104
+ "PLR0914",
105
+ "PLR0915",
106
+ "PLR2004",
107
+ "ANN401",
108
+ ]
109
+ fixable = ["ALL"]
110
+ unfixable = []
111
+
112
+ [tool.ruff.lint.per-file-ignores]
113
+ "tests/**/*.py" = [
114
+ "ANN",
115
+ "PLR2004",
116
+ ]
117
+ "**/*.ipynb" = [
118
+ "ANN",
119
+ "F401",
120
+ "F811",
121
+ "E402",
122
+ ]
123
+
124
+ [tool.ruff.lint.pydocstyle]
125
+ convention = "google"
126
+
127
+ [tool.ruff.format]
128
+ quote-style = "double"
129
+ indent-style = "space"
130
+ skip-magic-trailing-comma = false
131
+ line-ending = "auto"
132
+
133
+ [tool.ty.environment]
134
+ python-version = "3.13"
135
+
136
+ [tool.ty.src]
137
+ include = ["src/dcp_tools"]
138
+
139
+ [tool.pytest.ini_options]
140
+ testpaths = ["tests"]
141
+ python_files = ["test_*.py"]
142
+ addopts = "-v --cov=src/dcp_tools --cov-report=term"
143
+
144
+ [tool.coverage.run]
145
+ source = ["src"]
146
+ branch = true
147
+ omit = [
148
+ "*/tests/*",
149
+ "*/__pycache__/*",
150
+ ]
151
+
152
+ [tool.coverage.report]
153
+ exclude_lines = [
154
+ "pragma: no cover",
155
+ "def __repr__",
156
+ "def __str__",
157
+ "raise AssertionError",
158
+ "raise NotImplementedError",
159
+ "if __name__ == .__main__.:",
160
+ "if TYPE_CHECKING:",
161
+ ]
162
+ show_missing = true
163
+ precision = 2
@@ -0,0 +1,151 @@
1
+ [project]
2
+ name = "dcp-tools"
3
+ version = "1.0.0"
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.1",
20
+ ]
21
+ keywords = ["data-commons", "datacommons", "dcp", "etl", "statistics"]
22
+ classifiers = [
23
+ "Development Status :: 5 - Production/Stable",
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)