apprc 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- apprc/__init__.py +19 -0
- apprc/_dotenv_guard.py +29 -0
- apprc/_lazy.py +62 -0
- apprc/cli/__init__.py +31 -0
- apprc/cli/bootstrap.py +66 -0
- apprc/cli/config_app.py +555 -0
- apprc/cli/doctor.py +182 -0
- apprc/cli/options.py +17 -0
- apprc/cli/typer_utils.py +153 -0
- apprc/config/__init__.py +49 -0
- apprc/config/app_spec.py +69 -0
- apprc/config/base_config.py +429 -0
- apprc/config/environment.py +329 -0
- apprc/config/kit.py +299 -0
- apprc/config/local_env.py +171 -0
- apprc/config/schema.py +396 -0
- apprc/config/storage_registry.py +268 -0
- apprc/config/tui.py +452 -0
- apprc/config/tui_rendering.py +225 -0
- apprc/logging/__init__.py +5 -0
- apprc/logging/__init__.pyi +27 -0
- apprc/logging/_facade.py +44 -0
- apprc/logging/config.py +239 -0
- apprc/logging/context.py +168 -0
- apprc/logging/core.py +633 -0
- apprc/logging/exceptions.py +383 -0
- apprc/logging/formats.py +426 -0
- apprc/logging/functions/__init__.py +19 -0
- apprc/logging/functions/lifecycle.py +59 -0
- apprc/logging/functions/telemetry.py +326 -0
- apprc/logging/levels.py +192 -0
- apprc/logging/subprocess.py +64 -0
- apprc/main.py +28 -0
- apprc/paths.py +29 -0
- apprc/py.typed +1 -0
- apprc/utils/__init__.py +18 -0
- apprc/utils/path_resolver.py +206 -0
- apprc/utils/stdlib.py +91 -0
- apprc-0.1.0.dist-info/METADATA +498 -0
- apprc-0.1.0.dist-info/RECORD +42 -0
- apprc-0.1.0.dist-info/WHEEL +4 -0
- apprc-0.1.0.dist-info/licenses/LICENSE +21 -0
apprc/__init__.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Reusable application runtime configuration and logging helpers."""
|
|
2
|
+
|
|
3
|
+
# ruff: noqa: F401
|
|
4
|
+
|
|
5
|
+
from apprc.config import (
|
|
6
|
+
AppConfigKit,
|
|
7
|
+
AppConfigSpec,
|
|
8
|
+
BaseConfig,
|
|
9
|
+
BaseEnv,
|
|
10
|
+
ConfigField,
|
|
11
|
+
ConfigOwner,
|
|
12
|
+
EnvBootstrapSpec,
|
|
13
|
+
)
|
|
14
|
+
from apprc.logging import (
|
|
15
|
+
AppLogger,
|
|
16
|
+
LoggingConfig,
|
|
17
|
+
get_logger,
|
|
18
|
+
setup_logging,
|
|
19
|
+
)
|
apprc/_dotenv_guard.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Stdlib-only helpers for guarding dotenv autoload side effects."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
from collections.abc import Iterator
|
|
7
|
+
from contextlib import contextmanager
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@contextmanager
|
|
11
|
+
def _disable_dotenv_autoload() -> Iterator[None]:
|
|
12
|
+
"""Temporarily disable libraries that auto-load ``.env`` files.
|
|
13
|
+
|
|
14
|
+
Some libraries import ``python-dotenv`` through their dependency graph.
|
|
15
|
+
Setting ``PYTHON_DOTENV_DISABLED`` around those imports preserves the
|
|
16
|
+
application's explicit environment loading policy while restoring the
|
|
17
|
+
user's original process environment afterward.
|
|
18
|
+
|
|
19
|
+
:return: Context manager that restores ``PYTHON_DOTENV_DISABLED``.
|
|
20
|
+
"""
|
|
21
|
+
prev = os.environ.get("PYTHON_DOTENV_DISABLED")
|
|
22
|
+
os.environ["PYTHON_DOTENV_DISABLED"] = "1"
|
|
23
|
+
try:
|
|
24
|
+
yield
|
|
25
|
+
finally:
|
|
26
|
+
if prev is None:
|
|
27
|
+
os.environ.pop("PYTHON_DOTENV_DISABLED", None)
|
|
28
|
+
else:
|
|
29
|
+
os.environ["PYTHON_DOTENV_DISABLED"] = prev
|
apprc/_lazy.py
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""Small helpers for PEP 562 package facades. This speeds up import time a lot
|
|
2
|
+
|
|
3
|
+
Once Python 3.15 hits, replace all this logic with `lazy import`
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import sys
|
|
9
|
+
from collections.abc import Callable, Mapping, Sequence
|
|
10
|
+
from importlib import import_module
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
type LazyGetattr = Callable[[str], object]
|
|
14
|
+
type LazyDir = Callable[[], list[str]]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def build_lazy_facade(
|
|
18
|
+
*,
|
|
19
|
+
public_module: str,
|
|
20
|
+
all_exports: Sequence[str],
|
|
21
|
+
module_exports: Mapping[str, str],
|
|
22
|
+
symbol_exports: Mapping[str, str],
|
|
23
|
+
) -> tuple[list[str], LazyGetattr, LazyDir]:
|
|
24
|
+
"""Build module-level hooks for one lazy public facade.
|
|
25
|
+
|
|
26
|
+
The returned ``__getattr__`` resolves modules and symbols only when a caller
|
|
27
|
+
first touches them. Resolved values are stored on the public module, not on
|
|
28
|
+
the private ``_facade`` module, so repeated access is the same cheap global
|
|
29
|
+
lookup that an eager facade would provide.
|
|
30
|
+
|
|
31
|
+
:param public_module: Public module name that owns the lazy attributes.
|
|
32
|
+
:param all_exports: Stable ``__all__`` values for the facade.
|
|
33
|
+
:param module_exports: Exported submodule names to import paths.
|
|
34
|
+
:param symbol_exports: Exported symbol names to the module that defines them.
|
|
35
|
+
:return: ``(__all__, __getattr__, __dir__)`` for re-export by ``__init__``.
|
|
36
|
+
"""
|
|
37
|
+
all_names = list(all_exports)
|
|
38
|
+
module_map = dict(module_exports)
|
|
39
|
+
symbol_map = dict(symbol_exports)
|
|
40
|
+
known_names = frozenset((*module_map, *symbol_map))
|
|
41
|
+
|
|
42
|
+
def __getattr__(name: str) -> object:
|
|
43
|
+
namespace = sys.modules[public_module].__dict__
|
|
44
|
+
if name in module_map:
|
|
45
|
+
value = import_module(module_map[name])
|
|
46
|
+
else:
|
|
47
|
+
try:
|
|
48
|
+
module_name = symbol_map[name]
|
|
49
|
+
except KeyError as exc:
|
|
50
|
+
raise AttributeError(
|
|
51
|
+
f"module {public_module!r} has no attribute {name!r}"
|
|
52
|
+
) from exc
|
|
53
|
+
module = import_module(module_name)
|
|
54
|
+
value = getattr(module, name)
|
|
55
|
+
namespace[name] = value
|
|
56
|
+
return value
|
|
57
|
+
|
|
58
|
+
def __dir__() -> list[str]:
|
|
59
|
+
namespace = sys.modules[public_module].__dict__
|
|
60
|
+
return sorted(set(namespace) | known_names | set(all_names))
|
|
61
|
+
|
|
62
|
+
return all_names, __getattr__, __dir__
|
apprc/cli/__init__.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""Reusable CLI helpers for application config commands."""
|
|
2
|
+
|
|
3
|
+
# ruff: noqa: F401
|
|
4
|
+
|
|
5
|
+
from apprc.cli.bootstrap import bootstrap_cli_env, parse_log_level
|
|
6
|
+
from apprc.cli.config_app import (
|
|
7
|
+
ConfigCliState,
|
|
8
|
+
active_storage_root_from_state,
|
|
9
|
+
build_config_typer_app,
|
|
10
|
+
config_request_skips_bootstrap,
|
|
11
|
+
initial_storage_from_state,
|
|
12
|
+
)
|
|
13
|
+
from apprc.cli.doctor import (
|
|
14
|
+
build_config_doctor_payload,
|
|
15
|
+
config_command_text,
|
|
16
|
+
config_setup_message,
|
|
17
|
+
print_config_doctor,
|
|
18
|
+
)
|
|
19
|
+
from apprc.cli.options import (
|
|
20
|
+
COMMON_ROOT_FLAG_OPTIONS,
|
|
21
|
+
COMMON_ROOT_VALUE_OPTIONS,
|
|
22
|
+
)
|
|
23
|
+
from apprc.cli.typer_utils import (
|
|
24
|
+
MISSING_ACTION_MESSAGE,
|
|
25
|
+
args_after_command,
|
|
26
|
+
dump_json,
|
|
27
|
+
exit_missing_action,
|
|
28
|
+
run_typer_app,
|
|
29
|
+
state_from,
|
|
30
|
+
strip_leading_options,
|
|
31
|
+
)
|
apprc/cli/bootstrap.py
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""Root CLI bootstrap helpers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
# == Standard Library ========================
|
|
6
|
+
from collections.abc import Callable
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
# == 3rd Party ===============================
|
|
11
|
+
import typer
|
|
12
|
+
|
|
13
|
+
# == Internal ================================
|
|
14
|
+
from apprc.config.environment import BootstrapLogger, EnvBootstrapResult
|
|
15
|
+
from apprc.config.kit import AppConfigKit
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def parse_log_level(log_level: str) -> str | int:
|
|
19
|
+
"""Convert a CLI log-level token into the logging backend value.
|
|
20
|
+
|
|
21
|
+
:param log_level: User-provided Typer option value.
|
|
22
|
+
:return: Integer level for decimal strings, otherwise the original token.
|
|
23
|
+
"""
|
|
24
|
+
return int(log_level) if log_level.isdecimal() else log_level
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def bootstrap_cli_env(
|
|
28
|
+
kit: AppConfigKit,
|
|
29
|
+
*,
|
|
30
|
+
env_file: Path | None,
|
|
31
|
+
env_file_overrides_shell: bool,
|
|
32
|
+
no_dotenv: bool,
|
|
33
|
+
storage_name: str | None,
|
|
34
|
+
log_level: str | None = None,
|
|
35
|
+
setup_logging: Callable[..., Any] | None = None,
|
|
36
|
+
logger: BootstrapLogger | None = None,
|
|
37
|
+
) -> EnvBootstrapResult:
|
|
38
|
+
"""Initialize logging and dotenv layers for one CLI process.
|
|
39
|
+
|
|
40
|
+
:param kit: Application config facade.
|
|
41
|
+
:param env_file: Optional explicit dotenv file.
|
|
42
|
+
:param env_file_overrides_shell: Whether explicit dotenv values beat
|
|
43
|
+
already exported variables inside this process.
|
|
44
|
+
:param no_dotenv: Disable dotenv layer loading.
|
|
45
|
+
:param storage_name: Optional named storage selector.
|
|
46
|
+
:param log_level: Optional CLI log-level token.
|
|
47
|
+
:param setup_logging: Optional application logging setup callable.
|
|
48
|
+
:param logger: Optional application logger for bootstrap status messages.
|
|
49
|
+
:return: Bootstrap summary for diagnostics and tests.
|
|
50
|
+
:raises typer.BadParameter: If the explicit env file or storage selector
|
|
51
|
+
is invalid.
|
|
52
|
+
"""
|
|
53
|
+
if setup_logging is not None and log_level is not None:
|
|
54
|
+
setup_logging(level=parse_log_level(log_level))
|
|
55
|
+
try:
|
|
56
|
+
return kit.bootstrap(
|
|
57
|
+
env_file=env_file,
|
|
58
|
+
env_file_overrides_shell=env_file_overrides_shell,
|
|
59
|
+
no_dotenv=no_dotenv,
|
|
60
|
+
storage_name=storage_name,
|
|
61
|
+
logger=logger,
|
|
62
|
+
)
|
|
63
|
+
except FileNotFoundError as exc:
|
|
64
|
+
raise typer.BadParameter(str(exc), param_hint="--env-file") from exc
|
|
65
|
+
except ValueError as exc:
|
|
66
|
+
raise typer.BadParameter(str(exc), param_hint="--storage") from exc
|