Merge pull request #73 from YunoHost-Apps/testing

master <- testing
This commit is contained in:
Jens Diemer 2024-08-30 13:02:46 +02:00 committed by GitHub
commit b1c9fc5b91
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 543 additions and 197 deletions

354
conf/install_python.py Executable file
View file

@ -0,0 +1,354 @@
#!/usr/bin/env python3
"""
DocWrite: install_python.md # Install Python Interpreter
`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)
Origin of this script is:
* https://github.com/jedie/manageprojects/blob/main/manageprojects/install_python.py
Licensed under GPL-3.0-or-later (Feel free to copy and use it in your project)
"""
from __future__ import annotations
import argparse
import hashlib
import logging
import os
import re
import shlex
import shutil
import ssl
import subprocess
import sys
import tempfile
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 = {
# Thomas Wouters (3.12.x and 3.13.x source files and tags):
'3.13': 'A821E680E5FA6305',
'3.12': 'A821E680E5FA6305',
#
# 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'
"""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_'
logger = logging.getLogger(__name__)
class TemporaryDirectory:
"""tempfile.TemporaryDirectory in Python 3.9 has no "delete", yet."""
def __init__(self, prefix, delete: bool):
self.prefix = prefix
self.delete = delete
def __enter__(self) -> Path:
self.temp_path = Path(tempfile.mkdtemp(prefix=self.prefix))
return self.temp_path
def __exit__(self, exc_type, exc_val, exc_tb):
if self.delete:
shutil.rmtree(self.temp_path, ignore_errors=True)
if exc_type:
return False
def fetch(url: str) -> bytes:
"""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('Getting HTML page from %s', url)
html = fetch(url).decode('utf-8')
assert html, 'Failed to get Python FTP index page'
return html
def extract_versions(*, html, major_version) -> list[str]:
pattern = rf'href="({re.escape(major_version)}\.[0-9]+)'
logger.debug('Extracting versions with pattern: %s', pattern)
versions = re.findall(pattern, html)
versions.sort(reverse=True)
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('Latest version of Python %s: %s', major_version, latest_versions)
return latest_versions
def run(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('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('Failed to run %s step: %s', step, err)
run(['tail', temp_file.name])
raise
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('Downloading %s into %s...', url, dst_path)
dst_path.write_bytes(fetch(url))
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, 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('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('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]
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)')
def install_python(
major_version: str,
*,
write_check: bool = True,
delete_temp: bool = True,
) -> Path:
logger.info('Requested major Python version: %s', major_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('Checking %s...', filename)
if python3bin := shutil.which(filename):
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),
major_version=major_version,
)
local_bin_path = Path(DEFAULT_INSTALL_PREFIX) / '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')
"""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
"""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" ?!)')
"""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'{PY_FTP_INDEX_URL}{py_required_version}'
tar_filename = f'Python-{py_required_version}.tar.xz'
asc_filename = f'{tar_filename}.asc'
asc_file_path = download2temp(
temp_path=temp_path,
base_url=base_url,
filename=asc_filename,
)
tar_file_path = download2temp(
temp_path=temp_path,
base_url=base_url,
filename=tar_filename,
)
verify_download(
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('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('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',
cwd=extracted_dir,
)
run_build_step(
['make', f'-j{os.cpu_count()}'],
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('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}'
return local_python_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='Install Python Interpreter',
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
parser.add_argument(
'major_version',
nargs=argparse.OPTIONAL,
default=DEFAULT_MAJOR_VERSION,
choices=sorted(GPG_KEY_IDS.keys()),
help='Specify the Python version',
)
parser.add_argument(
'-v',
'--verbose',
action='count',
default=0,
help='Increase verbosity level (can be used multiple times, e.g.: -vv)',
)
parser.add_argument(
'--skip-temp-deletion',
action='store_true',
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(
level=verbose2level.get(args.verbose, logging.DEBUG),
format='%(levelname)9s %(message)s',
stream=sys.stderr,
)
logger.debug('Arguments: %s', args)
return install_python(
major_version=args.major_version,
write_check=not args.skip_write_check,
delete_temp=not args.skip_temp_deletion,
)
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)

View file

@ -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

View file

@ -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()

View file

@ -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

View file

@ -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

View file

@ -40,90 +40,16 @@ log_file="${log_path}/${app}.log"
#==================================================================================
# myynh_install_python() Borrowed from:
# https://github.com/YunoHost-Apps/homeassistant_ynh/blob/master/scripts/_common.sh
# Until we get a newer Python in YunoHost, see:
# https://forum.yunohost.org/t/use-newer-python-than-3-9/22568
#==================================================================================
py_required_major=3.11
py_required_version=$(curl -Ls https://www.python.org/ftp/python/ \
| grep '>'$py_required_major | cut -d '/' -f 2 \
| cut -d '>' -f 2 | sort -rV | head -n 1) #3.11.8
PY_REQUIRED_MAJOR=3.11
myynh_install_python() {
# Declare an array to define the options of this helper.
local legacy_args=u
local -A args_array=( [p]=python= )
local python
# Manage arguments with getopts
ynh_handle_getopts_args "$@"
ynh_print_info --message="Install latest Python v${PY_REQUIRED_MAJOR}..."
# Check python version from APT
local py_apt_version=$(python3 --version | cut -d ' ' -f 2)
# Usefull variables
local python_major=${python%.*}
# Check existing built version of python in /usr/local/bin
if [ -e "/usr/local/bin/python$python_major" ]
then
local py_built_version=$(/usr/local/bin/python$python_major --version \
| cut -d ' ' -f 2)
else
local py_built_version=0
fi
# Compare version
if $(dpkg --compare-versions $py_apt_version ge $python)
then
# APT >= Required
ynh_print_info --message="Using provided python3..."
py_app_version="python3"
else
# Either python already built or to build
if $(dpkg --compare-versions $py_built_version ge $python)
then
# Built >= Required
py_app_version="/usr/local/bin/python${py_built_version%.*}"
ynh_print_info --message="Using already used python3 built version: $py_app_version"
else
# APT < Minimal & Actual < Minimal => Build & install Python into /usr/local/bin
ynh_print_info --message="Building $python (may take a while)..."
# Store current direcotry
local MY_DIR=$(pwd)
# Create a temp direcotry
tmpdir="$(mktemp --directory)"
cd "$tmpdir"
# Download
wget --output-document="Python-$python.tar.xz" \
"https://www.python.org/ftp/python/$python/Python-$python.tar.xz" 2>&1
# Extract
tar xf "Python-$python.tar.xz"
# Install
cd "Python-$python"
./configure --enable-optimizations
ynh_exec_warn_less make -j4
ynh_exec_warn_less make altinstall
# Go back to working directory
cd "$MY_DIR"
# Clean
ynh_secure_remove "$tmpdir"
# Set version
py_app_version="/usr/local/bin/python$python_major"
fi
fi
# Save python version in settings
ynh_app_setting_set --app=$app --key=python --value="$python"
ynh_exec_warn_less python3 "$data_dir/install_python.py" -vv ${PY_REQUIRED_MAJOR}
py_app_version=$(python3 "$data_dir/install_python.py" ${PY_REQUIRED_MAJOR})
# Print some version information:
ynh_print_info --message="Python version: $($py_app_version -VV)"
@ -134,7 +60,7 @@ myynh_install_python() {
myynh_setup_python_venv() {
# Install Python if needed:
myynh_install_python --python="$py_required_version"
myynh_install_python
# Create a virtualenv with python installed by myynh_install_python():
# Skip pip because of: https://github.com/YunoHost/issues/issues/1960

View file

@ -68,6 +68,7 @@ ynh_use_logrotate --logfile="$log_file" --specific_user=$app
# PYTHON VIRTUALENV
#=================================================
ynh_script_progression --message="Create and setup Python virtualenv..." --weight=45
cp ../conf/install_python.py "$data_dir/install_python.py"
cp ../conf/requirements.txt "$data_dir/requirements.txt"
myynh_setup_python_venv

View file

@ -51,6 +51,7 @@ ynh_add_systemd_config --service=$app --template="systemd.service"
# PYTHON VIRTUALENV
#=================================================
ynh_script_progression --message="Create and setup Python virtualenv..." --weight=45
cp ../conf/install_python.py "$data_dir/install_python.py"
cp ../conf/requirements.txt "$data_dir/requirements.txt"
myynh_setup_python_venv