pyobo 0.10.12__py3-none-any.whl → 0.11.1__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 (153) hide show
  1. pyobo/__init__.py +0 -2
  2. pyobo/__main__.py +0 -2
  3. pyobo/api/__init__.py +0 -2
  4. pyobo/api/alts.py +6 -7
  5. pyobo/api/hierarchy.py +14 -15
  6. pyobo/api/metadata.py +3 -4
  7. pyobo/api/names.py +31 -32
  8. pyobo/api/properties.py +6 -7
  9. pyobo/api/relations.py +12 -11
  10. pyobo/api/species.py +5 -6
  11. pyobo/api/typedefs.py +1 -3
  12. pyobo/api/utils.py +61 -5
  13. pyobo/api/xrefs.py +4 -5
  14. pyobo/aws.py +3 -5
  15. pyobo/cli/__init__.py +0 -2
  16. pyobo/cli/aws.py +0 -2
  17. pyobo/cli/cli.py +0 -4
  18. pyobo/cli/database.py +1 -3
  19. pyobo/cli/lookup.py +0 -2
  20. pyobo/cli/utils.py +0 -2
  21. pyobo/constants.py +1 -33
  22. pyobo/getters.py +19 -26
  23. pyobo/gilda_utils.py +19 -17
  24. pyobo/identifier_utils.py +10 -10
  25. pyobo/mocks.py +5 -6
  26. pyobo/normalizer.py +24 -24
  27. pyobo/obographs.py +8 -5
  28. pyobo/plugins.py +3 -4
  29. pyobo/py.typed +0 -0
  30. pyobo/reader.py +19 -21
  31. pyobo/registries/__init__.py +0 -2
  32. pyobo/registries/metaregistry.py +6 -8
  33. pyobo/resource_utils.py +1 -3
  34. pyobo/resources/__init__.py +0 -2
  35. pyobo/resources/ncbitaxon.py +2 -3
  36. pyobo/resources/ro.py +2 -4
  37. pyobo/resources/so.py +55 -0
  38. pyobo/resources/so.tsv +2604 -0
  39. pyobo/sources/README.md +15 -0
  40. pyobo/sources/__init__.py +0 -2
  41. pyobo/sources/agrovoc.py +3 -3
  42. pyobo/sources/antibodyregistry.py +2 -3
  43. pyobo/sources/biogrid.py +4 -4
  44. pyobo/sources/ccle.py +3 -4
  45. pyobo/sources/cgnc.py +1 -3
  46. pyobo/sources/chebi.py +2 -4
  47. pyobo/sources/chembl.py +1 -3
  48. pyobo/sources/civic_gene.py +2 -3
  49. pyobo/sources/complexportal.py +57 -20
  50. pyobo/sources/conso.py +2 -4
  51. pyobo/sources/cpt.py +1 -3
  52. pyobo/sources/credit.py +1 -1
  53. pyobo/sources/cvx.py +1 -3
  54. pyobo/sources/depmap.py +3 -4
  55. pyobo/sources/dictybase_gene.py +15 -12
  56. pyobo/sources/drugbank.py +6 -7
  57. pyobo/sources/drugbank_salt.py +3 -4
  58. pyobo/sources/drugcentral.py +9 -8
  59. pyobo/sources/expasy.py +33 -16
  60. pyobo/sources/famplex.py +3 -5
  61. pyobo/sources/flybase.py +5 -6
  62. pyobo/sources/geonames.py +1 -1
  63. pyobo/sources/gmt_utils.py +5 -6
  64. pyobo/sources/go.py +4 -6
  65. pyobo/sources/gwascentral_phenotype.py +1 -3
  66. pyobo/sources/gwascentral_study.py +2 -3
  67. pyobo/sources/hgnc.py +30 -26
  68. pyobo/sources/hgncgenefamily.py +9 -11
  69. pyobo/sources/icd10.py +3 -4
  70. pyobo/sources/icd11.py +3 -4
  71. pyobo/sources/icd_utils.py +6 -7
  72. pyobo/sources/interpro.py +3 -5
  73. pyobo/sources/itis.py +1 -3
  74. pyobo/sources/kegg/__init__.py +0 -2
  75. pyobo/sources/kegg/api.py +3 -4
  76. pyobo/sources/kegg/genes.py +3 -4
  77. pyobo/sources/kegg/genome.py +19 -9
  78. pyobo/sources/kegg/pathway.py +5 -6
  79. pyobo/sources/mesh.py +19 -21
  80. pyobo/sources/mgi.py +1 -3
  81. pyobo/sources/mirbase.py +13 -9
  82. pyobo/sources/mirbase_constants.py +0 -2
  83. pyobo/sources/mirbase_family.py +1 -3
  84. pyobo/sources/mirbase_mature.py +1 -3
  85. pyobo/sources/msigdb.py +4 -5
  86. pyobo/sources/ncbigene.py +3 -5
  87. pyobo/sources/npass.py +2 -4
  88. pyobo/sources/omim_ps.py +1 -3
  89. pyobo/sources/pathbank.py +35 -28
  90. pyobo/sources/pfam.py +1 -3
  91. pyobo/sources/pfam_clan.py +1 -3
  92. pyobo/sources/pid.py +3 -5
  93. pyobo/sources/pombase.py +7 -6
  94. pyobo/sources/pubchem.py +2 -3
  95. pyobo/sources/reactome.py +30 -11
  96. pyobo/sources/rgd.py +3 -4
  97. pyobo/sources/rhea.py +7 -8
  98. pyobo/sources/ror.py +3 -2
  99. pyobo/sources/selventa/__init__.py +0 -2
  100. pyobo/sources/selventa/schem.py +1 -3
  101. pyobo/sources/selventa/scomp.py +1 -3
  102. pyobo/sources/selventa/sdis.py +1 -3
  103. pyobo/sources/selventa/sfam.py +1 -3
  104. pyobo/sources/sgd.py +1 -3
  105. pyobo/sources/slm.py +29 -17
  106. pyobo/sources/umls/__init__.py +0 -2
  107. pyobo/sources/umls/__main__.py +0 -2
  108. pyobo/sources/umls/get_synonym_types.py +1 -1
  109. pyobo/sources/umls/umls.py +2 -4
  110. pyobo/sources/uniprot/__init__.py +0 -2
  111. pyobo/sources/uniprot/uniprot.py +11 -10
  112. pyobo/sources/uniprot/uniprot_ptm.py +6 -5
  113. pyobo/sources/utils.py +3 -5
  114. pyobo/sources/wikipathways.py +1 -3
  115. pyobo/sources/zfin.py +20 -9
  116. pyobo/ssg/__init__.py +3 -2
  117. pyobo/struct/__init__.py +0 -2
  118. pyobo/struct/reference.py +22 -23
  119. pyobo/struct/struct.py +132 -116
  120. pyobo/struct/typedef.py +14 -10
  121. pyobo/struct/utils.py +0 -2
  122. pyobo/utils/__init__.py +0 -2
  123. pyobo/utils/cache.py +14 -6
  124. pyobo/utils/io.py +9 -10
  125. pyobo/utils/iter.py +5 -6
  126. pyobo/utils/misc.py +1 -3
  127. pyobo/utils/ndex_utils.py +6 -7
  128. pyobo/utils/path.py +4 -5
  129. pyobo/version.py +3 -5
  130. pyobo/xrefdb/__init__.py +0 -2
  131. pyobo/xrefdb/canonicalizer.py +27 -18
  132. pyobo/xrefdb/priority.py +0 -2
  133. pyobo/xrefdb/sources/__init__.py +3 -4
  134. pyobo/xrefdb/sources/biomappings.py +0 -2
  135. pyobo/xrefdb/sources/cbms2019.py +0 -2
  136. pyobo/xrefdb/sources/chembl.py +0 -2
  137. pyobo/xrefdb/sources/compath.py +1 -3
  138. pyobo/xrefdb/sources/famplex.py +3 -5
  139. pyobo/xrefdb/sources/gilda.py +0 -2
  140. pyobo/xrefdb/sources/intact.py +5 -5
  141. pyobo/xrefdb/sources/ncit.py +1 -3
  142. pyobo/xrefdb/sources/pubchem.py +2 -5
  143. pyobo/xrefdb/sources/wikidata.py +2 -4
  144. pyobo/xrefdb/xrefs_pipeline.py +15 -16
  145. {pyobo-0.10.12.dist-info → pyobo-0.11.1.dist-info}/LICENSE +1 -1
  146. pyobo-0.11.1.dist-info/METADATA +711 -0
  147. pyobo-0.11.1.dist-info/RECORD +173 -0
  148. {pyobo-0.10.12.dist-info → pyobo-0.11.1.dist-info}/WHEEL +1 -1
  149. pyobo-0.11.1.dist-info/entry_points.txt +2 -0
  150. pyobo-0.10.12.dist-info/METADATA +0 -499
  151. pyobo-0.10.12.dist-info/RECORD +0 -169
  152. pyobo-0.10.12.dist-info/entry_points.txt +0 -15
  153. {pyobo-0.10.12.dist-info → pyobo-0.11.1.dist-info}/top_level.txt +0 -0
pyobo/struct/struct.py CHANGED
@@ -1,12 +1,12 @@
1
- # -*- coding: utf-8 -*-
2
-
3
1
  """Data structures for OBO."""
4
2
 
5
3
  import gzip
6
4
  import json
7
5
  import logging
8
6
  import os
7
+ import sys
9
8
  from collections import defaultdict
9
+ from collections.abc import Collection, Iterable, Iterator, Mapping, Sequence
10
10
  from dataclasses import dataclass, field
11
11
  from datetime import datetime
12
12
  from operator import attrgetter
@@ -16,17 +16,8 @@ from typing import (
16
16
  Any,
17
17
  Callable,
18
18
  ClassVar,
19
- Collection,
20
- Dict,
21
- Iterable,
22
- Iterator,
23
- List,
24
- Mapping,
25
19
  Optional,
26
- Sequence,
27
- Set,
28
20
  TextIO,
29
- Tuple,
30
21
  Union,
31
22
  )
32
23
 
@@ -104,7 +95,7 @@ class Synonym:
104
95
  )
105
96
 
106
97
  #: References to articles where the synonym appears
107
- provenance: List[Reference] = field(default_factory=list)
98
+ provenance: list[Reference] = field(default_factory=list)
108
99
 
109
100
  def to_obo(self) -> str:
110
101
  """Write this synonym as an OBO line to appear in a [Term] stanza."""
@@ -168,7 +159,7 @@ abbreviation = SynonymTypeDef(
168
159
  acronym = SynonymTypeDef(reference=Reference(prefix="omo", identifier="0003012", name="acronym"))
169
160
 
170
161
 
171
- ReferenceHint = Union[Reference, "Term", Tuple[str, str], str]
162
+ ReferenceHint = Union[Reference, "Term", tuple[str, str], str]
172
163
 
173
164
 
174
165
  def _ensure_ref(reference: ReferenceHint) -> Reference:
@@ -199,26 +190,26 @@ class Term(Referenced):
199
190
  definition: Optional[str] = None
200
191
 
201
192
  #: References to articles in which the term appears
202
- provenance: List[Reference] = field(default_factory=list)
193
+ provenance: list[Reference] = field(default_factory=list)
203
194
 
204
195
  #: Relationships defined by [Typedef] stanzas
205
- relationships: Dict[TypeDef, List[Reference]] = field(default_factory=lambda: defaultdict(list))
196
+ relationships: dict[TypeDef, list[Reference]] = field(default_factory=lambda: defaultdict(list))
206
197
 
207
198
  #: Properties, which are not defined with Typedef and have scalar values instead of references.
208
- properties: Dict[str, List[str]] = field(default_factory=lambda: defaultdict(list))
199
+ properties: dict[str, list[str]] = field(default_factory=lambda: defaultdict(list))
209
200
 
210
201
  #: Relationships with the default "is_a"
211
- parents: List[Reference] = field(default_factory=list)
202
+ parents: list[Reference] = field(default_factory=list)
212
203
 
213
204
  #: Synonyms of this term
214
- synonyms: List[Synonym] = field(default_factory=list)
205
+ synonyms: list[Synonym] = field(default_factory=list)
215
206
 
216
207
  #: Equivalent references
217
- xrefs: List[Reference] = field(default_factory=list)
218
- xref_types: List[Reference] = field(default_factory=list)
208
+ xrefs: list[Reference] = field(default_factory=list)
209
+ xref_types: list[Reference] = field(default_factory=list)
219
210
 
220
211
  #: Alternate Identifiers
221
- alt_ids: List[Reference] = field(default_factory=list)
212
+ alt_ids: list[Reference] = field(default_factory=list)
222
213
 
223
214
  #: The sub-namespace within the ontology
224
215
  namespace: Optional[str] = None
@@ -228,7 +219,7 @@ class Term(Referenced):
228
219
 
229
220
  type: Literal["Term", "Instance"] = "Term"
230
221
 
231
- def __hash__(self): # noqa: D105
222
+ def __hash__(self):
232
223
  return hash((self.__class__, self.prefix, self.identifier))
233
224
 
234
225
  @classmethod
@@ -321,7 +312,7 @@ class Term(Referenced):
321
312
  raise ValueError("can not append a collection of parents containing a null parent")
322
313
  self.parents.extend(references)
323
314
 
324
- def get_properties(self, prop) -> List[str]:
315
+ def get_properties(self, prop) -> list[str]:
325
316
  """Get properties from the given key."""
326
317
  return self.properties[prop]
327
318
 
@@ -343,7 +334,7 @@ class Term(Referenced):
343
334
  raise ValueError
344
335
  return r[0]
345
336
 
346
- def get_relationships(self, typedef: TypeDef) -> List[Reference]:
337
+ def get_relationships(self, typedef: TypeDef) -> list[Reference]:
347
338
  """Get relationships from the given type."""
348
339
  return self.relationships[typedef]
349
340
 
@@ -399,16 +390,17 @@ class Term(Referenced):
399
390
  self.properties[prop].append(value)
400
391
 
401
392
  def _definition_fp(self) -> str:
402
- assert self.definition is not None
393
+ if self.definition is None:
394
+ raise AssertionError
403
395
  return f'"{obo_escape_slim(self.definition)}" [{comma_separate(self.provenance)}]'
404
396
 
405
- def iterate_relations(self) -> Iterable[Tuple[TypeDef, Reference]]:
397
+ def iterate_relations(self) -> Iterable[tuple[TypeDef, Reference]]:
406
398
  """Iterate over pairs of typedefs and targets."""
407
399
  for typedef, targets in sorted(self.relationships.items(), key=_sort_relations):
408
400
  for target in sorted(targets, key=lambda ref: ref.preferred_curie):
409
401
  yield typedef, target
410
402
 
411
- def iterate_properties(self) -> Iterable[Tuple[str, str]]:
403
+ def iterate_properties(self) -> Iterable[tuple[str, str]]:
412
404
  """Iterate over pairs of property and values."""
413
405
  for prop, values in sorted(self.properties.items()):
414
406
  for value in sorted(values):
@@ -470,7 +462,7 @@ class Term(Referenced):
470
462
 
471
463
 
472
464
  #: A set of warnings, used to make sure we don't show the same one over and over
473
- _TYPEDEF_WARNINGS: Set[Tuple[str, str]] = set()
465
+ _TYPEDEF_WARNINGS: set[tuple[str, str]] = set()
474
466
 
475
467
 
476
468
  def _sort_relations(r):
@@ -489,6 +481,8 @@ def _sort_properties(r):
489
481
 
490
482
 
491
483
  class BioregistryError(ValueError):
484
+ """An error raised for non-canonical prefixes."""
485
+
492
486
  def __str__(self) -> str:
493
487
  return dedent(
494
488
  f"""
@@ -518,10 +512,10 @@ class Obo:
518
512
  format_version: ClassVar[str] = "1.2"
519
513
 
520
514
  #: Type definitions
521
- typedefs: ClassVar[Optional[List[TypeDef]]] = None
515
+ typedefs: ClassVar[Optional[list[TypeDef]]] = None
522
516
 
523
517
  #: Synonym type definitions
524
- synonym_typedefs: ClassVar[Optional[List[SynonymTypeDef]]] = None
518
+ synonym_typedefs: ClassVar[Optional[list[SynonymTypeDef]]] = None
525
519
 
526
520
  #: An annotation about how an ontology was generated
527
521
  auto_generated_by: ClassVar[Optional[str]] = None
@@ -541,7 +535,7 @@ class Obo:
541
535
  bioversions_key: ClassVar[Optional[str]] = None
542
536
 
543
537
  #: Root terms to use for the ontology
544
- root_terms: ClassVar[Optional[List[Reference]]] = None
538
+ root_terms: ClassVar[Optional[list[Reference]]] = None
545
539
 
546
540
  #: The date the ontology was generated
547
541
  date: Optional[datetime] = field(default_factory=datetime.today)
@@ -555,7 +549,7 @@ class Obo:
555
549
  #: The hierarchy of terms
556
550
  _hierarchy: Optional[nx.DiGraph] = field(init=False, default=None, repr=False)
557
551
  #: A cache of terms
558
- _items: Optional[List[Term]] = field(init=False, default=None, repr=False)
552
+ _items: Optional[list[Term]] = field(init=False, default=None, repr=False)
559
553
 
560
554
  term_sort_key: ClassVar[Optional[Callable[["Obo", Term], int]]] = None
561
555
 
@@ -590,7 +584,7 @@ class Obo:
590
584
  return get_version(self.bioversions_key)
591
585
  except KeyError:
592
586
  logger.warning(f"[{self.bioversions_key}] bioversions doesn't list this resource ")
593
- except IOError:
587
+ except OSError:
594
588
  logger.warning(f"[{self.bioversions_key}] error while looking up version")
595
589
  return None
596
590
 
@@ -610,6 +604,11 @@ class Obo:
610
604
 
611
605
  return graph_from_obo(self)
612
606
 
607
+ def write_obograph(self, path: Path) -> None:
608
+ """Write OBO Graph json."""
609
+ graph = self.get_graph()
610
+ path.write_text(graph.model_dump_json(indent=2, exclude_none=True, exclude_unset=True))
611
+
613
612
  @classmethod
614
613
  def cli(cls) -> None:
615
614
  """Run the CLI for this class."""
@@ -623,22 +622,31 @@ class Obo:
623
622
  @click.command()
624
623
  @verbose_option
625
624
  @force_option
625
+ @click.option("--rewrite", "-r", is_flag=True)
626
626
  @click.option("--owl", is_flag=True, help="Write OWL via ROBOT")
627
- @click.option("--graph", is_flag=True, help="Write OBO Graph JSON via ROBOT")
628
627
  @click.option("--nodes", is_flag=True, help="Write nodes file")
629
628
  @click.option(
630
629
  "--version", help="Specify data version to get. Use this if bioversions is acting up."
631
630
  )
632
- def _main(force: bool, owl: bool, graph: bool, nodes: bool, version: Optional[str]):
633
- inst = cls(force=force, data_version=version)
634
- inst.write_default(
635
- write_obograph=graph,
636
- write_obo=True,
637
- write_owl=owl,
638
- write_nodes=nodes,
639
- force=force,
640
- use_tqdm=True,
641
- )
631
+ def _main(force: bool, owl: bool, nodes: bool, version: Optional[str], rewrite: bool):
632
+ try:
633
+ inst = cls(force=force, data_version=version)
634
+ except Exception as e:
635
+ click.secho(f"[{cls.ontology}] Got an exception during instantiation - {type(e)}")
636
+ sys.exit(1)
637
+
638
+ try:
639
+ inst.write_default(
640
+ write_obograph=True,
641
+ write_obo=True,
642
+ write_owl=owl,
643
+ write_nodes=nodes,
644
+ force=force or rewrite,
645
+ use_tqdm=True,
646
+ )
647
+ except Exception as e:
648
+ click.secho(f"[{cls.ontology}] Got an exception during OBO writing {type(e)}")
649
+ sys.exit(1)
642
650
 
643
651
  return _main
644
652
 
@@ -661,13 +669,14 @@ class Obo:
661
669
  def iterate_obo_lines(self) -> Iterable[str]:
662
670
  """Iterate over the lines to write in an OBO file."""
663
671
  yield f"format-version: {self.format_version}"
664
- yield f"date: {self.date_formatted}"
665
672
 
666
673
  if self.auto_generated_by is not None:
667
674
  yield f"auto-generated-by: {self.auto_generated_by}"
668
675
 
669
676
  if self.data_version is not None:
670
677
  yield f"data-version: {self.data_version}"
678
+ else:
679
+ yield f"date: {self.date_formatted}"
671
680
 
672
681
  for prefix, url in sorted((self.idspaces or {}).items()):
673
682
  yield f"idspace: {prefix} {url}"
@@ -716,7 +725,7 @@ class Obo:
716
725
  @staticmethod
717
726
  def _write_lines(it, file: Optional[TextIO]):
718
727
  for line in it:
719
- print(line, file=file) # noqa: T201
728
+ print(line, file=file)
720
729
 
721
730
  def write_obonet_gz(self, path: Union[str, Path]) -> None:
722
731
  """Write the OBO to a gzipped dump in Obonet JSON."""
@@ -871,16 +880,11 @@ class Obo:
871
880
  relation_df.sort_values(list(relation_df.columns), inplace=True)
872
881
  relation_df.to_csv(relations_path, sep="\t", index=False)
873
882
 
874
- if (write_obo or write_obograph or write_owl) and (not self._obo_path.exists() or force):
883
+ if (write_obo or write_owl) and (not self._obo_path.exists() or force):
875
884
  self.write_obo(self._obo_path, use_tqdm=use_tqdm)
876
- if write_obograph:
877
- # obo_to_obograph(self._obo_path, self._obograph_path)
878
- self._obograph_path.write_text(
879
- self.get_graph().json(
880
- indent=2, ensure_ascii=False, exclude_none=True, exclude_unset=True
881
- )
882
- )
883
- if write_owl:
885
+ if write_obograph and (not self._obograph_path.exists() or force):
886
+ self.write_obograph(self._obograph_path)
887
+ if write_owl and (not self._owl_path.exists() or force):
884
888
  obo_to_owl(self._obo_path, self._owl_path)
885
889
  if write_obonet and (not self._obonet_gz_path.exists() or force):
886
890
  logger.debug("writing obonet to %s", self._obonet_gz_path)
@@ -895,16 +899,16 @@ class Obo:
895
899
  self._items = sorted(self.iter_terms(force=self.force), key=key)
896
900
  return self._items
897
901
 
898
- def __iter__(self) -> Iterator["Term"]: # noqa: D105
902
+ def __iter__(self) -> Iterator["Term"]:
899
903
  if self.iter_only:
900
904
  return iter(self.iter_terms(force=self.force))
901
905
  return iter(self._items_accessor)
902
906
 
903
- def ancestors(self, identifier: str) -> Set[str]:
907
+ def ancestors(self, identifier: str) -> set[str]:
904
908
  """Return a set of identifiers for parents of the given identifier."""
905
909
  return nx.descendants(self.hierarchy, identifier) # note this is backwards
906
910
 
907
- def descendants(self, identifier: str) -> Set[str]:
911
+ def descendants(self, identifier: str) -> set[str]:
908
912
  """Return a set of identifiers for the children of the given identifier."""
909
913
  return nx.ancestors(self.hierarchy, identifier) # note this is backwards
910
914
 
@@ -914,11 +918,12 @@ class Obo:
914
918
  .. code-block:: python
915
919
 
916
920
  from pyobo import get_obo
917
- obo = get_obo('go')
918
921
 
919
- interleukin_10_complex = '1905571' # interleukin-10 receptor complex
920
- all_complexes = '0032991'
921
- assert obo.is_descendant('1905571', '0032991')
922
+ obo = get_obo("go")
923
+
924
+ interleukin_10_complex = "1905571" # interleukin-10 receptor complex
925
+ all_complexes = "0032991"
926
+ assert obo.is_descendant("1905571", "0032991")
922
927
  """
923
928
  return ancestor in self.ancestors(descendant)
924
929
 
@@ -931,11 +936,12 @@ class Obo:
931
936
  .. code-block:: python
932
937
 
933
938
  from pyobo import get_obo
934
- obo = get_obo('go')
935
939
 
936
- identifier = '1905571' # interleukin-10 receptor complex
937
- is_complex = '0032991' in nx.descendants(obo.hierarchy, identifier) # should be true
938
- """ # noqa:D401
940
+ obo = get_obo("go")
941
+
942
+ identifier = "1905571" # interleukin-10 receptor complex
943
+ is_complex = "0032991" in nx.descendants(obo.hierarchy, identifier) # should be true
944
+ """
939
945
  if self._hierarchy is None:
940
946
  self._hierarchy = nx.DiGraph()
941
947
  for term in self._iter_terms(desc=f"[{self.ontology}] getting hierarchy"):
@@ -1006,10 +1012,10 @@ class Obo:
1006
1012
 
1007
1013
  def get_metadata(self) -> Mapping[str, Any]:
1008
1014
  """Get metadata."""
1009
- return dict(
1010
- version=self.data_version,
1011
- date=self.date and self.date.isoformat(),
1012
- )
1015
+ return {
1016
+ "version": self.data_version,
1017
+ "date": self.date and self.date.isoformat(),
1018
+ }
1013
1019
 
1014
1020
  def iterate_ids(self, *, use_tqdm: bool = False) -> Iterable[str]:
1015
1021
  """Iterate over identifiers."""
@@ -1017,11 +1023,11 @@ class Obo:
1017
1023
  if term.prefix == self.ontology:
1018
1024
  yield term.identifier
1019
1025
 
1020
- def get_ids(self, *, use_tqdm: bool = False) -> Set[str]:
1026
+ def get_ids(self, *, use_tqdm: bool = False) -> set[str]:
1021
1027
  """Get the set of identifiers."""
1022
1028
  return set(self.iterate_ids(use_tqdm=use_tqdm))
1023
1029
 
1024
- def iterate_id_name(self, *, use_tqdm: bool = False) -> Iterable[Tuple[str, str]]:
1030
+ def iterate_id_name(self, *, use_tqdm: bool = False) -> Iterable[tuple[str, str]]:
1025
1031
  """Iterate identifier name pairs."""
1026
1032
  for term in self._iter_terms(use_tqdm=use_tqdm, desc=f"[{self.ontology}] getting names"):
1027
1033
  if term.prefix == self.ontology and term.name:
@@ -1031,19 +1037,23 @@ class Obo:
1031
1037
  """Get a mapping from identifiers to names."""
1032
1038
  return dict(self.iterate_id_name(use_tqdm=use_tqdm))
1033
1039
 
1034
- def iterate_id_definition(self, *, use_tqdm: bool = False) -> Iterable[Tuple[str, str]]:
1040
+ def iterate_id_definition(self, *, use_tqdm: bool = False) -> Iterable[tuple[str, str]]:
1035
1041
  """Iterate over pairs of terms' identifiers and their respective definitions."""
1036
1042
  for term in self._iter_terms(use_tqdm=use_tqdm, desc=f"[{self.ontology}] getting names"):
1037
1043
  if term.identifier and term.definition:
1038
- yield term.identifier, term.definition.strip('"').replace("\n", " ").replace(
1039
- "\t", " "
1040
- ).replace(" ", " ")
1044
+ yield (
1045
+ term.identifier,
1046
+ term.definition.strip('"')
1047
+ .replace("\n", " ")
1048
+ .replace("\t", " ")
1049
+ .replace(" ", " "),
1050
+ )
1041
1051
 
1042
1052
  def get_id_definition_mapping(self, *, use_tqdm: bool = False) -> Mapping[str, str]:
1043
1053
  """Get a mapping from identifiers to definitions."""
1044
1054
  return dict(self.iterate_id_definition(use_tqdm=use_tqdm))
1045
1055
 
1046
- def get_obsolete(self, *, use_tqdm: bool = False) -> Set[str]:
1056
+ def get_obsolete(self, *, use_tqdm: bool = False) -> set[str]:
1047
1057
  """Get the set of obsolete identifiers."""
1048
1058
  return {
1049
1059
  term.identifier
@@ -1059,7 +1069,7 @@ class Obo:
1059
1069
 
1060
1070
  def iterate_id_species(
1061
1071
  self, *, prefix: Optional[str] = None, use_tqdm: bool = False
1062
- ) -> Iterable[Tuple[str, str]]:
1072
+ ) -> Iterable[tuple[str, str]]:
1063
1073
  """Iterate over terms' identifiers and respective species (if available)."""
1064
1074
  if prefix is None:
1065
1075
  prefix = NCBITAXON_PREFIX
@@ -1086,7 +1096,7 @@ class Obo:
1086
1096
  ]
1087
1097
  return pd.DataFrame(rows, columns=["prefix", "identifier", "name"])
1088
1098
 
1089
- def iter_typedef_id_name(self) -> Iterable[Tuple[str, str]]:
1099
+ def iter_typedef_id_name(self) -> Iterable[tuple[str, str]]:
1090
1100
  """Iterate over typedefs' identifiers and their respective names."""
1091
1101
  for typedef in self.typedefs or []:
1092
1102
  yield typedef.identifier, typedef.name
@@ -1099,7 +1109,7 @@ class Obo:
1099
1109
  # PROPS #
1100
1110
  #########
1101
1111
 
1102
- def iterate_properties(self, *, use_tqdm: bool = False) -> Iterable[Tuple[Term, str, str]]:
1112
+ def iterate_properties(self, *, use_tqdm: bool = False) -> Iterable[tuple[Term, str, str]]:
1103
1113
  """Iterate over tuples of terms, properties, and their values."""
1104
1114
  # TODO if property_prefix is set, try removing that as a prefix from all prop strings.
1105
1115
  for term in self._iter_terms(
@@ -1110,10 +1120,10 @@ class Obo:
1110
1120
 
1111
1121
  @property
1112
1122
  def properties_header(self):
1113
- """Property dataframe header.""" # noqa:D401
1123
+ """Property dataframe header."""
1114
1124
  return [f"{self.ontology}_id", "property", "value"]
1115
1125
 
1116
- def iter_property_rows(self, *, use_tqdm: bool = False) -> Iterable[Tuple[str, str, str]]:
1126
+ def iter_property_rows(self, *, use_tqdm: bool = False) -> Iterable[tuple[str, str, str]]:
1117
1127
  """Iterate property rows."""
1118
1128
  for term, prop, value in self.iterate_properties(use_tqdm=use_tqdm):
1119
1129
  yield term.identifier, prop, value
@@ -1127,7 +1137,7 @@ class Obo:
1127
1137
 
1128
1138
  def iterate_filtered_properties(
1129
1139
  self, prop: str, *, use_tqdm: bool = False
1130
- ) -> Iterable[Tuple[Term, str]]:
1140
+ ) -> Iterable[tuple[Term, str]]:
1131
1141
  """Iterate over tuples of terms and the values for the given property."""
1132
1142
  for term in self._iter_terms(use_tqdm=use_tqdm):
1133
1143
  for _prop, value in term.iterate_properties():
@@ -1155,7 +1165,7 @@ class Obo:
1155
1165
 
1156
1166
  def get_filtered_properties_multimapping(
1157
1167
  self, prop: str, *, use_tqdm: bool = False
1158
- ) -> Mapping[str, List[str]]:
1168
+ ) -> Mapping[str, list[str]]:
1159
1169
  """Get a mapping from a term's identifier to the property values."""
1160
1170
  return multidict(
1161
1171
  (term.identifier, value)
@@ -1168,7 +1178,7 @@ class Obo:
1168
1178
 
1169
1179
  def iterate_relations(
1170
1180
  self, *, use_tqdm: bool = False
1171
- ) -> Iterable[Tuple[Term, TypeDef, Reference]]:
1181
+ ) -> Iterable[tuple[Term, TypeDef, Reference]]:
1172
1182
  """Iterate over tuples of terms, relations, and their targets."""
1173
1183
  for term in self._iter_terms(
1174
1184
  use_tqdm=use_tqdm, desc=f"[{self.ontology}] getting relations"
@@ -1185,17 +1195,23 @@ class Obo:
1185
1195
 
1186
1196
  def iter_relation_rows(
1187
1197
  self, use_tqdm: bool = False
1188
- ) -> Iterable[Tuple[str, str, str, str, str]]:
1198
+ ) -> Iterable[tuple[str, str, str, str, str]]:
1189
1199
  """Iterate the relations' rows."""
1190
1200
  for term, typedef, reference in self.iterate_relations(use_tqdm=use_tqdm):
1191
- yield term.identifier, typedef.prefix, typedef.identifier, reference.prefix, reference.identifier
1201
+ yield (
1202
+ term.identifier,
1203
+ typedef.prefix,
1204
+ typedef.identifier,
1205
+ reference.prefix,
1206
+ reference.identifier,
1207
+ )
1192
1208
 
1193
1209
  def iterate_filtered_relations(
1194
1210
  self,
1195
1211
  relation: RelationHint,
1196
1212
  *,
1197
1213
  use_tqdm: bool = False,
1198
- ) -> Iterable[Tuple[Term, Reference]]:
1214
+ ) -> Iterable[tuple[Term, Reference]]:
1199
1215
  """Iterate over tuples of terms and ther targets for the given relation."""
1200
1216
  _target_prefix, _target_identifier = get_reference_tuple(relation)
1201
1217
  for term, typedef, reference in self.iterate_relations(use_tqdm=use_tqdm):
@@ -1204,7 +1220,7 @@ class Obo:
1204
1220
 
1205
1221
  @property
1206
1222
  def relations_header(self) -> Sequence[str]:
1207
- """Header for the relations dataframe.""" # noqa:D401
1223
+ """Header for the relations dataframe."""
1208
1224
  return [f"{self.ontology}_id", RELATION_PREFIX, RELATION_ID, TARGET_PREFIX, TARGET_ID]
1209
1225
 
1210
1226
  def get_relations_df(self, *, use_tqdm: bool = False) -> pd.DataFrame:
@@ -1235,7 +1251,7 @@ class Obo:
1235
1251
  target_prefix: str,
1236
1252
  *,
1237
1253
  use_tqdm: bool = False,
1238
- ) -> Iterable[Tuple[Term, Reference]]:
1254
+ ) -> Iterable[tuple[Term, Reference]]:
1239
1255
  """Iterate over relationships between one identifier and another."""
1240
1256
  for term, reference in self.iterate_filtered_relations(
1241
1257
  relation=relation, use_tqdm=use_tqdm
@@ -1258,9 +1274,9 @@ class Obo:
1258
1274
 
1259
1275
  >>> from pyobo.sources.hgnc import get_obo
1260
1276
  >>> obo = get_obo()
1261
- >>> human_mapt_hgnc_id = '6893'
1262
- >>> mouse_mapt_mgi_id = '97180'
1263
- >>> hgnc_mgi_orthology_mapping = obo.get_relation_mapping('ro:HOM0000017', 'mgi')
1277
+ >>> human_mapt_hgnc_id = "6893"
1278
+ >>> mouse_mapt_mgi_id = "97180"
1279
+ >>> hgnc_mgi_orthology_mapping = obo.get_relation_mapping("ro:HOM0000017", "mgi")
1264
1280
  >>> assert mouse_mapt_mgi_id == hgnc_mgi_orthology_mapping[human_mapt_hgnc_id]
1265
1281
  """
1266
1282
  return {
@@ -1284,9 +1300,9 @@ class Obo:
1284
1300
 
1285
1301
  >>> from pyobo.sources.hgnc import get_obo
1286
1302
  >>> obo = get_obo()
1287
- >>> human_mapt_hgnc_id = '6893'
1288
- >>> mouse_mapt_mgi_id = '97180'
1289
- >>> assert mouse_mapt_mgi_id == obo.get_relation(human_mapt_hgnc_id, 'ro:HOM0000017', 'mgi')
1303
+ >>> human_mapt_hgnc_id = "6893"
1304
+ >>> mouse_mapt_mgi_id = "97180"
1305
+ >>> assert mouse_mapt_mgi_id == obo.get_relation(human_mapt_hgnc_id, "ro:HOM0000017", "mgi")
1290
1306
  """
1291
1307
  relation_mapping = self.get_relation_mapping(
1292
1308
  relation=relation, target_prefix=target_prefix, use_tqdm=use_tqdm
@@ -1299,7 +1315,7 @@ class Obo:
1299
1315
  target_prefix: str,
1300
1316
  *,
1301
1317
  use_tqdm: bool = False,
1302
- ) -> Mapping[str, List[str]]:
1318
+ ) -> Mapping[str, list[str]]:
1303
1319
  """Get a mapping from the term's identifier to the target's identifiers."""
1304
1320
  return multidict(
1305
1321
  (term.identifier, reference.identifier)
@@ -1315,7 +1331,7 @@ class Obo:
1315
1331
  typedef: TypeDef,
1316
1332
  *,
1317
1333
  use_tqdm: bool = False,
1318
- ) -> Mapping[str, List[Reference]]:
1334
+ ) -> Mapping[str, list[Reference]]:
1319
1335
  """Get a mapping from identifiers to a list of all references for the given relation."""
1320
1336
  return multidict(
1321
1337
  (term.identifier, reference)
@@ -1329,18 +1345,18 @@ class Obo:
1329
1345
  # SYNONYMS #
1330
1346
  ############
1331
1347
 
1332
- def iterate_synonyms(self, *, use_tqdm: bool = False) -> Iterable[Tuple[Term, Synonym]]:
1348
+ def iterate_synonyms(self, *, use_tqdm: bool = False) -> Iterable[tuple[Term, Synonym]]:
1333
1349
  """Iterate over pairs of term and synonym object."""
1334
1350
  for term in self._iter_terms(use_tqdm=use_tqdm, desc=f"[{self.ontology}] getting synonyms"):
1335
1351
  for synonym in sorted(term.synonyms, key=attrgetter("name")):
1336
1352
  yield term, synonym
1337
1353
 
1338
- def iterate_synonym_rows(self, *, use_tqdm: bool = False) -> Iterable[Tuple[str, str]]:
1354
+ def iterate_synonym_rows(self, *, use_tqdm: bool = False) -> Iterable[tuple[str, str]]:
1339
1355
  """Iterate over pairs of identifier and synonym text."""
1340
1356
  for term, synonym in self.iterate_synonyms(use_tqdm=use_tqdm):
1341
1357
  yield term.identifier, synonym.name
1342
1358
 
1343
- def get_id_synonyms_mapping(self, *, use_tqdm: bool = False) -> Mapping[str, List[str]]:
1359
+ def get_id_synonyms_mapping(self, *, use_tqdm: bool = False) -> Mapping[str, list[str]]:
1344
1360
  """Get a mapping from identifiers to a list of sorted synonym strings."""
1345
1361
  return multidict(self.iterate_synonym_rows(use_tqdm=use_tqdm))
1346
1362
 
@@ -1348,7 +1364,7 @@ class Obo:
1348
1364
  # XREFS #
1349
1365
  #########
1350
1366
 
1351
- def iterate_xrefs(self, *, use_tqdm: bool = False) -> Iterable[Tuple[Term, Reference]]:
1367
+ def iterate_xrefs(self, *, use_tqdm: bool = False) -> Iterable[tuple[Term, Reference]]:
1352
1368
  """Iterate over xrefs."""
1353
1369
  for term in self._iter_terms(use_tqdm=use_tqdm, desc=f"[{self.ontology}] getting xrefs"):
1354
1370
  for xref in term.xrefs:
@@ -1356,20 +1372,20 @@ class Obo:
1356
1372
 
1357
1373
  def iterate_filtered_xrefs(
1358
1374
  self, prefix: str, *, use_tqdm: bool = False
1359
- ) -> Iterable[Tuple[Term, Reference]]:
1375
+ ) -> Iterable[tuple[Term, Reference]]:
1360
1376
  """Iterate over xrefs to a given prefix."""
1361
1377
  for term, xref in self.iterate_xrefs(use_tqdm=use_tqdm):
1362
1378
  if xref.prefix == prefix:
1363
1379
  yield term, xref
1364
1380
 
1365
- def iterate_xref_rows(self, *, use_tqdm: bool = False) -> Iterable[Tuple[str, str, str]]:
1381
+ def iterate_xref_rows(self, *, use_tqdm: bool = False) -> Iterable[tuple[str, str, str]]:
1366
1382
  """Iterate over terms' identifiers, xref prefixes, and xref identifiers."""
1367
1383
  for term, xref in self.iterate_xrefs(use_tqdm=use_tqdm):
1368
1384
  yield term.identifier, xref.prefix, xref.identifier
1369
1385
 
1370
1386
  @property
1371
1387
  def xrefs_header(self):
1372
- """The header for the xref dataframe.""" # noqa:D401
1388
+ """The header for the xref dataframe."""
1373
1389
  return [f"{self.ontology}_id", TARGET_PREFIX, TARGET_ID]
1374
1390
 
1375
1391
  def get_xrefs_df(self, *, use_tqdm: bool = False) -> pd.DataFrame:
@@ -1390,7 +1406,7 @@ class Obo:
1390
1406
 
1391
1407
  def get_filtered_multixrefs_mapping(
1392
1408
  self, prefix: str, *, use_tqdm: bool = False
1393
- ) -> Mapping[str, List[str]]:
1409
+ ) -> Mapping[str, list[str]]:
1394
1410
  """Get filtered xrefs as a dictionary."""
1395
1411
  return multidict(
1396
1412
  (term.identifier, xref.identifier)
@@ -1401,18 +1417,18 @@ class Obo:
1401
1417
  # ALTS #
1402
1418
  ########
1403
1419
 
1404
- def iterate_alts(self) -> Iterable[Tuple[Term, Reference]]:
1420
+ def iterate_alts(self) -> Iterable[tuple[Term, Reference]]:
1405
1421
  """Iterate over alternative identifiers."""
1406
1422
  for term in self:
1407
1423
  for alt in term.alt_ids:
1408
1424
  yield term, alt
1409
1425
 
1410
- def iterate_alt_rows(self) -> Iterable[Tuple[str, str]]:
1426
+ def iterate_alt_rows(self) -> Iterable[tuple[str, str]]:
1411
1427
  """Iterate over pairs of terms' primary identifiers and alternate identifiers."""
1412
1428
  for term, alt in self.iterate_alts():
1413
1429
  yield term.identifier, alt.identifier
1414
1430
 
1415
- def get_id_alts_mapping(self) -> Mapping[str, List[str]]:
1431
+ def get_id_alts_mapping(self) -> Mapping[str, list[str]]:
1416
1432
  """Get a mapping from identifiers to a list of alternative identifiers."""
1417
1433
  return multidict((term.identifier, alt.identifier) for term, alt in self.iterate_alts())
1418
1434
 
@@ -1422,14 +1438,14 @@ def make_ad_hoc_ontology(
1422
1438
  _name: str,
1423
1439
  _auto_generated_by: Optional[str] = None,
1424
1440
  _format_version: str = "1.2",
1425
- _typedefs: Optional[List[TypeDef]] = None,
1426
- _synonym_typedefs: Optional[List[SynonymTypeDef]] = None,
1441
+ _typedefs: Optional[list[TypeDef]] = None,
1442
+ _synonym_typedefs: Optional[list[SynonymTypeDef]] = None,
1427
1443
  _date: Optional[datetime] = None,
1428
1444
  _data_version: Optional[str] = None,
1429
1445
  _idspaces: Optional[Mapping[str, str]] = None,
1430
- _root_terms: Optional[List[Reference]] = None,
1446
+ _root_terms: Optional[list[Reference]] = None,
1431
1447
  *,
1432
- terms: List[Term],
1448
+ terms: list[Term],
1433
1449
  ) -> "Obo":
1434
1450
  """Make an ad-hoc ontology."""
1435
1451
 
@@ -1456,7 +1472,7 @@ def make_ad_hoc_ontology(
1456
1472
  return AdHocOntology()
1457
1473
 
1458
1474
 
1459
- def _convert_typedefs(typedefs: Optional[Iterable[TypeDef]]) -> List[Mapping[str, Any]]:
1475
+ def _convert_typedefs(typedefs: Optional[Iterable[TypeDef]]) -> list[Mapping[str, Any]]:
1460
1476
  """Convert the type defs."""
1461
1477
  if not typedefs:
1462
1478
  return []
@@ -1466,10 +1482,10 @@ def _convert_typedefs(typedefs: Optional[Iterable[TypeDef]]) -> List[Mapping[str
1466
1482
  def _convert_typedef(typedef: TypeDef) -> Mapping[str, Any]:
1467
1483
  """Convert a type def."""
1468
1484
  # TODO add more later
1469
- return typedef.reference.dict()
1485
+ return typedef.reference.model_dump()
1470
1486
 
1471
1487
 
1472
- def _convert_synonym_typedefs(synonym_typedefs: Optional[Iterable[SynonymTypeDef]]) -> List[str]:
1488
+ def _convert_synonym_typedefs(synonym_typedefs: Optional[Iterable[SynonymTypeDef]]) -> list[str]:
1473
1489
  """Convert the synonym type defs."""
1474
1490
  if not synonym_typedefs:
1475
1491
  return []