Source code for sleap.gui.release_checker
"""Module for checking for new releases on GitHub."""
import attr
import pandas as pd
import requests
from typing import List, Dict, Optional
REPO_ID = "murthylab/sleap"
@attr.s(auto_attribs=True)
class Release:
title: str = attr.ib(order=False)
version: str = attr.ib(order=False)
prerelease: bool = attr.ib(order=False)
date: pd.Timestamp
url: str = attr.ib(order=False)
description: str = attr.ib(order=False)
@classmethod
def from_json(cls, data: Dict) -> "Release":
"""Construct a release from a JSON-decoded response."""
return cls(
title=data["name"],
version=data["tag_name"],
prerelease=data["prerelease"],
date=pd.to_datetime(data["published_at"]),
url=data["html_url"],
description=data["body"],
)
[docs]def filter_test_releases(releases: List[Release]) -> List[Release]:
"""Filter test releases out of a list of `Release`s.
Args:
releases: A list of `Release`s.
Returns:
The filtered list of `Release`s. Any `Release` that has a description
containing the string `"Do not use this release. This is a test."` will be
excluded.
"""
# Exclude releases tagged with test string.
return [
rls
for rls in releases
if "Do not use this release. This is a test." not in rls.description
]
[docs]@attr.s(auto_attribs=True)
class ReleaseChecker:
"""Checker for new releases of SLEAP on GitHub.
This uses the GitHub REST API:
https://docs.github.com/en/free-pro-team@latest/rest/reference/repos#releases
Attributes:
repo_id: The name of the repository (defaults to: "murthylab/sleap")
releases: A list of `Release`s from querying GitHub.
checked: Indicates whether the releases page has been checked.
"""
repo_id: str = REPO_ID
releases: List[Release] = attr.ib(
factory=list, converter=filter_test_releases
)
checked: bool = attr.ib(default=False, init=False)
[docs] def check_for_releases(self) -> bool:
"""Check online for new releases.
Returns:
`True` if new releases were found, or `False` if no new releases or was not
able to connect to the web.
"""
try:
self.checked = True
response = requests.get(
f"https://api.github.com/repos/{self.repo_id}/releases"
)
except (requests.ConnectionError, requests.Timeout):
return False
self.releases = [Release.from_json(r) for r in response.json()]
return True
@property
def latest_release(self) -> Release:
"""Return latest release."""
if not self.checked:
self.check_for_releases()
releases = sorted(self.releases)
if len(releases) == 0:
return None
else:
return releases[-1]
@property
def latest_stable(self) -> Release:
"""Return latest stable release."""
if not self.checked:
self.check_for_releases()
releases = sorted([rls for rls in self.releases if not rls.prerelease])
if len(releases) == 0:
return None
else:
return releases[-1]
@property
def latest_prerelease(self) -> Release:
"""Return latest prerelease."""
if not self.checked:
self.check_for_releases()
releases = sorted([rls for rls in self.releases if rls.prerelease])
if len(releases) == 0:
return None
else:
return releases[-1]
[docs] def get_release(self, version: str) -> Release:
"""Get a release by version tag string.
Args:
version: Release version tag (e.g., "v1.0.9")
Returns:
The `Release` object with the associated version number.
"""
if not self.checked:
self.check_for_releases()
for rls in self.releases:
if rls.version == version:
return rls
raise ValueError(
f"Release version was not found: {version}. "
"Check the page online for a full listing: "
f"https://github.com/{self.repo_id}"
)