Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@

from __future__ import annotations

import click
import base_cli

import click

app = base_cli.App(
name="base-automation",
Expand Down
1 change: 0 additions & 1 deletion examples/automation_observability_app/tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from pathlib import Path

import base_cli

from automation_observability_app.cli import app


Expand Down
1 change: 0 additions & 1 deletion examples/minimal_cli/src/minimal_cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

import base_cli


app = base_cli.App(
name="base-minimal",
version="0.1.0",
Expand Down
1 change: 0 additions & 1 deletion examples/minimal_cli/tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from pathlib import Path

import base_cli

from minimal_cli.cli import app


Expand Down
2 changes: 1 addition & 1 deletion examples/nested_click_app/src/nested_click_app/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

from __future__ import annotations

import click
import base_cli
import click


@click.group(name="base-nested", help="A nested Click app with safe plugins.")
Expand Down
1 change: 0 additions & 1 deletion examples/nested_click_app/tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from pathlib import Path

import base_cli

from nested_click_app.cli import command


Expand Down
1 change: 0 additions & 1 deletion examples/typer_app/src/typer_app/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import base_cli
import typer


cli = typer.Typer(help="A typed application with a shared lifecycle.")


Expand Down
1 change: 0 additions & 1 deletion examples/typer_app/tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from pathlib import Path

import base_cli

from typer_app.cli import command


Expand Down
4 changes: 1 addition & 3 deletions examples/typer_consumer.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@

from __future__ import annotations

import typer

import base_cli

import typer

cli = typer.Typer(help="A small Typer application with a shared lifecycle.")

Expand Down
38 changes: 22 additions & 16 deletions lib/python/base_cli/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

from importlib.metadata import PackageNotFoundError, version as distribution_version
from importlib.metadata import PackageNotFoundError
from importlib.metadata import version as distribution_version
from pathlib import Path


Expand Down Expand Up @@ -41,14 +42,6 @@ def _resolve_version() -> str:
json_contracts,
testing,
)
from .attachment import (
AttachmentAdapter,
AttachmentContextFactory,
AttachmentContract,
AttachmentServiceFactory,
)
from .config import BatteriesIncludedConfigLoader, ConfigSnapshot, FrameworkConfig
from .deprecations import BaseCliDeprecationWarning, deprecated
from .app import (
App,
argument,
Expand All @@ -59,30 +52,44 @@ def _resolve_version() -> str:
option,
run_app,
)
from .command_filters import CommandFilterNormalizer, command_matches, normalize_command_filter, normalize_command_filters
from .attachment import (
AttachmentAdapter,
AttachmentContextFactory,
AttachmentContract,
AttachmentServiceFactory,
)
from .command_filters import (
CommandFilterNormalizer,
command_matches,
normalize_command_filter,
normalize_command_filters,
)
from .command_protocol import (
BOOLEAN,
DEFAULT_SCHEMA_REGISTRY,
CommandCodec,
NULLABLE_STRING,
RECORD_SCHEMAS,
STRING,
CommandCodec,
CommandProtocolError,
CommandSchemaRegistry,
FieldSpec,
RECORD_SCHEMAS,
dumps_record,
dumps_records,
loads_records,
register_record_schema,
)
from .config import BatteriesIncludedConfigLoader, ConfigSnapshot, FrameworkConfig
from .context import (
ApplicationStateT,
ConfigT,
Context,
ServicesT,
get_current_context,
)
from .deprecations import BaseCliDeprecationWarning, deprecated
from .errors import ConfigurationError
from .exit_codes import ExitCode
from .extensions import (
COMMAND_ENTRY_POINT_GROUP,
ENTRY_POINT_GROUPS,
Expand All @@ -96,32 +103,31 @@ def _resolve_version() -> str:
ExtensionLoadResult,
ExtensionsDisabledError,
)
from .exit_codes import ExitCode
from .inspection import inspection_envelope, render_inspection_json
from .integrations import TelemetryOptions, TelemetrySession, try_render_rich_table
from .json_contracts import (
JSON_CONTRACT_VERSION,
JSON_ERROR_SCHEMA,
JSON_LOG_SCHEMA,
JSON_OUTPUT_SCHEMA,
JsonLogFormatter,
MAX_JSON_LOG_MESSAGE_LENGTH,
JsonLogFormatter,
dumps_envelope,
error_envelope,
redact_json_value,
success_envelope,
)
from .logging import configure_logger, log_critical, log_debug, log_error, log_info, log_warning
from .lifecycle_options import (
LIFECYCLE_META_KEY,
LifecycleOption,
LifecycleOptions,
LifecycleValues,
get_lifecycle_values,
)
from .logging import configure_logger, log_critical, log_debug, log_error, log_info, log_warning
from .output import (
OutputFormatError,
PUBLIC_OUTPUT_FORMATS,
OutputFormatError,
is_terminal,
output_format_choices,
render_document,
Expand Down
6 changes: 3 additions & 3 deletions lib/python/base_cli/_click_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@

from __future__ import annotations

from collections.abc import Callable
from dataclasses import dataclass
from typing import Any, Callable

from typing import Any, cast

_DIALECT_ATTRIBUTE = "__base_cli_click_dialect__"

Expand Down Expand Up @@ -79,7 +79,7 @@ def decorator(source: Callable[..., Any]) -> Callable[..., Any]:
)
params = list(getattr(source, "__click_params__", ()))
params.append(parameter)
setattr(source, "__click_params__", params)
cast(Any, source).__click_params__ = params
return source

return decorator
Expand Down
2 changes: 1 addition & 1 deletion lib/python/base_cli/_lifecycle.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
from typing import Any

from ._private_files import write_private_json
from ._runtime import refresh_run_bundle_index
from .context import Context
from .exit_codes import ExitCode
from .history import format_timestamp
from ._runtime import refresh_run_bundle_index


@dataclass(frozen=True)
Expand Down
1 change: 0 additions & 1 deletion lib/python/base_cli/_private_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from pathlib import Path
from typing import Any


PRIVATE_FILE_MODE = 0o600
PRIVATE_DIRECTORY_MODE = 0o700

Expand Down
4 changes: 2 additions & 2 deletions lib/python/base_cli/_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@
import os
import stat
import time
from collections.abc import Iterable, Iterator
from contextlib import contextmanager
from datetime import datetime, timezone
from typing import Any, Iterable, Iterator
from pathlib import Path
from typing import Any

try: # pragma: no cover - platform branch
import fcntl as _fcntl
Expand All @@ -29,7 +30,6 @@
from .paths import runtime_run_directory_name, runtime_slug
from .runtime import RetentionPolicy, RuntimeLayout


_LOG_INDEX_NAME = ".base-cli-log-index.json"
_RUN_INDEX_NAME = ".base-cli-run-index.json"
_RUN_LOCK_NAME = ".base-cli-run-index.lock"
Expand Down
21 changes: 11 additions & 10 deletions lib/python/base_cli/app.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
from __future__ import annotations

import functools
import io
import inspect
import io
import logging
import os
import stat
import sys
import time
import traceback
from collections.abc import Iterable
from contextvars import ContextVar, Token
from collections.abc import Callable, Iterable
from contextlib import redirect_stdout
from contextvars import ContextVar, Token
from dataclasses import dataclass
from datetime import datetime
from pathlib import Path
from threading import RLock
from typing import Any, Callable, ParamSpec, TypeVar, cast
from typing import Any, ParamSpec, TypeVar, cast

from ._click_compat import dialect_for_command
from ._lifecycle import (
Expand All @@ -41,20 +41,19 @@
from .exit_codes import ExitCode
from .history import utc_now
from .integrations import TelemetryOptions, TelemetrySession, finish_telemetry, start_telemetry
from .logging import configure_logger, log_invocation
from .json_contracts import dumps_envelope, error_envelope, success_envelope
from .lifecycle_options import (
LIFECYCLE_META_KEY,
LifecycleOption,
LifecycleOptions,
LifecycleValues,
)
from .logging import configure_logger, log_invocation
from .paths import (
current_working_dir,
normalize_cli_name,
)
from .profile import CliProfile
from .runtime import RetentionPolicy
from .redaction import (
REDACTED,
RedactionPlan,
Expand All @@ -63,6 +62,7 @@
parameter_name_from_decls,
redact_argv,
)
from .runtime import RetentionPolicy

_STANDARD_OPTION_KEYS = ("debug", "quiet", "environment", "config", "keep_temp", "log_file", "json")
_FLAG_LIFECYCLE_OPTION_KEYS = frozenset({"debug", "quiet", "keep_temp", "dry_run", "json"})
Expand Down Expand Up @@ -2427,7 +2427,7 @@ def _selected_click_path(
if current is root_context:
contexts.reverse()
selected: list[tuple[str, Any]] = []
for parent, child in zip(contexts, contexts[1:]):
for parent, child in zip(contexts, contexts[1:], strict=False):
resolutions = resolved_children.get(id(parent), [])
recorded = next(
(
Expand Down Expand Up @@ -3222,7 +3222,8 @@ def option(
def decorator(func: Callable[_P, _R]) -> Callable[_P, _R]:
specs = list(getattr(func, "__base_cli_param_specs__", []))
specs.append(("option", param_decls, attrs, sensitive))
setattr(func, "__base_cli_param_specs__", specs)
typed_func = cast(Any, func)
typed_func.__base_cli_param_specs__ = specs
if dry_run:
dry_run_parameter = parameter_name_from_decls(param_decls)
existing_dry_run_parameter = getattr(func, "__base_cli_dry_run_parameter__", None)
Expand All @@ -3231,7 +3232,7 @@ def decorator(func: Callable[_P, _R]) -> Callable[_P, _R]:
f"{func.__name__} already designates '{existing_dry_run_parameter}' as dry-run. "
"only one option can be designated dry_run=True."
)
setattr(func, "__base_cli_dry_run_parameter__", dry_run_parameter)
typed_func.__base_cli_dry_run_parameter__ = dry_run_parameter
return func

return decorator
Expand All @@ -3245,7 +3246,7 @@ def argument(
def decorator(func: Callable[_P, _R]) -> Callable[_P, _R]:
specs = list(getattr(func, "__base_cli_param_specs__", []))
specs.append(("argument", param_decls, attrs, sensitive))
setattr(func, "__base_cli_param_specs__", specs)
cast(Any, func).__base_cli_param_specs__ = specs
return func

return decorator
Expand Down
1 change: 0 additions & 1 deletion lib/python/base_cli/attachment.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

from .context import Context


__all__ = [
"AttachmentAdapter",
"AttachmentContextFactory",
Expand Down
1 change: 0 additions & 1 deletion lib/python/base_cli/command_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from collections.abc import Callable
from typing import TypeAlias


__all__ = [
"CommandFilterNormalizer",
"command_matches",
Expand Down
1 change: 0 additions & 1 deletion lib/python/base_cli/command_protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from collections.abc import Mapping
from dataclasses import dataclass


__all__ = [
"BOOLEAN",
"CommandCodec",
Expand Down
3 changes: 1 addition & 2 deletions lib/python/base_cli/config.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

import stat
import re
import stat
from collections.abc import Mapping
from dataclasses import dataclass
from pathlib import Path
Expand All @@ -11,7 +11,6 @@
from ._dependencies import require_yaml
from .errors import ConfigurationError


__all__ = [
"BatteriesIncludedConfigLoader",
"ConfigSnapshot",
Expand Down
Loading
Loading