Add Python End-of-Life detection

This commit is contained in:
Labrys of Knossos 2019-02-03 11:14:51 -05:00
parent de86259bb0
commit f6e620a3fd
4 changed files with 211 additions and 0 deletions

View file

@ -1,6 +1,9 @@
#!/usr/bin/env python
# coding=utf-8
import eol
eol.check()
import cleanup
cleanup.clean(cleanup.FOLDER_STRUCTURE)

View file

@ -13,6 +13,7 @@ import time
import libs.autoload
import libs.util
import eol
if not libs.autoload.completed:
sys.exit('Could not load vendored libraries.')
@ -1085,6 +1086,28 @@ def configure_utility_locations():
logger.warning('Install ffmpeg with x264 support to enable this feature ...')
def check_python():
"""Check End-of-Life status for Python version."""
# Raise if end of life
eol.check()
# Warn if within grace period
grace_period = 365 # days
eol.warn_for_status(grace_period=-grace_period)
# Log warning if within grace period
days_left = eol.lifetime()
logger.info(
'Python v{major}.{minor} will reach end of life in {x} days.'.format(
major=sys.version_info[0],
minor=sys.version_info[1],
x=days_left,
)
)
if days_left <= grace_period:
logger.warning('Please upgrade to a more recent Python version.')
def initialize(section=None):
global __INITIALIZED__
@ -1101,6 +1124,9 @@ def initialize(section=None):
configure_migration()
configure_logging_part_2()
# check python version
check_python()
# initialize the main SB database
main_db.upgrade_database(main_db.DBConnection(), databases.InitialSchema)

179
eol.py Normal file
View file

@ -0,0 +1,179 @@
#!/usr/bin/env python
import datetime
import sys
import warnings
__version__ = '1.0.0'
def date(string, fmt='%Y-%m-%d'):
"""
Convert date string to date.
:param string: A date string
:param fmt: Format to use when parsing the date string
:return: A datetime.date
"""
return datetime.datetime.strptime(string, fmt).date()
# https://devguide.python.org/
# https://devguide.python.org/devcycle/#devcycle
PYTHON_EOL = {
(3, 7): date('2023-06-27'),
(3, 6): date('2021-12-23'),
(3, 5): date('2020-09-13'),
(3, 4): date('2019-03-16'),
(3, 3): date('2017-09-29'),
(3, 2): date('2016-02-20'),
(3, 1): date('2012-04-09'),
(3, 0): date('2009-01-13'),
(2, 7): date('2020-01-01'),
(2, 6): date('2013-10-29'),
}
class Error(Exception):
"""An error has occurred."""
class LifetimeError(Error):
"""Lifetime has been exceeded and upgrade is required."""
class LifetimeWarning(Warning):
"""Lifetime has been exceeded and is no longer supported."""
def lifetime(version=None):
"""
Calculate days left till End-of-Life for a version.
:param version: An optional tuple with version information
If a version is not provided, the current system version will be used.
:return: Days left until End-of-Life
"""
if version is None:
version = sys.version_info
major = version[0]
minor = version[1]
now = datetime.datetime.now().date()
time_left = PYTHON_EOL[(major, minor)] - now
return time_left.days
def expiration(version=None, grace_period=0):
"""
Calculate expiration date for a version given a grace period.
:param version: An optional tuple with version information
If a version is not provided, the current system version will be used.
:param grace_period: An optional number of days grace period
:return: Total days till expiration
"""
days_left = lifetime(version)
return days_left + grace_period
def check(version=None, grace_period=0):
"""
Raise an exception if end of life has been reached and recommend upgrade.
:param version: An optional tuple with version information
If a version is not provided, the current system version will be used.
:param grace_period: An optional number of days grace period
If a grace period is not provided, a default 60 days grace period will
be used.
:return: None
"""
try:
raise_for_status(version, grace_period)
except LifetimeError as error:
print('Please use a newer version of Python.')
print_statuses()
sys.exit(error)
def raise_for_status(version=None, grace_period=0):
"""
Raise an exception if end of life has been reached.
:param version: An optional tuple with version information
If a version is not provided, the current system version will be used.
:param grace_period: An optional number of days grace period
If a grace period is not provided, a default 60 days grace period will
be used.
:return: None
"""
if version is None:
version = sys.version_info
days_left = lifetime(version)
expires = days_left + grace_period
if expires <= 0:
msg = 'Python {major}.{minor} is no longer supported.'.format(
major=version[0],
minor=version[1],
)
raise LifetimeError(msg)
def warn_for_status(version=None, grace_period=0):
"""
Warn if end of life has been reached.
:param version: An optional tuple with version information
If a version is not provided, the current system version will be used.
:param grace_period: An optional number of days grace period
:return: None
"""
if version is None:
version = sys.version_info
days_left = lifetime(version)
expires = days_left + grace_period
if expires <= 0:
msg = 'Python {major}.{minor} is no longer supported.'.format(
major=version[0],
minor=version[1],
)
warnings.warn(msg, LifetimeWarning)
def print_statuses(show_expired=False):
"""
Print end-of-life statuses of known python versions.
:param show_expired: If true also print expired python version statuses
"""
lifetimes = sorted(
(lifetime(python_version), python_version)
for python_version in PYTHON_EOL
)
print('Python End-of-Life for current versions:')
for days_left, python_version in lifetimes:
if days_left >= 0:
print(
'v{major}.{minor} in {remaining:>4} days'.format(
major=python_version[0],
minor=python_version[1],
remaining=days_left,
)
)
if not show_expired:
return
print()
print('Python End-of-Life for expired versions:')
for days_left, python_version in lifetimes:
if days_left < 0:
print(
'v{major}.{minor} {remaining:>4} days ago'.format(
major=python_version[0],
minor=python_version[1],
remaining=-days_left,
)
)
if __name__ == '__main__':
print_statuses(show_expired=True)

View file

@ -623,6 +623,9 @@
from __future__ import print_function
import eol
eol.check()
import cleanup
cleanup.clean(cleanup.FOLDER_STRUCTURE)