bioversions 0.7.40__py3-none-any.whl → 0.7.42__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.
bioversions/__main__.py CHANGED
@@ -1,4 +1,4 @@
1
- """Command line interface for bioversions."""
1
+ """Entrypoint module, in case you use `python -m bioversions`."""
2
2
 
3
3
  from .cli import main
4
4
 
bioversions/charts.py CHANGED
@@ -13,13 +13,13 @@ from bioversions.utils import IMG, VersionType
13
13
  sns.set(style="whitegrid")
14
14
 
15
15
 
16
- def version_types_pie_chart():
16
+ def version_types_pie_chart() -> None:
17
17
  """Make a pie chart with types of versions."""
18
- counts = Counter(
18
+ counter = Counter(
19
19
  "Missing" if getter.version_type is None else getter.version_type.value
20
20
  for getter in get_getters()
21
21
  )
22
- labels, counts = zip(*counts.most_common(), strict=False)
22
+ labels, counts = zip(*counter.most_common(), strict=False)
23
23
  fig, ax = plt.subplots()
24
24
  ax.pie(
25
25
  counts,
@@ -34,14 +34,14 @@ def version_types_pie_chart():
34
34
  plt.close(fig)
35
35
 
36
36
 
37
- def verioning_date_formats_pie_chart():
37
+ def verioning_date_formats_pie_chart() -> None:
38
38
  """Make a pie chart with types of date/month versions."""
39
- counts = Counter(
39
+ counter = Counter(
40
40
  getter.date_version_fmt
41
41
  for getter in get_getters()
42
42
  if getter.version_type in {VersionType.date, VersionType.month}
43
43
  )
44
- labels, counts = zip(*counts.most_common(), strict=False)
44
+ labels, counts = zip(*counter.most_common(), strict=False)
45
45
  fig, ax = plt.subplots()
46
46
  ax.pie(
47
47
  counts,
@@ -56,14 +56,14 @@ def verioning_date_formats_pie_chart():
56
56
  plt.close(fig)
57
57
 
58
58
 
59
- def has_release_url():
59
+ def has_release_url() -> None:
60
60
  """Make a pie chart for how many have a release URL."""
61
- counts = Counter(
61
+ counter = Counter(
62
62
  "Has Stable Version URL" if getter.homepage_fmt is not None else "No Stable Version URL"
63
63
  for getter in get_getters()
64
64
  if getter.version_type != VersionType.unversioned
65
65
  )
66
- labels, counts = zip(*counts.most_common(), strict=False)
66
+ labels, counts = zip(*counter.most_common(), strict=False)
67
67
  fig, ax = plt.subplots()
68
68
  ax.pie(
69
69
  counts,
@@ -79,7 +79,7 @@ def has_release_url():
79
79
 
80
80
 
81
81
  @click.command()
82
- def charts():
82
+ def charts() -> None:
83
83
  """Generate charts for bioversions."""
84
84
  version_types_pie_chart()
85
85
  verioning_date_formats_pie_chart()
bioversions/cli.py CHANGED
@@ -1,4 +1,4 @@
1
- """Command line interface for bioversions."""
1
+ """Command line interface for :mod:`bioversions`."""
2
2
 
3
3
  import click
4
4
  from click_default_group import DefaultGroup
@@ -10,7 +10,7 @@ from bioversions.resources.update import update
10
10
 
11
11
  @click.group(cls=DefaultGroup, default="web", default_if_no_args=True)
12
12
  @click.version_option()
13
- def main():
13
+ def main() -> None:
14
14
  """The bioversions CLI.""" # noqa:D401
15
15
 
16
16
 
@@ -25,19 +25,19 @@ web = make_web_command(
25
25
  )
26
26
 
27
27
 
28
- @main.command()
28
+ @main.command() # type:ignore
29
29
  @click.argument("key")
30
- @verbose_option
31
- def get(key: str):
30
+ @verbose_option # type:ignore
31
+ def get(key: str) -> None:
32
32
  """Print the version."""
33
33
  from . import get_version
34
34
 
35
35
  click.echo(get_version(key))
36
36
 
37
37
 
38
- @main.command()
38
+ @main.command() # type:ignore
39
39
  @click.option("--terse", "-t", is_flag=True)
40
- def ls(terse: bool):
40
+ def ls(terse: bool) -> None:
41
41
  """List versions."""
42
42
  from . import get_rows
43
43
 
@@ -29,7 +29,7 @@ def _get_clean_dict(d):
29
29
 
30
30
  @click.command()
31
31
  @click.option("--force", is_flag=True)
32
- def update(force: bool):
32
+ def update(force: bool) -> None:
33
33
  """Update the data file."""
34
34
  with logging_redirect_tqdm():
35
35
  _update(force=force)
@@ -123,13 +123,6 @@ def _log_update(bv) -> None:
123
123
  else:
124
124
  slack_client.post(text)
125
125
 
126
- try:
127
- from .. import twitter_client
128
- except ImportError:
129
- pass
130
- else:
131
- twitter_client.post(text)
132
-
133
126
 
134
127
  if __name__ == "__main__":
135
128
  update()
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "annotations": {
3
- "revision": 941,
4
- "date": "2025-03-06",
3
+ "revision": 943,
4
+ "date": "2025-03-21",
5
5
  "author": "runner"
6
6
  },
7
7
  "database": [
@@ -334,6 +334,16 @@
334
334
  "retrieved": "2025-03-05",
335
335
  "version": "2025-03-05",
336
336
  "homepage": "https://antibodyregistry.org/"
337
+ },
338
+ {
339
+ "retrieved": "2025-03-20",
340
+ "version": "2025-03-19",
341
+ "homepage": "https://antibodyregistry.org/"
342
+ },
343
+ {
344
+ "retrieved": "2025-03-21",
345
+ "version": "2025-03-20",
346
+ "homepage": "https://antibodyregistry.org/"
337
347
  }
338
348
  ],
339
349
  "name": "Antibody Registry",
@@ -2190,6 +2200,10 @@
2190
2200
  {
2191
2201
  "retrieved": "2025-02-27",
2192
2202
  "version": "2.238"
2203
+ },
2204
+ {
2205
+ "retrieved": "2025-03-20",
2206
+ "version": "2.239"
2193
2207
  }
2194
2208
  ],
2195
2209
  "vtype": "date"
@@ -4095,7 +4109,7 @@
4095
4109
  },
4096
4110
  {
4097
4111
  "name": "ExPASy",
4098
- "prefix": "eccode",
4112
+ "prefix": "ec",
4099
4113
  "releases": [
4100
4114
  {
4101
4115
  "retrieved": "2021-01-02",
@@ -4342,6 +4356,10 @@
4342
4356
  {
4343
4357
  "retrieved": "2025-02-27",
4344
4358
  "version": "4.195"
4359
+ },
4360
+ {
4361
+ "retrieved": "2025-03-20",
4362
+ "version": "4.196"
4345
4363
  }
4346
4364
  ],
4347
4365
  "vtype": "date"
@@ -4853,6 +4871,10 @@
4853
4871
  {
4854
4872
  "retrieved": "2025-01-28",
4855
4873
  "version": "2025-01-14"
4874
+ },
4875
+ {
4876
+ "retrieved": "2025-03-20",
4877
+ "version": "2025-02-28"
4856
4878
  }
4857
4879
  ],
4858
4880
  "vtype": "date"
@@ -4988,7 +5010,7 @@
4988
5010
  ],
4989
5011
  "name": "FlyBase",
4990
5012
  "prefix": "flybase",
4991
- "vtype": "date"
5013
+ "vtype": "month"
4992
5014
  },
4993
5015
  {
4994
5016
  "releases": [
@@ -5909,6 +5931,11 @@
5909
5931
  "retrieved": "2025-02-12",
5910
5932
  "version": "2025-02-04",
5911
5933
  "homepage": "https://storage.googleapis.com/public-download-files/hgnc/archive/archive/monthly/json/hgnc_complete_set_2025-02-04.json"
5934
+ },
5935
+ {
5936
+ "retrieved": "2025-03-20",
5937
+ "version": "2025-03-04",
5938
+ "homepage": "https://storage.googleapis.com/public-download-files/hgnc/archive/archive/monthly/json/hgnc_complete_set_2025-03-04.json"
5912
5939
  }
5913
5940
  ],
5914
5941
  "name": "HGNC",
@@ -5999,6 +6026,10 @@
5999
6026
  {
6000
6027
  "retrieved": "2024-09-01",
6001
6028
  "version": "2024-08-19"
6029
+ },
6030
+ {
6031
+ "retrieved": "2025-03-20",
6032
+ "version": "2025-02-24"
6002
6033
  }
6003
6034
  ],
6004
6035
  "vtype": "semver"
@@ -7231,6 +7262,10 @@
7231
7262
  {
7232
7263
  "retrieved": "2025-02-27",
7233
7264
  "version": "4.1.190"
7265
+ },
7266
+ {
7267
+ "retrieved": "2025-03-20",
7268
+ "version": "4.1.191"
7234
7269
  }
7235
7270
  ],
7236
7271
  "name": "Mass spectrometry ontology",
@@ -7928,6 +7963,12 @@
7928
7963
  "version": "2025-02-07",
7929
7964
  "homepage": "https://github.com/vanallenlab/moalmanac-db/releases/tag/v.2025-02-07",
7930
7965
  "date": "2025-02-07"
7966
+ },
7967
+ {
7968
+ "retrieved": "2025-03-20",
7969
+ "version": "2025-03-06",
7970
+ "homepage": "https://github.com/vanallenlab/moalmanac-db/releases/tag/v.2025-03-06",
7971
+ "date": "2025-03-06"
7931
7972
  }
7932
7973
  ],
7933
7974
  "name": "Molecular Oncology Almanac",
@@ -8529,6 +8570,11 @@
8529
8570
  "retrieved": "2024-12-12",
8530
8571
  "version": "24.11d",
8531
8572
  "date": "2024-11-25"
8573
+ },
8574
+ {
8575
+ "retrieved": "2025-03-20",
8576
+ "version": "25.03c",
8577
+ "date": "2025-03-17"
8532
8578
  }
8533
8579
  ],
8534
8580
  "name": "National Cancer Institute Thesaurus",
@@ -9899,6 +9945,14 @@
9899
9945
  {
9900
9946
  "retrieved": "2025-03-06",
9901
9947
  "version": "2025-03-04"
9948
+ },
9949
+ {
9950
+ "retrieved": "2025-03-20",
9951
+ "version": "2025-03-18"
9952
+ },
9953
+ {
9954
+ "retrieved": "2025-03-21",
9955
+ "version": "2025-03-19"
9902
9956
  }
9903
9957
  ],
9904
9958
  "name": "Online Mendelian Inheritance in Man",
@@ -10753,6 +10807,10 @@
10753
10807
  {
10754
10808
  "retrieved": "2025-02-27",
10755
10809
  "version": "2.0.58"
10810
+ },
10811
+ {
10812
+ "retrieved": "2025-03-20",
10813
+ "version": "2.0.59"
10756
10814
  }
10757
10815
  ],
10758
10816
  "name": "Ontology of units of Measure",
@@ -12537,6 +12595,10 @@
12537
12595
  {
12538
12596
  "retrieved": "2025-03-04",
12539
12597
  "version": "2025-02-28"
12598
+ },
12599
+ {
12600
+ "retrieved": "2025-03-20",
12601
+ "version": "2025-03-14"
12540
12602
  }
12541
12603
  ],
12542
12604
  "name": "Rat Genome Database",
@@ -12642,6 +12704,10 @@
12642
12704
  {
12643
12705
  "retrieved": "2025-02-27",
12644
12706
  "version": "6.242"
12707
+ },
12708
+ {
12709
+ "retrieved": "2025-03-20",
12710
+ "version": "6.243"
12645
12711
  }
12646
12712
  ],
12647
12713
  "vtype": "date"
@@ -16109,6 +16175,14 @@
16109
16175
  {
16110
16176
  "retrieved": "2025-03-06",
16111
16177
  "version": "2025-03-06"
16178
+ },
16179
+ {
16180
+ "retrieved": "2025-03-20",
16181
+ "version": "2025-03-20"
16182
+ },
16183
+ {
16184
+ "retrieved": "2025-03-21",
16185
+ "version": "2025-03-21"
16112
16186
  }
16113
16187
  ],
16114
16188
  "name": "SwissLipids",
@@ -16604,6 +16678,10 @@
16604
16678
  {
16605
16679
  "retrieved": "2025-02-27",
16606
16680
  "version": "2025-02-22"
16681
+ },
16682
+ {
16683
+ "retrieved": "2025-03-20",
16684
+ "version": "2025-02-23"
16607
16685
  }
16608
16686
  ],
16609
16687
  "name": "The Statistical Methods Ontology",
@@ -17197,6 +17275,10 @@
17197
17275
  {
17198
17276
  "retrieved": "2025-01-05",
17199
17277
  "version": "2024-12-29"
17278
+ },
17279
+ {
17280
+ "retrieved": "2025-03-20",
17281
+ "version": "2025-02-26"
17200
17282
  }
17201
17283
  ],
17202
17284
  "vtype": "semver"
@@ -17732,6 +17814,12 @@
17732
17814
  "version": "20250210",
17733
17815
  "homepage": "http://data.wikipathways.org/20250210/",
17734
17816
  "date": "2025-02-10"
17817
+ },
17818
+ {
17819
+ "retrieved": "2025-03-20",
17820
+ "version": "20250310",
17821
+ "homepage": "http://data.wikipathways.org/20250310/",
17822
+ "date": "2025-03-10"
17735
17823
  }
17736
17824
  ],
17737
17825
  "vtype": "date"
@@ -21431,6 +21519,10 @@
21431
21519
  {
21432
21520
  "retrieved": "2025-03-06",
21433
21521
  "version": "2025-03-04"
21522
+ },
21523
+ {
21524
+ "retrieved": "2025-03-20",
21525
+ "version": "2025-03-19"
21434
21526
  }
21435
21527
  ],
21436
21528
  "name": "Zebrafish Information Network",
@@ -6,6 +6,7 @@ from functools import lru_cache
6
6
  import pystow
7
7
  from slack_sdk import WebClient
8
8
  from slack_sdk.errors import SlackApiError
9
+ from slack_sdk.web import SlackResponse
9
10
 
10
11
  __all__ = [
11
12
  "post",
@@ -22,7 +23,7 @@ def _get_client(token: str | None = None) -> WebClient | None:
22
23
  return WebClient(token=token)
23
24
 
24
25
 
25
- def post(text: str, channel: str = "random", token: str | None = None):
26
+ def post(text: str, channel: str = "random", token: str | None = None) -> SlackResponse | None:
26
27
  """Post the message to a given Slack channel."""
27
28
  client = _get_client(token)
28
29
  if client is None:
@@ -40,6 +41,7 @@ def post(text: str, channel: str = "random", token: str | None = None):
40
41
  if not e.response["ok"]:
41
42
  raise ValueError('Response is not "ok"') from e
42
43
  logger.warning(f"Got an error: {e.response['error']}")
44
+ return None
43
45
  else:
44
46
  return response
45
47
 
@@ -7,7 +7,7 @@ import logging
7
7
  import traceback
8
8
  from collections.abc import Iterable, Mapping
9
9
  from functools import lru_cache
10
- from typing import NamedTuple
10
+ from typing import Literal, NamedTuple, overload
11
11
 
12
12
  from tqdm import tqdm
13
13
 
@@ -186,9 +186,35 @@ def _resolve_helper(name: str) -> Bioversion:
186
186
  return getter.resolve()
187
187
 
188
188
 
189
- def get_version(name: str) -> str:
190
- """Resolve a database name to its version string."""
191
- return resolve(name).version
189
+ # docstr-coverage:excused `overload`
190
+ @overload
191
+ def get_version(name: str, *, strict: Literal[True] = True) -> str: ...
192
+
193
+
194
+ # docstr-coverage:excused `overload`
195
+ @overload
196
+ def get_version(name: str, *, strict: Literal[False] = False) -> str | None: ...
197
+
198
+
199
+ def get_version(name: str, *, strict: bool = True) -> str | None:
200
+ """Resolve a database name to its version string.
201
+
202
+ :param name:
203
+ The name of the resource to get the version from. Often, this is a Bioregistry
204
+ prefix, but sometimes can be an ad-hoc key for a database.
205
+ :param strict:
206
+ Re-raises errors in version resolution by default. Set explicitly to
207
+ ``false`` to return None on errors.
208
+ :return: The version of the resource as a string
209
+ """
210
+ try:
211
+ rv = resolve(name).version
212
+ except Exception:
213
+ if strict:
214
+ raise
215
+ return None
216
+ else:
217
+ return rv
192
218
 
193
219
 
194
220
  def get_rows(use_tqdm: bool | None = False) -> list[Bioversion]:
@@ -1,6 +1,6 @@
1
1
  """A getter for BioGRID."""
2
2
 
3
- from ..utils import Getter, VersionType, get_soup
3
+ from ..utils import Getter, VersionType, find, get_soup
4
4
 
5
5
  __all__ = [
6
6
  "BioGRIDGetter",
@@ -20,8 +20,8 @@ class BioGRIDGetter(Getter):
20
20
  def get(self) -> str:
21
21
  """Get the latest BioGRID version number."""
22
22
  soup = get_soup(URL)
23
- manifest = soup.find(id="manifestDesc")
24
- header = manifest.find("h2")
23
+ manifest = find(soup, id="manifestDesc")
24
+ header = find(manifest, "h2")
25
25
  return header.text[len("BioGRID Release ") :]
26
26
 
27
27
 
@@ -16,7 +16,7 @@ URL = "https://ftp.expasy.org/databases/enzyme/enzuser.txt"
16
16
  class ExPASyGetter(Getter):
17
17
  """A getter for ExPASy."""
18
18
 
19
- bioregistry_id = "eccode"
19
+ bioregistry_id = "ec"
20
20
  name = "ExPASy"
21
21
  version_type = VersionType.date
22
22
 
@@ -1,31 +1,37 @@
1
1
  """A getter for FlyBase."""
2
2
 
3
- import ftplib
3
+ import re
4
4
 
5
- from bioversions.utils import Getter, VersionType
5
+ from bioversions.utils import Getter, VersionType, get_soup
6
6
 
7
7
  __all__ = [
8
8
  "FlybaseGetter",
9
9
  ]
10
10
 
11
+ URL = "http://flybase-ftp.s3-website-us-east-1.amazonaws.com/releases/index.html"
12
+ PATTERN = re.compile(r"FB\d{4}_\d{2}")
13
+
11
14
 
12
15
  class FlybaseGetter(Getter):
13
16
  """A getter for FlyBase."""
14
17
 
15
18
  bioregistry_id = "flybase"
16
19
  name = "FlyBase"
17
- homepage_fmt = "http://ftp.flybase.net/releases/FB{version}/"
18
- version_type = VersionType.date
20
+ homepage_fmt = "http://flybase-ftp.s3-website-us-east-1.amazonaws.com/releases/FB{version}/"
21
+ version_type = VersionType.month
19
22
 
20
23
  def get(self):
21
24
  """Get the latest flybase version number."""
22
- with ftplib.FTP("ftp.flybase.net") as ftp:
23
- ftp.login()
24
- ftp.cwd("releases")
25
- for name in sorted(ftp.nlst(), reverse=True):
26
- if name.startswith("FB2"):
27
- return name[len("FB") :]
28
- raise ValueError
25
+ soup = get_soup(URL)
26
+
27
+ releases = []
28
+ # We check links to find ones that look like releases
29
+ for anchor_tag in soup.find_all("a", href=True):
30
+ match = PATTERN.search(anchor_tag.text)
31
+ if match:
32
+ releases.append(match.group().removeprefix("FB"))
33
+ latest_version = max(releases)
34
+ return latest_version
29
35
 
30
36
 
31
37
  if __name__ == "__main__":
@@ -26,7 +26,9 @@ class GuideToPharmacologyGetter(Getter):
26
26
  def get(self) -> dict[str, str]:
27
27
  """Get the latest Guide to Pharmacology version number."""
28
28
  soup = get_soup(URL)
29
- text = soup.findAll("div", {"class": "contentboxfullhelp"})[4].div.ul.li.a.text
29
+ divs = list(soup.find_all("div", {"class": "contentboxfullhelp"}))
30
+ # the type ignore is because mypy doesn't understand the attribute-based dispatch
31
+ text = divs[4].div.ul.li.a.text # type:ignore[attr-defined]
30
32
  search = RE.search(text)
31
33
  if not search:
32
34
  raise ValueError(
@@ -5,7 +5,7 @@ from typing import ClassVar
5
5
 
6
6
  import bioregistry
7
7
 
8
- from bioversions.utils import Getter, VersionType, get_soup
8
+ from bioversions.utils import Getter, VersionType, find, get_soup
9
9
 
10
10
  __all__ = [
11
11
  "KEGGGetter",
@@ -25,9 +25,12 @@ class KEGGGetter(Getter):
25
25
  def get(self) -> Mapping[str, str]:
26
26
  """Get the latest KEGG version number."""
27
27
  soup = get_soup(URL)
28
- header = soup.find("h4")
29
- sibling = header.next_sibling.strip()
30
- version, date = (part.strip() for part in sibling.split(",", 1))
28
+ header = find(soup, "h4")
29
+ sibling = header.next_sibling
30
+ if not sibling:
31
+ raise ValueError
32
+ sibling_text = sibling.text.strip()
33
+ version, date = (part.strip() for part in sibling_text.split(",", 1))
31
34
  version = version[len("Release ") :]
32
35
  return {"version": version, "date": date}
33
36
 
@@ -1,6 +1,6 @@
1
1
  """A getter for the Molecular Oncology Almanac."""
2
2
 
3
- from ..utils import Getter, VersionType, get_soup
3
+ from ..utils import Getter, VersionType, find, get_soup
4
4
 
5
5
  __all__ = [
6
6
  "MOAlmanacGetter",
@@ -18,8 +18,9 @@ class MOAlmanacGetter(Getter):
18
18
  def get(self) -> str:
19
19
  """Get the latest MOAlmanac version number."""
20
20
  soup = get_soup("https://moalmanac.org/")
21
- sub_footer = soup.find("div", {"class": "text-right"})
22
- version = sub_footer.find("a").text.strip("v").strip(".")
21
+ sub_footer = find(soup, "div", {"class": "text-right"})
22
+ anchor = find(sub_footer, "a")
23
+ version = anchor.text.strip("v").strip(".")
23
24
  return version
24
25
 
25
26
 
@@ -1,17 +1,14 @@
1
1
  """A getter for the NCI Thesaurus."""
2
2
 
3
- import re
3
+ import requests
4
4
 
5
- from ..utils import Getter, VersionType, get_soup
5
+ from ..utils import Getter, VersionType
6
6
 
7
7
  __all__ = [
8
8
  "NCItGetter",
9
9
  ]
10
10
 
11
- URL = "https://ncithesaurus.nci.nih.gov/ncitbrowser/"
12
- PATTERN = re.compile(
13
- r"Version:([0-9]{2}\.[0-9]{2}[a-z]) " r"\(Release date:([0-9]{4}-[0-9]{2}-[0-9]{2})"
14
- )
11
+ URL = "https://evsexplore.semantics.cancer.gov/evsexplore/api/v1/metadata/terminologies"
15
12
 
16
13
 
17
14
  class NCItGetter(Getter):
@@ -19,19 +16,16 @@ class NCItGetter(Getter):
19
16
 
20
17
  bioregistry_id = "ncit"
21
18
  name = "National Cancer Institute Thesaurus"
22
- date_fmt = "%Y-%m-%d"
19
+ date_fmt = "%B %d, %Y"
23
20
  version_type = VersionType.other
24
21
 
25
22
  def get(self) -> dict[str, str]:
26
23
  """Get the latest NCIt version number."""
27
- soup = get_soup(URL)
28
- version_str = soup.find("span", {"class": "vocabularynamelong_ncit"}).contents[0]
29
- match = re.search(PATTERN, version_str)
30
- if match is None:
31
- raise ValueError(f"could not parse version from {URL}")
24
+ records = requests.get(URL, timeout=5).json()
25
+ ncit_record = next(record for record in records if record["terminology"] == "ncit")
32
26
  return {
33
- "version": match.group(1),
34
- "date": match.group(2),
27
+ "version": ncit_record["version"],
28
+ "date": ncit_record["date"],
35
29
  }
36
30
 
37
31
 
@@ -1,6 +1,6 @@
1
1
  """A getter for NPASS."""
2
2
 
3
- from bioversions.utils import Getter, VersionType, get_soup
3
+ from bioversions.utils import Getter, VersionType, find, get_soup
4
4
 
5
5
  __all__ = [
6
6
  "NPASSGetter",
@@ -19,7 +19,9 @@ class NPASSGetter(Getter):
19
19
  def get(self) -> str:
20
20
  """Get the latest NPASS version number."""
21
21
  soup = get_soup(URL)
22
- for li in soup.find(name="footer").find(name="ul").findAll(name="li"):
22
+ footer = find(soup, name="footer")
23
+ ul = find(footer, name="ul")
24
+ for li in ul.find_all(name="li"):
23
25
  if li.text.startswith("Version:"):
24
26
  return li.text[len("Version: ") :]
25
27
  raise ValueError(f"could not parse NPASS version from {URL}")
@@ -1,6 +1,6 @@
1
1
  """A getter for PathBank."""
2
2
 
3
- from bioversions.utils import Getter, VersionType, get_soup
3
+ from bioversions.utils import Getter, VersionType, find, get_soup
4
4
 
5
5
  __all__ = [
6
6
  "PathBankGetter",
@@ -19,13 +19,11 @@ class PathBankGetter(Getter):
19
19
  def get(self) -> str:
20
20
  """Get the latest PathBank version number."""
21
21
  soup = get_soup(URL)
22
- version = (
23
- soup.find(id="main")
24
- .find(name="footer")
25
- .find(**{"class": "wishart-clear"})
26
- .find(name="strong")
27
- )
28
- return version.text
22
+ main = find(soup, id="main")
23
+ footer = find(main, name="footer")
24
+ clear = find(footer, **{"class": "wishart-clear"})
25
+ strong = find(clear, name="strong")
26
+ return strong.text
29
27
 
30
28
 
31
29
  if __name__ == "__main__":
@@ -1,6 +1,6 @@
1
1
  """A getter for Pathway Commons."""
2
2
 
3
- from bioversions.utils import Getter, VersionType, get_soup
3
+ from bioversions.utils import Getter, VersionType, find, get_soup
4
4
 
5
5
  __all__ = [
6
6
  "PathwayCommonsGetter",
@@ -18,10 +18,10 @@ class PathwayCommonsGetter(Getter):
18
18
  def get(self) -> str:
19
19
  """Get the latest Pathway Commons version number."""
20
20
  soup = get_soup(URL)
21
- boost = soup.find(**{"class": "boost"})
22
- boost = boost.text[len("Version ") :]
23
- boost = boost.split(":")[0]
24
- return boost
21
+ boost = find(soup, {"class": "boost"})
22
+ boost_text = boost.text[len("Version ") :]
23
+ boost_text = boost_text.split(":")[0]
24
+ return boost_text
25
25
 
26
26
 
27
27
  if __name__ == "__main__":
@@ -2,7 +2,7 @@
2
2
 
3
3
  from datetime import datetime
4
4
 
5
- from ..utils import Getter, VersionType, get_soup
5
+ from ..utils import Getter, VersionType, find, get_soup
6
6
 
7
7
  __all__ = [
8
8
  "RxNormGetter",
@@ -22,7 +22,8 @@ class RxNormGetter(Getter):
22
22
  def get(self) -> datetime:
23
23
  """Get the latest RxNorm version number."""
24
24
  soup = get_soup(URL)
25
- raw_version = soup.find("th", {"class": "current"}).contents[2].strip()
25
+ tag = find(soup, "th", {"class": "current"})
26
+ raw_version = tag.contents[2].text.strip()
26
27
  raw_fmt = "%B %d, %Y"
27
28
  return datetime.strptime(raw_version, raw_fmt)
28
29
 
@@ -1,8 +1,6 @@
1
1
  """A getter for UMLS."""
2
2
 
3
- from datetime import datetime
4
-
5
- from bioversions.utils import Getter, VersionType, get_soup
3
+ from bioversions.utils import Getter, VersionType, find, get_soup
6
4
 
7
5
  __all__ = [
8
6
  "UMLSGetter",
@@ -18,15 +16,13 @@ class UMLSGetter(Getter):
18
16
  name = "UMLS"
19
17
  version_type = VersionType.other
20
18
 
21
- def get(self) -> datetime:
19
+ def get(self) -> str:
22
20
  """Get the latest UMLS version number."""
23
21
  soup = get_soup(URL)
24
- version_tag = (
25
- soup.find("main")
26
- .find("div", {"class": "grid-row grid-gap-1"})
27
- .find("div", {"class": "tablet:grid-col-12"})
28
- .find("h2")
29
- )
22
+ main_tag = find(soup, "main")
23
+ t1 = find(main_tag, "div", {"class": "grid-row grid-gap-1"}) # type:ignore
24
+ t2 = find(t1, "div", {"class": "tablet:grid-col-12"})
25
+ version_tag = find(t2, "h2")
30
26
  version = version_tag.text.split()[0]
31
27
  return version
32
28
 
bioversions/utils.py CHANGED
@@ -11,7 +11,7 @@ import bioregistry
11
11
  import pydantic
12
12
  import pystow
13
13
  import requests
14
- from bs4 import BeautifulSoup
14
+ from bs4 import BeautifulSoup, Tag
15
15
  from cachier import cachier
16
16
 
17
17
  BIOVERSIONS_HOME = pystow.join("bioversions")
@@ -64,6 +64,14 @@ def get_soup(
64
64
  return soup
65
65
 
66
66
 
67
+ def find(element: Tag, *args: Any, **kwargs: Any) -> Tag:
68
+ """Find a sub-element."""
69
+ tag = element.find(*args, **kwargs)
70
+ if not isinstance(tag, Tag):
71
+ raise ValueError(f"could not find an element matching {args=} and {kwargs=}")
72
+ return tag
73
+
74
+
67
75
  #: A decorator for functions whose return values
68
76
  #: should be cached and refreshed once per day
69
77
  refresh_daily = cachier(
bioversions/version.py CHANGED
@@ -5,9 +5,10 @@ from subprocess import CalledProcessError, check_output
5
5
 
6
6
  __all__ = [
7
7
  "VERSION",
8
+ "get_git_hash",
8
9
  ]
9
10
 
10
- VERSION = "0.7.40"
11
+ VERSION = "0.7.42"
11
12
 
12
13
 
13
14
  def get_git_hash() -> str:
bioversions/wsgi.py CHANGED
@@ -12,13 +12,13 @@ Bootstrap(app)
12
12
 
13
13
 
14
14
  @app.route("/")
15
- def home():
15
+ def home() -> str:
16
16
  """Show the home page with a list of latest database versions."""
17
17
  return flask.render_template("home.html", rows=get_rows())
18
18
 
19
19
 
20
20
  @app.route("/database/<name>.json")
21
- def database(name: str):
21
+ def database(name: str) -> flask.Response:
22
22
  """Resolve information about a given database."""
23
23
  rv: dict[str, Any] = {"query": name}
24
24
  try:
@@ -27,7 +27,7 @@ def database(name: str):
27
27
  rv["success"] = False
28
28
  else:
29
29
  rv["success"] = True
30
- rv["result"] = bioversion.dict()
30
+ rv["result"] = bioversion.model_dump()
31
31
  return flask.jsonify(rv)
32
32
 
33
33
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bioversions
3
- Version: 0.7.40
3
+ Version: 0.7.42
4
4
  Summary: Get the current version for biological databases
5
5
  Keywords: snekpack,cookiecutter,databases,biological databases,biomedical databases
6
6
  Author: Charles Tapley Hoyt
@@ -39,13 +39,7 @@ Requires-Dist: pydantic>=2.0
39
39
  Requires-Dist: psycopg2-binary
40
40
  Requires-Dist: matplotlib ; extra == 'charts'
41
41
  Requires-Dist: seaborn ; extra == 'charts'
42
- Requires-Dist: sphinx>=8 ; extra == 'docs'
43
- Requires-Dist: sphinx-rtd-theme>=3.0 ; extra == 'docs'
44
- Requires-Dist: sphinx-click ; extra == 'docs'
45
- Requires-Dist: sphinx-automodapi ; extra == 'docs'
46
42
  Requires-Dist: slack-sdk ; extra == 'slack'
47
- Requires-Dist: pytest ; extra == 'tests'
48
- Requires-Dist: coverage[toml] ; extra == 'tests'
49
43
  Requires-Dist: tweepy ; extra == 'twitter'
50
44
  Requires-Dist: flask ; extra == 'web'
51
45
  Requires-Dist: bootstrap-flask ; extra == 'web'
@@ -58,9 +52,7 @@ Project-URL: Funding, https://github.com/sponsors/cthoyt
58
52
  Project-URL: Homepage, https://github.com/biopragmatics/bioversions
59
53
  Project-URL: Repository, https://github.com/biopragmatics/bioversions.git
60
54
  Provides-Extra: charts
61
- Provides-Extra: docs
62
55
  Provides-Extra: slack
63
- Provides-Extra: tests
64
56
  Provides-Extra: twitter
65
57
  Provides-Extra: web
66
58
  Description-Content-Type: text/markdown
@@ -173,18 +165,15 @@ $ python3 -m pip install bioversions
173
165
  The most recent code and data can be installed directly from GitHub with uv:
174
166
 
175
167
  ```console
176
- $ uv --preview pip install git+https://github.com/biopragmatics/bioversions.git
168
+ $ uv pip install git+https://github.com/biopragmatics/bioversions.git
177
169
  ```
178
170
 
179
171
  or with pip:
180
172
 
181
173
  ```console
182
- $ UV_PREVIEW=1 python3 -m pip install git+https://github.com/biopragmatics/bioversions.git
174
+ $ python3 -m pip install git+https://github.com/biopragmatics/bioversions.git
183
175
  ```
184
176
 
185
- Note that this requires setting `UV_PREVIEW` mode enabled until the uv build
186
- backend becomes a stable feature.
187
-
188
177
  ## 👐 Contributing
189
178
 
190
179
  Contributions, whether filing an issue, making a pull request, or forking, are
@@ -247,18 +236,15 @@ To install in development mode, use the following:
247
236
  ```console
248
237
  $ git clone git+https://github.com/biopragmatics/bioversions.git
249
238
  $ cd bioversions
250
- $ uv --preview pip install -e .
239
+ $ uv pip install -e .
251
240
  ```
252
241
 
253
242
  Alternatively, install using pip:
254
243
 
255
244
  ```console
256
- $ UV_PREVIEW=1 python3 -m pip install -e .
245
+ $ python3 -m pip install -e .
257
246
  ```
258
247
 
259
- Note that this requires setting `UV_PREVIEW` mode enabled until the uv build
260
- backend becomes a stable feature.
261
-
262
248
  ### Updating Package Boilerplate
263
249
 
264
250
  This project uses `cruft` to keep boilerplate (i.e., configuration, contribution
@@ -1,7 +1,6 @@
1
- bioversions/charts.py,sha256=dff05cc80031529e1b06af54c0011d241a383278319d0c6fa90b3e6ad4476332,2419
2
- bioversions/twitter_client.py,sha256=f5de409b4152b3bfc4806763931aa9a3df2f3e2afdae32172318593262e02b94,1285
3
- bioversions/__main__.py,sha256=4e799066f5fbbe005dc99aee68c4146b3d8572ec52891b82ad0f4e1f2de96227,108
4
- bioversions/version.py,sha256=f40854cde9455ee428bc859eb53092051d2651d7d1bfbb34255c29536a0442b3,586
1
+ bioversions/charts.py,sha256=be29a2fde227a4bd02611112f1cbe58a00e261e435fc8f00e82104a15dadbdfe,2457
2
+ bioversions/__main__.py,sha256=0e97cd1eac70162293fb809292e2cba2464218394244001f3f9e0c74b8f71351,128
3
+ bioversions/version.py,sha256=ef25b0fa21def576b61362dc54718557d9d6c8d7167cefbe43ef31213a67eb3f,606
5
4
  bioversions/sources/interpro.py,sha256=1fa75923bd60517a3b2f661e7c24e2243e2ab90440bf2621e670c36e1da2baf1,1238
6
5
  bioversions/sources/uniprot.py,sha256=c3e16b68fc8a65e12d9a3b3288fedbd9a8e0e7b47f0a69f0fb032fb072c68a1b,924
7
6
  bioversions/sources/itis.py,sha256=99a480060d52ac6e06404be347080c28af56e984e80cc4763f0a98266212a1df,582
@@ -12,26 +11,26 @@ bioversions/sources/intact.py,sha256=06e67eda7e8eededc74f63eb1c73db0648665dae783
12
11
  bioversions/sources/disgenet.py,sha256=3c02c84643c1913d9cb2b37e1679fe019cc273d67633685e904fbf16ba84f8bc,739
13
12
  bioversions/sources/slm.py,sha256=84fe81b16cf8cb3cdc817f4ed56482364bb46a9d3af1f01c3726273b26d106d6,766
14
13
  bioversions/sources/dgi.py,sha256=8b613bedea979b8bbadfcbe4b2fd539e4d29deccf329d936c83a72626d8808bc,940
15
- bioversions/sources/kegg.py,sha256=89f784cc7b97ad22436b59b5616c35dd4e82ef1f2335d4001a99a8620d3a00ca,913
14
+ bioversions/sources/kegg.py,sha256=24574e015a28f77f77451a3b48dbb54b740ff36e7e310bbdf434ee4f63adb094,1014
16
15
  bioversions/sources/bigg.py,sha256=895af1caf2a2108517b3a14cd8088b0d86bec980cd18c38d9a222ffd1e8a060e,661
17
16
  bioversions/sources/pubchem.py,sha256=57e6f33479eef0935322abde994efe3292f91c7c6bb1889c5724c99ebd7d72f9,526
18
17
  bioversions/sources/ensembl.py,sha256=994779fcbb08ea8494e1af0324b49a9bd9649dd7fa65fba7d156b1648c9edad2,737
19
18
  bioversions/sources/silva.py,sha256=e677f3502f516b48977191274ad08d593e4c683442281043a819dde028157274,984
20
19
  bioversions/sources/icd10.py,sha256=f3ace5f72c5e532cb758a8104b9e48fb56cafa47a01f9f6c6458b06062856805,703
21
- bioversions/sources/expasy.py,sha256=e42f66f4e93281aab60fbceeb939e4383e15db8414e02f3d95dced7cbb62aa72,771
20
+ bioversions/sources/expasy.py,sha256=625d33571c58d40584ac5ad572da0999e6bec4db7327c0860b9f017836034f9e,767
22
21
  bioversions/sources/homologene.py,sha256=4da5b4037dcf2d2e3cd38ceb45664a0e6a3fcf01332bd6f15ffcc089a526779c,622
23
22
  bioversions/sources/msigdb.py,sha256=8689c6234a84ae6e70b19b2bd21c165e2c37d83de7e71c47e605f7c54121de9a,778
24
23
  bioversions/sources/signor.py,sha256=f0a0bd043c1344027e31fe8fc4e5922f44e86044ca16370e6d66368161f05c83,969
25
- bioversions/sources/ncit.py,sha256=eabc33412087108799d70b76ca60b27debcceb8e3bf6782ba41107c5f2dcda87,1015
24
+ bioversions/sources/ncit.py,sha256=887238481b9cd61f525019541624d03f455f4e0c4465d4ba40fbcf704aac231b,832
26
25
  bioversions/sources/gtdb.py,sha256=95bb664a1e2e872ebe55efec9703be63bff01d15724aea1fd48feb47e150d399,1001
27
- bioversions/sources/pathwaycommons.py,sha256=f7c9ef2ed143a9c1ec755c6dd8bbbc5797682df4ae3ae621c2980fa80ec16619,661
26
+ bioversions/sources/pathwaycommons.py,sha256=34b6bc0f44d87fa4a4abf7ee4adf8a350117b5623786feeff187987c9bc947f6,686
28
27
  bioversions/sources/depmap.py,sha256=00b9fb914b27902ef2023f5c2d899a4235829b6b20d3045643e4fbe8deea4168,641
29
28
  bioversions/sources/antibodyregistry.py,sha256=5c29963e1d7bd40780582ce9539d6120bd593d0cda6f3b763b08af876a2bef8f,713
30
29
  bioversions/sources/reactome.py,sha256=12ae2e1cc763c323eaab9d90ec4f6cbdcea1cd9645b40e6d32d93c76333006f7,596
31
30
  bioversions/sources/oncotree.py,sha256=69b039f07e37800fd3b623816b00595333caede9403d8a9620fee515de8aa8ee,1032
32
31
  bioversions/sources/rfam.py,sha256=3c8de33a8920baac6789fd07160da00752f524ed25ad045b3b48a24716eda5a8,540
33
32
  bioversions/sources/civic.py,sha256=321967e8b7c7a7aecf896b49e6ad4520d0b00a114103a71f71a49c775291f11e,1086
34
- bioversions/sources/flybase.py,sha256=2f5aacd0e1743a18dd927c15e837ef9e79713f7ed9d3d863ba4fa9cf5527d863,754
33
+ bioversions/sources/flybase.py,sha256=cf898bc12970d7840d14d8a6c0022d6712dbeea09ba0269f95af0e51d8fa3de1,1016
35
34
  bioversions/sources/daily.py,sha256=501fcf689d9b11035b08255c208c5bca0bb631f79e9a8fee3d268f85d07b4033,256
36
35
  bioversions/sources/sgd.py,sha256=3e05c0bf0aa5c78f10b869e75473a5d2e034323b84ec89748e2055e1f69835d0,1084
37
36
  bioversions/sources/pombase.py,sha256=e65348dc0aaed5f9c35049c5d117ee7103abf8714f620afbfa5e084eded1c986,766
@@ -45,38 +44,38 @@ bioversions/sources/omim.py,sha256=7aad8a3615748f5171db47098a1cdbec36b1e8596e0e8
45
44
  bioversions/sources/stringdb.py,sha256=9afd81dd24d02469cce66e246cb6f696e4a501ba3e7e8dc7aff0f022563a37b2,787
46
45
  bioversions/sources/chembl.py,sha256=35cfa0149a5eac1c8efe2577b43aa47e359874558ef48ce227022d7bd0b60932,1513
47
46
  bioversions/sources/rhea.py,sha256=ddcb28b84fa2a76520ecc123703e785ff3d4bccb93638af442d3883f54fbd57e,806
48
- bioversions/sources/guidetopharmacology.py,sha256=5806ac03a665caa262a8fef456bac21298b6f895bb50cad4ba702e13aa5393f8,1377
49
- bioversions/sources/rxnorm.py,sha256=ba8a68262850132282d79c6ab5293f4997c496672ca614b26da8e22ee6856253,1010
47
+ bioversions/sources/guidetopharmacology.py,sha256=7864d5d2b74f25d3baa4a91f9a24caec4777a19c442e0055112d2f790998b0e0,1523
48
+ bioversions/sources/rxnorm.py,sha256=abb4a225e16e57c6f59102558c41504711ba81cdb5e07bf557c70ceab552c541,1040
50
49
  bioversions/sources/rgd.py,sha256=64f6cfd7bff88004699b00832560ef033f14f2977e70684ebef546b431a04d23,766
51
- bioversions/sources/__init__.py,sha256=bc68aa57c4ca0680e547dbd7992b7a4fe0f888131ba7cf91bf18499a227a2df4,6367
50
+ bioversions/sources/__init__.py,sha256=d475777684fbb0fd5b2bbfba5344dfce5bc6e2ef27742d2fe00200229cdf6f92,7156
52
51
  bioversions/sources/icf.py,sha256=0580247e61d6b50b0c08d5331a97d188a5671dda4333298628bc327af313c08a,720
53
- bioversions/sources/npass.py,sha256=b516902495d04397e054b51a51046b11432f37deb7046758d7337ffca804d616,714
54
- bioversions/sources/biogrid.py,sha256=15c400f0020ded3c167704506ffaf985467087d66d975dc67865ca5efd4a71a8,734
52
+ bioversions/sources/npass.py,sha256=09355592fd1fee53e99165316c6b6053931927589a58e255b3db2aefde02c103,763
53
+ bioversions/sources/biogrid.py,sha256=df37707dbc42423111e9be6a98c7b866312430d042712d392170a8f2cf8b2daf,742
55
54
  bioversions/sources/mgi.py,sha256=4d7f95d3171616692db2c8d195d8d86f9f751c2b6885e63df70d054c7d9c2199,841
56
- bioversions/sources/pathbank.py,sha256=620621044418e05d3d720ed2e01704107e260fa97a2c38ee0d1bf507f7bce62f,693
57
- bioversions/sources/moalmanac.py,sha256=0cca2d4980f8b0639365a2609ff88f7947c47618e5826ce828a2d84be2fa4eba,749
55
+ bioversions/sources/pathbank.py,sha256=ad5a8a277ab673881cb6a520fe78bd7d29b6273d2882475ec07fb2b0f762003b,704
56
+ bioversions/sources/moalmanac.py,sha256=2f314cc81d89e0e604514217ed5346508dab890603eb6a20f4fb9d3c97144801,781
58
57
  bioversions/sources/cellosaurus.py,sha256=d17ae067aade4a433c0f350b26d681dda881603d1057734750b67ef19950ee01,975
59
58
  bioversions/sources/drugbank.py,sha256=599c215452b5e8219e2c31423c2c6d1c7c867848309696c834b9b5f3af1f3f16,994
60
59
  bioversions/sources/mirbase.py,sha256=ab70baf82cbebc42f22424029e9838a6f7a846b9587ea81be37d779871b90a9e,996
61
60
  bioversions/sources/mesh.py,sha256=5ea8cf53950980e1d5736f1cffa37b46225dd45f51a1418f5c69a621a368a6f3,971
62
61
  bioversions/sources/chemidplus.py,sha256=cc93605ba1d416c5939fdfcf62e01f1449d999284b1af7beee0185696b231702,1194
63
- bioversions/sources/umls.py,sha256=ff9cfd631a1d39804a29a901db6da32e68e6e1c526e04e30a1be82359ea155aa,817
62
+ bioversions/sources/umls.py,sha256=276513c45b33d31f5eaa1395ef176b9ed5ae8013c4ecd4332b4f627880115146,803
64
63
  bioversions/sources/obo.py,sha256=727b7470ba4cf30b421b5e1eebe758bbadeac57e9801df4fceb13948a27ff0b7,1713
65
64
  bioversions/sources/ols.py,sha256=35e49f5841e26161ebb063e2bba5f58754031b98128ac132532ef528346f69ac,2929
66
65
  bioversions/sources/zfin.py,sha256=dcea33de50f1f09e36380a3253c78923e7d19cc46263250c723e1f0c4e4354b4,683
67
- bioversions/slack_client.py,sha256=a7d1e69f244256e42f8ded116dd0caf50b91952c3ffd6c05089f017bd7089333,1209
66
+ bioversions/slack_client.py,sha256=bda7d71401bc03f7dc19fec98d7d5abad5083285cb5c97b5b575b1f9459a1285,1293
68
67
  bioversions/py.typed,sha256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855,0
69
68
  bioversions/resources/__init__.py,sha256=371c3ac3afe0442e01fc9c2f6c000aa4d476ac8a6435167952404831d36a95d6,1659
70
- bioversions/resources/update.py,sha256=6c819d96095f445905cad830239ffc7f67a4bdbcae5b6cb1b62c6c97704beeca,3642
71
- bioversions/resources/versions.json,sha256=ea14109614f6cc4c5299cc2e15fc014fc3bffbc742d1fd26a7ea0434679d7bb1,523800
72
- bioversions/utils.py,sha256=d96017bd9986329496f7c5b9bf7072d466517c6981c3aff36f7658c4954e206d,10437
73
- bioversions/wsgi.py,sha256=f85ee95198a9710823d53fdffbd40264155d43db19047f77c7787187d87b9255,794
69
+ bioversions/resources/update.py,sha256=610e47d0ca8a475740237911e32c146b186b31f3b1ca22501bf099cca07de9d3,3521
70
+ bioversions/resources/versions.json,sha256=b344b8595d09bc2f6845bd3292e5be2b223757db256941c7864372314d190018,526212
71
+ bioversions/utils.py,sha256=65760e94607996df0ef32e6d946b03b1b2a2faa8ff9bee37d1822fe9136bf4fa,10706
72
+ bioversions/wsgi.py,sha256=b611913189165699cd67480f3d17308344ac935e31c693017aabea89bd0ba8ab,825
74
73
  bioversions/__init__.py,sha256=7f04aa5bf8ba4ceb843188a32f6f09dfb20b2300f067284d35a1fb0441eaba38,194
75
- bioversions/cli.py,sha256=939b0f29af9f7fc8aeba207b95d46f1cf59c659d15deccc348cabdcf07486bce,1563
74
+ bioversions/cli.py,sha256=75eaa237668bef45ef6f16b5c5a20036aef228995b872dda224a54dcb30ad2d5,1639
76
75
  bioversions/templates/base.html,sha256=00a07a693dfd53d56d38cdb3bd6fd49b922060ef4acbe08ba41cb1cb95d73b93,713
77
76
  bioversions/templates/home.html,sha256=cfdf054ac94244fd8adfdc5b1e948f824d7d8fb676d4f49b44602d69723431dd,2756
78
- bioversions-0.7.40.dist-info/licenses/LICENSE,sha256=41c80964a1b1956e41c013670812fc5592d5b51bd7b3cd4287d949450488a498,1076
79
- bioversions-0.7.40.dist-info/WHEEL,sha256=92b1076a87444a608e101305744f03ef99e792a629ea2ddd7828b8200771ef04,78
80
- bioversions-0.7.40.dist-info/entry_points.txt,sha256=4cdd92beb5155987fe3fa990cbaa0268658f0e30d27ed349fada88c48b97484e,54
81
- bioversions-0.7.40.dist-info/METADATA,sha256=f3e01595afcb8d4853627a9dd178eb8e2163b93f8a097c586da6301c3bcae5cd,19271
82
- bioversions-0.7.40.dist-info/RECORD,,
77
+ bioversions-0.7.42.dist-info/licenses/LICENSE,sha256=41c80964a1b1956e41c013670812fc5592d5b51bd7b3cd4287d949450488a498,1076
78
+ bioversions-0.7.42.dist-info/WHEEL,sha256=db80548af42267cd471eee88549da60408958e861ac626a83b4e0dc7299bd85e,78
79
+ bioversions-0.7.42.dist-info/entry_points.txt,sha256=4cdd92beb5155987fe3fa990cbaa0268658f0e30d27ed349fada88c48b97484e,54
80
+ bioversions-0.7.42.dist-info/METADATA,sha256=ccf66611309cda3bd239b7b28117424999e27881abd95a034c89e03f71d0e6b0,18673
81
+ bioversions-0.7.42.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: uv 0.6.4
2
+ Generator: uv 0.6.9
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,45 +0,0 @@
1
- """Utilities for interacting with Twitter."""
2
-
3
- from functools import lru_cache
4
-
5
- import pystow
6
- import tweepy
7
-
8
-
9
- @lru_cache(maxsize=1)
10
- def _get_api(
11
- consumer_key: str | None = None,
12
- consumer_secret: str | None = None,
13
- access_token: str | None = None,
14
- access_token_secret: str | None = None,
15
- ) -> tweepy.API | None:
16
- consumer_key = pystow.get_config("bioversions", "consumer_key", passthrough=consumer_key)
17
- consumer_secret = pystow.get_config(
18
- "bioversions", "consumer_secret", passthrough=consumer_secret
19
- )
20
- access_token = pystow.get_config("bioversions", "access_token", passthrough=access_token)
21
- access_token_secret = pystow.get_config(
22
- "bioversions", "access_token_secret", passthrough=access_token_secret
23
- )
24
-
25
- if consumer_key and consumer_secret and access_token and access_token_secret:
26
- auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
27
- auth.set_access_token(access_token, access_token_secret)
28
-
29
- # Create API object
30
- api = tweepy.API(auth)
31
- return api
32
-
33
- return None
34
-
35
-
36
- def post(text: str):
37
- """Post the message to Twitter."""
38
- api = _get_api()
39
- if api is None:
40
- return None
41
- return api.update_status(text)
42
-
43
-
44
- if __name__ == "__main__":
45
- post("Twitter test!")