#!/usr/bin/env python3 from os.path import join from subprocess import check_call, check_output from sys import argv, stdout from tempfile import TemporaryDirectory with TemporaryDirectory() as tmpdir: check_call(['python3', '-m', 'venv', tmpdir]) def install_and_list(target): check_call([join(tmpdir, 'bin', 'pip'), 'install', target]) frozen = ( check_output([join(tmpdir, 'bin', 'pip'), 'freeze']) .decode('utf-8') .strip() .split('\n') ) # file bit skips ourself return set(p.split('=', 1)[0] for p in frozen if 'file' not in p) # base needs frozen = install_and_list('.') # dev needs dev_frozen = install_and_list('.[dev]') - frozen # docs needs docs_frozen = install_and_list('.[docs]') - dev_frozen - frozen # find the installed version for each package versions = {} for pv in ( check_output([join(tmpdir, 'bin', 'pip'), 'freeze']) .decode('utf-8') .strip() .split('\n') ): if 'file' in pv: # skip ourself continue p, v = pv.split('==') versions[p] = (v,) # special handling for older python versions due to libraries dropping support # early versions['alabaster'] = ( "0.7.16; python_version<'3.10'", f"{versions['alabaster'][0]}; python_version>='3.10'", ) versions['click'] = ( "8.1.8; python_version<'3.10'", f"{versions['click'][0]}; python_version>='3.10'", ) versions['myst-parser'] = ( "3.0.1; python_version<'3.10'", f"{versions['myst-parser'][0]}; python_version>='3.10'", ) versions['Sphinx'] = ( "7.4.7; python_version=='3.9'", "8.1.3; python_version=='3.10'", f"{versions['Sphinx'][0]}; python_version>='3.11'", ) def write_packages(fh, packages, header, prefix=''): fh.write(header) for p in sorted(packages): for v in versions[p]: fh.write(prefix) fh.write(p) fh.write('==') fh.write(v) fh.write('\n') write_packages(stdout, frozen, header='base\n', prefix=' ') write_packages(stdout, dev_frozen, header='dev\n', prefix=' ') write_packages(stdout, docs_frozen, header='docs\n', prefix=' ') header = f'# DO NOT EDIT THIS FILE DIRECTLY - use {argv[0]} to update\n' with open('requirements.txt', 'w') as fh: write_packages(fh, frozen, header=header) with open('requirements-dev.txt', 'w') as fh: write_packages(fh, dev_frozen, header=header) with open('requirements-docs.txt', 'w') as fh: write_packages(fh, docs_frozen, header=header)