pyobo 0.11.1__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 (242) 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.1.dist-info → pyobo-0.12.0.dist-info}/METADATA +224 -225
  199. pyobo-0.12.0.dist-info/RECORD +202 -0
  200. pyobo-0.12.0.dist-info/WHEEL +4 -0
  201. {pyobo-0.11.1.dist-info → pyobo-0.12.0.dist-info}/entry_points.txt +1 -0
  202. {pyobo-0.11.1.dist-info → pyobo-0.12.0.dist-info/licenses}/LICENSE +0 -0
  203. pyobo/apps/__init__.py +0 -3
  204. pyobo/apps/cli.py +0 -24
  205. pyobo/apps/gilda/__init__.py +0 -3
  206. pyobo/apps/gilda/__main__.py +0 -8
  207. pyobo/apps/gilda/app.py +0 -48
  208. pyobo/apps/gilda/cli.py +0 -36
  209. pyobo/apps/gilda/templates/base.html +0 -33
  210. pyobo/apps/gilda/templates/home.html +0 -11
  211. pyobo/apps/gilda/templates/matches.html +0 -32
  212. pyobo/apps/mapper/__init__.py +0 -3
  213. pyobo/apps/mapper/__main__.py +0 -11
  214. pyobo/apps/mapper/cli.py +0 -37
  215. pyobo/apps/mapper/mapper.py +0 -187
  216. pyobo/apps/mapper/templates/base.html +0 -35
  217. pyobo/apps/mapper/templates/mapper_home.html +0 -64
  218. pyobo/aws.py +0 -162
  219. pyobo/cli/aws.py +0 -47
  220. pyobo/identifier_utils.py +0 -142
  221. pyobo/normalizer.py +0 -232
  222. pyobo/registries/__init__.py +0 -16
  223. pyobo/registries/metaregistry.json +0 -507
  224. pyobo/registries/metaregistry.py +0 -135
  225. pyobo/sources/icd11.py +0 -105
  226. pyobo/xrefdb/__init__.py +0 -1
  227. pyobo/xrefdb/canonicalizer.py +0 -214
  228. pyobo/xrefdb/priority.py +0 -59
  229. pyobo/xrefdb/sources/__init__.py +0 -60
  230. pyobo/xrefdb/sources/biomappings.py +0 -36
  231. pyobo/xrefdb/sources/cbms2019.py +0 -91
  232. pyobo/xrefdb/sources/chembl.py +0 -83
  233. pyobo/xrefdb/sources/compath.py +0 -82
  234. pyobo/xrefdb/sources/famplex.py +0 -64
  235. pyobo/xrefdb/sources/gilda.py +0 -50
  236. pyobo/xrefdb/sources/intact.py +0 -113
  237. pyobo/xrefdb/sources/ncit.py +0 -133
  238. pyobo/xrefdb/sources/pubchem.py +0 -27
  239. pyobo/xrefdb/sources/wikidata.py +0 -116
  240. pyobo-0.11.1.dist-info/RECORD +0 -173
  241. pyobo-0.11.1.dist-info/WHEEL +0 -5
  242. pyobo-0.11.1.dist-info/top_level.txt +0 -1
@@ -0,0 +1,61 @@
1
+ """Load the manually curated metaregistry."""
2
+
3
+ import json
4
+ from functools import lru_cache
5
+ from pathlib import Path
6
+
7
+ from bioregistry import NormalizedNamableReference
8
+
9
+ from .model import Rules
10
+ from ..resources.goc import load_goc_map
11
+
12
+ __all__ = [
13
+ "remap_full",
14
+ "remap_prefix",
15
+ "str_is_blacklisted",
16
+ ]
17
+
18
+ HERE = Path(__file__).parent.resolve()
19
+ RULES_PATH = HERE.joinpath("preprocessing.json")
20
+
21
+
22
+ @lru_cache(1)
23
+ def get_rules() -> Rules:
24
+ """Get the CURIE/URI string preprocessing rules."""
25
+ rules = Rules.model_validate_json(RULES_PATH.read_text())
26
+ rules.rewrites.full.update(load_goc_map())
27
+ return rules
28
+
29
+
30
+ def remap_full(
31
+ str_or_curie_or_uri: str, *, ontology_prefix: str | None = None
32
+ ) -> NormalizedNamableReference | None:
33
+ """Remap the string if possible otherwise return it."""
34
+ return get_rules().remap_full(
35
+ str_or_curie_or_uri, cls=NormalizedNamableReference, ontology_prefix=ontology_prefix
36
+ )
37
+
38
+
39
+ def remap_prefix(str_or_curie_or_uri: str, ontology_prefix: str | None = None) -> str:
40
+ """Remap a prefix."""
41
+ return get_rules().remap_prefix(str_or_curie_or_uri, ontology_prefix=ontology_prefix)
42
+
43
+
44
+ def _lint() -> None:
45
+ rules = Rules.model_validate_json(RULES_PATH.read_text())
46
+ rules.blacklists._sort()
47
+ RULES_PATH.write_text(json.dumps(rules.model_dump(), sort_keys=True, indent=2))
48
+
49
+
50
+ def str_is_blacklisted(str_or_curie_or_uri: str, *, ontology_prefix: str | None = None) -> bool:
51
+ """Check if the full CURIE string is blacklisted."""
52
+ rules = get_rules()
53
+ return (
54
+ rules.str_is_blacklisted_full(str_or_curie_or_uri, ontology_prefix=ontology_prefix)
55
+ or rules.str_has_blacklisted_prefix(str_or_curie_or_uri, ontology_prefix=ontology_prefix)
56
+ or rules.str_has_blacklisted_suffix(str_or_curie_or_uri)
57
+ )
58
+
59
+
60
+ if __name__ == "__main__":
61
+ _lint()
@@ -0,0 +1,8 @@
1
+ """Tools for grounding relations."""
2
+
3
+ from .api import get_normalized_label, ground_relation
4
+
5
+ __all__ = [
6
+ "get_normalized_label",
7
+ "ground_relation",
8
+ ]
@@ -0,0 +1,162 @@
1
+ """API for grounding relations."""
2
+
3
+ import json
4
+ from collections.abc import Mapping
5
+ from functools import lru_cache
6
+ from pathlib import Path
7
+
8
+ import requests
9
+ from bioregistry import NormalizedNamedReference
10
+ from tqdm import tqdm
11
+
12
+ __all__ = [
13
+ "get_normalized_label",
14
+ "ground_relation",
15
+ ]
16
+
17
+ HERE = Path(__file__).parent.resolve()
18
+ PATH = HERE.joinpath("data.json")
19
+ URLS = [
20
+ ("ro", "http://purl.obolibrary.org/obo/ro.json"),
21
+ (
22
+ "debio",
23
+ "https://raw.githubusercontent.com/biopragmatics/debio/main/releases/current/debio.json",
24
+ ),
25
+ ("bfo", None),
26
+ ("oboinowl", None),
27
+ ("bspo", None),
28
+ ("iao", None),
29
+ ("omo", None),
30
+ ("vo", None),
31
+ ("obi", None),
32
+ ]
33
+ PREFIX_OBO = "http://purl.obolibrary.org/obo/"
34
+ PREFIX_OIO = "http://www.geneontology.org/formats/oboInOwl#"
35
+
36
+ LABELS = {
37
+ "http://www.w3.org/2000/01/rdf-schema#isDefinedBy": "is_defined_by",
38
+ "rdf:type": "type",
39
+ "owl:inverseOf": "inverse_of",
40
+ "skos:exactMatch": "exact_match",
41
+ "rdfs:subClassOf": "is_a",
42
+ "rdfs:subPropertyOf": "subproperty",
43
+ "http://www.w3.org/1999/02/22-rdf-syntax-ns#type": "type",
44
+ "obo:has_prefix": "has_unit_prefix", # weird thing from UO
45
+ # FIXME deal with these relations
46
+ "http://purl.obolibrary.org/obo/uberon/core#proximally_connected_to": "proximally_connected_to",
47
+ "http://purl.obolibrary.org/obo/uberon/core#extends_fibers_into": "proximally_connected_to",
48
+ "http://purl.obolibrary.org/obo/uberon/core#channel_for": "proximally_connected_to",
49
+ "http://purl.obolibrary.org/obo/uberon/core#distally_connected_to": "proximally_connected_to",
50
+ "http://purl.obolibrary.org/obo/uberon/core#channels_into": "channels_into",
51
+ "http://purl.obolibrary.org/obo/uberon/core#channels_from": "channels_from",
52
+ "http://purl.obolibrary.org/obo/uberon/core#subdivision_of": "subdivision_of",
53
+ "http://purl.obolibrary.org/obo/uberon/core#protects": "protects",
54
+ "http://purl.obolibrary.org/obo/uberon/core#posteriorly_connected_to": "posteriorly_connected_to",
55
+ "http://purl.obolibrary.org/obo/uberon/core#evolved_from": "evolved_from",
56
+ "http://purl.obolibrary.org/obo/uberon/core#anteriorly_connected_to": "anteriorly_connected_to",
57
+ #
58
+ "obi:0000304": "is_manufactured_by",
59
+ "vo:0003355": "immunizes_against_microbe",
60
+ "bao:0002846": "has_assay_protocol",
61
+ }
62
+
63
+
64
+ def _norm(s: str) -> str:
65
+ return s.replace(" ", "").replace("_", "").replace(":", "").lower()
66
+
67
+
68
+ def ground_relation(s: str) -> NormalizedNamedReference | None:
69
+ """Ground a string to a RO property."""
70
+ return get_lookups().get(_norm(s))
71
+
72
+
73
+ def get_normalized_label(curie_or_uri: str) -> str | None:
74
+ """Get a normalized label."""
75
+ rv = LABELS.get(curie_or_uri)
76
+ if rv:
77
+ return rv
78
+ rv = get_curie_to_norm_name().get(curie_or_uri)
79
+ if rv:
80
+ return rv
81
+ return None
82
+
83
+
84
+ @lru_cache(1)
85
+ def get_lookups() -> Mapping[str, NormalizedNamedReference]:
86
+ """Get lookups for relation ontology properties."""
87
+ d = {}
88
+ for record in json.loads(PATH.read_text()):
89
+ prefix, identifier, label = record["prefix"], record["identifier"], record["label"]
90
+ d[_norm(label)] = NormalizedNamedReference(prefix=prefix, identifier=identifier, name=label)
91
+ for s in record.get("synonyms", []):
92
+ d[_norm(s)] = NormalizedNamedReference(prefix=prefix, identifier=identifier, name=label)
93
+ return d
94
+
95
+
96
+ def label_norm(s: str) -> str:
97
+ """Normalize a label string."""
98
+ return s.lower().replace(" ", "_")
99
+
100
+
101
+ @lru_cache(1)
102
+ def get_curie_to_norm_name() -> Mapping[str, str]:
103
+ """Get a dictionary mapping CURIEs to their normalized names."""
104
+ curie_to_norm_name = {}
105
+ for record in json.loads(PATH.read_text()):
106
+ prefix, identifier, label = record["prefix"], record["identifier"], record["label"]
107
+ curie_to_norm_name[f"{prefix}:{identifier}"] = label_norm(label)
108
+ return curie_to_norm_name
109
+
110
+
111
+ HEADER = ["prefix", "identifier", "label", "synonyms"]
112
+
113
+
114
+ def main():
115
+ """Download and process the relation ontology data."""
116
+ from bioontologies import get_obograph_by_prefix
117
+ from bioontologies.obograph import GraphDocument
118
+ from bioontologies.robot import correct_raw_json
119
+
120
+ rows = []
121
+ for source, url in URLS:
122
+ if url is not None:
123
+ res = requests.get(url, timeout=60)
124
+ res.raise_for_status()
125
+ res_json = res.json()
126
+ correct_raw_json(res_json)
127
+ graph_document = GraphDocument.model_validate(res_json)
128
+ graph = graph_document.guess(source)
129
+ else:
130
+ try:
131
+ results = get_obograph_by_prefix(source)
132
+ graph = results.guess(source)
133
+ except ValueError as e:
134
+ tqdm.write(f"[{source}] error: {e}")
135
+ continue
136
+ for node in tqdm(graph.nodes, desc=source, unit="node"):
137
+ if node.type != "PROPERTY" or not node.name:
138
+ continue
139
+ node.standardize()
140
+ if not node.prefix:
141
+ tqdm.write(f"[{source}] could not parse node: {node.id}")
142
+ continue
143
+ rows.append(
144
+ (
145
+ node.prefix,
146
+ node.identifier,
147
+ node.name,
148
+ tuple(sorted(synonym.value for synonym in node.synonyms)),
149
+ )
150
+ )
151
+
152
+ for p in ["rdf", "rdfs", "owl"]:
153
+ j = json.loads(HERE.joinpath(f"data_{p}.json").read_text())
154
+ rows.extend(tuple(row.get(h, ()) for h in HEADER) for row in j)
155
+
156
+ rows = sorted(set(rows))
157
+ row_dicts = [{k: v for k, v in zip(HEADER, row, strict=False) if v} for row in rows]
158
+ PATH.write_text(json.dumps(row_dicts, indent=2, sort_keys=True))
159
+
160
+
161
+ if __name__ == "__main__":
162
+ main()