bam-masterdata 0.1.0__tar.gz → 0.2.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 (102) hide show
  1. bam_masterdata-0.2.0/.coveragerc +6 -0
  2. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/.vscode/settings.json +13 -0
  3. bam_masterdata-0.2.0/LICENSE +21 -0
  4. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/PKG-INFO +37 -5
  5. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/README.md +10 -3
  6. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/bam_masterdata/_version.py +2 -2
  7. bam_masterdata-0.2.0/bam_masterdata/checker/__init__.py +1 -0
  8. bam_masterdata-0.2.0/bam_masterdata/checker/checker.py +45 -0
  9. bam_masterdata-0.2.0/bam_masterdata/checker/datamodel_loader.py +9 -0
  10. bam_masterdata-0.2.0/bam_masterdata/checker/masterdata_validator.py +34 -0
  11. bam_masterdata-0.2.0/bam_masterdata/checker/source_loader.py +27 -0
  12. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/bam_masterdata/cli/cli.py +136 -13
  13. bam_masterdata-0.2.0/bam_masterdata/cli/entities_to_rdf.py +236 -0
  14. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/bam_masterdata/cli/fill_masterdata.py +9 -4
  15. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/bam_masterdata/datamodel/property_types.py +4 -2
  16. bam_masterdata-0.2.0/bam_masterdata/excel/__init__.py +1 -0
  17. bam_masterdata-0.2.0/bam_masterdata/excel/excel_to_entities.py +692 -0
  18. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/bam_masterdata/metadata/definitions.py +37 -5
  19. bam_masterdata-0.2.0/bam_masterdata/metadata/entities.py +390 -0
  20. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/bam_masterdata/utils/__init__.py +2 -0
  21. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/bam_masterdata/utils/utils.py +96 -6
  22. bam_masterdata-0.2.0/bam_masterdata/validation_rules/excel_validation_rules.json +73 -0
  23. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/bam_masterdata.egg-info/PKG-INFO +37 -5
  24. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/bam_masterdata.egg-info/SOURCES.txt +14 -1
  25. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/bam_masterdata.egg-info/requires.txt +3 -1
  26. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/docs/assets/drawio/masterdata-workflow.drawio +73 -77
  27. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/pyproject.toml +3 -1
  28. bam_masterdata-0.2.0/tests/cli/test_entities_to_rdf.py +111 -0
  29. bam_masterdata-0.2.0/tests/data/utils/example_prop_types_1.py +23 -0
  30. bam_masterdata-0.2.0/tests/data/utils/example_prop_types_2.py +16 -0
  31. bam_masterdata-0.2.0/tests/excel/test_excel_to_entities.py +1470 -0
  32. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/tests/metadata/test_definitions.py +40 -21
  33. bam_masterdata-0.2.0/tests/metadata/test_entities.py +116 -0
  34. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/tests/utils/test_utils.py +145 -3
  35. bam_masterdata-0.1.0/.coveragerc +0 -4
  36. bam_masterdata-0.1.0/bam_masterdata/cli/excel_to_entities.py +0 -884
  37. bam_masterdata-0.1.0/bam_masterdata/metadata/entities.py +0 -181
  38. bam_masterdata-0.1.0/tests/metadata/test_entities.py +0 -54
  39. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/.github/workflows/actions.yml +0 -0
  40. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/.github/workflows/coveralls.yml +0 -0
  41. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/.github/workflows/mkdocs-deploy.yml +0 -0
  42. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/.github/workflows/publish.yml +0 -0
  43. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/.gitignore +0 -0
  44. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/bam_masterdata/__init__.py +0 -0
  45. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/bam_masterdata/cli/__init__.py +0 -0
  46. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/bam_masterdata/cli/entities_to_excel.py +0 -0
  47. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/bam_masterdata/cli/entities_to_json.py +0 -0
  48. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/bam_masterdata/datamodel/__init__.py +0 -0
  49. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/bam_masterdata/datamodel/collection_types.py +0 -0
  50. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/bam_masterdata/datamodel/dataset_types.py +0 -0
  51. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/bam_masterdata/datamodel/object_types.py +0 -0
  52. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/bam_masterdata/datamodel/vocabulary_types.py +0 -0
  53. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/bam_masterdata/logger.py +0 -0
  54. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/bam_masterdata/metadata/__init__.py +0 -0
  55. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/bam_masterdata/openbis/__init__.py +0 -0
  56. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/bam_masterdata/openbis/get_entities.py +0 -0
  57. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/bam_masterdata/openbis/login.py +0 -0
  58. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/bam_masterdata.egg-info/dependency_links.txt +0 -0
  59. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/bam_masterdata.egg-info/entry_points.txt +0 -0
  60. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/bam_masterdata.egg-info/top_level.txt +0 -0
  61. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/docs/assets/bammasterdata_blue_transparent.png +0 -0
  62. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/docs/assets/bammasterdata_blue_transparent_text.png +0 -0
  63. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/docs/assets/bammasterdata_blue_transparent_text.svg +0 -0
  64. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/docs/assets/bammasterdata_blue_white.png +0 -0
  65. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/docs/assets/bammasterdata_blue_white_text.png +0 -0
  66. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/docs/assets/datastore-logo-white.png +0 -0
  67. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/docs/assets/datastore-logo.png +0 -0
  68. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/docs/assets/drawio/masterdata-workflow.drawio.png +0 -0
  69. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/docs/assets/fonts/BAMKlavika-Light.ttf +0 -0
  70. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/docs/assets/fonts/BAMKlavika-LightItalic.ttf +0 -0
  71. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/docs/assets/fonts/BAMKlavika-Medium.ttf +0 -0
  72. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/docs/assets/fonts/BAMKlavika-MediumItalic.ttf +0 -0
  73. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/docs/explanations/data-store.md +0 -0
  74. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/docs/explanations/openbis.md +0 -0
  75. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/docs/explanations/pybis.md +0 -0
  76. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/docs/howtos/overview.md +0 -0
  77. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/docs/howtos/pybis/collections.md +0 -0
  78. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/docs/howtos/pybis/datasets.md +0 -0
  79. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/docs/howtos/pybis/objects.md +0 -0
  80. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/docs/howtos/pybis/objects_props.md +0 -0
  81. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/docs/howtos/pybis/parent_child.md +0 -0
  82. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/docs/howtos/pybis/projects.md +0 -0
  83. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/docs/howtos/pybis/searches.md +0 -0
  84. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/docs/howtos/pybis/setup.md +0 -0
  85. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/docs/howtos/pybis/spaces.md +0 -0
  86. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/docs/index.md +0 -0
  87. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/docs/references/collection.md +0 -0
  88. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/docs/references/controlled-vocabulary.md +0 -0
  89. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/docs/references/dataset.md +0 -0
  90. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/docs/stylesheets/extra.css +0 -0
  91. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/docs/tutorials/create-masterdata.md +0 -0
  92. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/docs/tutorials/pybis.md +0 -0
  93. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/mkdocs.yml +0 -0
  94. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/scripts/install_python_dependencies.sh +0 -0
  95. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/scripts/pkg_size.py +0 -0
  96. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/setup.cfg +0 -0
  97. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/setup.py +0 -0
  98. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/tests/__init__.py +0 -0
  99. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/tests/cli/test_entities_to_excel.py +0 -0
  100. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/tests/cli/test_entities_to_json.py +0 -0
  101. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/tests/conftest.py +0 -0
  102. {bam_masterdata-0.1.0 → bam_masterdata-0.2.0}/tests/test_logger.py +0 -0
@@ -0,0 +1,6 @@
1
+ [run]
2
+ omit =
3
+ bam_masterdata/_version.py
4
+ */__init__.py
5
+ bam_masterdata/datamodel/*.py
6
+ bam_masterdata/openbis/*.py
@@ -33,6 +33,7 @@
33
33
  "type": "debugpy",
34
34
  "request": "launch",
35
35
  "console": "integratedTerminal",
36
+ "justMyCode": false,
36
37
  "program": "${workspaceFolder}/bam_masterdata/metadata/entities.py", // path to your entry point Python module
37
38
  },
38
39
  {
@@ -80,6 +81,18 @@
80
81
  "justMyCode": false,
81
82
  "args": ["export_to_excel"]
82
83
  },
84
+ {
85
+ "name": "BM export-to-rdf",
86
+ "type": "debugpy",
87
+ "request": "launch",
88
+ "cwd": "${workspaceFolder}",
89
+ "program": "${workspaceFolder}/.venv/bin/bam_masterdata",
90
+ "justMyCode": false,
91
+ "args": [
92
+ "export_to_rdf",
93
+ // "--python-path=${workspaceFolder}/bam_masterdata/datamodel/property_types.py"
94
+ ]
95
+ },
83
96
  ]
84
97
  },
85
98
  }
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Bundesanstalt für Materialforschung und -prüfung
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.
@@ -1,9 +1,31 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: bam-masterdata
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: The BAM Data Store utility tools and masterdata models wrapped in a Python package with a front-end web interface.
5
5
  Author-email: BAM Data Store <datastore@bam.de>
6
6
  Maintainer-email: "Jose M. Pizarro" <jose.pizarro-blanco@bam.de>
7
+ License: MIT License
8
+
9
+ Copyright (c) 2025 Bundesanstalt für Materialforschung und -prüfung
10
+
11
+ Permission is hereby granted, free of charge, to any person obtaining a copy
12
+ of this software and associated documentation files (the "Software"), to deal
13
+ in the Software without restriction, including without limitation the rights
14
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
+ copies of the Software, and to permit persons to whom the Software is
16
+ furnished to do so, subject to the following conditions:
17
+
18
+ The above copyright notice and this permission notice shall be included in all
19
+ copies or substantial portions of the Software.
20
+
21
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
+ SOFTWARE.
28
+
7
29
  Project-URL: Homepage, https://github.com/BAMresearch/bam-masterdata
8
30
  Project-URL: Bug Tracker, https://github.com/BAMresearch/bam-masterdata/issues
9
31
  Classifier: Natural Language :: English
@@ -16,10 +38,13 @@ Classifier: Programming Language :: Python :: 3.11
16
38
  Classifier: Programming Language :: Python :: 3.12
17
39
  Requires-Python: >=3.9
18
40
  Description-Content-Type: text/markdown
41
+ License-File: LICENSE
19
42
  Requires-Dist: pybis~=1.37.1rc4
20
43
  Requires-Dist: openpyxl
21
44
  Requires-Dist: click
22
- Requires-Dist: pydantic
45
+ Requires-Dist: pydantic~=2.10.5
46
+ Requires-Dist: rdflib
47
+ Requires-Dist: h5py~=3.12.1
23
48
  Provides-Extra: dev
24
49
  Requires-Dist: mypy==1.0.1; extra == "dev"
25
50
  Requires-Dist: ruff; extra == "dev"
@@ -47,15 +72,22 @@ Requires-Dist: mkdocstrings-python; extra == "docu"
47
72
 
48
73
  [![CI Status](https://github.com/BAMresearch/bam-masterdata/actions/workflows/actions.yml/badge.svg)](https://github.com/BAMresearch/bam-masterdata/actions/workflows/actions.yml/badge.svg)
49
74
  [![Coverage](https://coveralls.io/repos/github/BAMresearch/bam-masterdata/badge.svg?branch=main)](https://coveralls.io/repos/github/BAMresearch/bam-masterdata/badge.svg?branch=main)
75
+ [![PyPI versions](https://img.shields.io/pypi/v/bam-masterdata)](https://img.shields.io/pypi/v/bam-masterdata)
76
+ [![Python supported versions](https://img.shields.io/pypi/pyversions/bam-masterdata)](https://img.shields.io/pypi/pyversions/bam-masterdata)
50
77
 
51
78
  </h4>
52
79
 
53
80
  The BAM Masterdata is a repository containing all the masterdata schema defining in BAM, as well as some utility functions to handle the masterdata.
54
81
 
55
- <!--
56
- ## Getting started
82
+ If you want to install it, do:
83
+ ```sh
84
+ pip install bam-masterdata
85
+ ```
57
86
 
58
- Add here installation instructions once the package is deployed -->
87
+ In order to include the CLI functionalities, you have to add the optional `[dev]` dependencies when pip installing the package:
88
+ ```sh
89
+ pip install bam-masterdata[dev]
90
+ ```
59
91
 
60
92
  ## Development
61
93
 
@@ -12,15 +12,22 @@
12
12
 
13
13
  [![CI Status](https://github.com/BAMresearch/bam-masterdata/actions/workflows/actions.yml/badge.svg)](https://github.com/BAMresearch/bam-masterdata/actions/workflows/actions.yml/badge.svg)
14
14
  [![Coverage](https://coveralls.io/repos/github/BAMresearch/bam-masterdata/badge.svg?branch=main)](https://coveralls.io/repos/github/BAMresearch/bam-masterdata/badge.svg?branch=main)
15
+ [![PyPI versions](https://img.shields.io/pypi/v/bam-masterdata)](https://img.shields.io/pypi/v/bam-masterdata)
16
+ [![Python supported versions](https://img.shields.io/pypi/pyversions/bam-masterdata)](https://img.shields.io/pypi/pyversions/bam-masterdata)
15
17
 
16
18
  </h4>
17
19
 
18
20
  The BAM Masterdata is a repository containing all the masterdata schema defining in BAM, as well as some utility functions to handle the masterdata.
19
21
 
20
- <!--
21
- ## Getting started
22
+ If you want to install it, do:
23
+ ```sh
24
+ pip install bam-masterdata
25
+ ```
22
26
 
23
- Add here installation instructions once the package is deployed -->
27
+ In order to include the CLI functionalities, you have to add the optional `[dev]` dependencies when pip installing the package:
28
+ ```sh
29
+ pip install bam-masterdata[dev]
30
+ ```
24
31
 
25
32
  ## Development
26
33
 
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.1.0'
16
- __version_tuple__ = version_tuple = (0, 1, 0)
15
+ __version__ = version = '0.2.0'
16
+ __version_tuple__ = version_tuple = (0, 2, 0)
@@ -0,0 +1 @@
1
+ from .checker import MasterdataChecker
@@ -0,0 +1,45 @@
1
+ from bam_masterdata.checker.datamodel_loader import DataModelLoader
2
+ from bam_masterdata.checker.masterdata_validator import MasterDataValidator
3
+ from bam_masterdata.checker.source_loader import SourceLoader
4
+
5
+
6
+ class MasterdataChecker:
7
+ def __init__(self, validation_rules_path: str):
8
+ """
9
+ Initialize the comparator with validation rules.
10
+ """
11
+ self.validation_rules = self._load_validation_rules(validation_rules_path)
12
+ self.current_model = None
13
+ self.new_entities = None
14
+
15
+ def _load_validation_rules(self, path: str) -> dict:
16
+ """
17
+ Load validation rules from a JSON file.
18
+ """
19
+ pass
20
+
21
+ def load_current_model(self, source_path: str):
22
+ """
23
+ Load and transform the current data model (Pydantic classes) into JSON.
24
+ """
25
+ # loader = DataModelLoader(source_path)
26
+ # self.current_model = loader.parse_pydantic_models()
27
+
28
+ def load_new_entities(self, source: str, source_type: str):
29
+ """
30
+ Load new entities from various sources (Python classes, Excel, etc.).
31
+ """
32
+ # loader = SourceLoader(source, source_type)
33
+ # self.new_entities = loader.load()
34
+
35
+ def validate(self, mode: str = "all") -> dict:
36
+ """
37
+ Run validations. Mode can be:
38
+ - "self" -> Validate only the new entity structure.
39
+ - "compare" -> Validate new entities against current model.
40
+ - "all" -> Run both validation types.
41
+ """
42
+ validator = MasterDataValidator(
43
+ self.new_entities, self.current_model, self.validation_rules
44
+ )
45
+ return validator.validate(mode)
@@ -0,0 +1,9 @@
1
+ class DataModelLoader:
2
+ def __init__(self, source_path: str):
3
+ self.source_path = source_path
4
+
5
+ def parse_pydantic_models(self) -> dict:
6
+ """
7
+ Read and transform Pydantic classes into JSON format.
8
+ """
9
+ pass
@@ -0,0 +1,34 @@
1
+ class MasterDataValidator:
2
+ def __init__(self, new_entities: dict, current_model: dict, validation_rules: dict):
3
+ self.new_entities = new_entities
4
+ self.current_model = current_model
5
+ self.validation_rules = validation_rules
6
+
7
+ def validate(self, mode: str = "all") -> dict:
8
+ """
9
+ Run validations based on mode:
10
+ - "self": Validate new entity JSON structure.
11
+ - "compare": Validate new entities against the current model.
12
+ - "all": Run both.
13
+ """
14
+ results = {}
15
+
16
+ if mode in ["self", "all"]:
17
+ results["self_validation"] = self._validate_new_entities()
18
+
19
+ if mode in ["compare", "all"]:
20
+ results["comparison"] = self._compare_with_current_model()
21
+
22
+ return results
23
+
24
+ def _validate_new_entities(self) -> dict:
25
+ """
26
+ Check structure, ordering, and internal consistency of new entity JSON.
27
+ """
28
+ pass
29
+
30
+ def _compare_with_current_model(self) -> dict:
31
+ """
32
+ Compare new entities against the current model using validation rules.
33
+ """
34
+ pass
@@ -0,0 +1,27 @@
1
+ class SourceLoader:
2
+ def __init__(self, source: str, source_type: str):
3
+ self.source = source
4
+ self.source_type = source_type
5
+
6
+ def load(self) -> dict:
7
+ """
8
+ Read and transform the new entity data into JSON.
9
+ """
10
+ if self.source_type == "python":
11
+ return self._parse_python_classes()
12
+ elif self.source_type == "excel":
13
+ return self._parse_excel()
14
+ else:
15
+ raise NotImplementedError(f"Source type {self.source_type} not supported.")
16
+
17
+ def _parse_python_classes(self) -> dict:
18
+ """
19
+ Parse new entities defined as Python classes.
20
+ """
21
+ pass
22
+
23
+ def _parse_excel(self) -> dict:
24
+ """
25
+ Parse new entities stored in an Excel file.
26
+ """
27
+ pass
@@ -6,18 +6,40 @@ from pathlib import Path
6
6
  import click
7
7
  from decouple import config as environ
8
8
  from openpyxl import Workbook
9
+ from rdflib import Graph
9
10
 
10
11
  from bam_masterdata.cli.entities_to_excel import entities_to_excel
11
12
  from bam_masterdata.cli.entities_to_json import entities_to_json
13
+ from bam_masterdata.cli.entities_to_rdf import entities_to_rdf
12
14
  from bam_masterdata.cli.fill_masterdata import MasterdataCodeGenerator
13
15
  from bam_masterdata.logger import logger
14
16
  from bam_masterdata.utils import (
15
17
  delete_and_create_dir,
18
+ duplicated_property_types,
16
19
  import_module,
17
20
  listdir_py_modules,
18
21
  )
19
22
 
20
- DATAMODEL_DIR = os.path.join(".", "bam_masterdata", "datamodel")
23
+
24
+ def find_datamodel_dir():
25
+ """Search for 'datamodel/' in possible locations and return its absolute path."""
26
+ possible_locations = [
27
+ # Case: Running from a project with `datamodel/`
28
+ Path.cwd() / "datamodel",
29
+ # Case: Running inside bam-masterdata
30
+ Path.cwd() / "bam_masterdata" / "datamodel",
31
+ # Case: Running inside installed package
32
+ Path(__file__).parent / "datamodel",
33
+ ]
34
+
35
+ for path in possible_locations:
36
+ if path.exists():
37
+ return str(path.resolve())
38
+
39
+ raise FileNotFoundError("Could not find a valid 'datamodel/' directory.")
40
+
41
+
42
+ DATAMODEL_DIR = find_datamodel_dir()
21
43
 
22
44
 
23
45
  @click.group(help="Entry point to run `bam_masterdata` CLI commands.")
@@ -129,11 +151,20 @@ def fill_masterdata(url, excel_file):
129
151
  Default is `./bam_masterdata/datamodel/`.
130
152
  """,
131
153
  )
132
- def export_to_json(force_delete, python_path):
133
- # Get the directories from the Python modules and the export directory for the static artifacts
134
- export_dir = os.path.join(".", "artifacts")
135
-
154
+ @click.option(
155
+ "--export-dir",
156
+ type=str,
157
+ required=False,
158
+ default="./artifacts",
159
+ help="The directory where the JSON files will be exported. Default is `./artifacts`.",
160
+ )
161
+ def export_to_json(force_delete, python_path, export_dir):
136
162
  # Delete and create the export directory
163
+ if force_delete:
164
+ click.confirm(
165
+ f"Are you sure you want to delete the directory {export_dir}?",
166
+ abort=True,
167
+ )
137
168
  delete_and_create_dir(
138
169
  directory_path=export_dir,
139
170
  logger=logger,
@@ -145,6 +176,12 @@ def export_to_json(force_delete, python_path):
145
176
 
146
177
  # Process each module using the `model_to_json` method of each entity
147
178
  for module_path in py_modules:
179
+ if module_path.endswith("property_types.py"):
180
+ if duplicated_property_types(module_path=module_path, logger=logger):
181
+ click.echo(
182
+ "Please fix the duplicated property types before exporting to RDF/XML."
183
+ )
184
+ return
148
185
  entities_to_json(module_path=module_path, export_dir=export_dir, logger=logger)
149
186
 
150
187
  click.echo(f"All entity artifacts have been generated and saved to {export_dir}")
@@ -173,11 +210,20 @@ def export_to_json(force_delete, python_path):
173
210
  Default is `./bam_masterdata/datamodel/`.
174
211
  """,
175
212
  )
176
- def export_to_excel(force_delete, python_path):
177
- # Get the directories from the Python modules and the export directory for the static artifacts
178
- export_dir = os.path.join(".", "artifacts")
179
-
213
+ @click.option(
214
+ "--export-dir",
215
+ type=str,
216
+ required=False,
217
+ default="./artifacts",
218
+ help="The directory where the Excel file will be exported. Default is `./artifacts`.",
219
+ )
220
+ def export_to_excel(force_delete, python_path, export_dir):
180
221
  # Delete and create the export directory
222
+ if force_delete:
223
+ click.confirm(
224
+ f"Are you sure you want to delete the directory {export_dir}?",
225
+ abort=True,
226
+ )
181
227
  delete_and_create_dir(
182
228
  directory_path=export_dir,
183
229
  logger=logger,
@@ -188,14 +234,19 @@ def export_to_excel(force_delete, python_path):
188
234
  py_modules = listdir_py_modules(directory_path=python_path, logger=logger)
189
235
 
190
236
  # Load the definitions module classes
191
- definitions_module = import_module(
192
- module_path="./bam_masterdata/metadata/definitions.py"
193
- )
237
+ definitions_path = Path(__file__).parent / ".." / "metadata" / "definitions.py"
238
+ definitions_module = import_module(module_path=str(definitions_path.resolve()))
194
239
 
195
240
  # Process the modules and save the entities to the openBIS masterdata Excel file
196
- masterdata_file = os.path.join(".", "artifacts", "masterdata.xlsx")
241
+ masterdata_file = os.path.join(export_dir, "masterdata.xlsx")
197
242
  wb = Workbook()
198
243
  for i, module_path in enumerate(py_modules):
244
+ if module_path.endswith("property_types.py"):
245
+ if duplicated_property_types(module_path=module_path, logger=logger):
246
+ click.echo(
247
+ "Please fix the duplicated property types before exporting to RDF/XML."
248
+ )
249
+ return
199
250
  if i == 0:
200
251
  ws = wb.active
201
252
  else:
@@ -216,5 +267,77 @@ def export_to_excel(force_delete, python_path):
216
267
  click.echo(f"All masterdata have been generated and saved to {masterdata_file}")
217
268
 
218
269
 
270
+ @cli.command(
271
+ name="export_to_rdf",
272
+ help="Export entities to a RDF/XML file in the path `./artifacts/bam_masterdata.owl`.",
273
+ )
274
+ @click.option(
275
+ "--force-delete",
276
+ type=bool,
277
+ required=False,
278
+ default=False,
279
+ help="""
280
+ (Optional) If set to `True`, it will delete the current `./artifacts/` folder and create a new one. Default is `False`.
281
+ """,
282
+ )
283
+ @click.option(
284
+ "--python-path",
285
+ type=str,
286
+ required=False,
287
+ default=DATAMODEL_DIR,
288
+ help="""
289
+ (Optional) The path to the individual Python module or the directory containing the Python modules to process the datamodel.
290
+ Default is `./bam_masterdata/datamodel/`.
291
+ """,
292
+ )
293
+ @click.option(
294
+ "--export-dir",
295
+ type=str,
296
+ required=False,
297
+ default="./artifacts",
298
+ help="The directory where the RDF/XML file will be exported. Default is `./artifacts`.",
299
+ )
300
+ def export_to_rdf(force_delete, python_path, export_dir):
301
+ # Delete and create the export directory
302
+ if force_delete:
303
+ click.confirm(
304
+ f"Are you sure you want to delete the directory {export_dir}?",
305
+ abort=True,
306
+ )
307
+ delete_and_create_dir(
308
+ directory_path=export_dir,
309
+ logger=logger,
310
+ force_delete=force_delete,
311
+ )
312
+
313
+ # Get the Python modules to process the datamodel
314
+ py_modules = listdir_py_modules(directory_path=python_path, logger=logger)
315
+ # ! Remove the module containing 'vocabulary_types.py'
316
+ py_modules = [
317
+ module for module in py_modules if "vocabulary_types.py" not in module
318
+ ]
319
+
320
+ # Process each module using the `model_to_rdf` method of each entity
321
+ graph = Graph()
322
+ for module_path in py_modules:
323
+ if module_path.endswith("property_types.py"):
324
+ if duplicated_property_types(module_path=module_path, logger=logger):
325
+ click.echo(
326
+ "Please fix the duplicated property types before exporting to RDF/XML."
327
+ )
328
+ return
329
+ entities_to_rdf(graph=graph, module_path=module_path, logger=logger)
330
+
331
+ # Saving RDF/XML to file
332
+ rdf_output = graph.serialize(format="pretty-xml")
333
+ masterdata_file = os.path.join(export_dir, "masterdata.owl")
334
+ with open(masterdata_file, "w", encoding="utf-8") as f:
335
+ f.write(rdf_output)
336
+
337
+ click.echo(
338
+ f"All masterdata has been generated in RDF/XML format and saved to {masterdata_file}"
339
+ )
340
+
341
+
219
342
  if __name__ == "__main__":
220
343
  cli()