Skip to content

Instantly share code, notes, and snippets.

@tomviner
Last active November 4, 2023 23:42
Show Gist options
  • Save tomviner/a8df1ba639ccee20f9f6de63c6352c85 to your computer and use it in GitHub Desktop.
Save tomviner/a8df1ba639ccee20f9f6de63c6352c85 to your computer and use it in GitHub Desktop.
Instal latest patch versions of python
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintainted in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

latest python versions

Clone

$ git clone git@gist.github.com:a8df1ba639ccee20f9f6de63c6352c85.git latest_python_versions

Use pyenv to install the latest patch version of each minor version of Python.

$ git clone git@gist.github.com:a8df1ba639ccee20f9f6de63c6352c85.git latest_python_versions
$ python latest_python_versions.py

Current:
	pyenv global  3.11.1  3.10.9  3.9.16  3.8.16  3.7.16  3.6.15  2.7.18  3.12.0a4  system

After new installs:
	pyenv global  3.11.3  3.10.11  3.9.16  3.8.16  3.7.16  3.6.15  2.7.18  3.12.0b1  3.13-dev  system

Need:
	pyenv install --skip-existing 3.11.3; \
	pyenv install --skip-existing 3.10.11; \
	pyenv install --skip-existing 3.12.0b1; \
	pyenv install --skip-existing 3.13-dev

Got latest:
	3.9.16
	3.8.16
	3.7.16
	3.6.15
	2.7.18
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
{
"pyenv install --list --bare": "Available versions:\n 2.1.3\n 2.2.3\n 2.3.7\n 2.4.0\n 2.4.1\n 2.4.2\n 2.4.3\n 2.4.4\n 2.4.5\n 2.4.6\n 2.5.0\n 2.5.1\n 2.5.2\n 2.5.3\n 2.5.4\n 2.5.5\n 2.5.6\n 2.6.0\n 2.6.1\n 2.6.2\n 2.6.3\n 2.6.4\n 2.6.5\n 2.6.6\n 2.6.7\n 2.6.8\n 2.6.9\n 2.7.0\n 2.7-dev\n 2.7.1\n 2.7.2\n 2.7.3\n 2.7.4\n 2.7.5\n 2.7.6\n 2.7.7\n 2.7.8\n 2.7.9\n 2.7.10\n 2.7.11\n 2.7.12\n 2.7.13\n 2.7.14\n 2.7.15\n 2.7.16\n 2.7.17\n 2.7.18\n 3.0.1\n 3.1.0\n 3.1.1\n 3.1.2\n 3.1.3\n 3.1.4\n 3.1.5\n 3.2.0\n 3.2.1\n 3.2.2\n 3.2.3\n 3.2.4\n 3.2.5\n 3.2.6\n 3.3.0\n 3.3.1\n 3.3.2\n 3.3.3\n 3.3.4\n 3.3.5\n 3.3.6\n 3.3.7\n 3.4.0\n 3.4-dev\n 3.4.1\n 3.4.2\n 3.4.3\n 3.4.4\n 3.4.5\n 3.4.6\n 3.4.7\n 3.4.8\n 3.4.9\n 3.4.10\n 3.5.0\n 3.5-dev\n 3.5.1\n 3.5.2\n 3.5.3\n 3.5.4\n 3.5.5\n 3.5.6\n 3.5.7\n 3.5.8\n 3.5.9\n 3.5.10\n 3.6.0\n 3.6-dev\n 3.6.1\n 3.6.2\n 3.6.3\n 3.6.4\n 3.6.5\n 3.6.6\n 3.6.7\n 3.6.8\n 3.6.9\n 3.6.10\n 3.6.11\n 3.6.12\n 3.6.13\n 3.6.14\n 3.6.15\n 3.7.0\n 3.7-dev\n 3.7.1\n 3.7.2\n 3.7.3\n 3.7.4\n 3.7.5\n 3.7.6\n 3.7.7\n 3.7.8\n 3.7.9\n 3.7.10\n 3.7.11\n 3.7.12\n 3.8.0\n 3.8-dev\n 3.8.1\n 3.8.2\n 3.8.3\n 3.8.4\n 3.8.5\n 3.8.6\n 3.8.7\n 3.8.8\n 3.8.9\n 3.8.10\n 3.8.11\n 3.8.12\n 3.9.0\n 3.9-dev\n 3.9.1\n 3.9.2\n 3.9.4\n 3.9.5\n 3.9.6\n 3.9.7\n 3.9.8\n 3.9.9\n 3.9.10\n 3.10.0\n 3.10-dev\n 3.10.1\n 3.10.2\n 3.11.0a4\n 3.11-dev\n activepython-2.7.14\n activepython-3.5.4\n activepython-3.6.0\n anaconda-1.4.0\n anaconda-1.5.0\n anaconda-1.5.1\n anaconda-1.6.0\n anaconda-1.6.1\n anaconda-1.7.0\n anaconda-1.8.0\n anaconda-1.9.0\n anaconda-1.9.1\n anaconda-1.9.2\n anaconda-2.0.0\n anaconda-2.0.1\n anaconda-2.1.0\n anaconda-2.2.0\n anaconda-2.3.0\n anaconda-2.4.0\n anaconda-4.0.0\n anaconda2-2.4.0\n anaconda2-2.4.1\n anaconda2-2.5.0\n anaconda2-4.0.0\n anaconda2-4.1.0\n anaconda2-4.1.1\n anaconda2-4.2.0\n anaconda2-4.3.0\n anaconda2-4.3.1\n anaconda2-4.4.0\n anaconda2-5.0.0\n anaconda2-5.0.1\n anaconda2-5.1.0\n anaconda2-5.2.0\n anaconda2-5.3.0\n anaconda2-5.3.1\n anaconda2-2018.12\n anaconda2-2019.03\n anaconda2-2019.07\n anaconda3-2.0.0\n anaconda3-2.0.1\n anaconda3-2.1.0\n anaconda3-2.2.0\n anaconda3-2.3.0\n anaconda3-2.4.0\n anaconda3-2.4.1\n anaconda3-2.5.0\n anaconda3-4.0.0\n anaconda3-4.1.0\n anaconda3-4.1.1\n anaconda3-4.2.0\n anaconda3-4.3.0\n anaconda3-4.3.1\n anaconda3-4.4.0\n anaconda3-5.0.0\n anaconda3-5.0.1\n anaconda3-5.1.0\n anaconda3-5.2.0\n anaconda3-5.3.0\n anaconda3-5.3.1\n anaconda3-2018.12\n anaconda3-2019.03\n anaconda3-2019.07\n anaconda3-2019.10\n anaconda3-2020.02\n anaconda3-2020.07\n anaconda3-2020.11\n anaconda3-2021.05\n anaconda3-2021.11\n graalpython-20.1.0\n graalpython-20.2.0\n graalpython-20.3.0\n graalpython-21.0.0\n graalpython-21.1.0\n graalpython-21.2.0\n graalpython-21.3.0\n ironpython-dev\n ironpython-2.7.4\n ironpython-2.7.5\n ironpython-2.7.6.3\n ironpython-2.7.7\n jython-dev\n jython-2.5.0\n jython-2.5-dev\n jython-2.5.1\n jython-2.5.2\n jython-2.5.3\n jython-2.5.4-rc1\n jython-2.7.0\n jython-2.7.1\n jython-2.7.2\n mambaforge-pypy3\n mambaforge\n mambaforge-4.10.1-4\n mambaforge-4.10.1-5\n mambaforge-4.10.3-10\n micropython-dev\n micropython-1.9.3\n micropython-1.9.4\n micropython-1.10\n micropython-1.11\n micropython-1.12\n micropython-1.13\n micropython-1.14\n micropython-1.15\n micropython-1.16\n micropython-1.17\n miniconda-latest\n miniconda-2.2.2\n miniconda-3.0.0\n miniconda-3.0.4\n miniconda-3.0.5\n miniconda-3.3.0\n miniconda-3.4.2\n miniconda-3.7.0\n miniconda-3.8.3\n miniconda-3.9.1\n miniconda-3.10.1\n miniconda-3.16.0\n miniconda-3.18.3\n miniconda2-latest\n miniconda2-2.7-4.8.3\n miniconda2-3.18.3\n miniconda2-3.19.0\n miniconda2-4.0.5\n miniconda2-4.1.11\n miniconda2-4.3.14\n miniconda2-4.3.21\n miniconda2-4.3.27\n miniconda2-4.3.30\n miniconda2-4.3.31\n miniconda2-4.4.10\n miniconda2-4.5.1\n miniconda2-4.5.4\n miniconda2-4.5.11\n miniconda2-4.5.12\n miniconda2-4.6.14\n miniconda2-4.7.10\n miniconda2-4.7.12\n miniconda3-latest\n miniconda3-2.2.2\n miniconda3-3.0.0\n miniconda3-3.0.4\n miniconda3-3.0.5\n miniconda3-3.3.0\n miniconda3-3.4.2\n miniconda3-3.7.0\n miniconda3-3.7-4.8.2\n miniconda3-3.7-4.8.3\n miniconda3-3.7-4.9.2\n miniconda3-3.7-4.10.3\n miniconda3-3.8.3\n miniconda3-3.8-4.8.2\n miniconda3-3.8-4.8.3\n miniconda3-3.8-4.9.2\n miniconda3-3.8-4.10.3\n miniconda3-3.9.1\n miniconda3-3.9-4.9.2\n miniconda3-3.9-4.10.3\n miniconda3-3.10.1\n miniconda3-3.16.0\n miniconda3-3.18.3\n miniconda3-3.19.0\n miniconda3-4.0.5\n miniconda3-4.1.11\n miniconda3-4.2.12\n miniconda3-4.3.11\n miniconda3-4.3.14\n miniconda3-4.3.21\n miniconda3-4.3.27\n miniconda3-4.3.30\n miniconda3-4.3.31\n miniconda3-4.4.10\n miniconda3-4.5.1\n miniconda3-4.5.4\n miniconda3-4.5.11\n miniconda3-4.5.12\n miniconda3-4.6.14\n miniconda3-4.7.10\n miniconda3-4.7.12\n miniforge-pypy3\n miniforge3\n miniforge3-4.9.2\n miniforge3-4.10\n miniforge3-4.10.1-1\n miniforge3-4.10.1-3\n miniforge3-4.10.1-5\n miniforge3-4.10.3-10\n pypy-c-jit-latest\n pypy-dev\n pypy-stm-2.3\n pypy-stm-2.5.1\n pypy-1.5-src\n pypy-1.6\n pypy-1.7\n pypy-1.8\n pypy-1.9\n pypy-2.0-src\n pypy-2.0\n pypy-2.0.1-src\n pypy-2.0.1\n pypy-2.0.2-src\n pypy-2.0.2\n pypy-2.1-src\n pypy-2.1\n pypy-2.2-src\n pypy-2.2\n pypy-2.2.1-src\n pypy-2.2.1\n pypy-2.3-src\n pypy-2.3\n pypy-2.3.1-src\n pypy-2.3.1\n pypy-2.4.0-src\n pypy-2.4.0\n pypy-2.5.0-src\n pypy-2.5.0\n pypy-2.5.1-src\n pypy-2.5.1\n pypy-2.6.0-src\n pypy-2.6.0\n pypy-2.6.1-src\n pypy-2.6.1\n pypy-4.0.0-src\n pypy-4.0.0\n pypy-4.0.1-src\n pypy-4.0.1\n pypy-5.0.0-src\n pypy-5.0.0\n pypy-5.0.1-src\n pypy-5.0.1\n pypy-5.1-src\n pypy-5.1\n pypy-5.1.1-src\n pypy-5.1.1\n pypy-5.3-src\n pypy-5.3\n pypy-5.3.1-src\n pypy-5.3.1\n pypy-5.4-src\n pypy-5.4\n pypy-5.4.1-src\n pypy-5.4.1\n pypy-5.6.0-src\n pypy-5.6.0\n pypy-5.7.0-src\n pypy-5.7.0\n pypy-5.7.1-src\n pypy-5.7.1\n pypy2-5.3-src\n pypy2-5.3\n pypy2-5.3.1-src\n pypy2-5.3.1\n pypy2-5.4-src\n pypy2-5.4\n pypy2-5.4.1-src\n pypy2-5.4.1\n pypy2-5.6.0-src\n pypy2-5.6.0\n pypy2-5.7.0-src\n pypy2-5.7.0\n pypy2-5.7.1-src\n pypy2-5.7.1\n pypy2.7-5.8.0-src\n pypy2.7-5.8.0\n pypy2.7-5.9.0-src\n pypy2.7-5.9.0\n pypy2.7-5.10.0-src\n pypy2.7-5.10.0\n pypy2.7-6.0.0-src\n pypy2.7-6.0.0\n pypy2.7-7.0.0-src\n pypy2.7-7.0.0\n pypy2.7-7.1.0-src\n pypy2.7-7.1.0\n pypy2.7-7.1.1-src\n pypy2.7-7.1.1\n pypy2.7-7.2.0-src\n pypy2.7-7.2.0\n pypy2.7-7.3.0-src\n pypy2.7-7.3.0\n pypy2.7-7.3.1-src\n pypy2.7-7.3.1\n pypy2.7-7.3.2-src\n pypy2.7-7.3.2\n pypy2.7-7.3.3-src\n pypy2.7-7.3.3\n pypy2.7-7.3.4-src\n pypy2.7-7.3.4\n pypy2.7-7.3.5-src\n pypy2.7-7.3.5\n pypy2.7-7.3.6-src\n pypy2.7-7.3.6\n pypy3-2.3.1-src\n pypy3-2.3.1\n pypy3-2.4.0-src\n pypy3-2.4.0\n pypy3.3-5.2-alpha1-src\n pypy3.3-5.2-alpha1\n pypy3.3-5.5-alpha-src\n pypy3.3-5.5-alpha\n pypy3.5-c-jit-latest\n pypy3.5-5.7-beta-src\n pypy3.5-5.7-beta\n pypy3.5-5.7.1-beta-src\n pypy3.5-5.7.1-beta\n pypy3.5-5.8.0-src\n pypy3.5-5.8.0\n pypy3.5-5.9.0-src\n pypy3.5-5.9.0\n pypy3.5-5.10.0-src\n pypy3.5-5.10.0\n pypy3.5-5.10.1-src\n pypy3.5-5.10.1\n pypy3.5-6.0.0-src\n pypy3.5-6.0.0\n pypy3.5-7.0.0-src\n pypy3.5-7.0.0\n pypy3.6-7.0.0-src\n pypy3.6-7.0.0\n pypy3.6-7.1.0-src\n pypy3.6-7.1.0\n pypy3.6-7.1.1-src\n pypy3.6-7.1.1\n pypy3.6-7.2.0-src\n pypy3.6-7.2.0\n pypy3.6-7.3.0-src\n pypy3.6-7.3.0\n pypy3.6-7.3.1-src\n pypy3.6-7.3.1\n pypy3.6-7.3.2-src\n pypy3.6-7.3.2\n pypy3.6-7.3.3-src\n pypy3.6-7.3.3\n pypy3.7-c-jit-latest\n pypy3.7-7.3.2-src\n pypy3.7-7.3.2\n pypy3.7-7.3.3-src\n pypy3.7-7.3.3\n pypy3.7-7.3.4-src\n pypy3.7-7.3.4\n pypy3.7-7.3.5-src\n pypy3.7-7.3.5\n pypy3.7-7.3.6-src\n pypy3.7-7.3.6\n pypy3.7-7.3.7-src\n pypy3.7-7.3.7\n pypy3.8-7.3.6-src\n pypy3.8-7.3.6\n pypy3.8-7.3.7-src\n pypy3.8-7.3.7\n pyston-2.2\n pyston-2.3\n pyston-2.3.1\n stackless-dev\n stackless-2.7-dev\n stackless-2.7.2\n stackless-2.7.3\n stackless-2.7.4\n stackless-2.7.5\n stackless-2.7.6\n stackless-2.7.7\n stackless-2.7.8\n stackless-2.7.9\n stackless-2.7.10\n stackless-2.7.11\n stackless-2.7.12\n stackless-2.7.14\n stackless-2.7.16\n stackless-3.2.2\n stackless-3.2.5\n stackless-3.3.5\n stackless-3.3.7\n stackless-3.4-dev\n stackless-3.4.2\n stackless-3.4.7\n stackless-3.5.4\n stackless-3.7.5\n",
"pyenv versions --bare": "2.7.18\n3.10.0\n3.10.1\n3.11.0a2\n3.11.0a3\n3.11.0a4\n3.5.10\n3.6.15\n3.7.12\n3.8.12\n3.9.10\n3.9.9\npypy3.8-7.3.7\n",
"pyenv global": "3.10.1\n3.9.9\n3.8.12\n3.7.12\n3.6.15\n3.5.10\n2.7.18\n3.11.0a3\npypy3.8-7.3.7\nsystem\n"
}
import shlex
from functools import total_ordering
from itertools import groupby
from operator import attrgetter
from subprocess import check_output
import funcy
from packaging.version import Version, parse, InvalidVersion
CMD_LIST_AVAILABLE = "pyenv install --list --bare"
CMD_GLOBAL = "pyenv global"
CMD_LIST_INSTALLED = "pyenv versions --bare"
def get_output(cmd):
return check_output(shlex.split(cmd), encoding="utf-8")
def get_outputs(cmd):
return get_output(cmd).splitlines()
def get_versions(cmd):
return [PyVersion(version) for version in get_outputs(cmd) if ":" not in version]
@total_ordering
class PyVersion:
def __init__(self, original_version):
# keep original because Version is not round-trip safe: .dev becomes .dev0
self.original_version = original_version.strip()
try:
self.version = parse(self.original_version)
except InvalidVersion:
self.version = '-'
self.is_cpython = False
else:
# non cpythons like jython, pypy etc, will have versions
# if type `LegacyVersion`.
self.is_cpython = isinstance(self.version, Version)
if not self.is_cpython:
try:
self.version = parse(self.original_version.partition("-")[2])
except InvalidVersion:
self.version = Version('0.0.0')
self.implementation = (
"" if self.is_cpython else self.original_version.split("-")[0]
)
# i.e. 3.7 3.6 3.5 3.4 3.9-dev 3.8-dev when reversed
self.sort_val = (
self.is_cpython,
(self.version.dev is None),
(self.version.pre is None),
self.version,
)
def __lt__(self, other):
return self.sort_val < other.sort_val
def __eq__(self, other):
return self.version == other.version
def __str__(self):
return str(self.original_version)
def get_cpython_versions():
for version in get_versions(CMD_LIST_AVAILABLE):
if version.is_cpython:
yield version
def get_major_minor(version):
if version.implementation:
return version.implementation, version.version.release
return version.version.release[:2]
def get_latests(versions):
versions = sorted(get_cpython_versions(), key=attrgetter("version"), reverse=True)
for major_minor, patches in groupby(versions, get_major_minor):
if major_minor == (2, 7) or major_minor >= (3, 6):
yield max(patches)
def print_global_set(versions):
versions = list(versions)
versions_str = " ".join([v.original_version for v in versions])
print(f"\tpyenv global {versions_str}")
def main():
versions_available = get_cpython_versions()
# latest version for each minor release
latests = sorted(get_latests(versions_available), reverse=True)
installed = get_versions(CMD_LIST_INSTALLED)
global_order = get_versions(CMD_GLOBAL)
gots = []
needs = []
not_in_globals = []
for max_patch in latests:
if max_patch in installed:
if max_patch not in global_order:
not_in_globals.append(max_patch)
gots.append(max_patch)
else:
needs.append(max_patch)
print("Current:")
print_global_set(global_order)
print()
if not_in_globals:
print("Use latest installed versions:")
def get_latest_globals(current, new):
grouped = funcy.group_by(get_major_minor, [*current, *new]).values()
for patches in grouped:
yield max(patches)
latest_globals = get_latest_globals(global_order, not_in_globals)
print_global_set(latest_globals)
print()
if needs:
print("After new installs:")
non_cpython = [v for v in global_order if not v.is_cpython]
print_global_set([*latests, *non_cpython])
print()
print("Need:")
print(
"; \\\n".join(f"\tpyenv install --skip-existing {need}" for need in needs)
)
print()
if gots:
print("Got latest:")
for got in gots:
print(f"\t{got}")
print()
if not needs:
print("All latest versions found.")
if __name__ == "__main__":
main()
packaging
funcy
colorama
pytest
black
isort
import shlex
from itertools import groupby
from pathlib import Path
from subprocess import check_output
from colorama import Back, Style, init
from packaging.version import Version, parse
CMD_ROOT = "pyenv root"
CMD_VERSIONS = "pyenv versions --bare"
def get_output(cmd):
return check_output(shlex.split(cmd), encoding="utf-8")
def get_outputs(cmd):
return get_output(cmd).splitlines()
def get_major_minor(version):
if "pypy" in str(version):
return "pypy", str(version).replace("pypy", "").split("-")[0]
if not isinstance(version, Version):
version = parse(version)
return version.release[:2]
def group_versions(versions):
vs = [parse(version) for version in versions]
vs.sort()
for (major, minor), patches in groupby(vs, get_major_minor):
print(f"{major}.{minor}")
for v in sorted(patches):
yield str(v)
def main():
init()
root = get_outputs(CMD_ROOT)[0]
installed = get_outputs(CMD_VERSIONS)
for version in group_versions(installed):
path = Path(root) / "versions" / version / "bin/python"
cmd = "import platform; print(platform.machine())"
platform = get_output(f'{path} -c "{cmd}"').strip()
if platform == "x86_64":
platform = f"{Back.RED}{platform}"
elif platform == "arm64":
platform = f"{Back.GREEN}{platform}"
else:
platform = f"{Back.YELLOW}{platform}"
print("\t", version, platform, Style.RESET_ALL)
if __name__ == "__main__":
main()
import json
import sys
from contextlib import contextmanager
from unittest.mock import patch
import pytest
import latest_python_versions
CMD_RECORD_FILEPATH = "cmd-record.json"
orig_get_output = latest_python_versions.get_output
@contextmanager
def recorder():
history = {}
def record(cmd):
output = orig_get_output(cmd)
history[cmd] = output
return output
yield record
json.dump(history, open(CMD_RECORD_FILEPATH, "w"), indent=4)
@contextmanager
def player():
history = json.load(open(CMD_RECORD_FILEPATH))
def play(cmd):
return history.pop(cmd)
yield play
if history:
raise RuntimeError(f'cmd(s) missed: {", ".join(history)}')
@pytest.fixture
def fake_command_output():
with player() as play:
with patch.object(latest_python_versions, "get_output", play):
yield
@contextmanager
def record_command_output():
with recorder() as record:
with patch.object(latest_python_versions, "get_output", record):
yield
def test_main(fake_command_output, capsys):
latest_python_versions.main()
out, err = capsys.readouterr()
assert out == (
"Current:\n"
"\tpyenv global 3.10.1 3.9.9 3.8.12 3.7.12 3.6.15 3.5.10 2.7.18 "
"3.11.0a3 pypy3.8-7.3.7 system\n"
"\n"
"Use latest installed versions:\n"
"\tpyenv global 3.10.1 3.9.10 3.8.12 3.7.12 3.6.15 3.5.10 2.7.18 "
"3.11.0a4 pypy3.8-7.3.7 system\n"
"\n"
"After new installs:\n"
"\tpyenv global 3.10.2 3.9.10 3.8.12 3.7.12 3.6.15 3.5.10 2.7.18 "
"3.11.0a4 pypy3.8-7.3.7 system\n"
"\n"
"Need:\n"
"\tpyenv install --skip-existing 3.10.2\n"
"\n"
"Got latest:\n"
"\t3.9.10\n"
"\t3.8.12\n"
"\t3.7.12\n"
"\t3.6.15\n"
"\t3.5.10\n"
"\t2.7.18\n"
"\t3.11.0a4\n"
"\n"
)
assert not err
if __name__ == "__main__":
if sys.argv[1:2] == ["RECORD"]:
with record_command_output():
latest_python_versions.main()
pushd ~/.pyenv
git pull
popd
~/.virtualenvs/latest_python_versions/bin/python latest_python_versions.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment