mash-core 0.9.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 (70) hide show
  1. mash_core-0.9.0/LICENSE +21 -0
  2. mash_core-0.9.0/PKG-INFO +198 -0
  3. mash_core-0.9.0/README.md +161 -0
  4. mash_core-0.9.0/pyproject.toml +132 -0
  5. mash_core-0.9.0/pyproject.toml.orig +117 -0
  6. mash_core-0.9.0/src/mash/__init__.py +426 -0
  7. mash_core-0.9.0/src/mash/core/__init__.py +0 -0
  8. mash_core-0.9.0/src/mash/core/catalog/__init__.py +1 -0
  9. mash_core-0.9.0/src/mash/core/catalog/api.py +76 -0
  10. mash_core-0.9.0/src/mash/core/catalog/frontend/assets/entry.client-Bl1bODN_.js +13 -0
  11. mash_core-0.9.0/src/mash/core/catalog/frontend/assets/helpers-CvVoHxcP.js +19 -0
  12. mash_core-0.9.0/src/mash/core/catalog/frontend/assets/home-D7SI6u38.js +1 -0
  13. mash_core-0.9.0/src/mash/core/catalog/frontend/assets/index-Dh-O-te8.js +26 -0
  14. mash_core-0.9.0/src/mash/core/catalog/frontend/assets/manifest-f8f091fe.js +1 -0
  15. mash_core-0.9.0/src/mash/core/catalog/frontend/assets/root-BE3ctyoe.css +1 -0
  16. mash_core-0.9.0/src/mash/core/catalog/frontend/assets/root-CIOxwHW_.js +1 -0
  17. mash_core-0.9.0/src/mash/core/catalog/frontend/favicon.ico +0 -0
  18. mash_core-0.9.0/src/mash/core/catalog/frontend/index.html +13 -0
  19. mash_core-0.9.0/src/mash/core/catalog/readme.md +3 -0
  20. mash_core-0.9.0/src/mash/core/compat/__init__.py +0 -0
  21. mash_core-0.9.0/src/mash/core/compat/maplib/__init__.py +1 -0
  22. mash_core-0.9.0/src/mash/core/compat/maplib/serialization_helper.py +249 -0
  23. mash_core-0.9.0/src/mash/core/config.py +35 -0
  24. mash_core-0.9.0/src/mash/core/linkml/__init__.py +2 -0
  25. mash_core-0.9.0/src/mash/core/linkml/schema.py +112 -0
  26. mash_core-0.9.0/src/mash/core/linkml/shapes.py +49 -0
  27. mash_core-0.9.0/src/mash/core/logging.py +47 -0
  28. mash_core-0.9.0/src/mash/core/maplib.py +8 -0
  29. mash_core-0.9.0/src/mash/core/metadata/__init__.py +1 -0
  30. mash_core-0.9.0/src/mash/core/metadata/models.py +291 -0
  31. mash_core-0.9.0/src/mash/core/mime.py +50 -0
  32. mash_core-0.9.0/src/mash/core/models.py +71 -0
  33. mash_core-0.9.0/src/mash/core/ns.py +53 -0
  34. mash_core-0.9.0/src/mash/core/profiles/__init__.py +2 -0
  35. mash_core-0.9.0/src/mash/core/profiles/mash_profile.py +53 -0
  36. mash_core-0.9.0/src/mash/core/profiles/metadata.py +31 -0
  37. mash_core-0.9.0/src/mash/core/utilities/__init__.py +3 -0
  38. mash_core-0.9.0/src/mash/core/utilities/add_prefix_url.py +34 -0
  39. mash_core-0.9.0/src/mash/core/utilities/attributes.py +106 -0
  40. mash_core-0.9.0/src/mash/core/utilities/azure.py +35 -0
  41. mash_core-0.9.0/src/mash/core/utilities/dataset.py +10 -0
  42. mash_core-0.9.0/src/mash/core/utilities/dynamic.py +11 -0
  43. mash_core-0.9.0/src/mash/core/utilities/files.py +24 -0
  44. mash_core-0.9.0/src/mash/core/utilities/identifiers.py +11 -0
  45. mash_core-0.9.0/src/mash/core/utilities/organizations.py +9 -0
  46. mash_core-0.9.0/src/mash/core/utilities/profiles.py +23 -0
  47. mash_core-0.9.0/src/mash/core/utilities/ranges.py +28 -0
  48. mash_core-0.9.0/src/mash/core/utilities/resource_descriptors.py +5 -0
  49. mash_core-0.9.0/src/mash/core/utilities/semantic_enum.py +40 -0
  50. mash_core-0.9.0/src/mash/core/utilities/user.py +22 -0
  51. mash_core-0.9.0/src/mash/core/validation.py +110 -0
  52. mash_core-0.9.0/src/mash/orm/__init__.py +4 -0
  53. mash_core-0.9.0/src/mash/orm/query/__init__.py +2 -0
  54. mash_core-0.9.0/src/mash/orm/query/filters.py +235 -0
  55. mash_core-0.9.0/src/mash/orm/query/query.py +149 -0
  56. mash_core-0.9.0/src/mash/orm/read.py +413 -0
  57. mash_core-0.9.0/src/mash/orm/update.py +253 -0
  58. mash_core-0.9.0/src/mash/orm/write.py +186 -0
  59. mash_core-0.9.0/src/mash/repositories/__init__.py +2 -0
  60. mash_core-0.9.0/src/mash/repositories/mesh/__init__.py +1 -0
  61. mash_core-0.9.0/src/mash/repositories/mesh/blob_mesh_repository.py +232 -0
  62. mash_core-0.9.0/src/mash/repositories/mesh/filesystem_mesh_repository.py +146 -0
  63. mash_core-0.9.0/src/mash/repositories/mesh/mesh_repository.py +52 -0
  64. mash_core-0.9.0/src/mash/repositories/mesh/multi_repository_view.py +157 -0
  65. mash_core-0.9.0/src/mash/repositories/mesh/repository_collection.py +48 -0
  66. mash_core-0.9.0/src/mash/repositories/mesh/utilities.py +69 -0
  67. mash_core-0.9.0/src/mash/repositories/models/__init__.py +1 -0
  68. mash_core-0.9.0/src/mash/repositories/models/model_registry.py +78 -0
  69. mash_core-0.9.0/src/mash/repositories/namespace/__init__.py +1 -0
  70. mash_core-0.9.0/src/mash/repositories/namespace/namespace.py +122 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) [year] [fullname]
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,198 @@
1
+ Metadata-Version: 2.4
2
+ Name: mash-core
3
+ Version: 0.9.0
4
+ Summary: Standardized data and RDF made practical
5
+ Keywords: RDF,DCAT,standards,serialization,deserialization
6
+ Author: Natalie Jakobsen
7
+ Author-email: Natalie Jakobsen <natalie@jkbn.no>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Intended Audience :: Information Technology
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Requires-Dist: ipykernel>=6.29.5
15
+ Requires-Dist: pytest>=8.3.5
16
+ Requires-Dist: uvicorn>=0.34.0
17
+ Requires-Dist: maplib>=0.20.25
18
+ Requires-Dist: polars>=0.20.13
19
+ Requires-Dist: pyarrow==23.0.1
20
+ Requires-Dist: fastapi[standard]>=0.115
21
+ Requires-Dist: pyproj>=3.7.1
22
+ Requires-Dist: platformdirs>=4.4.0
23
+ Requires-Dist: pyoxigraph>=0.5.2
24
+ Requires-Dist: colorama>=0.4.6
25
+ Requires-Dist: pydantic-settings>=2.12.0
26
+ Requires-Dist: cachetools>=6.2.2
27
+ Requires-Dist: azure-storage-blob>=12.27.1
28
+ Requires-Dist: azure-identity>=1.25.1
29
+ Requires-Dist: smart-open[azure]>=7.6.0
30
+ Requires-Dist: linkml>=1.11.1
31
+ Requires-Dist: jinja2>=3.1.6
32
+ Requires-Dist: pathvalidate>=3.3.1
33
+ Maintainer: Natalie Jakobsen
34
+ Maintainer-email: Natalie Jakobsen <natalie@jkbn.no>
35
+ Requires-Python: >=3.13
36
+ Description-Content-Type: text/markdown
37
+
38
+ # Mash
39
+
40
+ Mash attempts to solve the mess that is working with data spread between systems and people by making it easy to store your data alongside rich metadata. This brings with it organization, searchability, traceability and many other useful tings.
41
+
42
+ In practice mash allows you to:
43
+
44
+ - Search your data by any criteria from metadata
45
+ - See where your data originated and its history
46
+ - Validate that your data meets the criteria for a specified usage
47
+ - Connect to remote data sources while maintaining all of the above
48
+
49
+ #### Batteries-included
50
+
51
+ Mash comes pre-loaded with useful tools for working with RDF and grid models. The most helpful things for getting started are the profiles, standards and organizations found in the `grid` module. These can be used to search, validate and describe our data.
52
+
53
+ #### Standards-based
54
+
55
+ All models used in mash are based on widely-implemented standard vocabularies like `dcat`, `prof` and `prov-o`, and can be serialized into RDF following those standards.
56
+
57
+ #### Further documentation
58
+
59
+ Some deeper documentation can be found here:
60
+
61
+ - [Introduction to Mash](docs/intro.md)
62
+ - [Datasets and distributions](docs/datasets.md)
63
+ - [Profiles](docs/profiles.md)
64
+ - [Developer guidelines](docs/development.md)
65
+
66
+ ### Examples of usage
67
+
68
+ (more incoming!)
69
+
70
+ #### Define new data using datasets and distributions
71
+
72
+ ```Python
73
+ import mash
74
+
75
+ from mash import models
76
+ from mash.core.profiles import MetadataProfile
77
+ from mash.core.utilities.organizations import make_organization
78
+
79
+
80
+ dist_id = "http://example.com/example#metadata-plaintext"
81
+ dataset = models.Dataset(
82
+ identifier="http://example.com/example#metadata",
83
+ title="Example metadata",
84
+ description="Example dataset containing metadata with little",
85
+ conforms_to=[MetadataProfile], # This is a lie
86
+ information_owner=make_organization("ElBits AS", "931264079"),
87
+ distributions=[models.Distribution(identifier=dist_id, mime_type="text/plain")],
88
+ )
89
+
90
+ mash.save(dataset)
91
+ data = b"this is some text"
92
+ mash.write_data(data, dist_id)
93
+
94
+
95
+ print(mash.read_data(dist_id).decode())
96
+ ```
97
+
98
+
99
+ #### Write a SPARQL query towards a graph
100
+
101
+ ```Python
102
+ import mash
103
+
104
+ rdf_dataset = mash.fetch("urn:uuid:5393e12b-96c3-4fab-8b98-d4ba2e940b94")
105
+ m = mash.model_from_dataset(rdf_dataset)
106
+ res = m.query("""
107
+ PREFIX cim: <http://iec.ch/TC57/CIM100#>
108
+ SELECT (COUNT(?s) as ?substation_count) WHERE {
109
+ ?s a cim:Substation
110
+ }
111
+ """)
112
+ print(res)
113
+ ```
114
+
115
+ ## Mash ORM
116
+
117
+ Mash features a simple RDF ORM which allows you to extract data from RDF graphs into Pydantic BaseModel classes, and to serialize BaseModel classes into RDF graphs. Using the SemanticModel class and Predicate annotation you can define your own rich metadata classes - either based on existing standards or your own models.
118
+
119
+ #### A basic example
120
+
121
+ ```Python
122
+ from typing import Annotated, ClassVar
123
+ from mash import models, serialize, Predicate as P
124
+
125
+
126
+ class Person(models.SemanticModel):
127
+ _type: ClassVar = "foaf:Person"
128
+ name: Annotated[str, P("foaf:name")]
129
+ mail: Annotated[str | None, P("foaf:mbox")] = None
130
+ friends: Annotated[list["Person"], P("mash:friends")] = []
131
+
132
+
133
+ kristoffer_robin = Person(identifier="kr", name="Kristoffer Robin")
134
+ ole_brumm = Person(identifier="ob", name="Ole Brumm", mail="ole.brum@100meter.skogen", friends=[kristoffer_robin])
135
+ turtle_text = serialize(ole_brumm)
136
+ print(turtle_text)
137
+ ```
138
+
139
+ ```
140
+ <urn:mash:kr> a foaf:Person ;
141
+ foaf:name "Kristoffer Robin" .
142
+
143
+ <urn:mash:ob> a foaf:Person ;
144
+ mash:friends <urn:mash:kr> ;
145
+ foaf:mbox "ole.brum@100meter.skogen" ;
146
+ foaf:name "Ole Brumm" .
147
+ ```
148
+
149
+ #### Making data easier to parse with ReverseRelations
150
+
151
+ Normally in RDF some relations might go in directions that are not pracitical. If you want everything attached to one class rather than to point in all directions from different classes, you can achieve this with ReverseRelations.
152
+
153
+ Notice how in the previous example `Substation` has no references to `VoltageLevel` or `SubstationPart` since those actually contain the reference to `Substation`.
154
+
155
+ ```Python
156
+ from typing import Annotated, ClassVar
157
+
158
+ import mash
159
+
160
+ from mash import Predicate as P, ReverseRelation
161
+ from mash.grid import get_latest_nemo
162
+ from tests.grid.profiles.nemo import IdentifiedObject, VoltageLevel, SubstationPart, NemoProfile
163
+
164
+
165
+ class SubstationEmbed(IdentifiedObject):
166
+ _type: ClassVar = "cim:Substation"
167
+ substation_kind: Annotated[list[str], P("elb:Substation.substationKind")]
168
+ substation_parts: Annotated[list[SubstationPart], ReverseRelation("elb:SubstationPart.Substation")]
169
+ voltage_levels: Annotated[list[VoltageLevel], ReverseRelation("cim:VoltageLevel.Substation")]
170
+
171
+
172
+ latest_nemo = get_latest_nemo()
173
+ m = mash.model_from_dataset(latest_nemo)
174
+ with NemoProfile:
175
+ substations = mash.instantiate(m, model=SubstationEmbed)
176
+ print(substations[0:2])
177
+ ```
178
+
179
+ ### Use namespaces and models from a profile
180
+
181
+ You might have conflicting namespaces (links between a prefix like `cim` and its full URI like `http://iec.ch/TC57/CIM100`) in different contexts, and you might have different models that represent a resource with the same type.
182
+
183
+ Using profiles you can group models and namespaces, and tell mash when to use them. This avoids conflicts and confusion in the code.
184
+
185
+ Looking at a part of the example above, you will see the context manager that activates a profile (`with NemoProfile:`). Within this block mash will use the namespaces placed on Nemo, and will recognize Nemo models when relevant.
186
+
187
+ In this particular example the namespaces are important, since the `grid` module and the `NemoProfile` have different URI's for the prefix `elb`.
188
+
189
+ ```Python
190
+ latest_nemo = get_latest_nemo()
191
+ m = mash.model_from_dataset(latest_nemo)
192
+ with NemoProfile:
193
+ substations = mash.instantiate_all(m, model=SubstationEmbed)
194
+ ```
195
+
196
+ ## Data catalog
197
+
198
+ To open a visual catalog of the data mash has access to, simply run `uv run poe catalog` and a page will open in your browser.
@@ -0,0 +1,161 @@
1
+ # Mash
2
+
3
+ Mash attempts to solve the mess that is working with data spread between systems and people by making it easy to store your data alongside rich metadata. This brings with it organization, searchability, traceability and many other useful tings.
4
+
5
+ In practice mash allows you to:
6
+
7
+ - Search your data by any criteria from metadata
8
+ - See where your data originated and its history
9
+ - Validate that your data meets the criteria for a specified usage
10
+ - Connect to remote data sources while maintaining all of the above
11
+
12
+ #### Batteries-included
13
+
14
+ Mash comes pre-loaded with useful tools for working with RDF and grid models. The most helpful things for getting started are the profiles, standards and organizations found in the `grid` module. These can be used to search, validate and describe our data.
15
+
16
+ #### Standards-based
17
+
18
+ All models used in mash are based on widely-implemented standard vocabularies like `dcat`, `prof` and `prov-o`, and can be serialized into RDF following those standards.
19
+
20
+ #### Further documentation
21
+
22
+ Some deeper documentation can be found here:
23
+
24
+ - [Introduction to Mash](docs/intro.md)
25
+ - [Datasets and distributions](docs/datasets.md)
26
+ - [Profiles](docs/profiles.md)
27
+ - [Developer guidelines](docs/development.md)
28
+
29
+ ### Examples of usage
30
+
31
+ (more incoming!)
32
+
33
+ #### Define new data using datasets and distributions
34
+
35
+ ```Python
36
+ import mash
37
+
38
+ from mash import models
39
+ from mash.core.profiles import MetadataProfile
40
+ from mash.core.utilities.organizations import make_organization
41
+
42
+
43
+ dist_id = "http://example.com/example#metadata-plaintext"
44
+ dataset = models.Dataset(
45
+ identifier="http://example.com/example#metadata",
46
+ title="Example metadata",
47
+ description="Example dataset containing metadata with little",
48
+ conforms_to=[MetadataProfile], # This is a lie
49
+ information_owner=make_organization("ElBits AS", "931264079"),
50
+ distributions=[models.Distribution(identifier=dist_id, mime_type="text/plain")],
51
+ )
52
+
53
+ mash.save(dataset)
54
+ data = b"this is some text"
55
+ mash.write_data(data, dist_id)
56
+
57
+
58
+ print(mash.read_data(dist_id).decode())
59
+ ```
60
+
61
+
62
+ #### Write a SPARQL query towards a graph
63
+
64
+ ```Python
65
+ import mash
66
+
67
+ rdf_dataset = mash.fetch("urn:uuid:5393e12b-96c3-4fab-8b98-d4ba2e940b94")
68
+ m = mash.model_from_dataset(rdf_dataset)
69
+ res = m.query("""
70
+ PREFIX cim: <http://iec.ch/TC57/CIM100#>
71
+ SELECT (COUNT(?s) as ?substation_count) WHERE {
72
+ ?s a cim:Substation
73
+ }
74
+ """)
75
+ print(res)
76
+ ```
77
+
78
+ ## Mash ORM
79
+
80
+ Mash features a simple RDF ORM which allows you to extract data from RDF graphs into Pydantic BaseModel classes, and to serialize BaseModel classes into RDF graphs. Using the SemanticModel class and Predicate annotation you can define your own rich metadata classes - either based on existing standards or your own models.
81
+
82
+ #### A basic example
83
+
84
+ ```Python
85
+ from typing import Annotated, ClassVar
86
+ from mash import models, serialize, Predicate as P
87
+
88
+
89
+ class Person(models.SemanticModel):
90
+ _type: ClassVar = "foaf:Person"
91
+ name: Annotated[str, P("foaf:name")]
92
+ mail: Annotated[str | None, P("foaf:mbox")] = None
93
+ friends: Annotated[list["Person"], P("mash:friends")] = []
94
+
95
+
96
+ kristoffer_robin = Person(identifier="kr", name="Kristoffer Robin")
97
+ ole_brumm = Person(identifier="ob", name="Ole Brumm", mail="ole.brum@100meter.skogen", friends=[kristoffer_robin])
98
+ turtle_text = serialize(ole_brumm)
99
+ print(turtle_text)
100
+ ```
101
+
102
+ ```
103
+ <urn:mash:kr> a foaf:Person ;
104
+ foaf:name "Kristoffer Robin" .
105
+
106
+ <urn:mash:ob> a foaf:Person ;
107
+ mash:friends <urn:mash:kr> ;
108
+ foaf:mbox "ole.brum@100meter.skogen" ;
109
+ foaf:name "Ole Brumm" .
110
+ ```
111
+
112
+ #### Making data easier to parse with ReverseRelations
113
+
114
+ Normally in RDF some relations might go in directions that are not pracitical. If you want everything attached to one class rather than to point in all directions from different classes, you can achieve this with ReverseRelations.
115
+
116
+ Notice how in the previous example `Substation` has no references to `VoltageLevel` or `SubstationPart` since those actually contain the reference to `Substation`.
117
+
118
+ ```Python
119
+ from typing import Annotated, ClassVar
120
+
121
+ import mash
122
+
123
+ from mash import Predicate as P, ReverseRelation
124
+ from mash.grid import get_latest_nemo
125
+ from tests.grid.profiles.nemo import IdentifiedObject, VoltageLevel, SubstationPart, NemoProfile
126
+
127
+
128
+ class SubstationEmbed(IdentifiedObject):
129
+ _type: ClassVar = "cim:Substation"
130
+ substation_kind: Annotated[list[str], P("elb:Substation.substationKind")]
131
+ substation_parts: Annotated[list[SubstationPart], ReverseRelation("elb:SubstationPart.Substation")]
132
+ voltage_levels: Annotated[list[VoltageLevel], ReverseRelation("cim:VoltageLevel.Substation")]
133
+
134
+
135
+ latest_nemo = get_latest_nemo()
136
+ m = mash.model_from_dataset(latest_nemo)
137
+ with NemoProfile:
138
+ substations = mash.instantiate(m, model=SubstationEmbed)
139
+ print(substations[0:2])
140
+ ```
141
+
142
+ ### Use namespaces and models from a profile
143
+
144
+ You might have conflicting namespaces (links between a prefix like `cim` and its full URI like `http://iec.ch/TC57/CIM100`) in different contexts, and you might have different models that represent a resource with the same type.
145
+
146
+ Using profiles you can group models and namespaces, and tell mash when to use them. This avoids conflicts and confusion in the code.
147
+
148
+ Looking at a part of the example above, you will see the context manager that activates a profile (`with NemoProfile:`). Within this block mash will use the namespaces placed on Nemo, and will recognize Nemo models when relevant.
149
+
150
+ In this particular example the namespaces are important, since the `grid` module and the `NemoProfile` have different URI's for the prefix `elb`.
151
+
152
+ ```Python
153
+ latest_nemo = get_latest_nemo()
154
+ m = mash.model_from_dataset(latest_nemo)
155
+ with NemoProfile:
156
+ substations = mash.instantiate_all(m, model=SubstationEmbed)
157
+ ```
158
+
159
+ ## Data catalog
160
+
161
+ To open a visual catalog of the data mash has access to, simply run `uv run poe catalog` and a page will open in your browser.
@@ -0,0 +1,132 @@
1
+ [project]
2
+ name = "mash-core"
3
+ version = "0.9.0"
4
+ description = "Standardized data and RDF made practical"
5
+ license = "MIT"
6
+ license-files = ["LICENSE"]
7
+ keywords = [
8
+ "RDF",
9
+ "DCAT",
10
+ "standards",
11
+ "serialization",
12
+ "deserialization",
13
+ ]
14
+ classifiers = [
15
+ "Development Status :: 4 - Beta",
16
+ "Intended Audience :: Developers",
17
+ "Intended Audience :: Information Technology",
18
+ "License :: OSI Approved :: MIT License",
19
+ ]
20
+ readme = "README.md"
21
+ requires-python = ">=3.13"
22
+ dependencies = [
23
+ "ipykernel>=6.29.5",
24
+ "pytest>=8.3.5",
25
+ "uvicorn>=0.34.0",
26
+ "maplib>=0.20.25",
27
+ "polars>=0.20.13",
28
+ "pyarrow==23.0.1",
29
+ "fastapi[standard]>=0.115",
30
+ "pyproj>=3.7.1",
31
+ "platformdirs>=4.4.0",
32
+ "pyoxigraph>=0.5.2",
33
+ "colorama>=0.4.6",
34
+ "pydantic-settings>=2.12.0",
35
+ "cachetools>=6.2.2",
36
+ "azure-storage-blob>=12.27.1",
37
+ "azure-identity>=1.25.1",
38
+ "smart-open[azure]>=7.6.0",
39
+ "linkml>=1.11.1",
40
+ "jinja2>=3.1.6",
41
+ "pathvalidate>=3.3.1",
42
+ ]
43
+
44
+ [[project.authors]]
45
+ name = "Natalie Jakobsen"
46
+ email = "natalie@jkbn.no"
47
+
48
+ [[project.maintainers]]
49
+ name = "Natalie Jakobsen"
50
+ email = "natalie@jkbn.no"
51
+
52
+ [dependency-groups]
53
+ test = ["pytest>=8.3.4"]
54
+ dev = [
55
+ "pip-audit>=2.8.0",
56
+ "poethepoet>=0.32.2",
57
+ "pre-commit>=4.1.0",
58
+ "pytest>=8.3.4",
59
+ "pytest-cov>=6.0.0",
60
+ "python-dotenv>=1.0.1",
61
+ "ruff>=0.9.4",
62
+ ]
63
+
64
+ [tool.ruff]
65
+ line-length = 140
66
+
67
+ [tool.ruff.lint]
68
+ select = [
69
+ "E",
70
+ "F",
71
+ "UP",
72
+ "I",
73
+ ]
74
+
75
+ [tool.ruff.lint.per-file-ignores]
76
+ "tests/**" = ["ALL"]
77
+ "*/__init__.py" = [
78
+ "F401",
79
+ "E402",
80
+ ]
81
+
82
+ [tool.coverage.paths]
83
+ source = ["app"]
84
+
85
+ [tool.coverage.run]
86
+ branch = true
87
+ omit = ["tests/*"]
88
+
89
+ [tool.coverage.report]
90
+ show_missing = true
91
+
92
+ [tool.poe.tasks]
93
+ format = "uv run ruff format"
94
+ lint = "uv run ruff check --fix"
95
+ test = "uv run -m pytest -s --cov --cov-report=term-missing --cov-report=html:.htmlcov"
96
+ release = [
97
+ "lint",
98
+ "audit",
99
+ "test",
100
+ ]
101
+
102
+ [tool.poe.tasks.audit]
103
+ cmd = "uv run pip-audit ${VULN_IGNORES}"
104
+
105
+ [tool.poe.tasks.audit.uses]
106
+ VULN_IGNORES = "get_vuln_ignores"
107
+
108
+ [tool.poe.tasks.get_vuln_ignores]
109
+ script = "vulnignore:ignore"
110
+
111
+ [tool.poe.tasks.catalog]
112
+ cmd = "uv run uvicorn mash.core.catalog.api:app --port 8234"
113
+
114
+ [tool.poe.tasks.catalog.env]
115
+ DEV_WP = "true"
116
+
117
+ [tool.pytest.ini_options]
118
+ markers = ["remote: marks tests as requiring remote connections (skipped by default in some environments)"]
119
+
120
+ [tool.uv]
121
+ exclude-newer = "3 days"
122
+ required-environments = ["sys_platform == 'linux' and platform_machine == 'aarch64'"]
123
+
124
+ [tool.uv.exclude-newer-package]
125
+ maplib = false
126
+
127
+ [tool.uv.build-backend]
128
+ module-name = "mash"
129
+
130
+ [build-system]
131
+ requires = ["uv_build>=0.12.1,<0.13"]
132
+ build-backend = "uv_build"
@@ -0,0 +1,117 @@
1
+ [project]
2
+ name = "mash-core"
3
+ authors = [
4
+ {name = "Natalie Jakobsen", email = "natalie@jkbn.no"},
5
+ ]
6
+ maintainers = [
7
+ {name = "Natalie Jakobsen", email = "natalie@jkbn.no"}
8
+ ]
9
+ version = "0.9.0"
10
+ description = "Standardized data and RDF made practical"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ keywords = ["RDF", "DCAT", "standards", "serialization", "deserialization"]
14
+ classifiers = [
15
+ "Development Status :: 4 - Beta",
16
+ "Intended Audience :: Developers",
17
+ "Intended Audience :: Information Technology",
18
+ "License :: OSI Approved :: MIT License",
19
+ ]
20
+
21
+
22
+ readme = "README.md"
23
+ requires-python = ">=3.13"
24
+ dependencies = [
25
+ "ipykernel>=6.29.5",
26
+ "pytest>=8.3.5",
27
+ "uvicorn>=0.34.0",
28
+ "maplib>=0.20.25",
29
+ "polars>=0.20.13",
30
+ "pyarrow==23.0.1",
31
+ "fastapi[standard]>=0.115",
32
+ "pyproj>=3.7.1",
33
+ "platformdirs>=4.4.0",
34
+ "pyoxigraph>=0.5.2",
35
+ "colorama>=0.4.6",
36
+ "pydantic-settings>=2.12.0",
37
+ "cachetools>=6.2.2",
38
+ "azure-storage-blob>=12.27.1",
39
+ "azure-identity>=1.25.1",
40
+ "smart-open[azure]>=7.6.0",
41
+ "linkml>=1.11.1",
42
+ "jinja2>=3.1.6",
43
+ "pathvalidate>=3.3.1",
44
+ ]
45
+
46
+ [dependency-groups]
47
+ test = ["pytest>=8.3.4"]
48
+ dev = [
49
+ "pip-audit>=2.8.0",
50
+ "poethepoet>=0.32.2",
51
+ "pre-commit>=4.1.0",
52
+ "pytest>=8.3.4",
53
+ "pytest-cov>=6.0.0",
54
+ "python-dotenv>=1.0.1",
55
+ "ruff>=0.9.4",
56
+ ]
57
+
58
+ [tool.ruff]
59
+ line-length = 140
60
+
61
+ [tool.ruff.lint]
62
+ select = [
63
+ "E", # pycodestyle
64
+ "F", # Pyflakes
65
+ "UP", # pyupgrade
66
+ "I", # isort
67
+ ]
68
+
69
+ [tool.ruff.lint.per-file-ignores]
70
+ "tests/**" = ["ALL"]
71
+ "*/__init__.py" = ["F401", "E402"]
72
+
73
+ [tool.coverage.paths]
74
+ source = ["app"]
75
+
76
+ [tool.coverage.run]
77
+ branch = true
78
+ omit = ["tests/*"]
79
+
80
+ [tool.coverage.report]
81
+ show_missing = true
82
+
83
+ [tool.poe.tasks]
84
+ format = "uv run ruff format"
85
+ lint = "uv run ruff check --fix"
86
+ test = "uv run -m pytest -s --cov --cov-report=term-missing --cov-report=html:.htmlcov"
87
+ release = ["lint", "audit", "test"]
88
+
89
+ [tool.poe.tasks.audit]
90
+ cmd = "uv run pip-audit ${VULN_IGNORES}"
91
+ uses = { VULN_IGNORES = "get_vuln_ignores" }
92
+
93
+ [tool.poe.tasks.get_vuln_ignores]
94
+ script = "vulnignore:ignore"
95
+
96
+ [tool.poe.tasks.catalog]
97
+ cmd = "uv run uvicorn mash.core.catalog.api:app --port 8234"
98
+ env = { DEV_WP = "true" }
99
+
100
+ [tool.pytest.ini_options]
101
+ markers = [
102
+ "remote: marks tests as requiring remote connections (skipped by default in some environments)",
103
+ ]
104
+
105
+ [tool.uv]
106
+ exclude-newer = "3 days"
107
+ exclude-newer-package = { maplib = false }
108
+ required-environments = [ # This is to ensure our lockfile is useable for the github runners
109
+ "sys_platform == 'linux' and platform_machine == 'aarch64'"
110
+ ]
111
+
112
+ [build-system]
113
+ requires = ["uv_build>=0.12.1,<0.13"]
114
+ build-backend = "uv_build"
115
+
116
+ [tool.uv.build-backend]
117
+ module-name = "mash"