Last active
February 17, 2020 18:45
-
-
Save hmaarrfk/0e2a01d57f07f55eb99d177da92691b6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
# NEP 29 | |
NEP 29 reads | |
> When a project releases a new major or minor version, we recommend that they | |
> support at least [...] all minor versions of NumPy released in the prior | |
> 24 months from the anticipated release date with a minimum of 3 minor versions of NumPy | |
This means we have to create the union of two sets: | |
1. Releases that are in the last X months -- only consider X.X.0 releases | |
2. A certain number of minor versions. | |
Copyright Mark Harfouche 2019 | |
""" | |
from datetime import datetime, timedelta | |
import requests | |
def major_minor_version(version): | |
"""Given a version string, returns the major and minor version as an integer tuple""" | |
split = version.split('.') | |
return int(split[0]), int(split[1]) | |
def keep_oldest_minor_only(version_dates): | |
vd_dict = {} | |
for version, date in version_dates: | |
major_minor = major_minor_version(version) | |
if major_minor in vd_dict: | |
if vd_dict[major_minor][1] > date: | |
vd_dict[major_minor] = (version, date) | |
else: | |
vd_dict[major_minor] = (version, date) | |
return [val | |
for _, val in vd_dict.items()] | |
def get_versions_dates(package_name, skip_rc=True): | |
r = requests.get(f"https://pypi.org/pypi/{package_name}/json") | |
response = r.json() | |
release_dates = [] | |
for k, v in response['releases'].items(): | |
# print(k) | |
for item in v: | |
# print(item['packagetype']) | |
if item['packagetype'] == 'sdist': | |
if skip_rc and 'rc' in k: | |
continue | |
date = datetime.strptime(item['upload_time_iso_8601'], | |
'%Y-%m-%dT%H:%M:%S.%fZ') | |
release_dates.append((k, date)) | |
release_dates.sort(key=lambda x: x[1], reverse=True) | |
return release_dates | |
def good_nep29_date(version_dates, n_months=24, release_date=None): | |
delta_time = timedelta(days=365 / 12 * n_months) | |
if release_date is None: | |
release_date = datetime.utcnow() | |
oldest_release_date = release_date - delta_time | |
good_versions_date = [vd[1] > oldest_release_date | |
for vd in version_dates] | |
return good_versions_date | |
def good_nep29_minor(version_dates, n_minor=3): | |
major_minor_version_dates = [(major_minor_version(v), date) | |
for v, date in version_dates] | |
unique_major_minor = set() | |
n_unique_major_minor = [] | |
for mm, date in major_minor_version_dates: | |
unique_major_minor.add(mm) | |
n_unique_major_minor.append(len(unique_major_minor)) | |
# Find out if it is a new "minor" version | |
new_major_minor = [bool(n_current - n_old) | |
for n_current, n_old in zip(n_unique_major_minor[1:], n_unique_major_minor[:-1])] | |
# The very newest release is always "new" | |
new_major_minor = [1] + new_major_minor | |
good_versions_minor = [n <= n_minor and new | |
for n, new in zip(n_unique_major_minor, new_major_minor)] | |
return good_versions_minor | |
def nep29_versions(package_name, *, | |
n_months=24, n_minor=3, | |
skip_rc=True, | |
release_date=None, | |
consider_first_minor_only=True): | |
version_dates = get_versions_dates(package_name, skip_rc=True) | |
if consider_first_minor_only: | |
version_dates = keep_oldest_minor_only(version_dates) | |
good_nep29_date_indicator = good_nep29_date(version_dates, n_months=n_months, release_date=release_date) | |
good_nep29_minor_indicator = good_nep29_minor(version_dates, n_minor=n_minor) | |
# Take the combination of the two sets | |
good_indicator = [g1 or g2 | |
for g1, g2 in zip(good_nep29_date_indicator, good_nep29_minor_indicator)] | |
valid_releases = [vd | |
for vd, good in zip(version_dates, good_indicator) | |
if good] | |
return valid_releases | |
from pprint import pprint | |
print("SciPy NEP29 requirements") | |
pprint(nep29_versions('scipy', n_months=24, n_minor=3)) | |
print("NumPy NEP29 requirements") | |
pprint(nep29_versions('numpy', n_months=24, n_minor=3)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment