/
niceSOFT
/
python3-hatchling
Обзор
Документация
Войти
/
niceSOFT
/
python3-hatchling
Код
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/hatch/cli/dep/__init__.py
255 строк
10 KB
Cary Hawkins
Add sources to enable other types of local dependencies (#2313)
10 авг 2026, 06:24
Не верифицирован
10 авг 2026, 06:24
a885803
Код
Авторство
О чём код?
import click from hatch.cli.env.lock import dependency_lock_click_options, run_dep_lock @click.group(short_help="Manage environment dependencies") def dep(): pass @dep.command("lock", short_help="Generate a lockfile for the active environment (`-e` / `HATCH_ENV`)") @dependency_lock_click_options @click.pass_obj def dep_lock( app, *, upgrade: bool, upgrade_package: tuple[str, ...], export_path: str | None, export_all_path: str | None, check: bool, ): """Resolve dependencies and write a PEP 751 ``pylock.toml`` for the selected environment.""" app.ensure_environment_plugin_dependencies() run_dep_lock( app, upgrade=upgrade, upgrade_package=upgrade_package, export_path=export_path, export_all_path=export_all_path, check=check, ) @dep.command("sync", short_help="Install dependencies from the environment lockfile (`apply_lock`)") @click.pass_obj def dep_sync(app): """Sync the active environment to its lockfile (``locked`` environments only).""" app.ensure_environment_plugin_dependencies() environment = app.project.get_environment() if not environment.locked: app.abort( "The active environment is not `locked`. Set `locked = true` or use `hatch env lock --export` " "and a normal install workflow." ) from hatch.env.lock import LockerNotFoundError, LockerUnsupportedError, resolve_lockfile_path lock_path = resolve_lockfile_path(environment) if not lock_path.is_file(): app.abort(f"No lockfile at `{lock_path}`. Run `hatch dep lock` or `hatch env lock` first.") try: with app.status("Syncing from lockfile"): environment.sync_dependencies() except LockerNotFoundError as e: app.abort(str(e)) except LockerUnsupportedError as e: if e.detail: app.abort(f"Cannot sync environment `{environment.name}` from lockfile: {e.detail}") app.abort(str(e)) app.display_success(f"Synced environment `{environment.name}` from `{lock_path.name}`") @dep.command("hash", short_help="Output a hash of the currently defined dependencies") @click.option("--project-only", "-p", is_flag=True, help="Whether or not to exclude environment dependencies") @click.option("--env-only", "-e", is_flag=True, help="Whether or not to exclude project dependencies") @click.pass_obj def hash_dependencies(app, project_only, env_only): """Output a hash of the currently defined dependencies.""" app.ensure_environment_plugin_dependencies() from hatch.utils.dep import get_complex_dependencies, hash_dependencies environment = app.project.get_environment() all_requirements = [] if project_only: dependencies, _ = app.project.get_dependencies() dependencies_complex = get_complex_dependencies(dependencies) all_requirements.extend(dependencies_complex.values()) elif env_only: all_requirements.extend(environment.environment_dependencies_complex) else: dependencies, _ = app.project.get_dependencies() dependencies_complex = get_complex_dependencies(dependencies) all_requirements.extend(dependencies_complex.values()) all_requirements.extend(environment.environment_dependencies_complex) app.display(hash_dependencies(all_requirements)) @dep.group(short_help="Display dependencies in various formats") def show(): pass @show.command(short_help="Enumerate dependencies in a tabular format") @click.option("--project-only", "-p", is_flag=True, help="Whether or not to exclude environment dependencies") @click.option("--env-only", "-e", is_flag=True, help="Whether or not to exclude project dependencies") @click.option("--lines", "-l", "show_lines", is_flag=True, help="Whether or not to show lines between table rows") @click.option("--ascii", "force_ascii", is_flag=True, help="Whether or not to only use ASCII characters") @click.pass_obj def table(app, project_only, env_only, show_lines, force_ascii): """Enumerate dependencies in a tabular format.""" app.ensure_environment_plugin_dependencies() from hatch.dep.core import Dependency from hatch.utils.dep import get_complex_dependencies, get_normalized_dependencies, normalize_marker_quoting environment = app.project.get_environment() project_requirements = [] environment_requirements = [] if project_only: dependencies, _ = app.project.get_dependencies() dependencies_complex = get_complex_dependencies(dependencies) project_requirements.extend(dependencies_complex.values()) elif env_only: environment_requirements.extend(environment.environment_dependencies_complex) else: dependencies, _ = app.project.get_dependencies() dependencies_complex = get_complex_dependencies(dependencies) project_requirements.extend(dependencies_complex.values()) environment_requirements.extend(environment.environment_dependencies_complex) for all_requirements, table_title in ( (project_requirements, "Project"), (environment_requirements, f"Env: {app.env}"), ): if not all_requirements: continue normalized_requirements = [Dependency(d) for d in get_normalized_dependencies(all_requirements)] columns = {"Name": {}, "URL": {}, "Versions": {}, "Markers": {}, "Features": {}} for i, requirement in enumerate(normalized_requirements): columns["Name"][i] = requirement.name if requirement.url: columns["URL"][i] = str(requirement.url) if requirement.specifier: columns["Versions"][i] = str(requirement.specifier) if requirement.marker: columns["Markers"][i] = normalize_marker_quoting(str(requirement.marker)) if requirement.extras: columns["Features"][i] = ", ".join(sorted(requirement.extras)) column_options = {} for column_title in columns: if column_title != "URL": column_options[column_title] = {"no_wrap": True} app.display_table( table_title, columns, show_lines=show_lines, column_options=column_options, force_ascii=force_ascii ) @show.command("sources", short_help="Show dependency source redirections for the active environment") @click.option("--lines", "-l", "show_lines", is_flag=True, help="Whether or not to show lines between table rows") @click.option("--ascii", "force_ascii", is_flag=True, help="Whether or not to only use ASCII characters") @click.pass_obj def show_sources(app, show_lines, force_ascii): """ Show each configured dependency source, what it points at, and which dependencies of the active environment it redirects. """ app.ensure_environment_plugin_dependencies() from hatch.project.sources import describe_source, source_applied from hatch.utils.metadata import normalize_project_name environment = app.project.get_environment() configured = environment.sources if not configured: app.display(f"No sources defined for environment `{app.env}`") return root = str(environment.root) workspace_members = environment.source_workspace_members matched = {name: [] for name in configured} for dependency in environment.dependencies_complex: normalized = normalize_project_name(dependency.name) if normalized in matched and source_applied(dependency, configured[normalized], root, workspace_members): matched[normalized].append(str(dependency)) columns = {"Source": {}, "Type": {}, "Target": {}, "Dependencies": {}} for i, (name, source) in enumerate(sorted(configured.items())): source_type, target = describe_source(source) columns["Source"][i] = name columns["Type"][i] = source_type columns["Target"][i] = target columns["Dependencies"][i] = "\n".join(matched[name]) if matched[name] else "none" column_options = {"Source": {"no_wrap": True}, "Type": {"no_wrap": True}} app.display_table( f"Sources: {app.env}", columns, show_lines=show_lines, column_options=column_options, force_ascii=force_ascii ) unused = sorted(name for name, deps in matched.items() if not deps) if unused: app.display_warning(f"Sources matched no dependencies of environment `{app.env}`: {', '.join(unused)}") @show.command(short_help="Enumerate dependencies as a list of requirements") @click.option("--project-only", "-p", is_flag=True, help="Whether or not to exclude environment dependencies") @click.option("--env-only", "-e", is_flag=True, help="Whether or not to exclude project dependencies") @click.option( "--feature", "-f", "features", multiple=True, help="Whether or not to only show the dependencies of the specified features", ) @click.option("--all", "all_features", is_flag=True, help="Whether or not to include the dependencies of all features") @click.pass_obj def requirements(app, project_only, env_only, features, all_features): """Enumerate dependencies as a list of requirements.""" app.ensure_environment_plugin_dependencies() from hatch.utils.dep import get_complex_dependencies, get_complex_features, get_normalized_dependencies from hatchling.metadata.utils import normalize_project_name environment = app.project.get_environment() dependencies, optional_dependencies = app.project.get_dependencies() dependencies_complex = get_complex_dependencies(dependencies) optional_dependencies_complex = get_complex_features(optional_dependencies) all_requirements = [] if features: for raw_feature in features: feature = normalize_project_name(raw_feature) if feature not in optional_dependencies_complex: app.abort(f"Feature `{feature}` is not defined in field `project.optional-dependencies`") all_requirements.extend(optional_dependencies_complex[feature].values()) elif project_only: all_requirements.extend(dependencies_complex.values()) elif env_only: all_requirements.extend(environment.environment_dependencies_complex) else: all_requirements.extend(dependencies_complex.values()) all_requirements.extend(environment.environment_dependencies_complex) if not features and all_features: for optional_dependencies in optional_dependencies_complex.values(): all_requirements.extend(optional_dependencies.values()) for dependency in get_normalized_dependencies(all_requirements): app.display(dependency)