diff --git a/conf/install_python.py b/conf/install_python.py index dc72e83..8367a6d 100755 --- a/conf/install_python.py +++ b/conf/install_python.py @@ -1,22 +1,16 @@ #!/usr/bin/env python3 """ - Setup Python Interpreter - ~~~~~~~~~~~~~~~~~~~~~~~~ + DocWrite: install_python.md # Install Python Interpreter - This script downloads, builds and installs a Python interpreter, but: - - only if the required version is not already installed - - only if the required version is not already built + `install_python.py` downloads, builds and installs a Python interpreter, but: + - **only** if the system Python is not the required major version + - **only** once (if the required major version is not already build and installed) - Download Python source code from official Python FTP server. - Download only over verified HTTPS connection. - Verify the download with the GPG signature, if gpg is available. + Origin of this script is: + * https://github.com/jedie/manageprojects/blob/main/manageprojects/install_python.py - Has a CLI interface e.g.: - - $ python install_python.py --help - - Defaults to Python 3.11 and ~/.local/ as prefix. + Licensed under GPL-3.0-or-later (Feel free to copy and use it in your project) """ from __future__ import annotations @@ -35,26 +29,37 @@ import urllib.request from pathlib import Path +"""DocWrite: install_python.md # Install Python Interpreter +Minimal needed Python version to run the script is: **v3.9**.""" assert sys.version_info >= (3, 9), f'Python version {sys.version_info} is too old!' DEFAULT_MAJOR_VERSION = '3.11' + +"""DocWrite: install_python.md # Install Python Interpreter +Download Python source code from official Python FTP server: +DocWriteMacro: manageprojects.tests.docwrite_macros.ftp_url""" PY_FTP_INDEX_URL = 'https://www.python.org/ftp/python/' - +"""DocWrite: install_python.md ## Supported Python Versions +The following major Python versions are supported and verified with GPG keys: +DocWriteMacro: manageprojects.tests.docwrite_macros.supported_python_versions +The GPG keys taken from the official Python download page: https://www.python.org/downloads/""" GPG_KEY_IDS = { - # from: https://www.python.org/downloads/ + # Thomas Wouters (3.12.x and 3.13.x source files and tags): + '3.13': 'A821E680E5FA6305', + '3.12': 'A821E680E5FA6305', # - # Thomas Wouters (3.12.x and 3.13.x source files and tags) (key id: A821E680E5FA6305): - '3.13': '7169605F62C751356D054A26A821E680E5FA6305', - '3.12': '7169605F62C751356D054A26A821E680E5FA6305', - # - # Pablo Galindo Salgado (3.10.x and 3.11.x source files and tags) (key id: 64E628F8D684696D): - '3.11': 'A035C8C19219BA821ECEA86B64E628F8D684696D', - '3.10': 'A035C8C19219BA821ECEA86B64E628F8D684696D', + # Pablo Galindo Salgado (3.10.x and 3.11.x source files and tags): + '3.11': '64E628F8D684696D', + '3.10': '64E628F8D684696D', } +GPG_KEY_SERVER = 'hkps://keys.openpgp.org' -# https://docs.python.org/3/using/configure.html#cmdoption-prefix +"""DocWrite: install_python.md ## Workflow - 3. Check local installed Python +We assume that the `make altinstall` will install local Python interpreter into: +DocWriteMacro: manageprojects.tests.docwrite_macros.default_install_prefix +See: https://docs.python.org/3/using/configure.html#cmdoption-prefix""" DEFAULT_INSTALL_PREFIX = '/usr/local' TEMP_PREFIX = 'setup_python_' @@ -81,15 +86,15 @@ class TemporaryDirectory: def fetch(url: str) -> bytes: - with urllib.request.urlopen( - url=url, - context=ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH), - ) as response: + """DocWrite: install_python.md # Install Python Interpreter + Download only over verified HTTPS connection.""" + context = ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH) + with urllib.request.urlopen(url=url, context=context) as response: return response.read() def get_html_page(url) -> str: - logger.debug(f'Getting HTML page from {url}') + logger.debug('Getting HTML page from %s', url) html = fetch(url).decode('utf-8') assert html, 'Failed to get Python FTP index page' return html @@ -97,62 +102,73 @@ def get_html_page(url) -> str: def extract_versions(*, html, major_version) -> list[str]: pattern = rf'href="({re.escape(major_version)}\.[0-9]+)' - logger.debug(f'Extracting versions with pattern: {pattern}') + logger.debug('Extracting versions with pattern: %s', pattern) versions = re.findall(pattern, html) versions.sort(reverse=True) - logger.debug(f'Extracted versions: {versions}') + logger.debug('Extracted versions: %s', versions) return versions def get_latest_versions(*, html, major_version) -> str: latest_versions = extract_versions(html=html, major_version=major_version)[0] - logger.info(f'Latest version of Python {major_version}: {latest_versions}') + logger.info('Latest version of Python %s: %s', major_version, latest_versions) return latest_versions def run(args, **kwargs): - logger.debug(f'Running: {shlex.join(str(arg) for arg in args)} ({kwargs=})') + logger.debug('Running: %s (%s)', shlex.join(str(arg) for arg in args), kwargs) return subprocess.run(args, **kwargs) def run_build_step(args, *, step: str, cwd: Path) -> None: with tempfile.NamedTemporaryFile(prefix=f'{TEMP_PREFIX}_{step}_', suffix='.txt', delete=False) as temp_file: - logger.info(f'Running: {shlex.join(str(arg) for arg in args)}... Output in {temp_file.name}') + logger.info('Running: %s... Output in %s', shlex.join(str(arg) for arg in args), temp_file.name) try: subprocess.run(args, stdout=temp_file, stderr=temp_file, check=True, cwd=cwd) except subprocess.SubprocessError as err: - logger.error(f'Failed to run {step} step: {err}') + logger.error('Failed to run %s step: %s', step, err) run(['tail', temp_file.name]) raise -def get_python_version(python_bin) -> str: - logger.debug(f'Check {python_bin} version') - full_version = run([python_bin, '--version'], capture_output=True, text=True).stdout.split()[1] - logger.info(f'{python_bin} version: {full_version}') - return full_version +def get_python_version(python_bin: str | Path) -> str | None: + logger.debug('Check %s version', python_bin) + if output := run([python_bin, '-V'], capture_output=True, text=True).stdout.split(): + full_version = output[-1] + logger.info('Version of "%s" is: %r', python_bin, full_version) + return full_version def download2temp(*, temp_path: Path, base_url: str, filename: str) -> Path: url = f'{base_url}/{filename}' dst_path = temp_path / filename - logger.info(f'Downloading {url} into {dst_path}...') + logger.info('Downloading %s into %s...', url, dst_path) dst_path.write_bytes(fetch(url)) - logger.info(f'Downloaded {filename} is {dst_path.stat().st_size} Bytes') + logger.info('Downloaded %s is %d Bytes', filename, dst_path.stat().st_size) return dst_path -def verify_download(*, major_version: str, tar_file_path: Path, asc_file_path: Path): +def verify_download(*, major_version: str, tar_file_path: Path, asc_file_path: Path, delete_temp: bool): + """DocWrite: install_python.md ## Workflow - 5. Verify download + The sha256 hash downloaded tar archive will logged. + If `gpg` is available, the signature will be verified. + """ hash_obj = hashlib.sha256(tar_file_path.read_bytes()) - logger.info(f'Downloaded sha256: {hash_obj.hexdigest()}') + logger.info('Downloaded sha256: %s', hash_obj.hexdigest()) + """DocWrite: install_python.md # Install Python Interpreter + The Downloaded tar archive will be verified with the GPG signature, if `gpg` is available.""" if gpg_bin := shutil.which('gpg'): - logger.debug(f'Verifying signature with {gpg_bin}...') + logger.debug('Verifying signature with %s...', gpg_bin) assert major_version in GPG_KEY_IDS, f'No GPG key ID for Python {major_version}' gpg_key_id = GPG_KEY_IDS[major_version] - run([gpg_bin, '--keyserver', 'hkps://keys.openpgp.org', '--recv-keys', gpg_key_id], check=True) - run([gpg_bin, '--verify', asc_file_path, tar_file_path], check=True) - run(['gpgconf', '--kill', 'all'], check=True) + with TemporaryDirectory(prefix='install-python-gpg-', delete=delete_temp) as temp_path: + """DocWrite: install_python.md ## Workflow - 5. Verify download + We set the `GNUPGHOME` environment variable to a temporary directory.""" + env = {'GNUPGHOME': str(temp_path)} + run([gpg_bin, '--keyserver', GPG_KEY_SERVER, '--recv-keys', gpg_key_id], check=True, env=env) + run([gpg_bin, '--verify', asc_file_path, tar_file_path], check=True, env=env) + run(['gpgconf', '--kill', 'all'], check=True, env=env) else: logger.warning('No GPG verification possible! (gpg not found)') @@ -163,17 +179,26 @@ def install_python( write_check: bool = True, delete_temp: bool = True, ) -> Path: - logger.info(f'Installing Python {major_version} interpreter.') + logger.info('Requested major Python version: %s', major_version) - # Check system Python version + """DocWrite: install_python.md ## Workflow + The setup process is as follows:""" + + """DocWrite: install_python.md ## Workflow - 1. Check system Python + If the system Python is the same major version as the required Python, we skip the installation.""" for try_version in (major_version, '3'): filename = f'python{try_version}' - logger.debug(f'Checking {filename}...') + logger.debug('Checking %s...', filename) if python3bin := shutil.which(filename): - if get_python_version(python3bin).startswith(major_version): - logger.info('Python version already installed') + if (full_version := get_python_version(python3bin)) and full_version.startswith(major_version): + logger.info('Python version already installed: Return path %r of it.', python3bin) + """DocWrite: install_python.md ## Workflow - 1. Check system Python + The script just returns the path to the system Python interpreter.""" return Path(python3bin) + """DocWrite: install_python.md ## Workflow - 2. Get latest Python release + We fetch the latest Python release from the Python FTP server, from: + DocWriteMacro: manageprojects.tests.docwrite_macros.ftp_url""" # Get latest full version number of Python from Python FTP: py_required_version = get_latest_versions( html=get_html_page(PY_FTP_INDEX_URL), @@ -182,19 +207,27 @@ def install_python( local_bin_path = Path(DEFAULT_INSTALL_PREFIX) / 'bin' - # Check existing built version of Python in /usr/local/bin + """DocWrite: install_python.md ## Workflow - 3. Check local installed Python + The script checks if the latest release already build and installed.""" local_python_path = local_bin_path / f'python{major_version}' if local_python_path.exists() and get_python_version(local_python_path) == py_required_version: - logger.info('Local Python is up to date') + logger.info('Local Python is up-to-date') + """DocWrite: install_python.md ## Workflow - 3. Check local installed Python + If the local Python is up-to-date, the script exist and returns the path this local interpreter.""" return local_python_path - # Before we start building Python, check if we have write permissions: + """DocWrite: install_python.md ## Workflow - 4. Download Python sources + Before we start building Python, check if we have write permissions. + The check can be skipped via CLI argument.""" if write_check and not os.access(local_bin_path, os.W_OK): raise PermissionError(f'No write permission to {local_bin_path} (Hint: Call with "sudo" ?!)') - # Download, build and Setup Python + """DocWrite: install_python.md ## Workflow - 4. Download Python sources + The download will be done in a temporary directory. The directory will be deleted after the installation. + This can be skipped via CLI argument. The directory will be prefixed with: + DocWriteMacro: manageprojects.tests.docwrite_macros.temp_prefix""" with TemporaryDirectory(prefix=TEMP_PREFIX, delete=delete_temp) as temp_path: - base_url = f'https://www.python.org/ftp/python/{py_required_version}' + base_url = f'{PY_FTP_INDEX_URL}{py_required_version}' tar_filename = f'Python-{py_required_version}.tar.xz' asc_filename = f'{tar_filename}.asc' @@ -212,15 +245,18 @@ def install_python( major_version=major_version, tar_file_path=tar_file_path, asc_file_path=asc_file_path, + delete_temp=delete_temp, ) tar_bin = shutil.which('tar') - logger.debug(f'Extracting {tar_file_path} with ...') + logger.debug('Extracting %s with ...', tar_file_path) run([tar_bin, 'xf', tar_file_path], check=True, cwd=temp_path) extracted_dir = temp_path / f'Python-{py_required_version}' - logger.info(f'Building Python {py_required_version} (may take a while)...') + logger.info('Building Python %s (may take a while)...', py_required_version) + """DocWrite: install_python.md ## Workflow - 6. Build and install Python + If the verify passed, the script will start the build process.""" run_build_step( ['./configure', '--enable-optimizations'], step='configure', @@ -231,13 +267,16 @@ def install_python( step='make', cwd=extracted_dir, ) + + """DocWrite: install_python.md ## Workflow - 6. Build and install Python + The installation will be done with `make altinstall`.""" run_build_step( ['make', 'altinstall'], step='install', cwd=extracted_dir, ) - logger.info(f'Python {py_required_version} installed to {local_python_path}') + logger.info('Python %s installed to %s', py_required_version, local_python_path) local_python_version = get_python_version(local_python_path) assert local_python_version == py_required_version, f'{local_python_version} is not {py_required_version}' @@ -245,11 +284,21 @@ def install_python( return local_python_path -def main() -> Path: +def get_parser() -> argparse.ArgumentParser: + """ + DocWrite: install_python.md ## CLI + The CLI interface looks like e.g.: + ```shell + $ python3 install_python.py --help + + DocWriteMacro: manageprojects.tests.docwrite_macros.help + ``` + """ parser = argparse.ArgumentParser( - description='Setup Python Interpreter', + description='Install Python Interpreter', formatter_class=argparse.ArgumentDefaultsHelpFormatter, ) + parser.add_argument( 'major_version', nargs=argparse.OPTIONAL, @@ -267,13 +316,18 @@ def main() -> Path: parser.add_argument( '--skip-temp-deletion', action='store_true', - help='Skip deletion of temporary files created during build steps', + help='Skip deletion of temporary files', ) parser.add_argument( '--skip-write-check', action='store_true', help='Skip the test for write permission to /usr/local/bin', ) + return parser + + +def main() -> Path: + parser = get_parser() args = parser.parse_args() verbose2level = {0: logging.WARNING, 1: logging.INFO, 2: logging.DEBUG} logging.basicConfig( @@ -281,7 +335,7 @@ def main() -> Path: format='%(levelname)9s %(message)s', stream=sys.stderr, ) - logger.debug(f'Arguments: {args}') + logger.debug('Arguments: %s', args) return install_python( major_version=args.major_version, write_check=not args.skip_write_check, @@ -291,4 +345,10 @@ def main() -> Path: if __name__ == '__main__': python_path = main() + + """DocWrite: install_python.md ## Workflow - 7. print the path + If no errors occurred, the path to the Python interpreter will be printed to `stdout`. + So it's usable in shell scripts, like: + DocWriteMacro: manageprojects.tests.docwrite_macros.example_shell_script + """ print(python_path) diff --git a/conf/requirements.txt b/conf/requirements.txt index a1a3651..a62f4a9 100644 --- a/conf/requirements.txt +++ b/conf/requirements.txt @@ -41,9 +41,9 @@ bx-py-utils==98 \ # cli-base-utilities # django-for-runners # django-tools -cattrs==23.2.3 \ - --hash=sha256:0341994d94971052e9ee70662542699a3162ea1e0c62f7ce1b4a57f563685108 \ - --hash=sha256:a934090d95abaa9e911dac357e3a8699e0b4b14f8529bcc7d2b1ad9d51672b9f +cattrs==24.1.0 \ + --hash=sha256:043bb8af72596432a7df63abcff0055ac0f198a4d2e95af8db5a936a7074a761 \ + --hash=sha256:8274f18b253bf7674a43da851e3096370d67088165d23138b04a1c04c8eaf48e # via requests-cache certifi==2024.7.4 \ --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \ @@ -158,51 +158,72 @@ colorlog==6.8.2 \ # django-for-runners # django-tools # django-yunohost-integration -contourpy==1.2.1 \ - --hash=sha256:00e5388f71c1a0610e6fe56b5c44ab7ba14165cdd6d695429c5cd94021e390b2 \ - --hash=sha256:10a37ae557aabf2509c79715cd20b62e4c7c28b8cd62dd7d99e5ed3ce28c3fd9 \ - --hash=sha256:11959f0ce4a6f7b76ec578576a0b61a28bdc0696194b6347ba3f1c53827178b9 \ - --hash=sha256:187fa1d4c6acc06adb0fae5544c59898ad781409e61a926ac7e84b8f276dcef4 \ - --hash=sha256:1a07fc092a4088ee952ddae19a2b2a85757b923217b7eed584fdf25f53a6e7ce \ - --hash=sha256:1cac0a8f71a041aa587410424ad46dfa6a11f6149ceb219ce7dd48f6b02b87a7 \ - --hash=sha256:1d59e739ab0e3520e62a26c60707cc3ab0365d2f8fecea74bfe4de72dc56388f \ - --hash=sha256:2855c8b0b55958265e8b5888d6a615ba02883b225f2227461aa9127c578a4922 \ - --hash=sha256:2e785e0f2ef0d567099b9ff92cbfb958d71c2d5b9259981cd9bee81bd194c9a4 \ - --hash=sha256:309be79c0a354afff9ff7da4aaed7c3257e77edf6c1b448a779329431ee79d7e \ - --hash=sha256:39f3ecaf76cd98e802f094e0d4fbc6dc9c45a8d0c4d185f0f6c2234e14e5f75b \ - --hash=sha256:457499c79fa84593f22454bbd27670227874cd2ff5d6c84e60575c8b50a69619 \ - --hash=sha256:49e70d111fee47284d9dd867c9bb9a7058a3c617274900780c43e38d90fe1205 \ - --hash=sha256:4c75507d0a55378240f781599c30e7776674dbaf883a46d1c90f37e563453480 \ - --hash=sha256:4c863140fafc615c14a4bf4efd0f4425c02230eb8ef02784c9a156461e62c965 \ - --hash=sha256:4d8908b3bee1c889e547867ca4cdc54e5ab6be6d3e078556814a22457f49423c \ - --hash=sha256:5b9eb0ca724a241683c9685a484da9d35c872fd42756574a7cfbf58af26677fd \ - --hash=sha256:6022cecf8f44e36af10bd9118ca71f371078b4c168b6e0fab43d4a889985dbb5 \ - --hash=sha256:6150ffa5c767bc6332df27157d95442c379b7dce3a38dff89c0f39b63275696f \ - --hash=sha256:62828cada4a2b850dbef89c81f5a33741898b305db244904de418cc957ff05dc \ - --hash=sha256:7b4182299f251060996af5249c286bae9361fa8c6a9cda5efc29fe8bfd6062ec \ - --hash=sha256:94b34f32646ca0414237168d68a9157cb3889f06b096612afdd296003fdd32fd \ - --hash=sha256:9ce6889abac9a42afd07a562c2d6d4b2b7134f83f18571d859b25624a331c90b \ - --hash=sha256:9cffe0f850e89d7c0012a1fb8730f75edd4320a0a731ed0c183904fe6ecfc3a9 \ - --hash=sha256:a12a813949e5066148712a0626895c26b2578874e4cc63160bb007e6df3436fe \ - --hash=sha256:a1eea9aecf761c661d096d39ed9026574de8adb2ae1c5bd7b33558af884fb2ce \ - --hash=sha256:a31f94983fecbac95e58388210427d68cd30fe8a36927980fab9c20062645609 \ - --hash=sha256:ac58bdee53cbeba2ecad824fa8159493f0bf3b8ea4e93feb06c9a465d6c87da8 \ - --hash=sha256:af3f4485884750dddd9c25cb7e3915d83c2db92488b38ccb77dd594eac84c4a0 \ - --hash=sha256:b33d2bc4f69caedcd0a275329eb2198f560b325605810895627be5d4b876bf7f \ - --hash=sha256:b59c0ffceff8d4d3996a45f2bb6f4c207f94684a96bf3d9728dbb77428dd8cb8 \ - --hash=sha256:bb6834cbd983b19f06908b45bfc2dad6ac9479ae04abe923a275b5f48f1a186b \ - --hash=sha256:bd3db01f59fdcbce5b22afad19e390260d6d0222f35a1023d9adc5690a889364 \ - --hash=sha256:bd7c23df857d488f418439686d3b10ae2fbf9bc256cd045b37a8c16575ea1040 \ - --hash=sha256:c2528d60e398c7c4c799d56f907664673a807635b857df18f7ae64d3e6ce2d9f \ - --hash=sha256:d31a63bc6e6d87f77d71e1abbd7387ab817a66733734883d1fc0021ed9bfa083 \ - --hash=sha256:d4492d82b3bc7fbb7e3610747b159869468079fe149ec5c4d771fa1f614a14df \ - --hash=sha256:ddcb8581510311e13421b1f544403c16e901c4e8f09083c881fab2be80ee31ba \ - --hash=sha256:e1d59258c3c67c865435d8fbeb35f8c59b8bef3d6f46c1f29f6123556af28445 \ - --hash=sha256:eb3315a8a236ee19b6df481fc5f997436e8ade24a9f03dfdc6bd490fea20c6da \ - --hash=sha256:ef2b055471c0eb466033760a521efb9d8a32b99ab907fc8358481a1dd29e3bd3 \ - --hash=sha256:ef5adb9a3b1d0c645ff694f9bca7702ec2c70f4d734f9922ea34de02294fdf72 \ - --hash=sha256:f32c38afb74bd98ce26de7cc74a67b40afb7b05aae7b42924ea990d51e4dac02 \ - --hash=sha256:fe0ccca550bb8e5abc22f530ec0466136379c01321fd94f30a22231e8a48d985 +contourpy==1.3.0 \ + --hash=sha256:00ccd0dbaad6d804ab259820fa7cb0b8036bda0686ef844d24125d8287178ce0 \ + --hash=sha256:0be4d8425bfa755e0fd76ee1e019636ccc7c29f77a7c86b4328a9eb6a26d0639 \ + --hash=sha256:0dce35502151b6bd35027ac39ba6e5a44be13a68f55735c3612c568cac3805fd \ + --hash=sha256:0fa4c02abe6c446ba70d96ece336e621efa4aecae43eaa9b030ae5fb92b309ad \ + --hash=sha256:14e262f67bd7e6eb6880bc564dcda30b15e351a594657e55b7eec94b6ef72843 \ + --hash=sha256:167d6c890815e1dac9536dca00828b445d5d0df4d6a8c6adb4a7ec3166812fa8 \ + --hash=sha256:1ec4dc6bf570f5b22ed0d7efba0dfa9c5b9e0431aeea7581aa217542d9e809a4 \ + --hash=sha256:303c252947ab4b14c08afeb52375b26781ccd6a5ccd81abcdfc1fafd14cf93c1 \ + --hash=sha256:31cd3a85dbdf1fc002280c65caa7e2b5f65e4a973fcdf70dd2fdcb9868069294 \ + --hash=sha256:32b238b3b3b649e09ce9aaf51f0c261d38644bdfa35cbaf7b263457850957a84 \ + --hash=sha256:33c92cdae89ec5135d036e7218e69b0bb2851206077251f04a6c4e0e21f03927 \ + --hash=sha256:345af746d7766821d05d72cb8f3845dfd08dd137101a2cb9b24de277d716def8 \ + --hash=sha256:3634b5385c6716c258d0419c46d05c8aa7dc8cb70326c9a4fb66b69ad2b52e09 \ + --hash=sha256:364174c2a76057feef647c802652f00953b575723062560498dc7930fc9b1cb7 \ + --hash=sha256:36e0cff201bcb17a0a8ecc7f454fe078437fa6bda730e695a92f2d9932bd507f \ + --hash=sha256:36f965570cff02b874773c49bfe85562b47030805d7d8360748f3eca570f4cab \ + --hash=sha256:3bb3808858a9dc68f6f03d319acd5f1b8a337e6cdda197f02f4b8ff67ad2057b \ + --hash=sha256:3e1c7fa44aaae40a2247e2e8e0627f4bea3dd257014764aa644f319a5f8600e3 \ + --hash=sha256:3faeb2998e4fcb256542e8a926d08da08977f7f5e62cf733f3c211c2a5586223 \ + --hash=sha256:420d39daa61aab1221567b42eecb01112908b2cab7f1b4106a52caaec8d36973 \ + --hash=sha256:4553c421929ec95fb07b3aaca0fae668b2eb5a5203d1217ca7c34c063c53d087 \ + --hash=sha256:4865cd1d419e0c7a7bf6de1777b185eebdc51470800a9f42b9e9decf17762081 \ + --hash=sha256:4cfb5c62ce023dfc410d6059c936dcf96442ba40814aefbfa575425a3a7f19dc \ + --hash=sha256:4d63ee447261e963af02642ffcb864e5a2ee4cbfd78080657a9880b8b1868e18 \ + --hash=sha256:570ef7cf892f0afbe5b2ee410c507ce12e15a5fa91017a0009f79f7d93a1268f \ + --hash=sha256:637f674226be46f6ba372fd29d9523dd977a291f66ab2a74fbeb5530bb3f445d \ + --hash=sha256:68a32389b06b82c2fdd68276148d7b9275b5f5cf13e5417e4252f6d1a34f72a2 \ + --hash=sha256:69375194457ad0fad3a839b9e29aa0b0ed53bb54db1bfb6c3ae43d111c31ce41 \ + --hash=sha256:6cb6cc968059db9c62cb35fbf70248f40994dfcd7aa10444bbf8b3faeb7c2d67 \ + --hash=sha256:710a26b3dc80c0e4febf04555de66f5fd17e9cf7170a7b08000601a10570bda6 \ + --hash=sha256:732896af21716b29ab3e988d4ce14bc5133733b85956316fb0c56355f398099b \ + --hash=sha256:75ee7cb1a14c617f34a51d11fa7524173e56551646828353c4af859c56b766e2 \ + --hash=sha256:76a896b2f195b57db25d6b44e7e03f221d32fe318d03ede41f8b4d9ba1bff53c \ + --hash=sha256:76c905ef940a4474a6289c71d53122a4f77766eef23c03cd57016ce19d0f7b42 \ + --hash=sha256:7a52040312b1a858b5e31ef28c2e865376a386c60c0e248370bbea2d3f3b760d \ + --hash=sha256:7ffa0db17717a8ffb127efd0c95a4362d996b892c2904db72428d5b52e1938a4 \ + --hash=sha256:81cb5ed4952aae6014bc9d0421dec7c5835c9c8c31cdf51910b708f548cf58e5 \ + --hash=sha256:834e0cfe17ba12f79963861e0f908556b2cedd52e1f75e6578801febcc6a9f49 \ + --hash=sha256:87ddffef1dbe5e669b5c2440b643d3fdd8622a348fe1983fad7a0f0ccb1cd67b \ + --hash=sha256:880ea32e5c774634f9fcd46504bf9f080a41ad855f4fef54f5380f5133d343c7 \ + --hash=sha256:8ca947601224119117f7c19c9cdf6b3ab54c5726ef1d906aa4a69dfb6dd58102 \ + --hash=sha256:90f73a5116ad1ba7174341ef3ea5c3150ddf20b024b98fb0c3b29034752c8aeb \ + --hash=sha256:92f8557cbb07415a4d6fa191f20fd9d2d9eb9c0b61d1b2f52a8926e43c6e9af7 \ + --hash=sha256:94e848a6b83da10898cbf1311a815f770acc9b6a3f2d646f330d57eb4e87592e \ + --hash=sha256:9c0da700bf58f6e0b65312d0a5e695179a71d0163957fa381bb3c1f72972537c \ + --hash=sha256:a11077e395f67ffc2c44ec2418cfebed032cd6da3022a94fc227b6faf8e2acb8 \ + --hash=sha256:aea348f053c645100612b333adc5983d87be69acdc6d77d3169c090d3b01dc35 \ + --hash=sha256:b11b39aea6be6764f84360fce6c82211a9db32a7c7de8fa6dd5397cf1d079c3b \ + --hash=sha256:c6c7c2408b7048082932cf4e641fa3b8ca848259212f51c8c59c45aa7ac18f14 \ + --hash=sha256:c6ec93afeb848a0845a18989da3beca3eec2c0f852322efe21af1931147d12cb \ + --hash=sha256:cacd81e2d4b6f89c9f8a5b69b86490152ff39afc58a95af002a398273e5ce589 \ + --hash=sha256:d402880b84df3bec6eab53cd0cf802cae6a2ef9537e70cf75e91618a3801c20c \ + --hash=sha256:d51fca85f9f7ad0b65b4b9fe800406d0d77017d7270d31ec3fb1cc07358fdea0 \ + --hash=sha256:d73f659398a0904e125280836ae6f88ba9b178b2fed6884f3b1f95b989d2c8da \ + --hash=sha256:d78ab28a03c854a873787a0a42254a0ccb3cb133c672f645c9f9c8f3ae9d0800 \ + --hash=sha256:da84c537cb8b97d153e9fb208c221c45605f73147bd4cadd23bdae915042aad6 \ + --hash=sha256:dbc4c3217eee163fa3984fd1567632b48d6dfd29216da3ded3d7b844a8014a66 \ + --hash=sha256:e12968fdfd5bb45ffdf6192a590bd8ddd3ba9e58360b29683c6bb71a7b41edca \ + --hash=sha256:e1fd23e9d01591bab45546c089ae89d926917a66dceb3abcf01f6105d927e2cb \ + --hash=sha256:e8134301d7e204c88ed7ab50028ba06c683000040ede1d617298611f9dc6240c \ + --hash=sha256:eb8b141bb00fa977d9122636b16aa67d37fd40a3d8b52dd837e536d64b9a4d06 \ + --hash=sha256:eca7e17a65f72a5133bdbec9ecf22401c62bcf4821361ef7811faee695799779 \ + --hash=sha256:f317576606de89da6b7e0861cf6061f6146ead3528acabff9236458a6ba467f8 \ + --hash=sha256:fd2a0fc506eccaaa7595b7e1418951f213cf8255be2600f1ea1b61e46a60c55f \ + --hash=sha256:fe41b41505a5a33aeaed2a613dccaeaa74e0e3ead6dd6fd3a118fb471644fd6c # via matplotlib cycler==0.12.1 \ --hash=sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30 \ @@ -860,9 +881,9 @@ pygments==2.18.0 \ --hash=sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199 \ --hash=sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a # via rich -pyparsing==3.1.3 \ - --hash=sha256:1e80fdf93e6c1aeaf4702523f1d48f66d52fa6459096a8f812591157270a5896 \ - --hash=sha256:5d549d2a1b5e1c3e952bb55ea247bfb5ad427ea307566a350db2b3c34d4ce181 +pyparsing==3.1.4 \ + --hash=sha256:a6a7ee4235a3f944aa1fa2249307708f893fe5717dc603503c6c7969c070fb7c \ + --hash=sha256:f86ec8d1a83f11977c9a6ea7598e8c27fc5cddfa5b07ea2241edbbde1d7bc032 # via matplotlib python-dateutil==2.9.0.post0 \ --hash=sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3 \ @@ -952,9 +973,9 @@ retry-requests==2.0.0 \ --hash=sha256:38e8e3f55051e7b7915c1768884269097865a5da2ea87d5dcafd6ba9498c363f \ --hash=sha256:3d02135e5aafedf09240414182fc7389c5d2b4de0252daba0054c9d6a27e7639 # via django-for-runners -rich==13.7.1 \ - --hash=sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222 \ - --hash=sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432 +rich==13.8.0 \ + --hash=sha256:2e85306a063b9492dffc86278197a60cbece75bcb766022f3436f567cae11bdc \ + --hash=sha256:a5ac1f1cd448ade0d59cc3356f7db7a7ccda2c8cbae9c7a90c28ff463d3e91f4 # via # cli-base-utilities # django-rich diff --git a/for_runners_ynh/tests/test_install_python.py b/for_runners_ynh/tests/test_install_python.py new file mode 100644 index 0000000..c3df8c7 --- /dev/null +++ b/for_runners_ynh/tests/test_install_python.py @@ -0,0 +1,17 @@ +""" + https://github.com/jedie/manageprojects/blob/main/docs/install_python.md#include-in-own-projects +""" + +from django_yunohost_integration.path_utils import get_project_root +from manageprojects.utilities.include_install_python import IncludeInstallPythonBaseTestCase + + +class IncludeInstallPythonTestCase(IncludeInstallPythonBaseTestCase): + """ + Updates `conf/install_python.py` from `manageprojects` if needed. + """ + + DESTINATION_PATH = get_project_root() / 'conf' / 'install_python.py' + + def test_install_python_is_up2date(self): + self.auto_update_install_python() diff --git a/pyproject.toml b/pyproject.toml index fe43e7f..7c1ef8c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,7 +21,7 @@ dependencies = [ dev = [ "bx_django_utils", # https://github.com/boxine/bx_django_utils "beautifulsoup4", # https://pypi.org/project/beautifulsoup4/ - "manageprojects", # https://github.com/jedie/manageprojects + "manageprojects>=0.18.0", # https://github.com/jedie/manageprojects "pip-tools", # https://github.com/jazzband/pip-tools/ "tblib", # https://github.com/ionelmc/python-tblib "tox", # https://github.com/tox-dev/tox diff --git a/requirements.dev.txt b/requirements.dev.txt index 12ce78b..183263e 100644 --- a/requirements.dev.txt +++ b/requirements.dev.txt @@ -115,9 +115,9 @@ cachetools==5.5.0 \ --hash=sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292 \ --hash=sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a # via tox -cattrs==23.2.3 \ - --hash=sha256:0341994d94971052e9ee70662542699a3162ea1e0c62f7ce1b4a57f563685108 \ - --hash=sha256:a934090d95abaa9e911dac357e3a8699e0b4b14f8529bcc7d2b1ad9d51672b9f +cattrs==24.1.0 \ + --hash=sha256:043bb8af72596432a7df63abcff0055ac0f198a4d2e95af8db5a936a7074a761 \ + --hash=sha256:8274f18b253bf7674a43da851e3096370d67088165d23138b04a1c04c8eaf48e # via requests-cache certifi==2024.7.4 \ --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \ @@ -323,51 +323,72 @@ colorlog==6.8.2 \ # django-for-runners # django-tools # django-yunohost-integration -contourpy==1.2.1 \ - --hash=sha256:00e5388f71c1a0610e6fe56b5c44ab7ba14165cdd6d695429c5cd94021e390b2 \ - --hash=sha256:10a37ae557aabf2509c79715cd20b62e4c7c28b8cd62dd7d99e5ed3ce28c3fd9 \ - --hash=sha256:11959f0ce4a6f7b76ec578576a0b61a28bdc0696194b6347ba3f1c53827178b9 \ - --hash=sha256:187fa1d4c6acc06adb0fae5544c59898ad781409e61a926ac7e84b8f276dcef4 \ - --hash=sha256:1a07fc092a4088ee952ddae19a2b2a85757b923217b7eed584fdf25f53a6e7ce \ - --hash=sha256:1cac0a8f71a041aa587410424ad46dfa6a11f6149ceb219ce7dd48f6b02b87a7 \ - --hash=sha256:1d59e739ab0e3520e62a26c60707cc3ab0365d2f8fecea74bfe4de72dc56388f \ - --hash=sha256:2855c8b0b55958265e8b5888d6a615ba02883b225f2227461aa9127c578a4922 \ - --hash=sha256:2e785e0f2ef0d567099b9ff92cbfb958d71c2d5b9259981cd9bee81bd194c9a4 \ - --hash=sha256:309be79c0a354afff9ff7da4aaed7c3257e77edf6c1b448a779329431ee79d7e \ - --hash=sha256:39f3ecaf76cd98e802f094e0d4fbc6dc9c45a8d0c4d185f0f6c2234e14e5f75b \ - --hash=sha256:457499c79fa84593f22454bbd27670227874cd2ff5d6c84e60575c8b50a69619 \ - --hash=sha256:49e70d111fee47284d9dd867c9bb9a7058a3c617274900780c43e38d90fe1205 \ - --hash=sha256:4c75507d0a55378240f781599c30e7776674dbaf883a46d1c90f37e563453480 \ - --hash=sha256:4c863140fafc615c14a4bf4efd0f4425c02230eb8ef02784c9a156461e62c965 \ - --hash=sha256:4d8908b3bee1c889e547867ca4cdc54e5ab6be6d3e078556814a22457f49423c \ - --hash=sha256:5b9eb0ca724a241683c9685a484da9d35c872fd42756574a7cfbf58af26677fd \ - --hash=sha256:6022cecf8f44e36af10bd9118ca71f371078b4c168b6e0fab43d4a889985dbb5 \ - --hash=sha256:6150ffa5c767bc6332df27157d95442c379b7dce3a38dff89c0f39b63275696f \ - --hash=sha256:62828cada4a2b850dbef89c81f5a33741898b305db244904de418cc957ff05dc \ - --hash=sha256:7b4182299f251060996af5249c286bae9361fa8c6a9cda5efc29fe8bfd6062ec \ - --hash=sha256:94b34f32646ca0414237168d68a9157cb3889f06b096612afdd296003fdd32fd \ - --hash=sha256:9ce6889abac9a42afd07a562c2d6d4b2b7134f83f18571d859b25624a331c90b \ - --hash=sha256:9cffe0f850e89d7c0012a1fb8730f75edd4320a0a731ed0c183904fe6ecfc3a9 \ - --hash=sha256:a12a813949e5066148712a0626895c26b2578874e4cc63160bb007e6df3436fe \ - --hash=sha256:a1eea9aecf761c661d096d39ed9026574de8adb2ae1c5bd7b33558af884fb2ce \ - --hash=sha256:a31f94983fecbac95e58388210427d68cd30fe8a36927980fab9c20062645609 \ - --hash=sha256:ac58bdee53cbeba2ecad824fa8159493f0bf3b8ea4e93feb06c9a465d6c87da8 \ - --hash=sha256:af3f4485884750dddd9c25cb7e3915d83c2db92488b38ccb77dd594eac84c4a0 \ - --hash=sha256:b33d2bc4f69caedcd0a275329eb2198f560b325605810895627be5d4b876bf7f \ - --hash=sha256:b59c0ffceff8d4d3996a45f2bb6f4c207f94684a96bf3d9728dbb77428dd8cb8 \ - --hash=sha256:bb6834cbd983b19f06908b45bfc2dad6ac9479ae04abe923a275b5f48f1a186b \ - --hash=sha256:bd3db01f59fdcbce5b22afad19e390260d6d0222f35a1023d9adc5690a889364 \ - --hash=sha256:bd7c23df857d488f418439686d3b10ae2fbf9bc256cd045b37a8c16575ea1040 \ - --hash=sha256:c2528d60e398c7c4c799d56f907664673a807635b857df18f7ae64d3e6ce2d9f \ - --hash=sha256:d31a63bc6e6d87f77d71e1abbd7387ab817a66733734883d1fc0021ed9bfa083 \ - --hash=sha256:d4492d82b3bc7fbb7e3610747b159869468079fe149ec5c4d771fa1f614a14df \ - --hash=sha256:ddcb8581510311e13421b1f544403c16e901c4e8f09083c881fab2be80ee31ba \ - --hash=sha256:e1d59258c3c67c865435d8fbeb35f8c59b8bef3d6f46c1f29f6123556af28445 \ - --hash=sha256:eb3315a8a236ee19b6df481fc5f997436e8ade24a9f03dfdc6bd490fea20c6da \ - --hash=sha256:ef2b055471c0eb466033760a521efb9d8a32b99ab907fc8358481a1dd29e3bd3 \ - --hash=sha256:ef5adb9a3b1d0c645ff694f9bca7702ec2c70f4d734f9922ea34de02294fdf72 \ - --hash=sha256:f32c38afb74bd98ce26de7cc74a67b40afb7b05aae7b42924ea990d51e4dac02 \ - --hash=sha256:fe0ccca550bb8e5abc22f530ec0466136379c01321fd94f30a22231e8a48d985 +contourpy==1.3.0 \ + --hash=sha256:00ccd0dbaad6d804ab259820fa7cb0b8036bda0686ef844d24125d8287178ce0 \ + --hash=sha256:0be4d8425bfa755e0fd76ee1e019636ccc7c29f77a7c86b4328a9eb6a26d0639 \ + --hash=sha256:0dce35502151b6bd35027ac39ba6e5a44be13a68f55735c3612c568cac3805fd \ + --hash=sha256:0fa4c02abe6c446ba70d96ece336e621efa4aecae43eaa9b030ae5fb92b309ad \ + --hash=sha256:14e262f67bd7e6eb6880bc564dcda30b15e351a594657e55b7eec94b6ef72843 \ + --hash=sha256:167d6c890815e1dac9536dca00828b445d5d0df4d6a8c6adb4a7ec3166812fa8 \ + --hash=sha256:1ec4dc6bf570f5b22ed0d7efba0dfa9c5b9e0431aeea7581aa217542d9e809a4 \ + --hash=sha256:303c252947ab4b14c08afeb52375b26781ccd6a5ccd81abcdfc1fafd14cf93c1 \ + --hash=sha256:31cd3a85dbdf1fc002280c65caa7e2b5f65e4a973fcdf70dd2fdcb9868069294 \ + --hash=sha256:32b238b3b3b649e09ce9aaf51f0c261d38644bdfa35cbaf7b263457850957a84 \ + --hash=sha256:33c92cdae89ec5135d036e7218e69b0bb2851206077251f04a6c4e0e21f03927 \ + --hash=sha256:345af746d7766821d05d72cb8f3845dfd08dd137101a2cb9b24de277d716def8 \ + --hash=sha256:3634b5385c6716c258d0419c46d05c8aa7dc8cb70326c9a4fb66b69ad2b52e09 \ + --hash=sha256:364174c2a76057feef647c802652f00953b575723062560498dc7930fc9b1cb7 \ + --hash=sha256:36e0cff201bcb17a0a8ecc7f454fe078437fa6bda730e695a92f2d9932bd507f \ + --hash=sha256:36f965570cff02b874773c49bfe85562b47030805d7d8360748f3eca570f4cab \ + --hash=sha256:3bb3808858a9dc68f6f03d319acd5f1b8a337e6cdda197f02f4b8ff67ad2057b \ + --hash=sha256:3e1c7fa44aaae40a2247e2e8e0627f4bea3dd257014764aa644f319a5f8600e3 \ + --hash=sha256:3faeb2998e4fcb256542e8a926d08da08977f7f5e62cf733f3c211c2a5586223 \ + --hash=sha256:420d39daa61aab1221567b42eecb01112908b2cab7f1b4106a52caaec8d36973 \ + --hash=sha256:4553c421929ec95fb07b3aaca0fae668b2eb5a5203d1217ca7c34c063c53d087 \ + --hash=sha256:4865cd1d419e0c7a7bf6de1777b185eebdc51470800a9f42b9e9decf17762081 \ + --hash=sha256:4cfb5c62ce023dfc410d6059c936dcf96442ba40814aefbfa575425a3a7f19dc \ + --hash=sha256:4d63ee447261e963af02642ffcb864e5a2ee4cbfd78080657a9880b8b1868e18 \ + --hash=sha256:570ef7cf892f0afbe5b2ee410c507ce12e15a5fa91017a0009f79f7d93a1268f \ + --hash=sha256:637f674226be46f6ba372fd29d9523dd977a291f66ab2a74fbeb5530bb3f445d \ + --hash=sha256:68a32389b06b82c2fdd68276148d7b9275b5f5cf13e5417e4252f6d1a34f72a2 \ + --hash=sha256:69375194457ad0fad3a839b9e29aa0b0ed53bb54db1bfb6c3ae43d111c31ce41 \ + --hash=sha256:6cb6cc968059db9c62cb35fbf70248f40994dfcd7aa10444bbf8b3faeb7c2d67 \ + --hash=sha256:710a26b3dc80c0e4febf04555de66f5fd17e9cf7170a7b08000601a10570bda6 \ + --hash=sha256:732896af21716b29ab3e988d4ce14bc5133733b85956316fb0c56355f398099b \ + --hash=sha256:75ee7cb1a14c617f34a51d11fa7524173e56551646828353c4af859c56b766e2 \ + --hash=sha256:76a896b2f195b57db25d6b44e7e03f221d32fe318d03ede41f8b4d9ba1bff53c \ + --hash=sha256:76c905ef940a4474a6289c71d53122a4f77766eef23c03cd57016ce19d0f7b42 \ + --hash=sha256:7a52040312b1a858b5e31ef28c2e865376a386c60c0e248370bbea2d3f3b760d \ + --hash=sha256:7ffa0db17717a8ffb127efd0c95a4362d996b892c2904db72428d5b52e1938a4 \ + --hash=sha256:81cb5ed4952aae6014bc9d0421dec7c5835c9c8c31cdf51910b708f548cf58e5 \ + --hash=sha256:834e0cfe17ba12f79963861e0f908556b2cedd52e1f75e6578801febcc6a9f49 \ + --hash=sha256:87ddffef1dbe5e669b5c2440b643d3fdd8622a348fe1983fad7a0f0ccb1cd67b \ + --hash=sha256:880ea32e5c774634f9fcd46504bf9f080a41ad855f4fef54f5380f5133d343c7 \ + --hash=sha256:8ca947601224119117f7c19c9cdf6b3ab54c5726ef1d906aa4a69dfb6dd58102 \ + --hash=sha256:90f73a5116ad1ba7174341ef3ea5c3150ddf20b024b98fb0c3b29034752c8aeb \ + --hash=sha256:92f8557cbb07415a4d6fa191f20fd9d2d9eb9c0b61d1b2f52a8926e43c6e9af7 \ + --hash=sha256:94e848a6b83da10898cbf1311a815f770acc9b6a3f2d646f330d57eb4e87592e \ + --hash=sha256:9c0da700bf58f6e0b65312d0a5e695179a71d0163957fa381bb3c1f72972537c \ + --hash=sha256:a11077e395f67ffc2c44ec2418cfebed032cd6da3022a94fc227b6faf8e2acb8 \ + --hash=sha256:aea348f053c645100612b333adc5983d87be69acdc6d77d3169c090d3b01dc35 \ + --hash=sha256:b11b39aea6be6764f84360fce6c82211a9db32a7c7de8fa6dd5397cf1d079c3b \ + --hash=sha256:c6c7c2408b7048082932cf4e641fa3b8ca848259212f51c8c59c45aa7ac18f14 \ + --hash=sha256:c6ec93afeb848a0845a18989da3beca3eec2c0f852322efe21af1931147d12cb \ + --hash=sha256:cacd81e2d4b6f89c9f8a5b69b86490152ff39afc58a95af002a398273e5ce589 \ + --hash=sha256:d402880b84df3bec6eab53cd0cf802cae6a2ef9537e70cf75e91618a3801c20c \ + --hash=sha256:d51fca85f9f7ad0b65b4b9fe800406d0d77017d7270d31ec3fb1cc07358fdea0 \ + --hash=sha256:d73f659398a0904e125280836ae6f88ba9b178b2fed6884f3b1f95b989d2c8da \ + --hash=sha256:d78ab28a03c854a873787a0a42254a0ccb3cb133c672f645c9f9c8f3ae9d0800 \ + --hash=sha256:da84c537cb8b97d153e9fb208c221c45605f73147bd4cadd23bdae915042aad6 \ + --hash=sha256:dbc4c3217eee163fa3984fd1567632b48d6dfd29216da3ded3d7b844a8014a66 \ + --hash=sha256:e12968fdfd5bb45ffdf6192a590bd8ddd3ba9e58360b29683c6bb71a7b41edca \ + --hash=sha256:e1fd23e9d01591bab45546c089ae89d926917a66dceb3abcf01f6105d927e2cb \ + --hash=sha256:e8134301d7e204c88ed7ab50028ba06c683000040ede1d617298611f9dc6240c \ + --hash=sha256:eb8b141bb00fa977d9122636b16aa67d37fd40a3d8b52dd837e536d64b9a4d06 \ + --hash=sha256:eca7e17a65f72a5133bdbec9ecf22401c62bcf4821361ef7811faee695799779 \ + --hash=sha256:f317576606de89da6b7e0861cf6061f6146ead3528acabff9236458a6ba467f8 \ + --hash=sha256:fd2a0fc506eccaaa7595b7e1418951f213cf8255be2600f1ea1b61e46a60c55f \ + --hash=sha256:fe41b41505a5a33aeaed2a613dccaeaa74e0e3ead6dd6fd3a118fb471644fd6c # via matplotlib cookiecutter==2.6.0 \ --hash=sha256:a54a8e37995e4ed963b3e82831072d1ad4b005af736bb17b99c2cbd9d41b6e2d \ @@ -966,9 +987,9 @@ lxml==5.3.0 \ --hash=sha256:f914c03e6a31deb632e2daa881fe198461f4d06e57ac3d0e05bbcab8eae01945 \ --hash=sha256:fb66442c2546446944437df74379e9cf9e9db353e61301d1a0e26482f43f0dd8 # via django-for-runners -manageprojects==0.17.1 \ - --hash=sha256:355d970261f14b53b574d102e7e82462fe6769baa06c479f00f07a0bcfcb8e4d \ - --hash=sha256:4662ff7f0e64ea9b420b67c270594c88542858a1434ebe8b5f93b7bf2ae2e706 +manageprojects==0.18.0 \ + --hash=sha256:37b452c8eb464cf79d29f4e30e8e9c9bce0c1e525a3112d11ff66f99bd48dda4 \ + --hash=sha256:548ca16ba2c1d58c8f532d35cfbfb16fee236695b090b0e2d5303b1e9f60ce99 # via for_runners_ynh (pyproject.toml) markdown-it-py==3.0.0 \ --hash=sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1 \ @@ -1181,6 +1202,7 @@ mypy==1.11.2 \ # via # for_runners_ynh (pyproject.toml) # manageprojects + # refurb mypy-extensions==1.0.0 \ --hash=sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d \ --hash=sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782 @@ -1489,9 +1511,9 @@ pygments==2.18.0 \ # darker # readme-renderer # rich -pyparsing==3.1.3 \ - --hash=sha256:1e80fdf93e6c1aeaf4702523f1d48f66d52fa6459096a8f812591157270a5896 \ - --hash=sha256:5d549d2a1b5e1c3e952bb55ea247bfb5ad427ea307566a350db2b3c34d4ce181 +pyparsing==3.1.4 \ + --hash=sha256:a6a7ee4235a3f944aa1fa2249307708f893fe5717dc603503c6c7969c070fb7c \ + --hash=sha256:f86ec8d1a83f11977c9a6ea7598e8c27fc5cddfa5b07ea2241edbbde1d7bc032 # via # matplotlib # pip-requirements-parser @@ -1595,6 +1617,10 @@ redis==5.0.8 \ --hash=sha256:0c5b10d387568dfe0698c6fad6615750c24170e548ca2deac10c649d463e9870 \ --hash=sha256:56134ee08ea909106090934adc36f65c9bcbbaecea5b21ba704ba6fb561f8eb4 # via django-redis +refurb==2.0.0 \ + --hash=sha256:8a8f1e7c131ef7dc460cbecbeaf536f5eb0ecb657c099d7823941f0e65b1cfe1 \ + --hash=sha256:fa9e950dc6edd7473642569c118f8714eefd1e6f21a15ee4210a1be853aaaf80 + # via manageprojects requests==2.32.3 \ --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 @@ -1623,9 +1649,9 @@ rfc3986==2.0.0 \ --hash=sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd \ --hash=sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c # via twine -rich==13.7.1 \ - --hash=sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222 \ - --hash=sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432 +rich==13.8.0 \ + --hash=sha256:2e85306a063b9492dffc86278197a60cbece75bcb766022f3436f567cae11bdc \ + --hash=sha256:a5ac1f1cd448ade0d59cc3356f7db7a7ccda2c8cbae9c7a90c28ff463d3e91f4 # via # cli-base-utilities # cookiecutter @@ -1753,9 +1779,9 @@ wheel==0.44.0 \ --hash=sha256:2376a90c98cc337d18623527a97c31797bd02bad0033d41547043a1cbfbe448f \ --hash=sha256:a29c3f2817e95ab89aa4660681ad547c0e9547f20e75b0562fe7723c9a2a9d49 # via pip-tools -zipp==3.20.0 \ - --hash=sha256:0145e43d89664cfe1a2e533adc75adafed82fe2da404b4bbb6b026c0157bdb31 \ - --hash=sha256:58da6168be89f0be59beb194da1250516fdaa062ccebd30127ac65d30045e10d +zipp==3.20.1 \ + --hash=sha256:9960cd8967c8f85a56f920d5d507274e74f9ff813a0ab8889a5b5be2daf44064 \ + --hash=sha256:c22b14cc4763c5a5b04134207736c107db42e9d3ef2d9779d465f5f1bcba572b # via importlib-metadata # The following packages are considered to be unsafe in a requirements file: @@ -1765,7 +1791,7 @@ pip==24.2 \ # via # pip-api # pip-tools -setuptools==73.0.1 \ - --hash=sha256:b208925fcb9f7af924ed2dc04708ea89791e24bde0d3020b27df0e116088b34e \ - --hash=sha256:d59a3e788ab7e012ab2c4baed1b376da6366883ee20d7a5fc426816e3d7b1193 +setuptools==74.0.0 \ + --hash=sha256:0274581a0037b638b9fc1c6883cc71c0210865aaa76073f7882376b641b84e8f \ + --hash=sha256:a85e96b8be2b906f3e3e789adec6a9323abf79758ecfa3065bd740d81158b11e # via pip-tools