semra 0.0.9__tar.gz → 0.1.0.dev0__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 (140) hide show
  1. {semra-0.0.9 → semra-0.1.0.dev0}/LICENSE +1 -1
  2. semra-0.1.0.dev0/PKG-INFO +631 -0
  3. semra-0.1.0.dev0/README.md +556 -0
  4. semra-0.1.0.dev0/pyproject.toml +265 -0
  5. semra-0.1.0.dev0/src/semra/.DS_Store +0 -0
  6. {semra-0.0.9 → semra-0.1.0.dev0}/src/semra/__init__.py +12 -13
  7. semra-0.1.0.dev0/src/semra/__main__.py +6 -0
  8. semra-0.1.0.dev0/src/semra/api.py +942 -0
  9. semra-0.1.0.dev0/src/semra/cli.py +29 -0
  10. {semra-0.0.9 → semra-0.1.0.dev0}/src/semra/client.py +99 -64
  11. semra-0.1.0.dev0/src/semra/database.py +427 -0
  12. {semra-0.0.9 → semra-0.1.0.dev0}/src/semra/gilda_utils.py +39 -25
  13. semra-0.1.0.dev0/src/semra/inference.py +465 -0
  14. semra-0.1.0.dev0/src/semra/io/__init__.py +36 -0
  15. semra-0.1.0.dev0/src/semra/io/graph.py +102 -0
  16. semra-0.1.0.dev0/src/semra/io/io.py +865 -0
  17. semra-0.1.0.dev0/src/semra/io/io_utils.py +98 -0
  18. semra-0.1.0.dev0/src/semra/io/neo4j_io.py +377 -0
  19. semra-0.1.0.dev0/src/semra/io/templates/Dockerfile +45 -0
  20. semra-0.1.0.dev0/src/semra/io/templates/run_on_startup.sh +9 -0
  21. semra-0.1.0.dev0/src/semra/io/templates/startup.sh +14 -0
  22. semra-0.1.0.dev0/src/semra/landscape/__main__.py +6 -0
  23. {semra-0.0.9 → semra-0.1.0.dev0}/src/semra/landscape/anatomy.py +15 -15
  24. {semra-0.0.9 → semra-0.1.0.dev0}/src/semra/landscape/cells.py +57 -18
  25. semra-0.1.0.dev0/src/semra/landscape/cli.py +64 -0
  26. {semra-0.0.9 → semra-0.1.0.dev0}/src/semra/landscape/complexes.py +19 -13
  27. {semra-0.0.9 → semra-0.1.0.dev0}/src/semra/landscape/diseases.py +20 -22
  28. {semra-0.0.9 → semra-0.1.0.dev0}/src/semra/landscape/genes.py +19 -17
  29. semra-0.1.0.dev0/src/semra/landscape/taxrank.py +47 -0
  30. {semra-0.0.9 → semra-0.1.0.dev0}/src/semra/landscape/utils.py +185 -117
  31. semra-0.1.0.dev0/src/semra/pipeline.py +713 -0
  32. semra-0.1.0.dev0/src/semra/rules.py +106 -0
  33. {semra-0.0.9 → semra-0.1.0.dev0}/src/semra/sources/__init__.py +33 -23
  34. semra-0.1.0.dev0/src/semra/sources/__main__.py +6 -0
  35. {semra-0.0.9 → semra-0.1.0.dev0}/src/semra/sources/biopragmatics.py +39 -19
  36. semra-0.1.0.dev0/src/semra/sources/cbms2019.py +210 -0
  37. semra-0.1.0.dev0/src/semra/sources/cli.py +24 -0
  38. {semra-0.0.9 → semra-0.1.0.dev0}/src/semra/sources/clo.py +30 -18
  39. semra-0.1.0.dev0/src/semra/sources/compath.py +64 -0
  40. {semra-0.0.9 → semra-0.1.0.dev0}/src/semra/sources/famplex.py +11 -7
  41. {semra-0.0.9 → semra-0.1.0.dev0}/src/semra/sources/gilda.py +14 -6
  42. semra-0.1.0.dev0/src/semra/sources/intact.py +67 -0
  43. {semra-0.0.9 → semra-0.1.0.dev0}/src/semra/sources/ncit.py +43 -48
  44. {semra-0.0.9 → semra-0.1.0.dev0}/src/semra/sources/omim.py +15 -13
  45. semra-0.1.0.dev0/src/semra/sources/pubchem.py +61 -0
  46. semra-0.1.0.dev0/src/semra/sources/wikidata.py +129 -0
  47. semra-0.1.0.dev0/src/semra/struct.py +431 -0
  48. {semra-0.0.9 → semra-0.1.0.dev0}/src/semra/templates/base.html +1 -1
  49. {semra-0.0.9 → semra-0.1.0.dev0}/src/semra/templates/home.html +15 -4
  50. semra-0.1.0.dev0/src/semra/utils.py +44 -0
  51. {semra-0.0.9 → semra-0.1.0.dev0}/src/semra/version.py +6 -7
  52. {semra-0.0.9 → semra-0.1.0.dev0}/src/semra/wsgi.py +49 -33
  53. semra-0.0.9/MANIFEST.in +0 -17
  54. semra-0.0.9/PKG-INFO +0 -236
  55. semra-0.0.9/README.md +0 -173
  56. semra-0.0.9/docs/source/api/semra.api.assemble_evidences.rst +0 -6
  57. semra-0.0.9/docs/source/api/semra.api.assert_projection.rst +0 -6
  58. semra-0.0.9/docs/source/api/semra.api.count_source_target.rst +0 -6
  59. semra-0.0.9/docs/source/api/semra.api.deduplicate_evidence.rst +0 -6
  60. semra-0.0.9/docs/source/api/semra.api.filter_many_to_many.rst +0 -6
  61. semra-0.0.9/docs/source/api/semra.api.filter_mappings.rst +0 -6
  62. semra-0.0.9/docs/source/api/semra.api.filter_minimum_confidence.rst +0 -6
  63. semra-0.0.9/docs/source/api/semra.api.filter_prefixes.rst +0 -6
  64. semra-0.0.9/docs/source/api/semra.api.filter_self_matches.rst +0 -6
  65. semra-0.0.9/docs/source/api/semra.api.flip.rst +0 -6
  66. semra-0.0.9/docs/source/api/semra.api.from_digraph.rst +0 -6
  67. semra-0.0.9/docs/source/api/semra.api.get_index.rst +0 -6
  68. semra-0.0.9/docs/source/api/semra.api.get_many_to_many.rst +0 -6
  69. semra-0.0.9/docs/source/api/semra.api.get_priority_reference.rst +0 -6
  70. semra-0.0.9/docs/source/api/semra.api.get_test_evidence.rst +0 -6
  71. semra-0.0.9/docs/source/api/semra.api.get_test_reference.rst +0 -6
  72. semra-0.0.9/docs/source/api/semra.api.infer_chains.rst +0 -6
  73. semra-0.0.9/docs/source/api/semra.api.infer_dbxref_mutations.rst +0 -6
  74. semra-0.0.9/docs/source/api/semra.api.infer_mutations.rst +0 -6
  75. semra-0.0.9/docs/source/api/semra.api.infer_mutual_dbxref_mutations.rst +0 -6
  76. semra-0.0.9/docs/source/api/semra.api.infer_reversible.rst +0 -6
  77. semra-0.0.9/docs/source/api/semra.api.keep_object_prefixes.rst +0 -6
  78. semra-0.0.9/docs/source/api/semra.api.keep_prefixes.rst +0 -6
  79. semra-0.0.9/docs/source/api/semra.api.keep_subject_prefixes.rst +0 -6
  80. semra-0.0.9/docs/source/api/semra.api.print_source_target_counts.rst +0 -6
  81. semra-0.0.9/docs/source/api/semra.api.prioritize.rst +0 -6
  82. semra-0.0.9/docs/source/api/semra.api.project.rst +0 -6
  83. semra-0.0.9/docs/source/api/semra.api.project_dict.rst +0 -6
  84. semra-0.0.9/docs/source/api/semra.api.str_source_target_counts.rst +0 -6
  85. semra-0.0.9/docs/source/api/semra.api.summarize_prefixes.rst +0 -6
  86. semra-0.0.9/docs/source/api/semra.api.tabulate_index.rst +0 -6
  87. semra-0.0.9/docs/source/api/semra.api.to_digraph.rst +0 -6
  88. semra-0.0.9/docs/source/api/semra.api.to_multidigraph.rst +0 -6
  89. semra-0.0.9/docs/source/api/semra.api.unindex.rst +0 -6
  90. semra-0.0.9/docs/source/api/semra.api.validate_mappings.rst +0 -6
  91. semra-0.0.9/docs/source/api/semra.pipeline.Configuration.rst +0 -35
  92. semra-0.0.9/docs/source/api/semra.pipeline.Input.rst +0 -21
  93. semra-0.0.9/docs/source/api/semra.pipeline.Mutation.rst +0 -21
  94. semra-0.0.9/docs/source/api/semra.pipeline.get_mappings_from_config.rst +0 -6
  95. semra-0.0.9/docs/source/api/semra.pipeline.get_raw_mappings.rst +0 -6
  96. semra-0.0.9/docs/source/api/semra.pipeline.process.rst +0 -6
  97. semra-0.0.9/docs/source/api/semra.struct.Mapping.rst +0 -43
  98. semra-0.0.9/docs/source/api/semra.struct.MappingSet.rst +0 -33
  99. semra-0.0.9/docs/source/api/semra.struct.ReasonedEvidence.rst +0 -39
  100. semra-0.0.9/docs/source/api/semra.struct.SimpleEvidence.rst +0 -35
  101. semra-0.0.9/docs/source/api/semra.struct.line.rst +0 -6
  102. semra-0.0.9/docs/source/api/semra.struct.triple_key.rst +0 -6
  103. semra-0.0.9/docs/source/cli.rst +0 -8
  104. semra-0.0.9/docs/source/conf.py +0 -244
  105. semra-0.0.9/docs/source/index.rst +0 -19
  106. semra-0.0.9/docs/source/installation.rst +0 -22
  107. semra-0.0.9/docs/source/logo.png +0 -0
  108. semra-0.0.9/docs/source/usage.rst +0 -10
  109. semra-0.0.9/pyproject.toml +0 -15
  110. semra-0.0.9/setup.cfg +0 -157
  111. semra-0.0.9/src/semra/__main__.py +0 -14
  112. semra-0.0.9/src/semra/api.py +0 -1214
  113. semra-0.0.9/src/semra/cli.py +0 -34
  114. semra-0.0.9/src/semra/database.py +0 -140
  115. semra-0.0.9/src/semra/io.py +0 -868
  116. semra-0.0.9/src/semra/landscape/__main__.py +0 -30
  117. semra-0.0.9/src/semra/pipeline.py +0 -421
  118. semra-0.0.9/src/semra/rules.py +0 -47
  119. semra-0.0.9/src/semra/sources/chembl.py +0 -73
  120. semra-0.0.9/src/semra/sources/intact.py +0 -55
  121. semra-0.0.9/src/semra/sources/pubchem.py +0 -62
  122. semra-0.0.9/src/semra/sources/wikidata.py +0 -54
  123. semra-0.0.9/src/semra/struct.py +0 -314
  124. semra-0.0.9/src/semra.egg-info/PKG-INFO +0 -236
  125. semra-0.0.9/src/semra.egg-info/SOURCES.txt +0 -108
  126. semra-0.0.9/src/semra.egg-info/dependency_links.txt +0 -1
  127. semra-0.0.9/src/semra.egg-info/entry_points.txt +0 -2
  128. semra-0.0.9/src/semra.egg-info/not-zip-safe +0 -1
  129. semra-0.0.9/src/semra.egg-info/requires.txt +0 -30
  130. semra-0.0.9/src/semra.egg-info/top_level.txt +0 -1
  131. semra-0.0.9/tests/__init__.py +0 -1
  132. semra-0.0.9/tests/test_api.py +0 -418
  133. semra-0.0.9/tests/test_io.py +0 -24
  134. semra-0.0.9/tests/test_pipeline.py +0 -82
  135. {semra-0.0.9 → semra-0.1.0.dev0}/src/semra/landscape/__init__.py +0 -0
  136. {semra-0.0.9 → semra-0.1.0.dev0}/src/semra/py.typed +0 -0
  137. {semra-0.0.9 → semra-0.1.0.dev0}/src/semra/templates/concept.html +0 -0
  138. {semra-0.0.9 → semra-0.1.0.dev0}/src/semra/templates/mapping.html +0 -0
  139. {semra-0.0.9 → semra-0.1.0.dev0}/src/semra/templates/mapping_set.html +0 -0
  140. {semra-0.0.9 → semra-0.1.0.dev0}/src/semra/templates/utils.html +0 -0
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2024 Charles Tapley Hoyt
3
+ Copyright (c) 2025 Charles Tapley Hoyt
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -0,0 +1,631 @@
1
+ Metadata-Version: 2.4
2
+ Name: semra
3
+ Version: 0.1.0.dev0
4
+ Summary: Semantic mapping reasoner and assembler
5
+ Keywords: snekpack,cookiecutter,sssom,semantic mappings,ontology merging,ontology mappings
6
+ Author: Charles Tapley Hoyt
7
+ Author-email: Charles Tapley Hoyt <cthoyt@gmail.com>
8
+ License-File: LICENSE
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Environment :: Console
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Framework :: Pytest
15
+ Classifier: Framework :: tox
16
+ Classifier: Framework :: Sphinx
17
+ Classifier: Natural Language :: English
18
+ Classifier: Programming Language :: Python
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: 3 :: Only
24
+ Classifier: Typing :: Typed
25
+ Requires-Dist: pystow
26
+ Requires-Dist: pandas
27
+ Requires-Dist: pydantic
28
+ Requires-Dist: tqdm
29
+ Requires-Dist: more-itertools
30
+ Requires-Dist: networkx
31
+ Requires-Dist: bioregistry>=0.12.7
32
+ Requires-Dist: pyobo>=0.12.0
33
+ Requires-Dist: bioontologies>=0.7.0
34
+ Requires-Dist: typing-extensions
35
+ Requires-Dist: zenodo-client
36
+ Requires-Dist: ssslm
37
+ Requires-Dist: curies>=0.10.16
38
+ Requires-Dist: jinja2
39
+ Requires-Dist: class-resolver>=0.6.0
40
+ Requires-Dist: pyyaml
41
+ Requires-Dist: sphinx>=8 ; extra == 'docs'
42
+ Requires-Dist: sphinx-rtd-theme>=3.0 ; extra == 'docs'
43
+ Requires-Dist: sphinx-click ; extra == 'docs'
44
+ Requires-Dist: sphinx-automodapi ; extra == 'docs'
45
+ Requires-Dist: autodoc-pydantic ; extra == 'docs'
46
+ Requires-Dist: texext ; extra == 'docs'
47
+ Requires-Dist: ipython ; extra == 'landscape-notebooks'
48
+ Requires-Dist: jupyter ; extra == 'landscape-notebooks'
49
+ Requires-Dist: upsetplot ; extra == 'landscape-notebooks'
50
+ Requires-Dist: seaborn ; extra == 'landscape-notebooks'
51
+ Requires-Dist: matplotlib ; extra == 'landscape-notebooks'
52
+ Requires-Dist: pygraphviz ; extra == 'landscape-notebooks'
53
+ Requires-Dist: pytest ; extra == 'tests'
54
+ Requires-Dist: coverage[toml] ; extra == 'tests'
55
+ Requires-Dist: sssom ; extra == 'tests'
56
+ Requires-Dist: fastapi ; extra == 'web'
57
+ Requires-Dist: uvicorn ; extra == 'web'
58
+ Requires-Dist: flask ; extra == 'web'
59
+ Requires-Dist: bootstrap-flask ; extra == 'web'
60
+ Requires-Dist: neo4j ; extra == 'web'
61
+ Requires-Dist: biomappings ; extra == 'web'
62
+ Maintainer: Charles Tapley Hoyt
63
+ Maintainer-email: Charles Tapley Hoyt <cthoyt@gmail.com>
64
+ Requires-Python: >=3.10
65
+ Project-URL: Bug Tracker, https://github.com/biopragmatics/semra/issues
66
+ Project-URL: Documentation, https://semra.readthedocs.io
67
+ Project-URL: Funding, https://github.com/sponsors/cthoyt
68
+ Project-URL: Homepage, https://github.com/biopragmatics/semra
69
+ Project-URL: Repository, https://github.com/biopragmatics/semra.git
70
+ Provides-Extra: docs
71
+ Provides-Extra: landscape-notebooks
72
+ Provides-Extra: tests
73
+ Provides-Extra: web
74
+ Description-Content-Type: text/markdown
75
+
76
+ <p align="center">
77
+ <img src="https://github.com/biopragmatics/semra/raw/main/docs/source/logo.png" height="150">
78
+ </p>
79
+
80
+ <h1 align="center">
81
+ SeMRA
82
+ </h1>
83
+
84
+ <p align="center">
85
+ <a href="https://github.com/biopragmatics/semra/actions/workflows/tests.yml">
86
+ <img alt="Tests" src="https://github.com/biopragmatics/semra/actions/workflows/tests.yml/badge.svg" /></a>
87
+ <a href="https://pypi.org/project/semra">
88
+ <img alt="PyPI" src="https://img.shields.io/pypi/v/semra" /></a>
89
+ <a href="https://pypi.org/project/semra">
90
+ <img alt="PyPI - Python Version" src="https://img.shields.io/pypi/pyversions/semra" /></a>
91
+ <a href="https://github.com/biopragmatics/semra/blob/main/LICENSE">
92
+ <img alt="PyPI - License" src="https://img.shields.io/pypi/l/semra" /></a>
93
+ <a href='https://semra.readthedocs.io/en/latest/?badge=latest'>
94
+ <img src='https://readthedocs.org/projects/semra/badge/?version=latest' alt='Documentation Status' /></a>
95
+ <a href="https://codecov.io/gh/biopragmatics/semra/branch/main">
96
+ <img src="https://codecov.io/gh/biopragmatics/semra/branch/main/graph/badge.svg" alt="Codecov status" /></a>
97
+ <a href="https://github.com/cthoyt/cookiecutter-python-package">
98
+ <img alt="Cookiecutter template from @cthoyt" src="https://img.shields.io/badge/Cookiecutter-snekpack-blue" /></a>
99
+ <a href="https://github.com/astral-sh/ruff">
100
+ <img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json" alt="Ruff" style="max-width:100%;"></a>
101
+ <a href="https://github.com/biopragmatics/semra/blob/main/.github/CODE_OF_CONDUCT.md">
102
+ <img src="https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg" alt="Contributor Covenant"/></a>
103
+ <a href="https://zenodo.org/badge/latestdoi/10987909">
104
+ <img src="https://zenodo.org/badge/10987909.svg" alt="DOI"></a>
105
+ </p>
106
+
107
+ The Semantic Mapping Reasoner and Assembler (SeMRA) is a Python package that
108
+ provides:
109
+
110
+ 1. An object model for semantic mappings (based on SSSOM)
111
+ 2. Functionality for assembling and reasoning over semantic mappings at scale
112
+ 3. A provenance model for automatically generated mappings
113
+ 4. A confidence model granular at the curator-level, mapping set-level, and
114
+ community feedback-level
115
+
116
+ We also provide an accompanying raw semantic mapping database on Zenodo at
117
+ https://zenodo.org/records/15208251.
118
+
119
+ ## 💪 Getting Started
120
+
121
+ Here's a demonstration of SeMRA's object, provenance, and cascading confidence
122
+ model:
123
+
124
+ ```python
125
+ from semra import Reference, Mapping, EXACT_MATCH, SimpleEvidence, MappingSet, MANUAL_MAPPING
126
+
127
+ r1 = Reference(prefix="chebi", identifier="107635", name="2,3-diacetyloxybenzoic")
128
+ r2 = Reference(prefix="mesh", identifier="C011748", name="tosiben")
129
+
130
+ mapping = Mapping(
131
+ subject=r1, predicate=EXACT_MATCH, object=r2,
132
+ evidence=[
133
+ SimpleEvidence(
134
+ justification=MANUAL_MAPPING,
135
+ confidence=0.99,
136
+ author=Reference(prefix="orcid", identifier="0000-0003-4423-4370", name="Charles Tapley Hoyt"),
137
+ mapping_set=MappingSet(
138
+ name="biomappings", license="CC0", confidence=0.90,
139
+ ),
140
+ )
141
+ ]
142
+ )
143
+ ```
144
+
145
+ ### Assembly
146
+
147
+ Mappings can be assembled from many source formats using functions in the
148
+ `semra.io` submodule:
149
+
150
+ ```python
151
+ import semra.io
152
+
153
+ # load mappings from any standardized SSSOM file as a file path or URL, via `pandas.read_csv`
154
+ sssom_url = "https://w3id.org/biopragmatics/biomappings/sssom/biomappings.sssom.tsv"
155
+ mappings = semra.io.from_sssom(
156
+ sssom_url, license="spdx:CC0-1.0", mapping_set_title="biomappings",
157
+ )
158
+
159
+ # alternatively, metadata can be passed via a file/URL
160
+ mappings_alt = semra.io.from_sssom(
161
+ sssom_url,
162
+ metadata="https://w3id.org/biopragmatics/biomappings/sssom/biomappings.sssom.yml"
163
+ )
164
+
165
+ # load mappings from the Gene Ontology (via OBO format)
166
+ go_mappings = semra.io.from_pyobo("go")
167
+
168
+ # load mappings from the Uber Anatomy Ontology (via OWL format)
169
+ uberon_mappings = semra.io.from_bioontologies("uberon")
170
+ ```
171
+
172
+ SeMRA also implements custom importers in the `semra.sources` submodule. It's
173
+ based on a pluggable architecture (via
174
+ [`class-resovler`](https://github.com/cthoyt/class-resolver)) so additional
175
+ custom sources can be incorporated without modifying the SeMRA source code.
176
+
177
+ ```python
178
+ from semra.sources import get_omim_gene_mappings
179
+
180
+ omim_gene_mappings = get_omim_gene_mappings()
181
+ ```
182
+
183
+ ### Inference
184
+
185
+ SeMRA implements the chaining and inference rules described in the
186
+ [SSSOM](https://mapping-commons.github.io/sssom/chaining-rules/) specification.
187
+ The first rule is
188
+ [inversions](https://mapping-commons.github.io/sssom/chaining-rules/#inverse-rules):
189
+
190
+ ```python
191
+ from semra import Mapping, EXACT_MATCH, Reference
192
+ from semra.inference import infer_reversible
193
+
194
+ r1 = Reference(prefix="chebi", identifier="107635", name="2,3-diacetyloxybenzoic")
195
+ r2 = Reference(prefix="mesh", identifier="C011748", name="tosiben")
196
+
197
+ mapping = Mapping(subject=r1, predicate=EXACT_MATCH, object=r2)
198
+
199
+ # includes the mesh -> exact match-> chebi mapping with full provenance
200
+ mappings = infer_reversible([mapping])
201
+ ```
202
+
203
+ ```mermaid
204
+ graph LR
205
+ A[2,3-diacetyloxybenzoic<br/>chebi:107635] -- skos:exactMatch --> B[tosiben<br/>mesh:C011748]
206
+ B -. "skos:exactMatch<br/>(inferred)" .-> A
207
+ ```
208
+
209
+ The second rule is about
210
+ [transitivity](https://mapping-commons.github.io/sssom/chaining-rules/#transitivity-rule).
211
+ This means some predicates apply over chains. SeMRA further implements
212
+ configuration for two-length chains and could be extended to arbitrary chains.
213
+
214
+ ```python
215
+ from semra import Reference, Mapping, EXACT_MATCH
216
+ from semra.inference import infer_chains
217
+
218
+ r1 = Reference.from_curie("mesh:C406527", name="R 115866")
219
+ r2 = Reference.from_curie("chebi:101854", name="talarozole")
220
+ r3 = Reference.from_curie("chembl.compound:CHEMBL459505", name="TALAROZOLE")
221
+
222
+ m1 = Mapping(subject=r1, predicate=EXACT_MATCH, object=r2)
223
+ m2 = Mapping(subject=r2, predicate=EXACT_MATCH, object=r3)
224
+
225
+ # infers r1 -> exact match -> r3
226
+ mappings = infer_chains([m1, m2])
227
+ ```
228
+
229
+ ```mermaid
230
+ graph LR
231
+ A[R 115866<br/>mesh:C406527] -- skos:exactMatch --> B[talarozole<br/>chebi:101854]
232
+ B -- skos:exactMatch --> C[TALAROZOLE<br/>chembl.compound:CHEMBL459505]
233
+ A -. "skos:exactMatch<br/>(inferred)" .-> C
234
+ ```
235
+
236
+ The third rule is
237
+ [generalization](https://mapping-commons.github.io/sssom/chaining-rules/#generalisation-rules),
238
+ which means that a more strict predicate can be relaxed to a less specific
239
+ predicate, like `owl:equivalentTo` to `skos:exactMatch`.
240
+
241
+ ```python
242
+ from semra import Reference, Mapping, EXACT_MATCH
243
+ from semra.inference import infer_generalizations
244
+
245
+ r1 = Reference.from_curie("chebi:101854", name="talarozole")
246
+ r2 = Reference.from_curie("chembl.compound:CHEMBL459505", name="TALAROZOLE")
247
+
248
+ m1 = Mapping(subject=r1, predicate=EXACT_MATCH, object=r2)
249
+
250
+ mappings = infer_generalizations([m1])
251
+ ```
252
+
253
+ ```mermaid
254
+ graph LR
255
+ A[talarozole<br/>chebi:101854] -- owl:equivalentTo --> B[TALAROZOLE<br/>chembl.compound:CHEMBL459505]
256
+ A -. "skos:exactMatch<br/>(inferred)" .-> B
257
+ ```
258
+
259
+ The third rule can actually be generalized to any kinds of mutation of one
260
+ predicate to another, given some domain knowledge. For example, some resources
261
+ curate `oboInOwl:hasDbXref` predicates when it's implied that they mean
262
+ `skos:exactMatch` because the resource is curated in the OBO flat file format.
263
+
264
+ ```python
265
+ from semra import Reference, Mapping, DB_XREF
266
+ from semra.inference import infer_dbxref_mutations
267
+
268
+ r1 = Reference.from_curie("doid:0050577", name="cranioectodermal dysplasia")
269
+ r2 = Reference.from_curie("mesh:C562966", name="Cranioectodermal Dysplasia")
270
+ m1 = Mapping(subject=r1, predicate=DB_XREF, object=r2)
271
+
272
+ # we're 99% confident doid-mesh dbxrefs actually are exact matches
273
+ mappings = infer_dbxref_mutations([m1], {("doid", "mesh"): 0.99})
274
+ ```
275
+
276
+ ```mermaid
277
+ graph LR
278
+ A[cranioectodermal dysplasia<br/>doid:0050577] -- oboInOwl:hasDbXref --> B[Cranioectodermal Dysplasia<br/>mesh:C562966]
279
+ A -. "skos:exactMatch<br/>(inferred)" .-> B
280
+ ```
281
+
282
+ ### Processing
283
+
284
+ Mappings can be processed, aggregated, and summarized using functions from the
285
+ [`semra.api`](https://semra.readthedocs.io/en/latest/usage.html#module-semra.api)
286
+ submodule:
287
+
288
+ ```python
289
+ from semra.api import filter_minimum_confidence, prioritize, project, summarize_prefixes
290
+
291
+ mappings = ...
292
+ mappings = filter_minimum_confidence(mappings, cutoff=0.7)
293
+
294
+ summary_df = summarize_prefixes(mappings)
295
+
296
+ # get one-to-one mappings between entities from the given prefixes
297
+ chebi_to_mesh = project(mappings, source_prefix="chebi", target_prefix="mesh")
298
+
299
+ # process the mappings using a graph algorithm that creates
300
+ # a "star" graph for every equivalent entity, where the center
301
+ # of the star is determined by the equivalent entity with the
302
+ # highest priority based on the given list
303
+ priority_mapping = prioritize(mappings, priority=[
304
+ "chebi", "chembl.compound", "pubchem.compound", "drugbank",
305
+ ])
306
+ ```
307
+
308
+ The prioritization described by the code above works like this:
309
+
310
+ ```mermaid
311
+ graph LR
312
+ subgraph unprocessed [Exact Matches Graph]
313
+ A[R 115866<br/>mesh:C406527] --- B[talarozole<br/>chebi:101854]
314
+ B --- C[TALAROZOLE<br/>chembl.compound:CHEMBL459505]
315
+ A --- C
316
+ end
317
+ subgraph star [Prioritized Mapping Graph]
318
+ D[R 115866<br/>mesh:C406527] --> E[talarozole<br/>chebi:101854]
319
+ F[TALAROZOLE<br/>chembl.compound:CHEMBL459505] --> E
320
+ end
321
+ unprocessed --> star
322
+ ```
323
+
324
+ ## 🏞️ Landscape Analysis
325
+
326
+ We demonstrate using SeMRA to assess the [landscape](notebooks/landscape) of
327
+ five biomedical entity types:
328
+
329
+ 1. [Disease](notebooks/landscape/disease/disease-landscape.ipynb)
330
+ 2. [Cell & Cell Line](notebooks/landscape/cell/cell-landscape.ipynb)
331
+ 3. [Anatomy](notebooks/landscape/anatomy/anatomy-landscape.ipynb)
332
+ 4. [Protein Complex](notebooks/landscape/complex/complex-landscape.ipynb)
333
+ 5. [Gene](notebooks/landscape/gene/gene-landscape.ipynb)
334
+
335
+ These analyses are based on
336
+ [declarative configurations](https://semra.readthedocs.io/en/latest/api/semra.pipeline.Configuration.html)
337
+ for sources, processing rules, and inference rules that can be found in the
338
+ `semra.landscape` module of the source code.
339
+
340
+ ## 🤖 Tools for Data Scientists
341
+
342
+ SeMRA provides tools for data scientists to standardize references using
343
+ semantic mappings.
344
+
345
+ For example, the drug indications table in ChEMBL contains a variety of
346
+ references to EFO, MONDO, DOID, and other controlled vocabularies (described in
347
+ detail in
348
+ [this blog post](https://cthoyt.com/2025/04/17/chembl-indications-efo-exploration.html)).
349
+ Using SeMRA's pre-constructed
350
+ [disease and phenotype prioritization mapping](https://doi.org/10.5281/zenodo.11091885),
351
+ these references can be standardized in a deterministic and principled way.
352
+
353
+ ```python
354
+ import chembl_downloader
355
+ import semra.io
356
+ from semra.api import prioritize_df
357
+
358
+ # A dataframe of indication-disease pairs, where the
359
+ # "efo_id" column is actually an arbitrary disease or phenotype query
360
+ df = chembl_downloader.query("SELECT DISTINCT drugind_id, efo_id FROM DRUG_INDICATION")
361
+
362
+ # a pre-calculated prioritization of diseases and phenotypes from MONDO, DOID,
363
+ # HPO, ICD, GARD, and more.
364
+ url = "https://zenodo.org/records/15164180/files/priority.sssom.tsv?download=1"
365
+ mappings = semra.io.from_sssom(url)
366
+
367
+ # the dataframe will now have a new column with standardized references
368
+ prioritize_df(mappings, df, column="efo_id", target_column="priority_indication_curie")
369
+ ```
370
+
371
+ ## 🚀 Installation
372
+
373
+ The most recent release can be installed from
374
+ [PyPI](https://pypi.org/project/semra/) with uv:
375
+
376
+ ```console
377
+ $ uv pip install semra
378
+ ```
379
+
380
+ or with pip:
381
+
382
+ ```console
383
+ $ python3 -m pip install semra
384
+ ```
385
+
386
+ The most recent code and data can be installed directly from GitHub with uv:
387
+
388
+ ```console
389
+ $ uv pip install git+https://github.com/biopragmatics/semra.git
390
+ ```
391
+
392
+ or with pip:
393
+
394
+ ```console
395
+ $ python3 -m pip install git+https://github.com/biopragmatics/semra.git
396
+ ```
397
+
398
+ ## 👐 Contributing
399
+
400
+ Contributions, whether filing an issue, making a pull request, or forking, are
401
+ appreciated. See
402
+ [CONTRIBUTING.md](https://github.com/biopragmatics/semra/blob/master/.github/CONTRIBUTING.md)
403
+ for more information on getting involved.
404
+
405
+ ## 👋 Attribution
406
+
407
+ ### ⚖️ License
408
+
409
+ The code in this package is licensed under the MIT License.
410
+
411
+ ### 📖 Citation
412
+
413
+ > <a href="https://www.biorxiv.org/content/10.1101/2025.04.16.649126">Assembly
414
+ > and reasoning over semantic mappings at scale for biomedical data
415
+ > integration</a><br/>Hoyt, C. T., Karis K., and Gyori, B. M.<br/>_bioRxiv_,
416
+ > 2025.04.16.649126
417
+
418
+ ```bibtex
419
+ @article {hoyt2025semra,
420
+ author = {Hoyt, Charles Tapley and Karis, Klas and Gyori, Benjamin M},
421
+ title = {Assembly and reasoning over semantic mappings at scale for biomedical data integration},
422
+ year = {2025},
423
+ doi = {10.1101/2025.04.16.649126},
424
+ publisher = {Cold Spring Harbor Laboratory},
425
+ URL = {https://www.biorxiv.org/content/early/2025/04/21/2025.04.16.649126},
426
+ journal = {bioRxiv}
427
+ }
428
+ ```
429
+
430
+ <!--
431
+ ### 🎁 Support
432
+
433
+ This project has been supported by the following organizations (in alphabetical order):
434
+
435
+ - [Biopragmatics Lab](https://biopragmatics.github.io)
436
+
437
+ -->
438
+
439
+ <!--
440
+ ### 💰 Funding
441
+
442
+ This project has been supported by the following grants:
443
+
444
+ | Funding Body | Program | Grant Number |
445
+ |---------------|--------------------------------------------------------------|--------------|
446
+ | Funder | [Grant Name (GRANT-ACRONYM)](https://example.com/grant-link) | ABCXYZ |
447
+ -->
448
+
449
+ ### 🍪 Cookiecutter
450
+
451
+ This package was created with
452
+ [@audreyfeldroy](https://github.com/audreyfeldroy)'s
453
+ [cookiecutter](https://github.com/cookiecutter/cookiecutter) package using
454
+ [@cthoyt](https://github.com/cthoyt)'s
455
+ [cookiecutter-snekpack](https://github.com/cthoyt/cookiecutter-snekpack)
456
+ template.
457
+
458
+ ## 🛠️ For Developers
459
+
460
+ <details>
461
+ <summary>See developer instructions</summary>
462
+
463
+ The final section of the README is for if you want to get involved by making a
464
+ code contribution.
465
+
466
+ ### Development Installation
467
+
468
+ To install in development mode, use the following:
469
+
470
+ ```console
471
+ $ git clone git+https://github.com/biopragmatics/semra.git
472
+ $ cd semra
473
+ $ uv pip install -e .
474
+ ```
475
+
476
+ Alternatively, install using pip:
477
+
478
+ ```console
479
+ $ python3 -m pip install -e .
480
+ ```
481
+
482
+ ### Updating Package Boilerplate
483
+
484
+ This project uses `cruft` to keep boilerplate (i.e., configuration, contribution
485
+ guidelines, documentation configuration) up-to-date with the upstream
486
+ cookiecutter package. Install cruft with either `uv tool install cruft` or
487
+ `python3 -m pip install cruft` then run:
488
+
489
+ ```console
490
+ $ cruft update
491
+ ```
492
+
493
+ More info on Cruft's update command is available
494
+ [here](https://github.com/cruft/cruft?tab=readme-ov-file#updating-a-project).
495
+
496
+ ### 🥼 Testing
497
+
498
+ After cloning the repository and installing `tox` with
499
+ `uv tool install tox --with tox-uv` or `python3 -m pip install tox tox-uv`, the
500
+ unit tests in the `tests/` folder can be run reproducibly with:
501
+
502
+ ```console
503
+ $ tox -e py
504
+ ```
505
+
506
+ Additionally, these tests are automatically re-run with each commit in a
507
+ [GitHub Action](https://github.com/biopragmatics/semra/actions?query=workflow%3ATests).
508
+
509
+ ### 📖 Building the Documentation
510
+
511
+ The documentation can be built locally using the following:
512
+
513
+ ```console
514
+ $ git clone git+https://github.com/biopragmatics/semra.git
515
+ $ cd semra
516
+ $ tox -e docs
517
+ $ open docs/build/html/index.html
518
+ ```
519
+
520
+ The documentation automatically installs the package as well as the `docs` extra
521
+ specified in the [`pyproject.toml`](pyproject.toml). `sphinx` plugins like
522
+ `texext` can be added there. Additionally, they need to be added to the
523
+ `extensions` list in [`docs/source/conf.py`](docs/source/conf.py).
524
+
525
+ The documentation can be deployed to [ReadTheDocs](https://readthedocs.io) using
526
+ [this guide](https://docs.readthedocs.io/en/stable/intro/import-guide.html). The
527
+ [`.readthedocs.yml`](.readthedocs.yml) YAML file contains all the configuration
528
+ you'll need. You can also set up continuous integration on GitHub to check not
529
+ only that Sphinx can build the documentation in an isolated environment (i.e.,
530
+ with `tox -e docs-test`) but also that
531
+ [ReadTheDocs can build it too](https://docs.readthedocs.io/en/stable/pull-requests.html).
532
+
533
+ #### Configuring ReadTheDocs
534
+
535
+ 1. Log in to ReadTheDocs with your GitHub account to install the integration at
536
+ https://readthedocs.org/accounts/login/?next=/dashboard/
537
+ 2. Import your project by navigating to https://readthedocs.org/dashboard/import
538
+ then clicking the plus icon next to your repository
539
+ 3. You can rename the repository on the next screen using a more stylized name
540
+ (i.e., with spaces and capital letters)
541
+ 4. Click next, and you're good to go!
542
+
543
+ ### 📦 Making a Release
544
+
545
+ #### Configuring Zenodo
546
+
547
+ [Zenodo](https://zenodo.org) is a long-term archival system that assigns a DOI
548
+ to each release of your package.
549
+
550
+ 1. Log in to Zenodo via GitHub with this link:
551
+ https://zenodo.org/oauth/login/github/?next=%2F. This brings you to a page
552
+ that lists all of your organizations and asks you to approve installing the
553
+ Zenodo app on GitHub. Click "grant" next to any organizations you want to
554
+ enable the integration for, then click the big green "approve" button. This
555
+ step only needs to be done once.
556
+ 2. Navigate to https://zenodo.org/account/settings/github/, which lists all of
557
+ your GitHub repositories (both in your username and any organizations you
558
+ enabled). Click the on/off toggle for any relevant repositories. When you
559
+ make a new repository, you'll have to come back to this
560
+
561
+ After these steps, you're ready to go! After you make "release" on GitHub (steps
562
+ for this are below), you can navigate to
563
+ https://zenodo.org/account/settings/github/repository/biopragmatics/semra to see
564
+ the DOI for the release and link to the Zenodo record for it.
565
+
566
+ #### Registering with the Python Package Index (PyPI)
567
+
568
+ You only have to do the following steps once.
569
+
570
+ 1. Register for an account on the
571
+ [Python Package Index (PyPI)](https://pypi.org/account/register)
572
+ 2. Navigate to https://pypi.org/manage/account and make sure you have verified
573
+ your email address. A verification email might not have been sent by default,
574
+ so you might have to click the "options" dropdown next to your address to get
575
+ to the "re-send verification email" button
576
+ 3. 2-Factor authentication is required for PyPI since the end of 2023 (see this
577
+ [blog post from PyPI](https://blog.pypi.org/posts/2023-05-25-securing-pypi-with-2fa/)).
578
+ This means you have to first issue account recovery codes, then set up
579
+ 2-factor authentication
580
+ 4. Issue an API token from https://pypi.org/manage/account/token
581
+
582
+ #### Configuring your machine's connection to PyPI
583
+
584
+ You have to do the following steps once per machine.
585
+
586
+ ```console
587
+ $ uv tool install keyring
588
+ $ keyring set https://upload.pypi.org/legacy/ __token__
589
+ $ keyring set https://test.pypi.org/legacy/ __token__
590
+ ```
591
+
592
+ Note that this deprecates previous workflows using `.pypirc`.
593
+
594
+ #### Uploading to PyPI
595
+
596
+ After installing the package in development mode and installing `tox` with
597
+ `uv tool install tox --with tox-uv` or `python3 -m pip install tox tox-uv`, run
598
+ the following from the console:
599
+
600
+ ```console
601
+ $ tox -e finish
602
+ ```
603
+
604
+ This script does the following:
605
+
606
+ 1. Uses [bump-my-version](https://github.com/callowayproject/bump-my-version) to
607
+ switch the version number in the `pyproject.toml`, `CITATION.cff`,
608
+ `src/semra/version.py`, and [`docs/source/conf.py`](docs/source/conf.py) to
609
+ not have the `-dev` suffix
610
+ 2. Packages the code in both a tar archive and a wheel using
611
+ [`uv build`](https://docs.astral.sh/uv/guides/publish/#building-your-package)
612
+ 3. Uploads to PyPI using
613
+ [`uv publish`](https://docs.astral.sh/uv/guides/publish/#publishing-your-package).
614
+ 4. Push to GitHub. You'll need to make a release going with the commit where the
615
+ version was bumped.
616
+ 5. Bump the version to the next patch. If you made big changes and want to bump
617
+ the version by minor, you can use `tox -e bumpversion -- minor` after.
618
+
619
+ #### Releasing on GitHub
620
+
621
+ 1. Navigate to https://github.com/biopragmatics/semra/releases/new to draft a
622
+ new release
623
+ 2. Click the "Choose a Tag" dropdown and select the tag corresponding to the
624
+ release you just made
625
+ 3. Click the "Generate Release Notes" button to get a quick outline of recent
626
+ changes. Modify the title and description as you see fit
627
+ 4. Click the big green "Publish Release" button
628
+
629
+ This will trigger Zenodo to assign a DOI to your release as well.
630
+
631
+ </details>