Skip to content

Instantly share code, notes, and snippets.

@hmaarrfk
Last active February 17, 2020 18:45
Show Gist options
  • Save hmaarrfk/0e2a01d57f07f55eb99d177da92691b6 to your computer and use it in GitHub Desktop.
Save hmaarrfk/0e2a01d57f07f55eb99d177da92691b6 to your computer and use it in GitHub Desktop.
"""
# 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