diff options
author | Maximilian Cosmo Sitter <48606431+mcsitter@users.noreply.github.com> | 2021-01-29 15:19:54 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-01-29 16:19:54 +0200 |
commit | beda7a8a31a690a50d98e14263fcb2348ecb8bd6 (patch) | |
tree | c2e8ccf156473ca02a50bd202d9d7b214350ae40 /scripts | |
parent | 6a5d47a243d2ddbf92fca5e807cf1324d60cabb1 (diff) | |
download | pytest-beda7a8a31a690a50d98e14263fcb2348ecb8bd6.tar.gz |
Add plugin list
Diffstat (limited to 'scripts')
-rw-r--r-- | scripts/update-plugin-list.py | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/scripts/update-plugin-list.py b/scripts/update-plugin-list.py new file mode 100644 index 000000000..f80e63127 --- /dev/null +++ b/scripts/update-plugin-list.py @@ -0,0 +1,86 @@ +import datetime +import pathlib +import re + +import packaging.version +import requests +import tabulate + +FILE_HEAD = r"""Plugins List +============ + +PyPI projects that match "pytest-\*" are considered plugins and are listed +automatically. Packages classified as inactive are excluded. +""" +DEVELOPMENT_STATUS_CLASSIFIERS = ( + "Development Status :: 1 - Planning", + "Development Status :: 2 - Pre-Alpha", + "Development Status :: 3 - Alpha", + "Development Status :: 4 - Beta", + "Development Status :: 5 - Production/Stable", + "Development Status :: 6 - Mature", + "Development Status :: 7 - Inactive", +) + + +def iter_plugins(): + regex = r">([\d\w-]*)</a>" + response = requests.get("https://pypi.org/simple") + for match in re.finditer(regex, response.text): + name = match.groups()[0] + if not name.startswith("pytest-"): + continue + response = requests.get(f"https://pypi.org/pypi/{name}/json") + if response.status_code == 404: + # Some packages, like pytest-azurepipelines42, are included in https://pypi.org/simple but + # return 404 on the JSON API. Skip. + continue + response.raise_for_status() + info = response.json()["info"] + if "Development Status :: 7 - Inactive" in info["classifiers"]: + continue + for classifier in DEVELOPMENT_STATUS_CLASSIFIERS: + if classifier in info["classifiers"]: + status = classifier[22:] + break + else: + status = "N/A" + requires = "N/A" + if info["requires_dist"]: + for requirement in info["requires_dist"]: + if requirement == "pytest" or "pytest " in requirement: + requires = requirement + break + releases = response.json()["releases"] + for release in sorted(releases, key=packaging.version.parse, reverse=True): + if releases[release]: + release_date = datetime.date.fromisoformat( + releases[release][-1]["upload_time_iso_8601"].split("T")[0] + ) + last_release = release_date.strftime("%b %d, %Y") + break + name = f'`{info["name"]} <{info["project_url"]}>`_' + summary = info["summary"].replace("\n", "") + summary = re.sub(r"_\b", "", summary) + yield { + "name": name, + "summary": summary, + "last release": last_release, + "status": status, + "requires": requires, + } + + +def main(): + plugins = list(iter_plugins()) + plugin_table = tabulate.tabulate(plugins, headers="keys", tablefmt="rst") + plugin_list = pathlib.Path("doc", "en", "plugin_list.rst") + with plugin_list.open("w") as f: + f.write(FILE_HEAD) + f.write(f"This list contains {len(plugins)} plugins.\n\n") + f.write(plugin_table) + f.write("\n") + + +if __name__ == "__main__": + main() |