Source code for fastiot.cli.commands.manage_requirements

import logging
import os
import subprocess

import tomli
import typer

from fastiot.cli.model import ProjectContext
from fastiot.cli.typer_app import extras_cmd, DEFAULT_CONTEXT_SETTINGS


[docs]@extras_cmd.command(context_settings=DEFAULT_CONTEXT_SETTINGS) def set_requirements( update_requirements: bool = typer.Option(False, '-u', '--update-requirements', help="Update all requirements files to latest versions matching the " "dependencies listed in your `pyproject.toml`.")): """ Updates :file:`requirements.txt` and files in path :file:`requirements` according to the settings in your :file:`pyproject.toml`. """ logging.info("Starting to create fixed requirements.txt files based on pyproject.toml…") context = ProjectContext.default pyproject_toml = os.path.join(context.project_root_dir, 'pyproject.toml') if not os.path.isfile(pyproject_toml): logging.warning("Can not automatically create fixed requirements without `pyproject.toml`") logging.warning("Use `fiot create pyproject-toml` to create one!") return # Base _run_pip_compile(file_name=os.path.join(context.project_root_dir, 'requirements.txt'), upgrade=update_requirements, name='base') with open(pyproject_toml, "rb") as toml_file: toml_dict = tomli.load(toml_file) if 'optional-dependencies' in toml_dict['project']: os.makedirs(os.path.join(context.project_root_dir, 'requirements'), exist_ok=True) for extra_dep in toml_dict['project']['optional-dependencies'].keys(): target_file = os.path.join(context.project_root_dir, 'requirements', f"requirements.{extra_dep}.txt") _run_pip_compile(file_name=target_file, cmd_extras=f"--extra={extra_dep}", upgrade=update_requirements, name=extra_dep) target_file = os.path.join(context.project_root_dir, 'requirements', "requirements.all.txt") _run_pip_compile(file_name=target_file, cmd_extras="--all-extras", upgrade=update_requirements, name="all") logging.info("Don’t forget to add the changed requirements to git!")
def _run_pip_compile(file_name: str, cmd_extras: str = "", upgrade: bool = False, name: str = ""): logging.info(" Building %s requirements", name) cmd = f"pip-compile --annotation-style=line --resolver=backtracking --output-file={file_name} " if upgrade: cmd += "--upgrade " if cmd_extras: cmd += cmd_extras # Popen seems to be more stable than subprocess.call process = subprocess.Popen(cmd.split(), shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE) _, stderr = process.communicate() if process.returncode != 0: logging.warning("Building requirements for %s failed with return code %d. Command used was `%s`", name, process.returncode, cmd) logging.warning("The message was `%s`", stderr.decode().strip()) logging.info("Leaving file untouched.") return # Do some cleanup on the generated requirements file to avoid information leakage with open(file_name, 'r') as file: text = file.readlines() with open(file_name, "w") as file: for line in text: if "pip-compile --" in line or "pip-compile -" in line: file.write("# fiot config" + " --update-requirements\n" if upgrade else "\n") elif "extra-index-url" in line or "trusted-host" in line: continue else: file.write(line)