bioversions 0.5.376__py3-none-any.whl → 0.7.2__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 (85) hide show
  1. bioversions/__init__.py +7 -3
  2. bioversions/__main__.py +0 -2
  3. bioversions/charts.py +3 -7
  4. bioversions/cli.py +3 -5
  5. bioversions/py.typed +0 -0
  6. bioversions/resources/__init__.py +18 -7
  7. bioversions/resources/update.py +20 -12
  8. bioversions/resources/versions.json +20553 -0
  9. bioversions/slack_client.py +2 -5
  10. bioversions/sources/__init__.py +32 -17
  11. bioversions/sources/antibodyregistry.py +9 -6
  12. bioversions/sources/bigg.py +5 -7
  13. bioversions/sources/biogrid.py +0 -2
  14. bioversions/sources/cellosaurus.py +3 -5
  15. bioversions/sources/chebi.py +1 -3
  16. bioversions/sources/chembl.py +3 -4
  17. bioversions/sources/chemidplus.py +1 -3
  18. bioversions/sources/civic.py +9 -4
  19. bioversions/sources/complexportal.py +0 -2
  20. bioversions/sources/daily.py +0 -2
  21. bioversions/sources/depmap.py +1 -3
  22. bioversions/sources/dgi.py +9 -12
  23. bioversions/sources/disgenet.py +1 -3
  24. bioversions/sources/drugbank.py +2 -4
  25. bioversions/sources/drugcentral.py +2 -4
  26. bioversions/sources/ensembl.py +1 -3
  27. bioversions/sources/expasy.py +1 -4
  28. bioversions/sources/flybase.py +0 -2
  29. bioversions/sources/gtdb.py +35 -0
  30. bioversions/sources/guidetopharmacology.py +3 -5
  31. bioversions/sources/hgnc.py +13 -14
  32. bioversions/sources/homologene.py +0 -2
  33. bioversions/sources/icd10.py +1 -3
  34. bioversions/sources/icd11.py +1 -3
  35. bioversions/sources/icf.py +1 -3
  36. bioversions/sources/intact.py +0 -2
  37. bioversions/sources/interpro.py +1 -3
  38. bioversions/sources/itis.py +8 -15
  39. bioversions/sources/kegg.py +7 -7
  40. bioversions/sources/mesh.py +10 -5
  41. bioversions/sources/mgi.py +0 -2
  42. bioversions/sources/mirbase.py +13 -8
  43. bioversions/sources/moalmanac.py +0 -2
  44. bioversions/sources/msigdb.py +0 -2
  45. bioversions/sources/ncit.py +1 -4
  46. bioversions/sources/npass.py +0 -2
  47. bioversions/sources/obo.py +4 -6
  48. bioversions/sources/ols.py +6 -8
  49. bioversions/sources/omim.py +5 -6
  50. bioversions/sources/oncotree.py +4 -4
  51. bioversions/sources/pathbank.py +0 -2
  52. bioversions/sources/pathwaycommons.py +0 -2
  53. bioversions/sources/pfam.py +0 -2
  54. bioversions/sources/pombase.py +0 -2
  55. bioversions/sources/pr.py +1 -3
  56. bioversions/sources/pubchem.py +0 -2
  57. bioversions/sources/reactome.py +0 -2
  58. bioversions/sources/rfam.py +0 -2
  59. bioversions/sources/rgd.py +1 -3
  60. bioversions/sources/rhea.py +0 -2
  61. bioversions/sources/rxnorm.py +0 -2
  62. bioversions/sources/sgd.py +0 -2
  63. bioversions/sources/signor.py +36 -0
  64. bioversions/sources/slm.py +4 -3
  65. bioversions/sources/stringdb.py +2 -4
  66. bioversions/sources/umls.py +0 -2
  67. bioversions/sources/uniprot.py +1 -3
  68. bioversions/sources/unversioned.py +0 -2
  69. bioversions/sources/wikipathways.py +0 -2
  70. bioversions/sources/zfin.py +0 -2
  71. bioversions/templates/base.html +28 -0
  72. bioversions/templates/home.html +60 -0
  73. bioversions/twitter_client.py +5 -8
  74. bioversions/utils.py +30 -31
  75. bioversions/version.py +3 -5
  76. bioversions/wsgi.py +2 -4
  77. bioversions-0.7.2.dist-info/METADATA +393 -0
  78. bioversions-0.7.2.dist-info/RECORD +81 -0
  79. bioversions-0.7.2.dist-info/WHEEL +4 -0
  80. {bioversions-0.5.376.dist-info → bioversions-0.7.2.dist-info}/entry_points.txt +1 -0
  81. {bioversions-0.5.376.dist-info → bioversions-0.7.2.dist-info/licenses}/LICENSE +1 -1
  82. bioversions-0.5.376.dist-info/METADATA +0 -166
  83. bioversions-0.5.376.dist-info/RECORD +0 -77
  84. bioversions-0.5.376.dist-info/WHEEL +0 -5
  85. bioversions-0.5.376.dist-info/top_level.txt +0 -1
@@ -1,10 +1,7 @@
1
- # -*- coding: utf-8 -*-
2
-
3
1
  """Utilities for interacting with Slack."""
4
2
 
5
3
  import logging
6
4
  from functools import lru_cache
7
- from typing import Optional
8
5
 
9
6
  import pystow
10
7
  from slack_sdk import WebClient
@@ -18,14 +15,14 @@ logger = logging.getLogger(__name__)
18
15
 
19
16
 
20
17
  @lru_cache(maxsize=1)
21
- def _get_client(token: Optional[str] = None) -> Optional[WebClient]:
18
+ def _get_client(token: str | None = None) -> WebClient | None:
22
19
  token = pystow.get_config("bioversions", "slack_api_token", passthrough=token)
23
20
  if token is None:
24
21
  return None
25
22
  return WebClient(token=token)
26
23
 
27
24
 
28
- def post(text: str, channel: str = "random", token: Optional[str] = None):
25
+ def post(text: str, channel: str = "random", token: str | None = None):
29
26
  """Post the message to a given Slack channel."""
30
27
  client = _get_client(token)
31
28
  if client is None:
@@ -1,11 +1,13 @@
1
- # -*- coding: utf-8 -*-
2
-
3
1
  """Sources for Bioversions."""
4
2
 
3
+ from __future__ import annotations
4
+
5
5
  import ftplib
6
6
  import logging
7
+ import traceback
8
+ from collections.abc import Iterable, Mapping
7
9
  from functools import lru_cache
8
- from typing import Iterable, List, Mapping, Optional, Tuple, Type, Union
10
+ from typing import NamedTuple
9
11
 
10
12
  from tqdm import tqdm
11
13
 
@@ -27,6 +29,7 @@ from .drugcentral import DrugCentralGetter
27
29
  from .ensembl import EnsemblGetter
28
30
  from .expasy import ExPASyGetter
29
31
  from .flybase import FlybaseGetter
32
+ from .gtdb import GTDBGetter
30
33
  from .guidetopharmacology import GuideToPharmacologyGetter
31
34
  from .hgnc import HGNCGetter
32
35
  from .homologene import HomoloGeneGetter
@@ -60,6 +63,7 @@ from .rgd import RGDGetter
60
63
  from .rhea import RheaGetter
61
64
  from .rxnorm import RxNormGetter
62
65
  from .sgd import SgdGetter
66
+ from .signor import SignorGetter
63
67
  from .slm import SwissLipidGetter
64
68
  from .stringdb import StringDBGetter
65
69
  from .umls import UMLSGetter
@@ -69,19 +73,19 @@ from .zfin import ZfinGetter
69
73
  from ..utils import Bioversion, Getter, norm, refresh_daily
70
74
 
71
75
  __all__ = [
72
- "resolve",
73
76
  "get_rows",
74
77
  "get_version",
78
+ "resolve",
75
79
  ]
76
80
 
77
81
  logger = logging.getLogger(__name__)
78
82
 
79
83
 
80
84
  @lru_cache(maxsize=1)
81
- def get_getters() -> List[Type[Getter]]:
85
+ def get_getters() -> list[type[Getter]]:
82
86
  """Get a list of getters."""
83
87
  # TODO replace with entrypoint lookup
84
- getters: List[Type[Getter]] = [
88
+ getters: list[type[Getter]] = [
85
89
  BioGRIDGetter,
86
90
  ChEMBLGetter,
87
91
  ComplexPortalGetter,
@@ -137,6 +141,8 @@ def get_getters() -> List[Type[Getter]]:
137
141
  ICD10Getter,
138
142
  ICD11Getter,
139
143
  CiVICGetter,
144
+ GTDBGetter,
145
+ SignorGetter,
140
146
  ]
141
147
  getters.extend(iter_obo_getters())
142
148
  extend_ols_getters(getters)
@@ -144,7 +150,7 @@ def get_getters() -> List[Type[Getter]]:
144
150
  return getters
145
151
 
146
152
 
147
- def get_getter_dict() -> Mapping[str, Type[Getter]]:
153
+ def get_getter_dict() -> Mapping[str, type[Getter]]:
148
154
  """Get a dict of getters."""
149
155
  rv = {}
150
156
  for getter in get_getters():
@@ -174,7 +180,7 @@ def _resolve_helper_cached(name: str) -> Bioversion:
174
180
 
175
181
  def _resolve_helper(name: str) -> Bioversion:
176
182
  norm_name = norm(name)
177
- getter: Type[Getter] = get_getter_dict()[norm_name]
183
+ getter: type[Getter] = get_getter_dict()[norm_name]
178
184
  return getter.resolve()
179
185
 
180
186
 
@@ -183,31 +189,40 @@ def get_version(name: str) -> str:
183
189
  return resolve(name).version
184
190
 
185
191
 
186
- def get_rows(use_tqdm: Optional[bool] = False) -> List[Bioversion]:
192
+ def get_rows(use_tqdm: bool | None = False) -> list[Bioversion]:
187
193
  """Get the rows, refreshing once per day."""
188
194
  return [
189
195
  bioversion
190
- for bioversion, error in _iter_versions(use_tqdm=use_tqdm)
191
- if error is None and bioversion is not None
196
+ for bioversion in _iter_versions(use_tqdm=use_tqdm)
197
+ if isinstance(bioversion, Bioversion)
192
198
  ]
193
199
 
194
200
 
201
+ class FailureTuple(NamedTuple):
202
+ """Holds information about failures."""
203
+
204
+ name: str
205
+ clstype: str
206
+ message: str
207
+ trace: str
208
+
209
+
195
210
  def _iter_versions(
196
- use_tqdm: Optional[bool] = False,
197
- ) -> Iterable[Union[Tuple[Bioversion, None], Tuple[None, str]]]:
211
+ use_tqdm: bool | None = False,
212
+ ) -> Iterable[Bioversion | FailureTuple]:
198
213
  it = tqdm(get_getters(), disable=not use_tqdm)
199
214
 
200
215
  for cls in it:
201
216
  it.set_postfix(name=cls.name)
202
217
  try:
203
218
  yv = resolve(cls.name)
204
- except (IOError, AttributeError, ftplib.error_perm):
219
+ except (OSError, AttributeError, ftplib.error_perm):
205
220
  msg = f"failed to resolve {cls.name}"
206
221
  tqdm.write(msg)
207
- yield None, msg
222
+ yield FailureTuple(cls.name, cls.__name__, msg, traceback.format_exc())
208
223
  except ValueError as e:
209
224
  msg = f"issue parsing {cls.name}: {e}"
210
225
  tqdm.write(msg)
211
- yield None, msg
226
+ yield FailureTuple(cls.name, cls.__name__, msg, traceback.format_exc())
212
227
  else:
213
- yield yv, None
228
+ yield yv
@@ -1,13 +1,15 @@
1
- # -*- coding: utf-8 -*-
2
-
3
1
  """A getter for the Antibody Registry."""
4
2
 
5
- from bioversions.utils import Getter, VersionType, get_soup
3
+ import requests
4
+
5
+ from bioversions.utils import Getter, VersionType
6
6
 
7
7
  __all__ = [
8
8
  "AntibodyRegistryGetter",
9
9
  ]
10
10
 
11
+ URL = "https://www.antibodyregistry.org/api/datainfo"
12
+
11
13
 
12
14
  class AntibodyRegistryGetter(Getter):
13
15
  """A getter for the Antibody Registry."""
@@ -15,12 +17,13 @@ class AntibodyRegistryGetter(Getter):
15
17
  bioregistry_id = "antibodyregistry"
16
18
  name = "Antibody Registry"
17
19
  homepage_fmt = "https://antibodyregistry.org/"
18
- version_type = VersionType.semver_minor
20
+ version_type = VersionType.date
19
21
 
20
22
  def get(self):
21
23
  """Get the latest Antibody Registry version number."""
22
- soup = get_soup("https://antibodyregistry.org/")
23
- return soup.find(**{"class": "footer"}).find("a").text.lstrip("v")
24
+ res = requests.get(URL, timeout=3)
25
+ res_json = res.json()
26
+ return res_json["lastupdate"]
24
27
 
25
28
 
26
29
  if __name__ == "__main__":
@@ -1,5 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
-
3
1
  """A getter for BiGG."""
4
2
 
5
3
  from datetime import datetime
@@ -23,12 +21,12 @@ class BiGGGetter(Getter):
23
21
 
24
22
  def get(self):
25
23
  """Get the latest BiGG version number."""
26
- res = requests.get(URL).json()
24
+ res = requests.get(URL, timeout=15).json()
27
25
  date = datetime.fromisoformat(res["last_updated"])
28
- return dict(
29
- version=res["bigg_models_version"],
30
- date=date,
31
- )
26
+ return {
27
+ "version": res["bigg_models_version"],
28
+ "date": date,
29
+ }
32
30
 
33
31
 
34
32
  if __name__ == "__main__":
@@ -1,5 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
-
3
1
  """A getter for BioGRID."""
4
2
 
5
3
  from ..utils import Getter, VersionType, get_soup
@@ -1,5 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
-
3
1
  """A getter for Cellosaurus."""
4
2
 
5
3
  import requests
@@ -24,15 +22,15 @@ class CellosaurusGetter(Getter):
24
22
  # 12:15:2022 12:00
25
23
  def get(self):
26
24
  """Get the latest Cellosaurus version number."""
27
- res = requests.get(URL, stream=True)
25
+ res = requests.get(URL, stream=True, timeout=15)
28
26
  data = {}
29
27
  for line in res.iter_lines(decode_unicode=True):
30
28
  line = line.strip().decode("utf8")
31
29
  if not line:
32
30
  break
33
- key, value = [part.strip() for part in line.split(":", 1)]
31
+ key, value = (part.strip() for part in line.split(":", 1))
34
32
  data[key] = value
35
- return dict(version=data["data-version"], date=data["date"])
33
+ return {"version": data["data-version"], "date": data["date"]}
36
34
 
37
35
 
38
36
  if __name__ == "__main__":
@@ -1,5 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
-
3
1
  """A getter for ChEBI."""
4
2
 
5
3
  from bioversions.utils import Getter, VersionType, get_soup
@@ -27,7 +25,7 @@ class ChEBIGetter(Getter):
27
25
  last = list(anchors)[-1]
28
26
  date = last.next_sibling.strip().split()[0]
29
27
  version = last.text.rstrip("/")[len("rel") :]
30
- return dict(version=version, date=date)
28
+ return {"version": version, "date": date}
31
29
 
32
30
 
33
31
  if __name__ == "__main__":
@@ -1,9 +1,8 @@
1
- # -*- coding: utf-8 -*-
2
-
3
1
  """A getter for ChEMBL."""
4
2
 
5
3
  import ftplib
6
4
  import io
5
+ from typing import ClassVar
7
6
 
8
7
  from bioversions.utils import Getter, VersionType
9
8
 
@@ -23,7 +22,7 @@ class ChEMBLGetter(Getter):
23
22
  homepage_fmt = "ftp://ftp.ebi.ac.uk/pub/databases/chembl/ChEMBLdb/releases/chembl_{version}"
24
23
  date_fmt = "%d/%m/%Y"
25
24
  version_type = VersionType.sequential
26
- collection = ["chembl", "chembl.target", "chembl.compound", "chembl.cell"]
25
+ collection: ClassVar[list[str]] = ["chembl", "chembl.target", "chembl.compound", "chembl.cell"]
27
26
 
28
27
  def get(self):
29
28
  """Get the latest ChEMBL version number."""
@@ -40,7 +39,7 @@ class ChEMBLGetter(Getter):
40
39
  date = _removeprefix(line, DATE_PREFIX).strip()
41
40
  if version is None or date is None:
42
41
  raise ValueError
43
- return dict(date=date, version=version)
42
+ return {"date": date, "version": version}
44
43
 
45
44
 
46
45
  def _removeprefix(s, prefix):
@@ -1,5 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
-
3
1
  """A getter for ChemIDplus."""
4
2
 
5
3
  import re
@@ -26,7 +24,7 @@ class ChemIDplusGetter(Getter):
26
24
  """Get the latest ChemIDplus version number."""
27
25
  latest_url = "https://ftp.nlm.nih.gov/projects/chemidlease/CurrentChemID.xml"
28
26
  headers = {"Range": "bytes=0-300"} # leave some slack to capture date
29
- r = requests.get(latest_url, headers=headers)
27
+ r = requests.get(latest_url, headers=headers, timeout=15)
30
28
  if r.status_code == 206:
31
29
  result = re.search(r" date=\"([0-9]{4}-[0-9]{2}-[0-9]{2})\">", r.text)
32
30
  if result:
@@ -1,5 +1,8 @@
1
1
  """Get the version for CiVIC."""
2
2
 
3
+ import datetime
4
+ from typing import ClassVar
5
+
3
6
  import requests
4
7
 
5
8
  from bioversions.utils import Getter, VersionType
@@ -17,6 +20,7 @@ query dataReleases {
17
20
  }
18
21
  }
19
22
  """
23
+
20
24
  # see https://griffithlab.github.io/civic-v2/#query-dataReleases
21
25
  # and https://griffithlab.github.io/civic-v2/#definition-DownloadableFile
22
26
 
@@ -28,13 +32,14 @@ class CiVICGetter(Getter):
28
32
  date_fmt = "%d-%b-%Y"
29
33
  version_type = VersionType.date
30
34
  homepage = "https://civicdb.org"
31
- collection = ["civic.gid", "civic.eid"]
35
+ collection: ClassVar[list[str]] = ["civic.gid", "civic.eid"]
32
36
 
33
- def get(self):
37
+ def get(self) -> datetime.datetime:
34
38
  """Get the latest ChEMBL version number."""
35
- res = requests.post(API, json={"query": GRAPHQL_QUERY})
39
+ res = requests.post(API, json={"query": GRAPHQL_QUERY}, timeout=15)
36
40
  # 0 element is always nightly, 1 is latest
37
- return res.json()["data"]["dataReleases"][1]["name"]
41
+ value = res.json()["data"]["dataReleases"][1]["name"]
42
+ return datetime.datetime.strptime(value, "%d-%b-%Y")
38
43
 
39
44
 
40
45
  if __name__ == "__main__":
@@ -1,5 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
-
3
1
  """A getter for Complex Portal."""
4
2
 
5
3
  from bioversions.utils import Getter, VersionType, _get_ftp_date_version
@@ -1,5 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
-
3
1
  """A collection of daily updated resources that aren't assigned specific versions."""
4
2
 
5
3
  from bioversions.utils import DailyGetter
@@ -1,5 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
-
3
1
  """A getter for DepMap."""
4
2
 
5
3
  import requests
@@ -21,7 +19,7 @@ class DepMapGetter(Getter):
21
19
 
22
20
  def get(self) -> str:
23
21
  """Get the latest DepMap version number."""
24
- res = requests.get(URL)
22
+ res = requests.get(URL, timeout=15)
25
23
  latest = next(release for release in res.json()["releaseData"] if release["isLatest"])
26
24
  return latest["releaseName"][len("DepMap Public ") :]
27
25
 
@@ -1,15 +1,12 @@
1
- # -*- coding: utf-8 -*-
2
-
3
1
  """A getter for the `Drug Gene Interaction Database (DGI-DB) <http://www.dgidb.org>`_."""
4
2
 
5
- import os
6
-
7
3
  import bs4
4
+ import dateutil.parser
8
5
  import requests
9
6
 
10
7
  from bioversions.utils import Getter, VersionType
11
8
 
12
- DOWNLOADS_PAGE = "https://www.dgidb.org/downloads"
9
+ GITHUB_PAGE = "https://github.com/dgidb/dgidb-v5"
13
10
 
14
11
 
15
12
  class DGIGetter(Getter):
@@ -21,14 +18,14 @@ class DGIGetter(Getter):
21
18
 
22
19
  def get(self):
23
20
  """Get the latest DGI version number."""
24
- res = requests.get(DOWNLOADS_PAGE)
25
- soup = bs4.BeautifulSoup(res.content, parser="lxml", features="lxml")
26
- cells = list(soup.select("table#tsv_downloads tbody tr:first-child td:nth-child(2) a"))
27
- if 1 != len(cells):
21
+ res = requests.get(GITHUB_PAGE, timeout=15)
22
+ soup = bs4.BeautifulSoup(res.content, features="html.parser")
23
+ time_tag = soup.find("relative-time")
24
+ if time_tag is None:
28
25
  raise ValueError
29
- cell = cells[0]
30
- href = cell["href"]
31
- version = os.path.dirname(os.path.relpath(href, "data/monthly_tsvs"))
26
+ datetime_str = time_tag.attrs["datetime"]
27
+ dt_obj = dateutil.parser.parse(datetime_str)
28
+ version = dt_obj.strftime(self.date_version_fmt)
32
29
  return version
33
30
 
34
31
 
@@ -1,5 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
-
3
1
  """A getter for DisGeNet."""
4
2
 
5
3
  import requests
@@ -22,7 +20,7 @@ class DisGeNetGetter(Getter):
22
20
 
23
21
  def get(self):
24
22
  """Get the latest DisGeNet version number."""
25
- res = requests.get(URL, params={"format": "json"})
23
+ res = requests.get(URL, params={"format": "json"}, timeout=15)
26
24
  res_json = res.json()
27
25
  version = res_json["database_version"].split()[-1].lstrip("v")
28
26
  return {
@@ -1,5 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
-
3
1
  """A getter for DrugBank."""
4
2
 
5
3
  from operator import itemgetter
@@ -26,10 +24,10 @@ class DrugBankGetter(Getter):
26
24
 
27
25
  def get(self):
28
26
  """Get the latest DrugBank version number."""
29
- res = requests.get(URL)
27
+ res = requests.get(URL, timeout=15)
30
28
  res.raise_for_status()
31
29
  latest = max(res.json(), key=itemgetter("released_on"))
32
- return dict(date=latest["released_on"], version=latest["version"])
30
+ return {"date": latest["released_on"], "version": latest["version"]}
33
31
 
34
32
  @staticmethod
35
33
  def homepage_version_transform(version: str) -> str:
@@ -1,5 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
-
3
1
  """A getter for DrugCentral."""
4
2
 
5
3
  from contextlib import closing
@@ -13,9 +11,9 @@ __all__ = [
13
11
  HOST = "unmtid-dbs.net"
14
12
  PORT = 5433
15
13
  USER = "drugman"
16
- PASSWORD = "dosage"
14
+ PASSWORD = "dosage" # noqa:S105
17
15
  DBNAME = "drugcentral"
18
- PARAMS = dict(dbname=DBNAME, user=USER, password=PASSWORD, host=HOST, port=PORT)
16
+ PARAMS = {"dbname": DBNAME, "user": USER, "password": PASSWORD, "host": HOST, "port": PORT}
19
17
 
20
18
 
21
19
  class DrugCentralGetter(Getter):
@@ -1,5 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
-
3
1
  """A getter for Ensembl."""
4
2
 
5
3
  from bioversions.utils import Getter, VersionType, get_soup
@@ -25,7 +23,7 @@ class EnsemblGetter(Getter):
25
23
  soup = get_soup(URL)
26
24
  manifest = soup.find(**{"class": "box-header"}).text
27
25
  version, date = manifest.rstrip(")").split("(", 1)
28
- return dict(version=version.split()[-1], date=date)
26
+ return {"version": version.split()[-1], "date": date}
29
27
 
30
28
 
31
29
  if __name__ == "__main__":
@@ -1,5 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
-
3
1
  """A getter for ExPASy."""
4
2
 
5
3
  from datetime import datetime
@@ -12,7 +10,7 @@ __all__ = [
12
10
  "ExPASyGetter",
13
11
  ]
14
12
 
15
- URL = "ftp://ftp.expasy.org/databases/enzyme/enzuser.txt"
13
+ URL = "https://ftp.expasy.org/databases/enzyme/enzuser.txt"
16
14
 
17
15
 
18
16
  class ExPASyGetter(Getter):
@@ -20,7 +18,6 @@ class ExPASyGetter(Getter):
20
18
 
21
19
  bioregistry_id = "eccode"
22
20
  name = "ExPASy"
23
- # date_version_fmt = "%d-%b-%Y"
24
21
  version_type = VersionType.date
25
22
 
26
23
  def get(self) -> str:
@@ -1,5 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
-
3
1
  """A getter for FlyBase."""
4
2
 
5
3
  import ftplib
@@ -0,0 +1,35 @@
1
+ """A getter for GTDB."""
2
+
3
+ import requests
4
+
5
+ from bioversions.utils import Getter, VersionType
6
+
7
+ __all__ = [
8
+ "GTDBGetter",
9
+ ]
10
+
11
+ URL = "https://data.gtdb.ecogenomic.org/releases/latest/VERSION.txt"
12
+
13
+
14
+ class GTDBGetter(Getter):
15
+ """A getter for the Genome Taxonomy Database (GTDB)."""
16
+
17
+ bioregistry_id = "gtdb"
18
+ name = "Genome Taxonomy Database"
19
+ version_type = VersionType.sequential
20
+ date_fmt = "%b %d, %Y" # Format to match "Apr 24, 2024"
21
+ homepage_fmt = "https://gtdb.ecogenomic.org/"
22
+
23
+ def get(self):
24
+ """Get the latest GTDB version number from VERSION.txt."""
25
+ res = requests.get(URL, timeout=15)
26
+ lines = res.text.strip().split("\n")
27
+ # First line contains version like "v220"
28
+ version = lines[0].strip().lstrip("v")
29
+ # Third line contains date like "Released Apr 24, 2024"
30
+ date = lines[2].strip().removeprefix("Released ")
31
+ return {"version": version, "date": date}
32
+
33
+
34
+ if __name__ == "__main__":
35
+ GTDBGetter.print()
@@ -1,10 +1,8 @@
1
- # -*- coding: utf-8 -*-
2
-
3
1
  """A getter for GuideToPharmacology."""
4
2
 
5
3
  import re
6
4
  from datetime import datetime
7
- from typing import Dict
5
+ from typing import ClassVar
8
6
 
9
7
  from bioversions.utils import Getter, VersionType, get_soup
10
8
 
@@ -23,9 +21,9 @@ class GuideToPharmacologyGetter(Getter):
23
21
  homepage_fmt = "https://www.guidetopharmacology.org/DATA/public_iuphardb_v{version}.zip"
24
22
  date_fmt = "%Y-%m-%d"
25
23
  version_type = VersionType.year_minor
26
- collection = ["iuphar.family", "iuphar.ligand", "iuphar.receptor"]
24
+ collection: ClassVar[list[str]] = ["iuphar.family", "iuphar.ligand", "iuphar.receptor"]
27
25
 
28
- def get(self) -> Dict[str, str]:
26
+ def get(self) -> dict[str, str]:
29
27
  """Get the latest Guide to Pharmacology version number."""
30
28
  soup = get_soup(URL)
31
29
  text = soup.findAll("div", {"class": "contentboxfullhelp"})[4].div.ul.li.a.text
@@ -1,10 +1,10 @@
1
- # -*- coding: utf-8 -*-
2
-
3
1
  """A getter for HGNC."""
4
2
 
5
3
  import logging
6
4
 
7
- from bioversions.utils import Getter, VersionType, get_soup
5
+ import requests
6
+
7
+ from bioversions.utils import Getter, VersionType
8
8
 
9
9
  __all__ = [
10
10
  "HGNCGetter",
@@ -12,8 +12,9 @@ __all__ = [
12
12
 
13
13
  logger = logging.getLogger(__name__)
14
14
 
15
- PATH = "https://ftp.ebi.ac.uk/pub/databases/genenames/new/archive/monthly/json/"
16
- PREFIX = "hgnc_complete_set_"
15
+ PATH = "https://storage.googleapis.com/public-download-files/hgnc/archive/archive/monthly/json/"
16
+ URL = "https://storage.googleapis.com/storage/v1/b/public-download-files/o?prefix=hgnc/archive/archive/monthly"
17
+ PREFIX = "hgnc/archive/archive/monthly/json/hgnc_complete_set_"
17
18
  SUFFIX = ".json"
18
19
 
19
20
 
@@ -22,20 +23,18 @@ class HGNCGetter(Getter):
22
23
 
23
24
  bioregistry_id = "hgnc"
24
25
  name = "HGNC"
25
- homepage_fmt = (
26
- "http://ftp.ebi.ac.uk/pub/databases/genenames/hgnc/"
27
- "archive/monthly/json/hgnc_complete_set_{version}.json"
28
- )
26
+ homepage_fmt = PATH + "hgnc_complete_set_{version}.json"
29
27
 
30
28
  version_type = VersionType.date
31
29
 
32
30
  def get(self) -> str:
33
- """Get the latest HGNC version number."""
34
- soup = get_soup(PATH)
31
+ """Get the latest monthly HGNC version number."""
32
+ res = requests.get(URL, timeout=5)
33
+ items = res.json()["items"]
35
34
  return max(
36
- anchor.attrs["href"][len(PREFIX) : -len(SUFFIX)]
37
- for anchor in soup.find_all("a")
38
- if anchor.attrs["href"].startswith(PREFIX)
35
+ item["name"].removeprefix(PREFIX).removesuffix(SUFFIX)
36
+ for item in items
37
+ if (name := item["name"]).startswith(PREFIX) and name.endswith(SUFFIX)
39
38
  )
40
39
 
41
40
 
@@ -1,5 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
-
3
1
  """A getter for HomoloGene."""
4
2
 
5
3
  import requests
@@ -1,5 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
-
3
1
  """A getter for ICD10."""
4
2
 
5
3
  import requests
@@ -23,7 +21,7 @@ class ICD10Getter(Getter):
23
21
 
24
22
  def get(self) -> str:
25
23
  """Get the latest ICD10 version number."""
26
- response = requests.get(URL, allow_redirects=True)
24
+ response = requests.get(URL, allow_redirects=True, timeout=15)
27
25
  final_url = response.url
28
26
  return final_url[len("https://icd.who.int/browse10/") :].split("/")[0]
29
27