obographs 0.0.3__tar.gz → 0.0.5__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: obographs
3
- Version: 0.0.3
3
+ Version: 0.0.5
4
4
  Summary: A python data model for OBO Graphs
5
5
  Keywords: snekpack,cookiecutter
6
6
  Author: Charles Tapley Hoyt
@@ -23,15 +23,8 @@ Classifier: Programming Language :: Python :: 3.13
23
23
  Classifier: Programming Language :: Python :: 3 :: Only
24
24
  Classifier: Typing :: Typed
25
25
  Requires-Dist: pydantic
26
- Requires-Dist: curies>=0.10.7
26
+ Requires-Dist: curies>=0.10.19
27
27
  Requires-Dist: typing-extensions
28
- Requires-Dist: sphinx>=8 ; extra == 'docs'
29
- Requires-Dist: sphinx-rtd-theme>=3.0 ; extra == 'docs'
30
- Requires-Dist: sphinx-automodapi ; extra == 'docs'
31
- Requires-Dist: autodoc-pydantic ; extra == 'docs'
32
- Requires-Dist: requests ; extra == 'network'
33
- Requires-Dist: pytest ; extra == 'tests'
34
- Requires-Dist: coverage[toml] ; extra == 'tests'
35
28
  Maintainer: Charles Tapley Hoyt
36
29
  Maintainer-email: Charles Tapley Hoyt <cthoyt@gmail.com>
37
30
  Requires-Python: >=3.10
@@ -40,9 +33,6 @@ Project-URL: Documentation, https://obographs.readthedocs.io
40
33
  Project-URL: Funding, https://github.com/sponsors/cthoyt
41
34
  Project-URL: Homepage, https://github.com/cthoyt/obographs
42
35
  Project-URL: Repository, https://github.com/cthoyt/obographs.git
43
- Provides-Extra: docs
44
- Provides-Extra: network
45
- Provides-Extra: tests
46
36
  Description-Content-Type: text/markdown
47
37
 
48
38
  <!--
@@ -129,18 +119,15 @@ $ python3 -m pip install obographs
129
119
  The most recent code and data can be installed directly from GitHub with uv:
130
120
 
131
121
  ```console
132
- $ uv --preview pip install git+https://github.com/cthoyt/obographs.git
122
+ $ uv pip install git+https://github.com/cthoyt/obographs.git
133
123
  ```
134
124
 
135
125
  or with pip:
136
126
 
137
127
  ```console
138
- $ UV_PREVIEW=1 python3 -m pip install git+https://github.com/cthoyt/obographs.git
128
+ $ python3 -m pip install git+https://github.com/cthoyt/obographs.git
139
129
  ```
140
130
 
141
- Note that this requires setting `UV_PREVIEW` mode enabled until the uv build
142
- backend becomes a stable feature.
143
-
144
131
  ## 👐 Contributing
145
132
 
146
133
  Contributions, whether filing an issue, making a pull request, or forking, are
@@ -203,18 +190,15 @@ To install in development mode, use the following:
203
190
  ```console
204
191
  $ git clone git+https://github.com/cthoyt/obographs.git
205
192
  $ cd obographs
206
- $ uv --preview pip install -e .
193
+ $ uv pip install -e .
207
194
  ```
208
195
 
209
196
  Alternatively, install using pip:
210
197
 
211
198
  ```console
212
- $ UV_PREVIEW=1 python3 -m pip install -e .
199
+ $ python3 -m pip install -e .
213
200
  ```
214
201
 
215
- Note that this requires setting `UV_PREVIEW` mode enabled until the uv build
216
- backend becomes a stable feature.
217
-
218
202
  ### Updating Package Boilerplate
219
203
 
220
204
  This project uses `cruft` to keep boilerplate (i.e., configuration, contribution
@@ -82,18 +82,15 @@ $ python3 -m pip install obographs
82
82
  The most recent code and data can be installed directly from GitHub with uv:
83
83
 
84
84
  ```console
85
- $ uv --preview pip install git+https://github.com/cthoyt/obographs.git
85
+ $ uv pip install git+https://github.com/cthoyt/obographs.git
86
86
  ```
87
87
 
88
88
  or with pip:
89
89
 
90
90
  ```console
91
- $ UV_PREVIEW=1 python3 -m pip install git+https://github.com/cthoyt/obographs.git
91
+ $ python3 -m pip install git+https://github.com/cthoyt/obographs.git
92
92
  ```
93
93
 
94
- Note that this requires setting `UV_PREVIEW` mode enabled until the uv build
95
- backend becomes a stable feature.
96
-
97
94
  ## 👐 Contributing
98
95
 
99
96
  Contributions, whether filing an issue, making a pull request, or forking, are
@@ -156,18 +153,15 @@ To install in development mode, use the following:
156
153
  ```console
157
154
  $ git clone git+https://github.com/cthoyt/obographs.git
158
155
  $ cd obographs
159
- $ uv --preview pip install -e .
156
+ $ uv pip install -e .
160
157
  ```
161
158
 
162
159
  Alternatively, install using pip:
163
160
 
164
161
  ```console
165
- $ UV_PREVIEW=1 python3 -m pip install -e .
162
+ $ python3 -m pip install -e .
166
163
  ```
167
164
 
168
- Note that this requires setting `UV_PREVIEW` mode enabled until the uv build
169
- backend becomes a stable feature.
170
-
171
165
  ### Updating Package Boilerplate
172
166
 
173
167
  This project uses `cruft` to keep boilerplate (i.e., configuration, contribution
@@ -1,12 +1,10 @@
1
1
  [build-system]
2
- requires = ["uv>=0.5.13,<0.6.0"]
3
- # The uv backend entered preview mode in https://github.com/astral-sh/uv/pull/8886/files
4
- # with the 0.5.0 release. See also https://github.com/astral-sh/uv/issues/3957 for tracking.
5
- build-backend = "uv"
2
+ requires = ["uv_build>=0.6.6,<0.7"]
3
+ build-backend = "uv_build"
6
4
 
7
5
  [project]
8
6
  name = "obographs"
9
- version = "0.0.3"
7
+ version = "0.0.5"
10
8
  description = "A python data model for OBO Graphs"
11
9
  readme = "README.md"
12
10
  authors = [
@@ -52,11 +50,12 @@ license-files = [
52
50
  requires-python = ">=3.10"
53
51
  dependencies = [
54
52
  "pydantic",
55
- "curies>=0.10.7",
53
+ "curies>=0.10.19",
56
54
  "typing-extensions",
57
55
  ]
58
56
 
59
- [project.optional-dependencies]
57
+ # see https://peps.python.org/pep-0735/ and https://docs.astral.sh/uv/concepts/dependencies/#dependency-groups
58
+ [dependency-groups]
60
59
  tests = [
61
60
  "pytest",
62
61
  "coverage[toml]",
@@ -67,10 +66,51 @@ docs = [
67
66
  "sphinx_automodapi",
68
67
  "autodoc_pydantic",
69
68
  ]
69
+ lint = [
70
+ "ruff",
71
+ ]
72
+ typing = [
73
+ { include-group = "tests" },
74
+ "mypy",
75
+ "pydantic",
76
+ "types-requests",
77
+ ]
78
+ docs-lint = [
79
+ { include-group = "docs" },
80
+ "doc8",
81
+ ]
82
+ format-docs = [
83
+ { include-group = "docs" },
84
+ "docstrfmt",
85
+ ]
86
+ doctests = [
87
+ "xdoctest",
88
+ "pygments",
89
+ ]
90
+ pyroma = [
91
+ "pyroma",
92
+ "pygments",
93
+ ]
94
+ # follow https://github.com/astral-sh/uv/issues/6298 for switching to a uv-based version bump workflow
95
+ bump = [
96
+ "bump-my-version",
97
+ ]
98
+ build = [
99
+ "uv",
100
+ "uv-build",
101
+ ]
102
+ release = [
103
+ { include-group = "build" },
104
+ "uv",
105
+ "keyring",
106
+ ]
70
107
  network = [
71
108
  "requests",
72
109
  ]
73
110
 
111
+ # see https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#dependencies-optional-dependencies
112
+ # [project.optional-dependencies]
113
+
74
114
  # See https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#urls
75
115
  # and also https://packaging.python.org/en/latest/specifications/well-known-project-urls/
76
116
  [project.urls]
@@ -114,6 +154,9 @@ source = [
114
154
  omit = [
115
155
  "tests/*",
116
156
  "docs/*",
157
+ "src/obographs/version.py",
158
+ "src/obographs/__main__.py",
159
+ "src/obographs/cli.py",
117
160
  ]
118
161
 
119
162
  [tool.coverage.paths]
@@ -189,7 +232,7 @@ known-first-party = [
189
232
  docstring-code-format = true
190
233
 
191
234
  [tool.bumpversion]
192
- current_version = "0.0.3"
235
+ current_version = "0.0.5"
193
236
  parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)(?:-(?P<release>[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?(?:\\+(?P<build>[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?"
194
237
  serialize = [
195
238
  "{major}.{minor}.{patch}-{release}+{build}",
@@ -0,0 +1,73 @@
1
+ """A python data model for OBO Graphs."""
2
+
3
+ from .model import (
4
+ Definition,
5
+ DomainRangeAxiom,
6
+ Edge,
7
+ EquivalentNodeSet,
8
+ ExistentialRestrictionExpression,
9
+ Graph,
10
+ GraphDocument,
11
+ LogicalDefinition,
12
+ Meta,
13
+ Node,
14
+ NodeType,
15
+ Property,
16
+ PropertyChainAxiom,
17
+ PropertyType,
18
+ Synonym,
19
+ Xref,
20
+ read,
21
+ )
22
+ from .standardized import (
23
+ StandardizedBaseModel,
24
+ StandardizedDefinition,
25
+ StandardizedDomainRangeAxiom,
26
+ StandardizedEdge,
27
+ StandardizedEquivalentNodeSet,
28
+ StandardizedExistentialRestriction,
29
+ StandardizedGraph,
30
+ StandardizedGraphDocument,
31
+ StandardizedLogicalDefinition,
32
+ StandardizedMeta,
33
+ StandardizedNode,
34
+ StandardizedProperty,
35
+ StandardizedPropertyChainAxiom,
36
+ StandardizedSynonym,
37
+ StandardizedXref,
38
+ )
39
+
40
+ __all__ = [
41
+ "Definition",
42
+ "DomainRangeAxiom",
43
+ "Edge",
44
+ "EquivalentNodeSet",
45
+ "ExistentialRestrictionExpression",
46
+ "Graph",
47
+ "GraphDocument",
48
+ "LogicalDefinition",
49
+ "Meta",
50
+ "Node",
51
+ "NodeType",
52
+ "Property",
53
+ "PropertyChainAxiom",
54
+ "PropertyType",
55
+ "StandardizedBaseModel",
56
+ "StandardizedDefinition",
57
+ "StandardizedDomainRangeAxiom",
58
+ "StandardizedEdge",
59
+ "StandardizedEquivalentNodeSet",
60
+ "StandardizedExistentialRestriction",
61
+ "StandardizedGraph",
62
+ "StandardizedGraphDocument",
63
+ "StandardizedLogicalDefinition",
64
+ "StandardizedMeta",
65
+ "StandardizedNode",
66
+ "StandardizedProperty",
67
+ "StandardizedPropertyChainAxiom",
68
+ "StandardizedSynonym",
69
+ "StandardizedXref",
70
+ "Synonym",
71
+ "Xref",
72
+ "read",
73
+ ]
@@ -9,27 +9,35 @@
9
9
 
10
10
  from __future__ import annotations
11
11
 
12
+ import gzip
12
13
  import json
13
14
  import logging
14
15
  from collections import defaultdict
15
16
  from pathlib import Path
16
- from typing import TYPE_CHECKING, Any, Literal, TypeAlias, overload
17
+ from typing import TYPE_CHECKING, Literal, TypeAlias, overload
17
18
 
19
+ import curies
20
+ from curies.vocabulary import SynonymScopeOIO
18
21
  from pydantic import BaseModel, Field
19
22
 
20
23
  if TYPE_CHECKING:
21
- import curies
22
-
23
24
  from .standardized import StandardizedGraph
24
25
 
25
26
  __all__ = [
26
27
  "Definition",
28
+ "DomainRangeAxiom",
27
29
  "Edge",
30
+ "EquivalentNodeSet",
31
+ "ExistentialRestrictionExpression",
28
32
  "Graph",
29
33
  "GraphDocument",
34
+ "LogicalDefinition",
30
35
  "Meta",
31
36
  "Node",
37
+ "NodeType",
32
38
  "Property",
39
+ "PropertyChainAxiom",
40
+ "PropertyType",
33
41
  "Synonym",
34
42
  "Xref",
35
43
  "read",
@@ -40,24 +48,12 @@ logger = logging.getLogger(__name__)
40
48
  OBO_URI_PREFIX = "http://purl.obolibrary.org/obo/"
41
49
  OBO_URI_PREFIX_LEN = len(OBO_URI_PREFIX)
42
50
 
43
- SynonymPredicate: TypeAlias = Literal[
44
- "hasExactSynonym",
45
- "hasBroadSynonym",
46
- "hasNarrowSynonym",
47
- "hasRelatedSynonym",
48
- ]
49
51
  NodeType: TypeAlias = Literal["CLASS", "PROPERTY", "INDIVIDUAL"]
50
52
 
51
- TimeoutHint = int | float | None
53
+ #: When node type is ``PROPERTY``, this is extra information
54
+ PropertyType: TypeAlias = Literal["ANNOTATION", "OBJECT", "DATA"]
52
55
 
53
- #: A mapping from OBO flat file format internal synonym types to OBO in OWL vocabulary
54
- #: identifiers. See https://owlcollab.github.io/oboformat/doc/GO.format.obo-1_4.html
55
- OBO_SYNONYM_TO_OIO: dict[str, SynonymPredicate] = {
56
- "EXACT": "hasExactSynonym",
57
- "BROAD": "hasBroadSynonym",
58
- "NARROW": "hasNarrowSynonym",
59
- "RELATED": "hasRelatedSynonym",
60
- }
56
+ TimeoutHint = int | float | None
61
57
 
62
58
 
63
59
  class Property(BaseModel):
@@ -91,7 +87,7 @@ class Synonym(BaseModel):
91
87
  """Represents a synonym inside an object meta."""
92
88
 
93
89
  val: str | None = Field(default=None)
94
- pred: str = Field(default="hasExactSynonym")
90
+ pred: SynonymScopeOIO = Field(default="hasExactSynonym")
95
91
  synonymType: str | None = Field(None, examples=["OMO:0003000"]) # noqa:N815
96
92
  xrefs: list[str] = Field(
97
93
  default_factory=list,
@@ -129,6 +125,51 @@ class Node(BaseModel):
129
125
  lbl: str | None = Field(None, description="The name of the node")
130
126
  meta: Meta | None = None
131
127
  type: NodeType | None = Field(None, description="Type of node")
128
+ propertyType: PropertyType | None = Field( # noqa:N815
129
+ None, description="Type of property, if the node type is a property"
130
+ )
131
+
132
+
133
+ class DomainRangeAxiom(BaseModel):
134
+ """Represents a domain/range axiom."""
135
+
136
+ predicateId: str # noqa:N815
137
+ domainClassIds: list[str] | None = None # noqa:N815
138
+ rangeClassIds: list[str] | None = None # noqa:N815
139
+ allValuesFromEdges: list[Edge] | None = None # noqa:N815
140
+ meta: Meta | None = None
141
+
142
+
143
+ class PropertyChainAxiom(BaseModel):
144
+ """Represents a property chain axiom."""
145
+
146
+ predicateId: str # noqa:N815
147
+ chainPredicateIds: list[str] # noqa:N815
148
+ meta: Meta | None = None
149
+
150
+
151
+ class ExistentialRestrictionExpression(BaseModel):
152
+ """Represents an existential restriction."""
153
+
154
+ propertyId: str # noqa:N815
155
+ fillerId: str # noqa:N815
156
+
157
+
158
+ class LogicalDefinition(BaseModel):
159
+ """Represents a logical definition chain axiom."""
160
+
161
+ definedClassId: str # noqa:N815
162
+ genusIds: list[str] | None = None # noqa:N815
163
+ restrictions: list[ExistentialRestrictionExpression] | None = None
164
+ meta: Meta | None = None
165
+
166
+
167
+ class EquivalentNodeSet(BaseModel):
168
+ """Represents a set of equivalent nodes."""
169
+
170
+ representativeNodeId: str # noqa:N815
171
+ nodeIds: list[str] # noqa:N815
172
+ meta: Meta | None = None
132
173
 
133
174
 
134
175
  class Graph(BaseModel):
@@ -138,10 +179,10 @@ class Graph(BaseModel):
138
179
  meta: Meta | None = None
139
180
  nodes: list[Node] = Field(default_factory=list)
140
181
  edges: list[Edge] = Field(default_factory=list)
141
- equivalentNodesSets: list[Any] = Field(default_factory=list) # noqa:N815
142
- logicalDefinitionAxioms: list[Any] = Field(default_factory=list) # noqa:N815
143
- domainRangeAxioms: list[Any] = Field(default_factory=list) # noqa:N815
144
- propertyChainAxioms: list[Any] = Field(default_factory=list) # noqa:N815
182
+ equivalentNodesSets: list[EquivalentNodeSet] = Field(default_factory=list) # noqa:N815
183
+ logicalDefinitionAxioms: list[LogicalDefinition] = Field(default_factory=list) # noqa:N815
184
+ domainRangeAxioms: list[DomainRangeAxiom] = Field(default_factory=list) # noqa:N815
185
+ propertyChainAxioms: list[PropertyChainAxiom] = Field(default_factory=list) # noqa:N815
145
186
 
146
187
  def standardize(self, converter: curies.Converter) -> StandardizedGraph:
147
188
  """Standardize the graph."""
@@ -210,12 +251,14 @@ def read(
210
251
 
211
252
  elif isinstance(source, str | Path):
212
253
  path = Path(source).expanduser().resolve()
213
- if path.is_file():
214
- if path.suffix.endswith(".gz"):
215
- raise NotImplementedError
216
- else:
217
- with path.open() as file:
218
- graph_document = GraphDocument.model_validate(json.load(file))
254
+ if not path.is_file():
255
+ raise FileNotFoundError
256
+ if path.suffix.endswith(".gz"):
257
+ with gzip.open(path, mode="rt") as file:
258
+ graph_document = GraphDocument.model_validate(json.load(file))
259
+ else:
260
+ with path.open() as file:
261
+ graph_document = GraphDocument.model_validate(json.load(file))
219
262
  else:
220
263
  raise TypeError(f"Unhandled source: {source}")
221
264