pyobo 0.11.2__py3-none-any.whl → 0.12.0__py3-none-any.whl

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 (227) hide show
  1. pyobo/.DS_Store +0 -0
  2. pyobo/__init__.py +95 -20
  3. pyobo/__main__.py +0 -0
  4. pyobo/api/__init__.py +81 -10
  5. pyobo/api/alts.py +52 -42
  6. pyobo/api/combine.py +39 -0
  7. pyobo/api/edges.py +68 -0
  8. pyobo/api/hierarchy.py +231 -203
  9. pyobo/api/metadata.py +14 -19
  10. pyobo/api/names.py +207 -127
  11. pyobo/api/properties.py +117 -113
  12. pyobo/api/relations.py +68 -94
  13. pyobo/api/species.py +24 -21
  14. pyobo/api/typedefs.py +11 -11
  15. pyobo/api/utils.py +66 -13
  16. pyobo/api/xrefs.py +108 -114
  17. pyobo/cli/__init__.py +0 -0
  18. pyobo/cli/cli.py +35 -50
  19. pyobo/cli/database.py +183 -161
  20. pyobo/{xrefdb/xrefs_pipeline.py → cli/database_utils.py} +54 -73
  21. pyobo/cli/lookup.py +163 -195
  22. pyobo/cli/utils.py +19 -6
  23. pyobo/constants.py +102 -3
  24. pyobo/getters.py +196 -118
  25. pyobo/gilda_utils.py +79 -200
  26. pyobo/identifier_utils/__init__.py +41 -0
  27. pyobo/identifier_utils/api.py +296 -0
  28. pyobo/identifier_utils/model.py +130 -0
  29. pyobo/identifier_utils/preprocessing.json +812 -0
  30. pyobo/identifier_utils/preprocessing.py +61 -0
  31. pyobo/identifier_utils/relations/__init__.py +8 -0
  32. pyobo/identifier_utils/relations/api.py +162 -0
  33. pyobo/identifier_utils/relations/data.json +5824 -0
  34. pyobo/identifier_utils/relations/data_owl.json +57 -0
  35. pyobo/identifier_utils/relations/data_rdf.json +1 -0
  36. pyobo/identifier_utils/relations/data_rdfs.json +7 -0
  37. pyobo/mocks.py +9 -6
  38. pyobo/ner/__init__.py +9 -0
  39. pyobo/ner/api.py +72 -0
  40. pyobo/ner/normalizer.py +33 -0
  41. pyobo/obographs.py +43 -39
  42. pyobo/plugins.py +5 -4
  43. pyobo/py.typed +0 -0
  44. pyobo/reader.py +1358 -395
  45. pyobo/reader_utils.py +155 -0
  46. pyobo/resource_utils.py +42 -22
  47. pyobo/resources/__init__.py +0 -0
  48. pyobo/resources/goc.py +75 -0
  49. pyobo/resources/goc.tsv +188 -0
  50. pyobo/resources/ncbitaxon.py +4 -5
  51. pyobo/resources/ncbitaxon.tsv.gz +0 -0
  52. pyobo/resources/ro.py +3 -2
  53. pyobo/resources/ro.tsv +0 -0
  54. pyobo/resources/so.py +0 -0
  55. pyobo/resources/so.tsv +0 -0
  56. pyobo/sources/README.md +12 -8
  57. pyobo/sources/__init__.py +52 -29
  58. pyobo/sources/agrovoc.py +0 -0
  59. pyobo/sources/antibodyregistry.py +11 -12
  60. pyobo/sources/bigg/__init__.py +13 -0
  61. pyobo/sources/bigg/bigg_compartment.py +81 -0
  62. pyobo/sources/bigg/bigg_metabolite.py +229 -0
  63. pyobo/sources/bigg/bigg_model.py +46 -0
  64. pyobo/sources/bigg/bigg_reaction.py +77 -0
  65. pyobo/sources/biogrid.py +1 -2
  66. pyobo/sources/ccle.py +7 -12
  67. pyobo/sources/cgnc.py +0 -5
  68. pyobo/sources/chebi.py +1 -1
  69. pyobo/sources/chembl/__init__.py +9 -0
  70. pyobo/sources/{chembl.py → chembl/chembl_compound.py} +13 -25
  71. pyobo/sources/chembl/chembl_target.py +160 -0
  72. pyobo/sources/civic_gene.py +55 -15
  73. pyobo/sources/clinicaltrials.py +160 -0
  74. pyobo/sources/complexportal.py +24 -24
  75. pyobo/sources/conso.py +14 -22
  76. pyobo/sources/cpt.py +0 -0
  77. pyobo/sources/credit.py +1 -9
  78. pyobo/sources/cvx.py +27 -5
  79. pyobo/sources/depmap.py +9 -12
  80. pyobo/sources/dictybase_gene.py +2 -7
  81. pyobo/sources/drugbank/__init__.py +9 -0
  82. pyobo/sources/{drugbank.py → drugbank/drugbank.py} +11 -16
  83. pyobo/sources/{drugbank_salt.py → drugbank/drugbank_salt.py} +3 -8
  84. pyobo/sources/drugcentral.py +17 -13
  85. pyobo/sources/expasy.py +31 -34
  86. pyobo/sources/famplex.py +13 -18
  87. pyobo/sources/flybase.py +3 -8
  88. pyobo/sources/gard.py +62 -0
  89. pyobo/sources/geonames/__init__.py +9 -0
  90. pyobo/sources/geonames/features.py +28 -0
  91. pyobo/sources/{geonames.py → geonames/geonames.py} +87 -26
  92. pyobo/sources/geonames/utils.py +115 -0
  93. pyobo/sources/gmt_utils.py +6 -7
  94. pyobo/sources/go.py +20 -13
  95. pyobo/sources/gtdb.py +154 -0
  96. pyobo/sources/gwascentral/__init__.py +9 -0
  97. pyobo/sources/{gwascentral_phenotype.py → gwascentral/gwascentral_phenotype.py} +5 -7
  98. pyobo/sources/{gwascentral_study.py → gwascentral/gwascentral_study.py} +1 -7
  99. pyobo/sources/hgnc/__init__.py +9 -0
  100. pyobo/sources/{hgnc.py → hgnc/hgnc.py} +56 -70
  101. pyobo/sources/{hgncgenefamily.py → hgnc/hgncgenefamily.py} +8 -18
  102. pyobo/sources/icd/__init__.py +9 -0
  103. pyobo/sources/{icd10.py → icd/icd10.py} +35 -37
  104. pyobo/sources/icd/icd11.py +148 -0
  105. pyobo/sources/{icd_utils.py → icd/icd_utils.py} +66 -20
  106. pyobo/sources/interpro.py +4 -9
  107. pyobo/sources/itis.py +0 -5
  108. pyobo/sources/kegg/__init__.py +0 -0
  109. pyobo/sources/kegg/api.py +16 -38
  110. pyobo/sources/kegg/genes.py +9 -20
  111. pyobo/sources/kegg/genome.py +1 -7
  112. pyobo/sources/kegg/pathway.py +9 -21
  113. pyobo/sources/mesh.py +58 -24
  114. pyobo/sources/mgi.py +3 -10
  115. pyobo/sources/mirbase/__init__.py +11 -0
  116. pyobo/sources/{mirbase.py → mirbase/mirbase.py} +8 -11
  117. pyobo/sources/{mirbase_constants.py → mirbase/mirbase_constants.py} +0 -0
  118. pyobo/sources/{mirbase_family.py → mirbase/mirbase_family.py} +4 -8
  119. pyobo/sources/{mirbase_mature.py → mirbase/mirbase_mature.py} +3 -7
  120. pyobo/sources/msigdb.py +74 -39
  121. pyobo/sources/ncbi/__init__.py +9 -0
  122. pyobo/sources/ncbi/ncbi_gc.py +162 -0
  123. pyobo/sources/{ncbigene.py → ncbi/ncbigene.py} +18 -19
  124. pyobo/sources/nih_reporter.py +60 -0
  125. pyobo/sources/nlm/__init__.py +9 -0
  126. pyobo/sources/nlm/nlm_catalog.py +48 -0
  127. pyobo/sources/nlm/nlm_publisher.py +36 -0
  128. pyobo/sources/nlm/utils.py +116 -0
  129. pyobo/sources/npass.py +6 -8
  130. pyobo/sources/omim_ps.py +10 -3
  131. pyobo/sources/pathbank.py +4 -8
  132. pyobo/sources/pfam/__init__.py +9 -0
  133. pyobo/sources/{pfam.py → pfam/pfam.py} +3 -8
  134. pyobo/sources/{pfam_clan.py → pfam/pfam_clan.py} +2 -7
  135. pyobo/sources/pharmgkb/__init__.py +15 -0
  136. pyobo/sources/pharmgkb/pharmgkb_chemical.py +89 -0
  137. pyobo/sources/pharmgkb/pharmgkb_disease.py +77 -0
  138. pyobo/sources/pharmgkb/pharmgkb_gene.py +108 -0
  139. pyobo/sources/pharmgkb/pharmgkb_pathway.py +63 -0
  140. pyobo/sources/pharmgkb/pharmgkb_variant.py +84 -0
  141. pyobo/sources/pharmgkb/utils.py +86 -0
  142. pyobo/sources/pid.py +1 -6
  143. pyobo/sources/pombase.py +6 -10
  144. pyobo/sources/pubchem.py +4 -9
  145. pyobo/sources/reactome.py +5 -11
  146. pyobo/sources/rgd.py +11 -16
  147. pyobo/sources/rhea.py +37 -36
  148. pyobo/sources/ror.py +69 -42
  149. pyobo/sources/selventa/__init__.py +0 -0
  150. pyobo/sources/selventa/schem.py +4 -7
  151. pyobo/sources/selventa/scomp.py +1 -6
  152. pyobo/sources/selventa/sdis.py +4 -7
  153. pyobo/sources/selventa/sfam.py +1 -6
  154. pyobo/sources/sgd.py +6 -11
  155. pyobo/sources/signor/__init__.py +7 -0
  156. pyobo/sources/signor/download.py +41 -0
  157. pyobo/sources/signor/signor_complexes.py +105 -0
  158. pyobo/sources/slm.py +12 -15
  159. pyobo/sources/umls/__init__.py +7 -1
  160. pyobo/sources/umls/__main__.py +0 -0
  161. pyobo/sources/umls/get_synonym_types.py +20 -4
  162. pyobo/sources/umls/sty.py +57 -0
  163. pyobo/sources/umls/synonym_types.tsv +1 -1
  164. pyobo/sources/umls/umls.py +18 -22
  165. pyobo/sources/unimod.py +46 -0
  166. pyobo/sources/uniprot/__init__.py +1 -1
  167. pyobo/sources/uniprot/uniprot.py +40 -32
  168. pyobo/sources/uniprot/uniprot_ptm.py +4 -34
  169. pyobo/sources/utils.py +3 -2
  170. pyobo/sources/wikipathways.py +7 -10
  171. pyobo/sources/zfin.py +5 -10
  172. pyobo/ssg/__init__.py +12 -16
  173. pyobo/ssg/base.html +0 -0
  174. pyobo/ssg/index.html +26 -13
  175. pyobo/ssg/term.html +12 -2
  176. pyobo/ssg/typedef.html +0 -0
  177. pyobo/struct/__init__.py +54 -8
  178. pyobo/struct/functional/__init__.py +1 -0
  179. pyobo/struct/functional/dsl.py +2572 -0
  180. pyobo/struct/functional/macros.py +423 -0
  181. pyobo/struct/functional/obo_to_functional.py +385 -0
  182. pyobo/struct/functional/ontology.py +270 -0
  183. pyobo/struct/functional/utils.py +112 -0
  184. pyobo/struct/reference.py +331 -136
  185. pyobo/struct/struct.py +1413 -643
  186. pyobo/struct/struct_utils.py +1078 -0
  187. pyobo/struct/typedef.py +162 -210
  188. pyobo/struct/utils.py +12 -5
  189. pyobo/struct/vocabulary.py +138 -0
  190. pyobo/utils/__init__.py +0 -0
  191. pyobo/utils/cache.py +13 -11
  192. pyobo/utils/io.py +17 -31
  193. pyobo/utils/iter.py +5 -5
  194. pyobo/utils/misc.py +41 -53
  195. pyobo/utils/ndex_utils.py +0 -0
  196. pyobo/utils/path.py +76 -70
  197. pyobo/version.py +3 -3
  198. {pyobo-0.11.2.dist-info → pyobo-0.12.0.dist-info}/METADATA +228 -229
  199. pyobo-0.12.0.dist-info/RECORD +202 -0
  200. pyobo-0.12.0.dist-info/WHEEL +4 -0
  201. {pyobo-0.11.2.dist-info → pyobo-0.12.0.dist-info}/entry_points.txt +1 -0
  202. pyobo-0.12.0.dist-info/licenses/LICENSE +21 -0
  203. pyobo/aws.py +0 -162
  204. pyobo/cli/aws.py +0 -47
  205. pyobo/identifier_utils.py +0 -142
  206. pyobo/normalizer.py +0 -232
  207. pyobo/registries/__init__.py +0 -16
  208. pyobo/registries/metaregistry.json +0 -507
  209. pyobo/registries/metaregistry.py +0 -135
  210. pyobo/sources/icd11.py +0 -105
  211. pyobo/xrefdb/__init__.py +0 -1
  212. pyobo/xrefdb/canonicalizer.py +0 -214
  213. pyobo/xrefdb/priority.py +0 -59
  214. pyobo/xrefdb/sources/__init__.py +0 -60
  215. pyobo/xrefdb/sources/biomappings.py +0 -36
  216. pyobo/xrefdb/sources/cbms2019.py +0 -91
  217. pyobo/xrefdb/sources/chembl.py +0 -83
  218. pyobo/xrefdb/sources/compath.py +0 -82
  219. pyobo/xrefdb/sources/famplex.py +0 -64
  220. pyobo/xrefdb/sources/gilda.py +0 -50
  221. pyobo/xrefdb/sources/intact.py +0 -113
  222. pyobo/xrefdb/sources/ncit.py +0 -133
  223. pyobo/xrefdb/sources/pubchem.py +0 -27
  224. pyobo/xrefdb/sources/wikidata.py +0 -116
  225. pyobo-0.11.2.dist-info/RECORD +0 -157
  226. pyobo-0.11.2.dist-info/WHEEL +0 -5
  227. pyobo-0.11.2.dist-info/top_level.txt +0 -1
@@ -0,0 +1,423 @@
1
+ """Macros over functional OWL.
2
+
3
+ This module contains classes that are extensions
4
+ to functional OWL that reflect common usage.
5
+ """
6
+
7
+ import typing as t
8
+ from collections.abc import Sequence
9
+
10
+ import rdflib
11
+ from curies import Converter, Reference
12
+ from curies import vocabulary as v
13
+ from rdflib import Graph, term
14
+
15
+ from pyobo.struct import vocabulary as pv
16
+ from pyobo.struct.functional import dsl as f
17
+
18
+ __all__ = [
19
+ "AltMacro",
20
+ "DescriptionMacro",
21
+ "IsAnonymousMacro",
22
+ "IsObsoleteMacro",
23
+ "LabelMacro",
24
+ "MappingMacro",
25
+ "RelationshipMacro",
26
+ "SynonymMacro",
27
+ "XrefMacro",
28
+ ]
29
+
30
+
31
+ def _safe_literal(value: str | rdflib.Literal, *, language: str | None = None) -> rdflib.Literal:
32
+ if isinstance(value, rdflib.Literal):
33
+ return value
34
+ return rdflib.Literal(value, lang=language)
35
+
36
+
37
+ class Macro(f.Box):
38
+ """A macro, which wraps a more complicated set of functional OWL axioms."""
39
+
40
+ def __init__(self, box: f.Box):
41
+ """Initialize the macro with a given axiom."""
42
+ self.box = box
43
+
44
+ def to_rdflib_node(self, graph: Graph, converter: Converter) -> term.IdentifiedNode:
45
+ """Make an RDF node for the wrapped axiom."""
46
+ return self.box.to_rdflib_node(graph, converter)
47
+
48
+ def to_funowl(self) -> str:
49
+ """Serialize functional OWL for the wrapped axiom."""
50
+ return self.box.to_funowl()
51
+
52
+ def to_funowl_args(self) -> str: # pragma: no cover
53
+ """Get the inside of the functional OWL tag representing the wrapped axiom (unused)."""
54
+ raise RuntimeError
55
+
56
+
57
+ class RelationshipMacro(Macro):
58
+ """A macro for an object-to-object relationship.
59
+
60
+ Assert that the RAET1E gene from HGNC (16793) is
61
+ only in the human taxon (9606)
62
+
63
+ >>> RelationshipMacro("hgnc:16793", "RO:0002160", "NCBITaxon:9606").to_funowl()
64
+ 'SubClassOf(hgnc:16793 ObjectSomeValuesFrom(RO:0002160 NCBITaxon:9606))'
65
+ """
66
+
67
+ def __init__(
68
+ self,
69
+ s: f.IdentifierBoxOrHint,
70
+ p: f.IdentifierBoxOrHint,
71
+ o: f.IdentifierBoxOrHint,
72
+ *,
73
+ annotations: f.Annotations | None = None,
74
+ ) -> None:
75
+ """Instantiate the object-to-object SubClassOf macro."""
76
+ super().__init__(f.SubClassOf(s, f.ObjectSomeValuesFrom(p, o)))
77
+
78
+
79
+ class StringMacro(Macro):
80
+ """A macro for string assertion."""
81
+
82
+ annotation_property: t.ClassVar[rdflib.URIRef | Reference]
83
+
84
+ def __init__(
85
+ self,
86
+ subject: f.IdentifierBoxOrHint,
87
+ value: str | rdflib.Literal,
88
+ *,
89
+ language: str | None = None,
90
+ annotations: f.Annotations | None = None,
91
+ ) -> None:
92
+ """Instatitate the string assertion macro."""
93
+ super().__init__(
94
+ f.AnnotationAssertion(
95
+ self.annotation_property,
96
+ subject,
97
+ _safe_literal(value, language=language),
98
+ annotations=annotations,
99
+ )
100
+ )
101
+
102
+
103
+ class LabelMacro(StringMacro):
104
+ """A macro for label string assertion.
105
+
106
+ >>> LabelMacro("hgnc:16793", "RAET1E").to_funowl()
107
+ 'AnnotationAssertion(rdfs:label hgnc:16793 "RAET1E")'
108
+
109
+ Assert the language:
110
+
111
+ >>> LabelMacro("hgnc:16793", "RAET1E", language="en").to_funowl()
112
+ 'AnnotationAssertion(rdfs:label hgnc:16793 "RAET1E"@en)'
113
+ """
114
+
115
+ annotation_property = pv.label
116
+
117
+
118
+ class DescriptionMacro(StringMacro):
119
+ """A macro for description string assertion.
120
+
121
+ >>> DescriptionMacro("hgnc:16793", "retinoic acid early transcript 1E").to_funowl()
122
+ 'AnnotationAssertion(dcterms:description hgnc:16793 "retinoic acid early transcript 1E")'
123
+ """
124
+
125
+ annotation_property = pv.has_description
126
+
127
+
128
+ class CommentMacro(StringMacro):
129
+ """A macro for comment string assertion."""
130
+
131
+ annotation_property = pv.comment
132
+
133
+
134
+ class OBONamespaceMacro(StringMacro):
135
+ """A macro for OBO namespace string assertion."""
136
+
137
+ annotation_property = pv.has_obo_namespace
138
+
139
+
140
+ class ObjectAnnotationMacro(Macro):
141
+ """A macro for annotation properties."""
142
+
143
+ annotation_property: t.ClassVar[Reference]
144
+
145
+ def __init__(self, subject: f.IdentifierBoxOrHint, target: f.IdentifierBoxOrHint) -> None:
146
+ """Instatitate the annotation assertion macro."""
147
+ super().__init__(f.AnnotationAssertion(self.annotation_property, subject, target))
148
+
149
+
150
+ class AltMacro(ObjectAnnotationMacro):
151
+ """A macro for alternate ID assertion."""
152
+
153
+ annotation_property = pv.alternative_term
154
+
155
+
156
+ class ReplacedByMacro(ObjectAnnotationMacro):
157
+ """A macro for replaced by assertion."""
158
+
159
+ annotation_property = pv.term_replaced_by
160
+
161
+
162
+ class OBOConsiderMacro(ObjectAnnotationMacro):
163
+ """A macro for OBO consider assertion."""
164
+
165
+ # FIXME replace with see also
166
+ annotation_property = Reference(prefix="oboInOwl", identifier="consider")
167
+
168
+
169
+ class OBOIsSubsetMacro(ObjectAnnotationMacro):
170
+ """A macro for OBO "in subset" assertion."""
171
+
172
+ annotation_property = pv.in_subset
173
+
174
+
175
+ class BooleanAnnotationMacro(Macro):
176
+ """A macro for an annotation assertion with a boolean as its object."""
177
+
178
+ annotation_property: t.ClassVar[Reference]
179
+
180
+ def __init__(self, subject: f.IdentifierBoxOrHint, value: bool = True) -> None:
181
+ """Instatitate the annotation assertion macro, defaults to "true"."""
182
+ super().__init__(
183
+ f.AnnotationAssertion(self.annotation_property, subject, f.LiteralBox(value))
184
+ )
185
+
186
+
187
+ class IsAnonymousMacro(BooleanAnnotationMacro):
188
+ """A macro for an "is anonymous" assertion."""
189
+
190
+ annotation_property = Reference(prefix="oboInOwl", identifier="is_anonymous")
191
+
192
+
193
+ class IsOBOBuiltinMacro(BooleanAnnotationMacro):
194
+ """A macro for an "builtin" assertion."""
195
+
196
+ annotation_property = Reference(prefix="oboInOwl", identifier="builtin")
197
+
198
+
199
+ class OBOIsClassLevelMacro(BooleanAnnotationMacro):
200
+ """A macro for OBO "is class level" assertion."""
201
+
202
+ annotation_property = Reference(prefix="oboInOwl", identifier="is_class_level")
203
+
204
+
205
+ class IsObsoleteMacro(BooleanAnnotationMacro):
206
+ """A macro for obsoletion assertion."""
207
+
208
+ annotation_property = Reference(prefix="owl", identifier="deprecated")
209
+
210
+
211
+ class IsCyclic(BooleanAnnotationMacro):
212
+ """A macro for "is cyclic" assertion."""
213
+
214
+ annotation_property = Reference(prefix="oboInOwl", identifier="is_cyclic")
215
+
216
+
217
+ HAS_SYNONYM_TYPE = Reference.from_curie("oboInOwl:hasSynonymType")
218
+ HAS_MAPPING_JUSTIFICATION = Reference.from_curie("sssom:has_mapping_justification")
219
+
220
+
221
+ class SynonymMacro(Macro):
222
+ """A macro for synonym assertion.
223
+
224
+ You can just make a quick assertion, which defaults to ``RELATED``:
225
+
226
+ >>> SynonymMacro("hgnc:16793", "ULBP4").to_funowl()
227
+ 'AnnotationAssertion(oboInOwl:hasRelatedSynonym hgnc:16793 "ULBP4")'
228
+
229
+ You can make the predicate more explicit either with OBO-style
230
+ scoping (``EXACT``, ``BROAD``, ``NARROW``, ``RELATED``) or a CURIE/:class:`curies.Reference`/URIRef
231
+
232
+ >>> SynonymMacro("hgnc:16793", "ULBP4", "EXACT").to_funowl()
233
+ 'AnnotationAssertion(oboInOwl:hasExactSynonym hgnc:16793 "ULBP4")'
234
+
235
+ You can add a synonym type from OMO:
236
+
237
+ >>> SynonymMacro("hgnc:16793", "ULBP4", "EXACT", synonym_type="OMO:0003008").to_funowl()
238
+ 'AnnotationAssertion(Annotation(oboInOwl:hasSynonymType OMO:0003008) oboInOwl:hasExactSynonym hgnc:16793 "ULBP4")'
239
+ """
240
+
241
+ def __init__(
242
+ self,
243
+ subject: f.IdentifierBoxOrHint,
244
+ value: str | rdflib.Literal,
245
+ scope: v.SynonymScope | f.IdentifierBoxOrHint | None = None,
246
+ *,
247
+ language: str | None = None,
248
+ annotations: f.Annotations | None = None,
249
+ synonym_type: f.IdentifierBoxOrHint | None = None,
250
+ provenance: Sequence[f.PrimitiveHint] | None = None,
251
+ ) -> None:
252
+ """Instatitate the synonym annotation assertion macro."""
253
+ if annotations is None:
254
+ annotations = []
255
+ if provenance:
256
+ annotations.extend(f.Annotation(pv.has_dbxref, r) for r in provenance)
257
+ if synonym_type is not None:
258
+ annotations.append(f.Annotation(HAS_SYNONYM_TYPE, synonym_type))
259
+ if scope is None:
260
+ scope = v.has_related_synonym
261
+ elif isinstance(scope, str) and scope.upper() in t.get_args(v.SynonymScope):
262
+ scope = v.synonym_scopes[scope.upper()] # type:ignore[index]
263
+ super().__init__(
264
+ f.AnnotationAssertion(
265
+ scope,
266
+ subject,
267
+ _safe_literal(value, language=language),
268
+ annotations=annotations,
269
+ )
270
+ )
271
+
272
+
273
+ class MappingMacro(Macro):
274
+ """A macro for mapping assertion.
275
+
276
+ >>> MappingMacro(
277
+ ... "agrovoc:0619dd9e",
278
+ ... "EXACT",
279
+ ... "agro:00000137",
280
+ ... mapping_justification="semapv:ManualMappingCuration",
281
+ ... ).to_funowl()
282
+ 'AnnotationAssertion(Annotation(sssom:has_mapping_justification semapv:ManualMappingCuration) skos:exactMatch agrovoc:0619dd9e agro:00000137)'
283
+ """
284
+
285
+ def __init__(
286
+ self,
287
+ subject: f.IdentifierBoxOrHint,
288
+ predicate: v.SemanticMappingScope | f.IdentifierBoxOrHint,
289
+ target: f.IdentifierBoxOrHint,
290
+ *,
291
+ annotations: f.Annotations | None = None,
292
+ mapping_justification: f.IdentifierBoxOrHint | None = None,
293
+ ) -> None:
294
+ """Instatitate the mapping annotation assertion macro."""
295
+ if annotations is None:
296
+ annotations = []
297
+ if mapping_justification is not None:
298
+ # FIXME check mapping justification is from semapv
299
+ annotations.append(f.Annotation(HAS_MAPPING_JUSTIFICATION, mapping_justification))
300
+ if isinstance(predicate, str) and predicate.upper() in t.get_args(v.SemanticMappingScope):
301
+ predicate = v.semantic_mapping_scopes[predicate.upper()] # type:ignore[index]
302
+ super().__init__(
303
+ f.AnnotationAssertion(
304
+ predicate,
305
+ subject,
306
+ target,
307
+ annotations=annotations,
308
+ )
309
+ )
310
+
311
+
312
+ class XrefMacro(MappingMacro):
313
+ """A macro for database cross-reference assertion, based on the more generic Mapping macro.
314
+
315
+ >>> XrefMacro("agrovoc:0619dd9e", "agro:00000137").to_funowl()
316
+ 'AnnotationAssertion(oboInOwl:hasDbXref agrovoc:0619dd9e agro:00000137)'
317
+ """
318
+
319
+ def __init__(
320
+ self,
321
+ subject: f.IdentifierBoxOrHint,
322
+ target: f.IdentifierBoxOrHint,
323
+ **kwargs: t.Any,
324
+ ) -> None:
325
+ """Instatitate the database cross-reference annotation assertion macro."""
326
+ super().__init__(subject=subject, predicate="oboInOwl:hasDbXref", target=target, **kwargs)
327
+
328
+
329
+ class HoldsOverChain(Macro):
330
+ """A macro for the OBO-style "holds over chain" annotation."""
331
+
332
+ def __init__(self, predicate: f.IdentifierBoxOrHint, chain: Sequence[f.IdentifierBoxOrHint]):
333
+ """Instantiate a "holds over chain" macro."""
334
+ super().__init__(f.SubObjectPropertyOf(f.ObjectPropertyChain(chain), predicate))
335
+
336
+
337
+ class TransitiveOver(HoldsOverChain):
338
+ """A macro for the OBO-style "transitive over" annotation.
339
+
340
+ For example, ``BFO:0000066`` (occurs in) is transitive over
341
+ ``BFO:0000050`` (part of). This means that if X occurs in Y,
342
+ and Y is a part of Z, then X occurs in Z.
343
+
344
+ >>> TransitiveOver("BFO:0000066", "BFO:0000050").to_funowl()
345
+ 'SubObjectPropertyOf(ObjectPropertyChain(BFO:0000066 BFO:0000050) BFO:0000066)'
346
+
347
+ .. note:: This is a special case of :class:`HoldsOverChain`
348
+ """
349
+
350
+ def __init__(self, predicate: f.IdentifierBoxOrHint, target: f.IdentifierBoxOrHint):
351
+ """Instantiate a "transitive over" macro."""
352
+ super().__init__(predicate, [predicate, target])
353
+
354
+
355
+ class DataPropertyMaxCardinality(Macro):
356
+ r"""A macro over :class:`DataMaxCardinality` that adds an axiom.
357
+
358
+ For example, each person can be annotated with a maximum of one age.
359
+ This can be represented as:
360
+
361
+ >>> DataPropertyMaxCardinality(1, "a:hasAge").to_funowl()
362
+ 'SubClassOf(owl:Thing DataMaxCardinality(1 a:hasAge))'
363
+ """
364
+
365
+ def __init__(
366
+ self,
367
+ cardinality: int,
368
+ data_property_expression: f.DataPropertyExpression | f.IdentifierBoxOrHint,
369
+ ):
370
+ """Initialize a data property maximum cardinality macro."""
371
+ super().__init__(
372
+ f.SubClassOf(
373
+ "owl:Thing",
374
+ f.DataMaxCardinality(
375
+ cardinality=cardinality, data_property_expression=data_property_expression
376
+ ),
377
+ )
378
+ )
379
+
380
+
381
+ class ObjectListOfMacro(Macro):
382
+ """An object list macro."""
383
+
384
+ object_list_cls: t.ClassVar[type[f._ObjectList]]
385
+
386
+ def __init__(
387
+ self,
388
+ term: f.IdentifierBoxOrHint,
389
+ elements: Sequence[
390
+ f.IdentifierBoxOrHint | tuple[f.IdentifierBoxOrHint, f.IdentifierBoxOrHint]
391
+ ],
392
+ ) -> None:
393
+ """Instantiate an "intersection of" macro."""
394
+ expressions: list[f.ClassExpression | f.IdentifierBoxOrHint] = []
395
+ for element in elements:
396
+ if isinstance(element, tuple):
397
+ expressions.append(
398
+ f.ObjectSomeValuesFrom(f.IdentifierBox(element[0]), f.IdentifierBox(element[1]))
399
+ )
400
+ else:
401
+ expressions.append(element)
402
+
403
+ super().__init__(
404
+ f.EquivalentClasses([f.IdentifierBox(term), self.object_list_cls(expressions)])
405
+ )
406
+
407
+
408
+ class ClassIntersectionMacro(ObjectListOfMacro):
409
+ """A macro that represents a class intersection.
410
+
411
+ >>> ClassIntersectionMacro(
412
+ ... "ZFA:0000134", ["CL:0000540", ("BFO:0000050", "NCBITaxon:7955")]
413
+ ... ).to_funowl()
414
+ 'EquivalentClasses(ZFA:0000134 ObjectIntersectionOf(CL:0000540 ObjectSomeValuesFrom(BFO:0000050 NCBITaxon:7955)))'
415
+ """
416
+
417
+ object_list_cls = f.ObjectIntersectionOf
418
+
419
+
420
+ class ClassUnionMacro(ObjectListOfMacro):
421
+ """A macro that represents a class union."""
422
+
423
+ object_list_cls = f.ObjectUnionOf