From 3c64cb611c1c6bc319a893c7d1a3448be5cf402b Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Mon, 13 Jul 2026 12:21:28 -0300 Subject: [PATCH 01/37] chore: isolated checkpoint mro-wkii.17.26 flext-cli From 43f4735b4bff85be3efc189c6fdccfb7c3caa823 Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Mon, 13 Jul 2026 12:49:37 -0300 Subject: [PATCH 02/37] feat(utilities): make files_parse_content generic over TOML files_parse_content dispatched JSON/YAML only; ai-hub (golden parser, MCP validators, config generators) re-implemented TOML dispatch in ~10 places for lack of a single canonical reader. Add a TOML branch delegating to the existing toml_-prefixed FlextCliUtilitiesToml.toml_read_json, keyed on the new FileFormat.TOML / c.Cli.FILE_FORMAT_TOML constant. One canonical format-dispatch reader now covers json+yaml+toml; downstream consumers route through it. ruff/format/pyrefly/mypy 0 on both files; toml/json/yaml all parse via u.Cli. --- src/flext_cli/_constants/files.py | 2 ++ .../flextcliutilitiesfiletesthelpersmixin_part_04.py | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/flext_cli/_constants/files.py b/src/flext_cli/_constants/files.py index cc125c46a..b6d66d711 100644 --- a/src/flext_cli/_constants/files.py +++ b/src/flext_cli/_constants/files.py @@ -26,6 +26,7 @@ class FileFormat(StrEnum): BIN = "bin" JSON = "json" YAML = "yaml" + TOML = "toml" CSV = "csv" UNKNOWN = "unknown" @@ -34,6 +35,7 @@ class FileFormat(StrEnum): FILE_FORMAT_BIN: Final[FileFormat] = FileFormat.BIN FILE_FORMAT_JSON: Final[FileFormat] = FileFormat.JSON FILE_FORMAT_YAML: Final[FileFormat] = FileFormat.YAML + FILE_FORMAT_TOML: Final[FileFormat] = FileFormat.TOML FILE_FORMAT_CSV: Final[FileFormat] = FileFormat.CSV FILE_FORMAT_UNKNOWN: Final[FileFormat] = FileFormat.UNKNOWN diff --git a/src/flext_cli/_utilities/_file_test_helper_parts/flextcliutilitiesfiletesthelpersmixin_part_04.py b/src/flext_cli/_utilities/_file_test_helper_parts/flextcliutilitiesfiletesthelpersmixin_part_04.py index 3a714f9ab..1d1050504 100644 --- a/src/flext_cli/_utilities/_file_test_helper_parts/flextcliutilitiesfiletesthelpersmixin_part_04.py +++ b/src/flext_cli/_utilities/_file_test_helper_parts/flextcliutilitiesfiletesthelpersmixin_part_04.py @@ -12,6 +12,7 @@ from flext_cli import c, p, r from flext_cli._utilities.json import FlextCliUtilitiesJson as uj +from flext_cli._utilities.toml import FlextCliUtilitiesToml as ut from flext_cli._utilities.yaml import FlextCliUtilitiesYaml as uy if TYPE_CHECKING: @@ -23,7 +24,7 @@ class FlextCliUtilitiesFileTestHelpersMixin: @staticmethod def files_parse_content(path: Path, fmt: str) -> p.Result[object]: - """Parse JSON/YAML file content for ``files_info``.""" + """Parse JSON/YAML/TOML file content generically by format token.""" if fmt == c.Cli.FILE_FORMAT_JSON: result = uj.json_read(path) if result.failure: @@ -34,6 +35,11 @@ def files_parse_content(path: Path, fmt: str) -> p.Result[object]: if result.failure: return r[object].fail(result.error or "yaml_safe_load failed") return r[object].ok(result.value) + if fmt == c.Cli.FILE_FORMAT_TOML: + toml_result = ut.toml_read_json(path) + if toml_result.failure: + return r[object].fail(toml_result.error or "toml_read_json failed") + return r[object].ok(toml_result.value) msg = f"Cannot parse format: {fmt}" return r[object].fail(msg) From 84b48d7a7d78e1edfe7da960bc2543387a6773e5 Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Mon, 13 Jul 2026 15:12:25 -0300 Subject: [PATCH 03/37] fix(runtime): preserve raw command streams --- .../_models/_base_parts/flextclimodelsbase_part_01.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/flext_cli/_models/_base_parts/flextclimodelsbase_part_01.py b/src/flext_cli/_models/_base_parts/flextclimodelsbase_part_01.py index 1de71974e..7b9ed9887 100644 --- a/src/flext_cli/_models/_base_parts/flextclimodelsbase_part_01.py +++ b/src/flext_cli/_models/_base_parts/flextclimodelsbase_part_01.py @@ -13,7 +13,8 @@ class FlextCliModelsBase: """Implementation part for FlextCliModelsBase.""" - class CommandOutput(m.Value): + # mro-wkii.17.26: Preserve subprocess streams byte-for-byte for Git patches. + class CommandOutput(m.ImmutableValueModel): """Standardized external command execution payload. Use m.Cli.CommandOutput.""" stdout: Annotated[str, m.Field("", description="Captured standard output")] = "" From f507a249f0fa24d6f9126878da07c4ffb99f4432 Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Mon, 13 Jul 2026 15:15:42 -0300 Subject: [PATCH 04/37] chore(scaffold): regenerate project ignore rules --- .gitignore | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index b0bc36f14..bd8a89709 100644 --- a/.gitignore +++ b/.gitignore @@ -67,7 +67,6 @@ .internal.invalid .env.production .env.development -**/.env *.key *.pem *.p12 @@ -324,3 +323,20 @@ staging/ .venv/ __pycache__/ base.mk +!/config/ +!/config/** +!/tests/ +!/tests/** +!/templates/ +!/templates/** +!/schemas/ +!/schemas/** +!/examples/ +!/examples/** +!/scripts/ +!/scripts/** +**/.env +**/*.key +**/*.pem +**/credentials.json +**/secrets.y*ml From ce013d7d74d1530350a3b357c1c741a21e2e8b1b Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Mon, 13 Jul 2026 20:38:39 -0300 Subject: [PATCH 05/37] chore(workspace): sync generated gitignore --- .gitignore | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index bd8a89709..2e528791b 100644 --- a/.gitignore +++ b/.gitignore @@ -79,8 +79,6 @@ secrets.yml # PROJECT-SPECIFIC RULES: flext-cli # ============================================================================ -*.py[cod] -*.pyd *.so .installed.cfg MANIFEST @@ -143,10 +141,7 @@ LINT_CORRECTIONS*.md *.ai.txt *.ai.json *.ai.log -*.py[cod] -*$py.class *.so -*.pyd ENV/ .Python coverage.xml @@ -254,10 +249,6 @@ Desktop.ini # ============================================================================ # COMMON PATTERNS: Artifacts inside allowed directories # ============================================================================ -**/__pycache__/ -**/*.pyc -**/*.pyo -**/*.pyd .pytest_cache/ .mypy_cache/ .ruff_cache/ @@ -321,7 +312,6 @@ staging/ .direnv/ .reports/ .venv/ -__pycache__/ base.mk !/config/ !/config/** @@ -335,6 +325,8 @@ base.mk !/examples/** !/scripts/ !/scripts/** +**/__pycache__/ +**/*.py[cod] **/.env **/*.key **/*.pem From 22e18af18ee50611a50cb08ee4cc4f8c70513174 Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Mon, 13 Jul 2026 22:08:39 -0300 Subject: [PATCH 06/37] fixes --- src/flext_cli/_models/__init__.py | 2 -- src/flext_cli/_models/_base_parts/__init__.py | 6 +----- src/flext_cli/_protocols/__init__.py | 2 -- src/flext_cli/_protocols/_base_parts/__init__.py | 6 +----- src/flext_cli/_typings/__init__.py | 6 +----- src/flext_cli/_utilities/__init__.py | 2 -- .../_utilities/_file_test_helper_parts/__init__.py | 2 -- src/flext_cli/_utilities/_files_parts/__init__.py | 6 +----- src/flext_cli/_utilities/_json/__init__.py | 6 +----- src/flext_cli/_utilities/_options_parts/__init__.py | 2 -- src/flext_cli/_utilities/_rules/__init__.py | 6 +----- src/flext_cli/_utilities/_toml_parts/__init__.py | 6 +----- src/flext_cli/_utilities/_yaml/__init__.py | 6 +----- src/flext_cli/services/__init__.py | 2 -- src/flext_cli/services/_cli_parts/__init__.py | 6 +----- tests/unit/test_file_tools_yaml.py | 7 ++----- 16 files changed, 11 insertions(+), 62 deletions(-) diff --git a/src/flext_cli/_models/__init__.py b/src/flext_cli/_models/__init__.py index ad7aba90f..b3c46a22a 100644 --- a/src/flext_cli/_models/__init__.py +++ b/src/flext_cli/_models/__init__.py @@ -9,8 +9,6 @@ from flext_cli._models.__unit__ import ( CHILD_MODULE_PATHS as _CHILD_MODULE_PATHS, EXCLUDED_LAZY_NAMES as _EXCLUDED_LAZY_NAMES, - LAZY_ALIAS_GROUPS as _LAZY_ALIAS_GROUPS, - LAZY_MODULES as _LAZY_MODULES, PUBLIC_EXPORTS as _PUBLIC_EXPORTS, ) from flext_core.lazy import ( diff --git a/src/flext_cli/_models/_base_parts/__init__.py b/src/flext_cli/_models/_base_parts/__init__.py index 4e61be4b3..0903ea042 100644 --- a/src/flext_cli/_models/_base_parts/__init__.py +++ b/src/flext_cli/_models/_base_parts/__init__.py @@ -6,11 +6,7 @@ from typing import TYPE_CHECKING # mro-i6nq.10: The package consumes its manifest's public-export contract. -from flext_cli._models._base_parts.__unit__ import ( - LAZY_ALIAS_GROUPS as _LAZY_ALIAS_GROUPS, - LAZY_MODULES as _LAZY_MODULES, - PUBLIC_EXPORTS as _PUBLIC_EXPORTS, -) +from flext_cli._models._base_parts.__unit__ import PUBLIC_EXPORTS as _PUBLIC_EXPORTS from flext_core.lazy import build_lazy_import_map, install_lazy_exports if TYPE_CHECKING: diff --git a/src/flext_cli/_protocols/__init__.py b/src/flext_cli/_protocols/__init__.py index e58472772..407a17c9a 100644 --- a/src/flext_cli/_protocols/__init__.py +++ b/src/flext_cli/_protocols/__init__.py @@ -9,8 +9,6 @@ from flext_cli._protocols.__unit__ import ( CHILD_MODULE_PATHS as _CHILD_MODULE_PATHS, EXCLUDED_LAZY_NAMES as _EXCLUDED_LAZY_NAMES, - LAZY_ALIAS_GROUPS as _LAZY_ALIAS_GROUPS, - LAZY_MODULES as _LAZY_MODULES, PUBLIC_EXPORTS as _PUBLIC_EXPORTS, ) from flext_core.lazy import ( diff --git a/src/flext_cli/_protocols/_base_parts/__init__.py b/src/flext_cli/_protocols/_base_parts/__init__.py index 52dc81583..48e54a322 100644 --- a/src/flext_cli/_protocols/_base_parts/__init__.py +++ b/src/flext_cli/_protocols/_base_parts/__init__.py @@ -6,11 +6,7 @@ from typing import TYPE_CHECKING # mro-i6nq.10: The package consumes its manifest's public-export contract. -from flext_cli._protocols._base_parts.__unit__ import ( - LAZY_ALIAS_GROUPS as _LAZY_ALIAS_GROUPS, - LAZY_MODULES as _LAZY_MODULES, - PUBLIC_EXPORTS as _PUBLIC_EXPORTS, -) +from flext_cli._protocols._base_parts.__unit__ import PUBLIC_EXPORTS as _PUBLIC_EXPORTS from flext_core.lazy import build_lazy_import_map, install_lazy_exports if TYPE_CHECKING: diff --git a/src/flext_cli/_typings/__init__.py b/src/flext_cli/_typings/__init__.py index d8061e3ec..88cb3cf5a 100644 --- a/src/flext_cli/_typings/__init__.py +++ b/src/flext_cli/_typings/__init__.py @@ -6,11 +6,7 @@ from typing import TYPE_CHECKING # mro-i6nq.10: The package consumes its manifest's public-export contract. -from flext_cli._typings.__unit__ import ( - LAZY_ALIAS_GROUPS as _LAZY_ALIAS_GROUPS, - LAZY_MODULES as _LAZY_MODULES, - PUBLIC_EXPORTS as _PUBLIC_EXPORTS, -) +from flext_cli._typings.__unit__ import PUBLIC_EXPORTS as _PUBLIC_EXPORTS from flext_core.lazy import build_lazy_import_map, install_lazy_exports if TYPE_CHECKING: diff --git a/src/flext_cli/_utilities/__init__.py b/src/flext_cli/_utilities/__init__.py index a92eabc05..540db773b 100644 --- a/src/flext_cli/_utilities/__init__.py +++ b/src/flext_cli/_utilities/__init__.py @@ -9,8 +9,6 @@ from flext_cli._utilities.__unit__ import ( CHILD_MODULE_PATHS as _CHILD_MODULE_PATHS, EXCLUDED_LAZY_NAMES as _EXCLUDED_LAZY_NAMES, - LAZY_ALIAS_GROUPS as _LAZY_ALIAS_GROUPS, - LAZY_MODULES as _LAZY_MODULES, PUBLIC_EXPORTS as _PUBLIC_EXPORTS, ) from flext_core.lazy import ( diff --git a/src/flext_cli/_utilities/_file_test_helper_parts/__init__.py b/src/flext_cli/_utilities/_file_test_helper_parts/__init__.py index 76fd591aa..a770f61d7 100644 --- a/src/flext_cli/_utilities/_file_test_helper_parts/__init__.py +++ b/src/flext_cli/_utilities/_file_test_helper_parts/__init__.py @@ -7,8 +7,6 @@ # mro-i6nq.10: The package consumes its manifest's public-export contract. from flext_cli._utilities._file_test_helper_parts.__unit__ import ( - LAZY_ALIAS_GROUPS as _LAZY_ALIAS_GROUPS, - LAZY_MODULES as _LAZY_MODULES, PUBLIC_EXPORTS as _PUBLIC_EXPORTS, ) from flext_core.lazy import build_lazy_import_map, install_lazy_exports diff --git a/src/flext_cli/_utilities/_files_parts/__init__.py b/src/flext_cli/_utilities/_files_parts/__init__.py index 2e2937da8..e781914d8 100644 --- a/src/flext_cli/_utilities/_files_parts/__init__.py +++ b/src/flext_cli/_utilities/_files_parts/__init__.py @@ -6,11 +6,7 @@ from typing import TYPE_CHECKING # mro-i6nq.10: The package consumes its manifest's public-export contract. -from flext_cli._utilities._files_parts.__unit__ import ( - LAZY_ALIAS_GROUPS as _LAZY_ALIAS_GROUPS, - LAZY_MODULES as _LAZY_MODULES, - PUBLIC_EXPORTS as _PUBLIC_EXPORTS, -) +from flext_cli._utilities._files_parts.__unit__ import PUBLIC_EXPORTS as _PUBLIC_EXPORTS from flext_core.lazy import build_lazy_import_map, install_lazy_exports if TYPE_CHECKING: diff --git a/src/flext_cli/_utilities/_json/__init__.py b/src/flext_cli/_utilities/_json/__init__.py index f47e1f8e2..83dd4361b 100644 --- a/src/flext_cli/_utilities/_json/__init__.py +++ b/src/flext_cli/_utilities/_json/__init__.py @@ -6,11 +6,7 @@ from typing import TYPE_CHECKING # mro-i6nq.10: The package consumes its manifest's public-export contract. -from flext_cli._utilities._json.__unit__ import ( - LAZY_ALIAS_GROUPS as _LAZY_ALIAS_GROUPS, - LAZY_MODULES as _LAZY_MODULES, - PUBLIC_EXPORTS as _PUBLIC_EXPORTS, -) +from flext_cli._utilities._json.__unit__ import PUBLIC_EXPORTS as _PUBLIC_EXPORTS from flext_core.lazy import build_lazy_import_map, install_lazy_exports if TYPE_CHECKING: diff --git a/src/flext_cli/_utilities/_options_parts/__init__.py b/src/flext_cli/_utilities/_options_parts/__init__.py index 087eed895..9545efb8b 100644 --- a/src/flext_cli/_utilities/_options_parts/__init__.py +++ b/src/flext_cli/_utilities/_options_parts/__init__.py @@ -7,8 +7,6 @@ # mro-i6nq.10: The package consumes its manifest's public-export contract. from flext_cli._utilities._options_parts.__unit__ import ( - LAZY_ALIAS_GROUPS as _LAZY_ALIAS_GROUPS, - LAZY_MODULES as _LAZY_MODULES, PUBLIC_EXPORTS as _PUBLIC_EXPORTS, ) from flext_core.lazy import build_lazy_import_map, install_lazy_exports diff --git a/src/flext_cli/_utilities/_rules/__init__.py b/src/flext_cli/_utilities/_rules/__init__.py index 7f2dfa9b5..7f627a373 100644 --- a/src/flext_cli/_utilities/_rules/__init__.py +++ b/src/flext_cli/_utilities/_rules/__init__.py @@ -6,11 +6,7 @@ from typing import TYPE_CHECKING # mro-i6nq.10: The package consumes its manifest's public-export contract. -from flext_cli._utilities._rules.__unit__ import ( - LAZY_ALIAS_GROUPS as _LAZY_ALIAS_GROUPS, - LAZY_MODULES as _LAZY_MODULES, - PUBLIC_EXPORTS as _PUBLIC_EXPORTS, -) +from flext_cli._utilities._rules.__unit__ import PUBLIC_EXPORTS as _PUBLIC_EXPORTS from flext_core.lazy import build_lazy_import_map, install_lazy_exports if TYPE_CHECKING: diff --git a/src/flext_cli/_utilities/_toml_parts/__init__.py b/src/flext_cli/_utilities/_toml_parts/__init__.py index a38b1ea96..923cbe0ee 100644 --- a/src/flext_cli/_utilities/_toml_parts/__init__.py +++ b/src/flext_cli/_utilities/_toml_parts/__init__.py @@ -6,11 +6,7 @@ from typing import TYPE_CHECKING # mro-i6nq.10: The package consumes its manifest's public-export contract. -from flext_cli._utilities._toml_parts.__unit__ import ( - LAZY_ALIAS_GROUPS as _LAZY_ALIAS_GROUPS, - LAZY_MODULES as _LAZY_MODULES, - PUBLIC_EXPORTS as _PUBLIC_EXPORTS, -) +from flext_cli._utilities._toml_parts.__unit__ import PUBLIC_EXPORTS as _PUBLIC_EXPORTS from flext_core.lazy import build_lazy_import_map, install_lazy_exports if TYPE_CHECKING: diff --git a/src/flext_cli/_utilities/_yaml/__init__.py b/src/flext_cli/_utilities/_yaml/__init__.py index b1da1911e..3560f9b4a 100644 --- a/src/flext_cli/_utilities/_yaml/__init__.py +++ b/src/flext_cli/_utilities/_yaml/__init__.py @@ -6,11 +6,7 @@ from typing import TYPE_CHECKING # mro-i6nq.10: The package consumes its manifest's public-export contract. -from flext_cli._utilities._yaml.__unit__ import ( - LAZY_ALIAS_GROUPS as _LAZY_ALIAS_GROUPS, - LAZY_MODULES as _LAZY_MODULES, - PUBLIC_EXPORTS as _PUBLIC_EXPORTS, -) +from flext_cli._utilities._yaml.__unit__ import PUBLIC_EXPORTS as _PUBLIC_EXPORTS from flext_core.lazy import build_lazy_import_map, install_lazy_exports if TYPE_CHECKING: diff --git a/src/flext_cli/services/__init__.py b/src/flext_cli/services/__init__.py index 1db994933..e4ec3030f 100644 --- a/src/flext_cli/services/__init__.py +++ b/src/flext_cli/services/__init__.py @@ -9,8 +9,6 @@ from flext_cli.services.__unit__ import ( CHILD_MODULE_PATHS as _CHILD_MODULE_PATHS, EXCLUDED_LAZY_NAMES as _EXCLUDED_LAZY_NAMES, - LAZY_ALIAS_GROUPS as _LAZY_ALIAS_GROUPS, - LAZY_MODULES as _LAZY_MODULES, PUBLIC_EXPORTS as _PUBLIC_EXPORTS, ) from flext_core.lazy import ( diff --git a/src/flext_cli/services/_cli_parts/__init__.py b/src/flext_cli/services/_cli_parts/__init__.py index e3d837166..e1515555e 100644 --- a/src/flext_cli/services/_cli_parts/__init__.py +++ b/src/flext_cli/services/_cli_parts/__init__.py @@ -6,11 +6,7 @@ from typing import TYPE_CHECKING # mro-i6nq.10: The package consumes its manifest's public-export contract. -from flext_cli.services._cli_parts.__unit__ import ( - LAZY_ALIAS_GROUPS as _LAZY_ALIAS_GROUPS, - LAZY_MODULES as _LAZY_MODULES, - PUBLIC_EXPORTS as _PUBLIC_EXPORTS, -) +from flext_cli.services._cli_parts.__unit__ import PUBLIC_EXPORTS as _PUBLIC_EXPORTS from flext_core.lazy import build_lazy_import_map, install_lazy_exports if TYPE_CHECKING: diff --git a/tests/unit/test_file_tools_yaml.py b/tests/unit/test_file_tools_yaml.py index c0463f3d5..89dd18d19 100644 --- a/tests/unit/test_file_tools_yaml.py +++ b/tests/unit/test_file_tools_yaml.py @@ -2,15 +2,12 @@ from __future__ import annotations -from typing import TYPE_CHECKING - from flext_tests import tm from flext_cli import cli -from tests.models import m +from tests import m -if TYPE_CHECKING: - from pathlib import Path +from pathlib import Path class TestsFlextCliYamlModelLoading: From d02c431854dbcf44f16737aec1666807b578c041 Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Mon, 13 Jul 2026 23:43:17 -0300 Subject: [PATCH 07/37] refactor flext patterns --- src/flext_cli/__init__.py | 103 +++++++-- src/flext_cli/_models/__init__.py | 88 +------ src/flext_cli/_models/_base_parts/__init__.py | 25 +- src/flext_cli/_protocols/__init__.py | 67 +----- .../_protocols/_base_parts/__init__.py | 25 +- src/flext_cli/_typings/__init__.py | 28 +-- src/flext_cli/_utilities/__init__.py | 217 +----------------- .../_file_test_helper_parts/__init__.py | 27 +-- .../_utilities/_files_parts/__init__.py | 25 +- src/flext_cli/_utilities/_json/__init__.py | 28 +-- .../_utilities/_options_parts/__init__.py | 30 +-- src/flext_cli/_utilities/_rules/__init__.py | 28 +-- .../_utilities/_toml_parts/__init__.py | 25 +- .../flextcliutilitiestoml_part_02.py | 15 +- src/flext_cli/_utilities/_yaml/__init__.py | 31 +-- src/flext_cli/services/__init__.py | 80 +++---- src/flext_cli/services/_cli_parts/__init__.py | 25 +- 17 files changed, 128 insertions(+), 739 deletions(-) diff --git a/src/flext_cli/__init__.py b/src/flext_cli/__init__.py index 96e9a8a7f..53f886d24 100644 --- a/src/flext_cli/__init__.py +++ b/src/flext_cli/__init__.py @@ -5,14 +5,6 @@ from typing import TYPE_CHECKING -# mro-i6nq.10: The package consumes its manifest's public-export contract. -from flext_cli.__unit__ import ( - CHILD_MODULE_PATHS as _CHILD_MODULE_PATHS, - EXCLUDED_LAZY_NAMES as _EXCLUDED_LAZY_NAMES, - LAZY_ALIAS_GROUPS as _LAZY_ALIAS_GROUPS, - LAZY_MODULES as _LAZY_MODULES, - PUBLIC_EXPORTS as _PUBLIC_EXPORTS, -) from flext_cli.__version__ import ( __author__ as __author__, __author_email__ as __author_email__, @@ -23,14 +15,9 @@ __version__ as __version__, __version_info__ as __version_info__, ) -from flext_core.lazy import ( - build_lazy_import_map, - install_lazy_exports, - merge_lazy_imports, -) +from flext_core.lazy import build_lazy_import_map, install_lazy_exports if TYPE_CHECKING: - from flext_cli import services as services from flext_cli._config import FlextCliConfig as FlextCliConfig, config as config from flext_cli._settings import ( FlextCliSettings as FlextCliSettings, @@ -67,19 +54,85 @@ x as x, ) - # mro-i6nq.10: Static declaration mirrors the installer-owned runtime binding. - __all__: tuple[str, ...] +_LAZY_MODULES: dict[str, tuple[str, ...]] = { + "._config": ("FlextCliConfig", "config"), + "._settings": ("FlextCliSettings", "settings"), + ".api": ("FlextCli", "cli"), + ".base": ("FlextCliServiceBase", "s"), + ".constants": ("FlextCliConstants", "c"), + ".models": ("FlextCliModels", "m"), + ".protocols": ("FlextCliProtocols", "p"), + ".services.auth": ("FlextCliAuth",), + ".services.cli": ("FlextCliCli",), + ".services.cli_params": ("FlextCliCommonParams",), + ".services.cmd": ("FlextCliCmd",), + ".services.file_tools": ("FlextCliFileTools",), + ".services.formatters": ("FlextCliFormatters",), + ".services.output": ("FlextCliOutput",), + ".services.pipeline": ("FlextCliPipeline",), + ".services.prompts": ("FlextCliPrompts",), + ".services.rules": ("FlextCliRules",), + ".services.runtime": ("FlextCliRuntime",), + ".services.tables": ("FlextCliTables",), + ".services.xlsx": ("FlextCliXlsx",), + ".services.yaml_model": ("FlextCliYamlModel",), + ".typings": ("FlextCliTypes", "t"), + ".utilities": ("FlextCliUtilities", "u"), + "flext_core._root_typing_parts.facades": ("d", "e", "h", "r", "x"), +} +_LAZY_ALIAS_GROUPS: dict[str, tuple[tuple[str, str], ...]] = {} -_LAZY_IMPORTS = merge_lazy_imports( - _CHILD_MODULE_PATHS, - build_lazy_import_map( - _LAZY_MODULES, alias_groups=_LAZY_ALIAS_GROUPS, sort_keys=False - ), - exclude_names=_EXCLUDED_LAZY_NAMES, - module_name=__name__, +_LAZY_IMPORTS = build_lazy_import_map( + _LAZY_MODULES, alias_groups=_LAZY_ALIAS_GROUPS, sort_keys=False ) +__all__: tuple[str, ...] = ( + "FlextCli", + "FlextCliAuth", + "FlextCliCli", + "FlextCliCmd", + "FlextCliCommonParams", + "FlextCliConfig", + "FlextCliConstants", + "FlextCliFileTools", + "FlextCliFormatters", + "FlextCliModels", + "FlextCliOutput", + "FlextCliPipeline", + "FlextCliPrompts", + "FlextCliProtocols", + "FlextCliRules", + "FlextCliRuntime", + "FlextCliServiceBase", + "FlextCliSettings", + "FlextCliTables", + "FlextCliTypes", + "FlextCliUtilities", + "FlextCliXlsx", + "FlextCliYamlModel", + "__author__", + "__author_email__", + "__description__", + "__license__", + "__title__", + "__url__", + "__version__", + "__version_info__", + "c", + "cli", + "config", + "d", + "e", + "h", + "m", + "p", + "r", + "s", + "settings", + "t", + "u", + "x", +) -# mro-i6nq.10: The installer publishes __all__ from the manifest's literal ABI. -install_lazy_exports(__name__, globals(), _LAZY_IMPORTS, public_exports=_PUBLIC_EXPORTS) +install_lazy_exports(__name__, globals(), _LAZY_IMPORTS, public_exports=__all__) diff --git a/src/flext_cli/_models/__init__.py b/src/flext_cli/_models/__init__.py index b3c46a22a..02d13741c 100644 --- a/src/flext_cli/_models/__init__.py +++ b/src/flext_cli/_models/__init__.py @@ -1,90 +1,4 @@ # AUTO-GENERATED FILE — Regenerate with: make gen -"""Flext Cli. Models package.""" +"""Models package.""" from __future__ import annotations - -from typing import TYPE_CHECKING - -# mro-i6nq.10: The package consumes its manifest's public-export contract. -from flext_cli._models.__unit__ import ( - CHILD_MODULE_PATHS as _CHILD_MODULE_PATHS, - EXCLUDED_LAZY_NAMES as _EXCLUDED_LAZY_NAMES, - PUBLIC_EXPORTS as _PUBLIC_EXPORTS, -) -from flext_core.lazy import ( - build_lazy_import_map, - install_lazy_exports, - merge_lazy_imports, -) - -if TYPE_CHECKING: - from flext_cli._models import _base_parts as _base_parts - from flext_cli._models._base_parts.flextclimodelsbase_part_07 import ( - FlextCliModelsBase as FlextCliModelsBase, - ) - from flext_cli._models._test_tmp import X as X - from flext_cli._models.config import FlextCliConfigModels as FlextCliConfigModels - from flext_cli._models.pipeline import ( - FlextCliModelsPipeline as FlextCliModelsPipeline, - ) - from flext_cli._models.rules import FlextCliModelsRules as FlextCliModelsRules - from flext_cli._models.template import ( - FlextCliModelsTemplate as FlextCliModelsTemplate, - ) - from flext_cli._models.xlsx import FlextCliModelsXlsx as FlextCliModelsXlsx - from flext_cli._models.xlsx_archive import ( - FlextCliModelsXlsxArchive as FlextCliModelsXlsxArchive, - ) - from flext_cli._models.xlsx_cells import ( - FlextCliModelsXlsxCells as FlextCliModelsXlsxCells, - ) - from flext_cli._models.xlsx_layout import ( - FlextCliModelsXlsxLayout as FlextCliModelsXlsxLayout, - ) - from flext_cli._models.xlsx_recalc import ( - FlextCliModelsXlsxRecalc as FlextCliModelsXlsxRecalc, - ) - from flext_cli._models.xlsx_rules import ( - FlextCliModelsXlsxRules as FlextCliModelsXlsxRules, - ) - from flext_cli._models.xlsx_snapshot import ( - FlextCliModelsXlsxSnapshot as FlextCliModelsXlsxSnapshot, - ) - from flext_cli._models.xlsx_style_catalog import ( - FlextCliModelsXlsxStyleCatalog as FlextCliModelsXlsxStyleCatalog, - ) - from flext_cli._models.xlsx_style_fills import ( - FlextCliModelsXlsxStyleFills as FlextCliModelsXlsxStyleFills, - ) - from flext_cli._models.xlsx_style_primitives import ( - FlextCliModelsXlsxStylePrimitives as FlextCliModelsXlsxStylePrimitives, - ) - from flext_cli._models.xlsx_styles import ( - FlextCliModelsXlsxStyles as FlextCliModelsXlsxStyles, - ) - from flext_cli._models.xlsx_tables import ( - FlextCliModelsXlsxTables as FlextCliModelsXlsxTables, - ) - from flext_cli._models.xlsx_validation import ( - FlextCliModelsXlsxValidation as FlextCliModelsXlsxValidation, - ) - from flext_cli._models.xlsx_workbook import ( - FlextCliModelsXlsxWorkbook as FlextCliModelsXlsxWorkbook, - ) - - # mro-i6nq.10: Static declaration mirrors the installer-owned runtime binding. - __all__: tuple[str, ...] - - -_LAZY_IMPORTS = merge_lazy_imports( - _CHILD_MODULE_PATHS, - build_lazy_import_map( - _LAZY_MODULES, alias_groups=_LAZY_ALIAS_GROUPS, sort_keys=False - ), - exclude_names=_EXCLUDED_LAZY_NAMES, - module_name=__name__, -) - - -# mro-i6nq.10: The installer publishes __all__ from the manifest's literal ABI. -install_lazy_exports(__name__, globals(), _LAZY_IMPORTS, public_exports=_PUBLIC_EXPORTS) diff --git a/src/flext_cli/_models/_base_parts/__init__.py b/src/flext_cli/_models/_base_parts/__init__.py index 0903ea042..d83ebd486 100644 --- a/src/flext_cli/_models/_base_parts/__init__.py +++ b/src/flext_cli/_models/_base_parts/__init__.py @@ -1,27 +1,4 @@ # AUTO-GENERATED FILE — Regenerate with: make gen -"""Flext Cli. Models. Base Parts package.""" +"""Base Parts package.""" from __future__ import annotations - -from typing import TYPE_CHECKING - -# mro-i6nq.10: The package consumes its manifest's public-export contract. -from flext_cli._models._base_parts.__unit__ import PUBLIC_EXPORTS as _PUBLIC_EXPORTS -from flext_core.lazy import build_lazy_import_map, install_lazy_exports - -if TYPE_CHECKING: - from flext_cli._models._base_parts.flextclimodelsbase_part_07 import ( - FlextCliModelsBase as FlextCliModelsBase, - ) - - # mro-i6nq.10: Static declaration mirrors the installer-owned runtime binding. - __all__: tuple[str, ...] - - -_LAZY_IMPORTS = build_lazy_import_map( - _LAZY_MODULES, alias_groups=_LAZY_ALIAS_GROUPS, sort_keys=False -) - - -# mro-i6nq.10: The installer publishes __all__ from the manifest's literal ABI. -install_lazy_exports(__name__, globals(), _LAZY_IMPORTS, public_exports=_PUBLIC_EXPORTS) diff --git a/src/flext_cli/_protocols/__init__.py b/src/flext_cli/_protocols/__init__.py index 407a17c9a..d88400b7c 100644 --- a/src/flext_cli/_protocols/__init__.py +++ b/src/flext_cli/_protocols/__init__.py @@ -1,69 +1,4 @@ # AUTO-GENERATED FILE — Regenerate with: make gen -"""Flext Cli. Protocols package.""" +"""Protocols package.""" from __future__ import annotations - -from typing import TYPE_CHECKING - -# mro-i6nq.10: The package consumes its manifest's public-export contract. -from flext_cli._protocols.__unit__ import ( - CHILD_MODULE_PATHS as _CHILD_MODULE_PATHS, - EXCLUDED_LAZY_NAMES as _EXCLUDED_LAZY_NAMES, - PUBLIC_EXPORTS as _PUBLIC_EXPORTS, -) -from flext_core.lazy import ( - build_lazy_import_map, - install_lazy_exports, - merge_lazy_imports, -) - -if TYPE_CHECKING: - from flext_cli._protocols import _base_parts as _base_parts - from flext_cli._protocols._base_parts.flextcliprotocolsbase_part_05 import ( - FlextCliProtocolsBase as FlextCliProtocolsBase, - ) - from flext_cli._protocols.config import ( - FlextCliProtocolsConfig as FlextCliProtocolsConfig, - ) - from flext_cli._protocols.domain import ( - FlextCliProtocolsDomain as FlextCliProtocolsDomain, - ) - from flext_cli._protocols.framework import ( - FlextCliProtocolsFramework as FlextCliProtocolsFramework, - ) - from flext_cli._protocols.pipeline import ( - FlextCliProtocolsPipeline as FlextCliProtocolsPipeline, - ) - from flext_cli._protocols.xlsx import FlextCliProtocolsXlsx as FlextCliProtocolsXlsx - from flext_cli._protocols.xlsx_archive import ( - FlextCliProtocolsXlsxArchive as FlextCliProtocolsXlsxArchive, - ) - from flext_cli._protocols.xlsx_rules import ( - FlextCliProtocolsXlsxRules as FlextCliProtocolsXlsxRules, - ) - from flext_cli._protocols.xlsx_snapshot import ( - FlextCliProtocolsXlsxSnapshot as FlextCliProtocolsXlsxSnapshot, - ) - from flext_cli._protocols.xlsx_snapshot_structure import ( - FlextCliProtocolsXlsxSnapshotStructure as FlextCliProtocolsXlsxSnapshotStructure, - ) - from flext_cli._protocols.xlsx_workbook import ( - FlextCliProtocolsXlsxWorkbook as FlextCliProtocolsXlsxWorkbook, - ) - - # mro-i6nq.10: Static declaration mirrors the installer-owned runtime binding. - __all__: tuple[str, ...] - - -_LAZY_IMPORTS = merge_lazy_imports( - _CHILD_MODULE_PATHS, - build_lazy_import_map( - _LAZY_MODULES, alias_groups=_LAZY_ALIAS_GROUPS, sort_keys=False - ), - exclude_names=_EXCLUDED_LAZY_NAMES, - module_name=__name__, -) - - -# mro-i6nq.10: The installer publishes __all__ from the manifest's literal ABI. -install_lazy_exports(__name__, globals(), _LAZY_IMPORTS, public_exports=_PUBLIC_EXPORTS) diff --git a/src/flext_cli/_protocols/_base_parts/__init__.py b/src/flext_cli/_protocols/_base_parts/__init__.py index 48e54a322..d83ebd486 100644 --- a/src/flext_cli/_protocols/_base_parts/__init__.py +++ b/src/flext_cli/_protocols/_base_parts/__init__.py @@ -1,27 +1,4 @@ # AUTO-GENERATED FILE — Regenerate with: make gen -"""Flext Cli. Protocols. Base Parts package.""" +"""Base Parts package.""" from __future__ import annotations - -from typing import TYPE_CHECKING - -# mro-i6nq.10: The package consumes its manifest's public-export contract. -from flext_cli._protocols._base_parts.__unit__ import PUBLIC_EXPORTS as _PUBLIC_EXPORTS -from flext_core.lazy import build_lazy_import_map, install_lazy_exports - -if TYPE_CHECKING: - from flext_cli._protocols._base_parts.flextcliprotocolsbase_part_05 import ( - FlextCliProtocolsBase as FlextCliProtocolsBase, - ) - - # mro-i6nq.10: Static declaration mirrors the installer-owned runtime binding. - __all__: tuple[str, ...] - - -_LAZY_IMPORTS = build_lazy_import_map( - _LAZY_MODULES, alias_groups=_LAZY_ALIAS_GROUPS, sort_keys=False -) - - -# mro-i6nq.10: The installer publishes __all__ from the manifest's literal ABI. -install_lazy_exports(__name__, globals(), _LAZY_IMPORTS, public_exports=_PUBLIC_EXPORTS) diff --git a/src/flext_cli/_typings/__init__.py b/src/flext_cli/_typings/__init__.py index 88cb3cf5a..517d9d8bb 100644 --- a/src/flext_cli/_typings/__init__.py +++ b/src/flext_cli/_typings/__init__.py @@ -1,30 +1,4 @@ # AUTO-GENERATED FILE — Regenerate with: make gen -"""Flext Cli. Typings package.""" +"""Typings package.""" from __future__ import annotations - -from typing import TYPE_CHECKING - -# mro-i6nq.10: The package consumes its manifest's public-export contract. -from flext_cli._typings.__unit__ import PUBLIC_EXPORTS as _PUBLIC_EXPORTS -from flext_core.lazy import build_lazy_import_map, install_lazy_exports - -if TYPE_CHECKING: - from flext_cli._typings.base import FlextCliTypesBase as FlextCliTypesBase - from flext_cli._typings.domain import FlextCliTypesDomain as FlextCliTypesDomain - from flext_cli._typings.pipeline import ( - FlextCliTypesPipeline as FlextCliTypesPipeline, - ) - from flext_cli._typings.xlsx import FlextCliTypesXlsx as FlextCliTypesXlsx - - # mro-i6nq.10: Static declaration mirrors the installer-owned runtime binding. - __all__: tuple[str, ...] - - -_LAZY_IMPORTS = build_lazy_import_map( - _LAZY_MODULES, alias_groups=_LAZY_ALIAS_GROUPS, sort_keys=False -) - - -# mro-i6nq.10: The installer publishes __all__ from the manifest's literal ABI. -install_lazy_exports(__name__, globals(), _LAZY_IMPORTS, public_exports=_PUBLIC_EXPORTS) diff --git a/src/flext_cli/_utilities/__init__.py b/src/flext_cli/_utilities/__init__.py index 98bfb4051..5538ced2d 100644 --- a/src/flext_cli/_utilities/__init__.py +++ b/src/flext_cli/_utilities/__init__.py @@ -1,219 +1,4 @@ # AUTO-GENERATED FILE — Regenerate with: make gen -"""Flext Cli. Utilities package.""" +"""Utilities package.""" from __future__ import annotations - -from typing import TYPE_CHECKING - -# mro-i6nq.10: The package consumes its manifest's public-export contract. -from flext_cli._utilities.__unit__ import ( - CHILD_MODULE_PATHS as _CHILD_MODULE_PATHS, - EXCLUDED_LAZY_NAMES as _EXCLUDED_LAZY_NAMES, - PUBLIC_EXPORTS as _PUBLIC_EXPORTS, -) -from flext_core.lazy import ( - build_lazy_import_map, - install_lazy_exports, - merge_lazy_imports, -) - -if TYPE_CHECKING: - from flext_cli._utilities import ( - _file_test_helper_parts as _file_test_helper_parts, - _files_parts as _files_parts, - _json as _json, - _options_parts as _options_parts, - _rules as _rules, - _toml_parts as _toml_parts, - _yaml as _yaml, - ) - from flext_cli._utilities._cli_namespace import ( - FlextCliUtilitiesCli as FlextCliUtilitiesCli, - ) - from flext_cli._utilities._file_test_helper_parts.flextcliutilitiesfiletesthelpersmixin_part_04 import ( - FlextCliUtilitiesFileTestHelpersMixin as FlextCliUtilitiesFileTestHelpersMixin, - ) - from flext_cli._utilities._files_parts.flextcliutilitiesfiles_part_04 import ( - FlextCliUtilitiesFiles as FlextCliUtilitiesFiles, - ) - from flext_cli._utilities._json._core import ( - FlextCliUtilitiesJsonCoreMixin as FlextCliUtilitiesJsonCoreMixin, - ) - from flext_cli._utilities._json._navigate import ( - FlextCliUtilitiesJsonNavigateMixin as FlextCliUtilitiesJsonNavigateMixin, - ) - from flext_cli._utilities._options_parts.flextcliutilitiesoptionbuilder_part_01 import ( - FlextCliUtilitiesOptionBuilder as FlextCliUtilitiesOptionBuilder, - ) - from flext_cli._utilities._options_parts.flextcliutilitiesoptions_part_02 import ( - FlextCliUtilitiesOptions as FlextCliUtilitiesOptions, - ) - from flext_cli._utilities._rules._loaders import ( - FlextCliUtilitiesRulesLoadersMixin as FlextCliUtilitiesRulesLoadersMixin, - ) - from flext_cli._utilities._rules._matchers import ( - FlextCliUtilitiesRulesMatchersMixin as FlextCliUtilitiesRulesMatchersMixin, - ) - from flext_cli._utilities._toml_parts.flextcliutilitiestoml_part_07 import ( - FlextCliUtilitiesToml as FlextCliUtilitiesToml, - ) - from flext_cli._utilities._yaml._convert import ( - FlextCliUtilitiesYamlConvertMixin as FlextCliUtilitiesYamlConvertMixin, - ) - from flext_cli._utilities._yaml._editing import ( - FlextCliUtilitiesYamlEditingMixin as FlextCliUtilitiesYamlEditingMixin, - ) - from flext_cli._utilities._yaml._engine import ( - FlextCliUtilitiesYamlEngineMixin as FlextCliUtilitiesYamlEngineMixin, - ) - from flext_cli._utilities.auth import FlextCliUtilitiesAuth as FlextCliUtilitiesAuth - from flext_cli._utilities.cmd import FlextCliUtilitiesCmd as FlextCliUtilitiesCmd - from flext_cli._utilities.commands import ( - FlextCliUtilitiesCommands as FlextCliUtilitiesCommands, - ) - from flext_cli._utilities.config import ( - FlextCliUtilitiesConfig as FlextCliUtilitiesConfig, - ) - from flext_cli._utilities.conversion import ( - FlextCliUtilitiesConversion as FlextCliUtilitiesConversion, - ) - from flext_cli._utilities.formatters import ( - FlextCliUtilitiesFormatters as FlextCliUtilitiesFormatters, - ) - from flext_cli._utilities.framework import ( - FlextCliUtilitiesFramework as FlextCliUtilitiesFramework, - ) - from flext_cli._utilities.json import FlextCliUtilitiesJson as FlextCliUtilitiesJson - from flext_cli._utilities.matching import ( - FlextCliUtilitiesMatching as FlextCliUtilitiesMatching, - ) - from flext_cli._utilities.model_commands import ( - FlextCliUtilitiesModelCommands as FlextCliUtilitiesModelCommands, - ) - from flext_cli._utilities.output import ( - FlextCliUtilitiesOutput as FlextCliUtilitiesOutput, - ) - from flext_cli._utilities.params import ( - FlextCliUtilitiesParams as FlextCliUtilitiesParams, - ) - from flext_cli._utilities.pipeline import ( - FlextCliUtilitiesPipeline as FlextCliUtilitiesPipeline, - ) - from flext_cli._utilities.processes import ( - FlextCliUtilitiesProcesses as FlextCliUtilitiesProcesses, - ) - from flext_cli._utilities.prompts import ( - FlextCliUtilitiesPrompts as FlextCliUtilitiesPrompts, - ) - from flext_cli._utilities.rules import ( - FlextCliUtilitiesRules as FlextCliUtilitiesRules, - ) - from flext_cli._utilities.runtime import ( - FlextCliUtilitiesRuntime as FlextCliUtilitiesRuntime, - ) - from flext_cli._utilities.settings import ( - FlextCliUtilitiesSettings as FlextCliUtilitiesSettings, - ) - from flext_cli._utilities.tables import ( - FlextCliUtilitiesTables as FlextCliUtilitiesTables, - ) - from flext_cli._utilities.template import ( - FlextCliUtilitiesTemplate as FlextCliUtilitiesTemplate, - ) - from flext_cli._utilities.validation import ( - FlextCliUtilitiesValidation as FlextCliUtilitiesValidation, - ) - from flext_cli._utilities.xlsx import FlextCliUtilitiesXlsx as FlextCliUtilitiesXlsx - from flext_cli._utilities._xlxx.xlsx_addresses import ( - FlextCliUtilitiesXlsxAddresses as FlextCliUtilitiesXlsxAddresses, - ) - from flext_cli._utilities._xlxx.xlsx_archive import ( - FlextCliUtilitiesXlsxArchive as FlextCliUtilitiesXlsxArchive, - ) - from flext_cli._utilities._xlxx.xlsx_archive_checks import ( - FlextCliUtilitiesXlsxArchiveChecks as FlextCliUtilitiesXlsxArchiveChecks, - ) - from flext_cli._utilities._xlxx.xlsx_cells import ( - FlextCliUtilitiesXlsxCells as FlextCliUtilitiesXlsxCells, - ) - from flext_cli._utilities._xlxx.xlsx_conditional import ( - FlextCliUtilitiesXlsxConditional as FlextCliUtilitiesXlsxConditional, - ) - from flext_cli._utilities._xlxx.xlsx_formula_codec import ( - FlextCliUtilitiesXlsxFormulaCodec as FlextCliUtilitiesXlsxFormulaCodec, - ) - from flext_cli._utilities._xlxx.xlsx_layout import ( - FlextCliUtilitiesXlsxLayout as FlextCliUtilitiesXlsxLayout, - ) - from flext_cli._utilities._xlxx.xlsx_protection import ( - FlextCliUtilitiesXlsxProtection as FlextCliUtilitiesXlsxProtection, - ) - from flext_cli._utilities._xlxx.xlsx_recalc import ( - FlextCliUtilitiesXlsxRecalc as FlextCliUtilitiesXlsxRecalc, - ) - from flext_cli._utilities._xlxx.xlsx_recalc_evidence import ( - FlextCliUtilitiesXlsxRecalcEvidence as FlextCliUtilitiesXlsxRecalcEvidence, - ) - from flext_cli._utilities._xlxx.xlsx_renderer import ( - FlextCliUtilitiesXlsxRenderer as FlextCliUtilitiesXlsxRenderer, - ) - from flext_cli._utilities._xlxx.xlsx_rules import ( - FlextCliUtilitiesXlsxRules as FlextCliUtilitiesXlsxRules, - ) - from flext_cli._utilities._xlxx.xlsx_snapshot import ( - FlextCliUtilitiesXlsxSnapshot as FlextCliUtilitiesXlsxSnapshot, - ) - from flext_cli._utilities._xlxx.xlsx_snapshot_sheet import ( - FlextCliUtilitiesXlsxSnapshotSheet as FlextCliUtilitiesXlsxSnapshotSheet, - ) - from flext_cli._utilities._xlxx.xlsx_snapshot_structure import ( - FlextCliUtilitiesXlsxSnapshotStructure as FlextCliUtilitiesXlsxSnapshotStructure, - ) - from flext_cli._utilities._xlxx.xlsx_snapshot_values import ( - FlextCliUtilitiesXlsxSnapshotValues as FlextCliUtilitiesXlsxSnapshotValues, - ) - from flext_cli._utilities._xlxx.xlsx_style_builders import ( - FlextCliUtilitiesXlsxStyleBuilders as FlextCliUtilitiesXlsxStyleBuilders, - ) - from flext_cli._utilities._xlxx.xlsx_style_catalog import ( - FlextCliUtilitiesXlsxStyleCatalog as FlextCliUtilitiesXlsxStyleCatalog, - ) - from flext_cli._utilities._xlxx.xlsx_style_codec import ( - FlextCliUtilitiesXlsxStyleCodec as FlextCliUtilitiesXlsxStyleCodec, - ) - from flext_cli._utilities._xlxx.xlsx_style_readers import ( - FlextCliUtilitiesXlsxStyleReaders as FlextCliUtilitiesXlsxStyleReaders, - ) - from flext_cli._utilities._xlxx.xlsx_tables import ( - FlextCliUtilitiesXlsxTables as FlextCliUtilitiesXlsxTables, - ) - from flext_cli._utilities._xlxx.xlsx_validations import ( - FlextCliUtilitiesXlsxValidations as FlextCliUtilitiesXlsxValidations, - ) - from flext_cli._utilities._xlxx.xlsx_workbook_io import ( - FlextCliUtilitiesXlsxWorkbookIo as FlextCliUtilitiesXlsxWorkbookIo, - ) - from flext_cli._utilities._xlxx.xlsx_workbook_plan import ( - FlextCliUtilitiesXlsxWorkbookPlan as FlextCliUtilitiesXlsxWorkbookPlan, - ) - from flext_cli._utilities.yaml import FlextCliUtilitiesYaml as FlextCliUtilitiesYaml - from flext_cli._utilities.yaml_model import ( - FlextCliUtilitiesYamlModel as FlextCliUtilitiesYamlModel, - ) - - # mro-i6nq.10: Static declaration mirrors the installer-owned runtime binding. - __all__: tuple[str, ...] - - -_LAZY_IMPORTS = merge_lazy_imports( - _CHILD_MODULE_PATHS, - build_lazy_import_map( - _LAZY_MODULES, alias_groups=_LAZY_ALIAS_GROUPS, sort_keys=False - ), - exclude_names=_EXCLUDED_LAZY_NAMES, - module_name=__name__, -) - - -# mro-i6nq.10: The installer publishes __all__ from the manifest's literal ABI. -install_lazy_exports(__name__, globals(), _LAZY_IMPORTS, public_exports=_PUBLIC_EXPORTS) diff --git a/src/flext_cli/_utilities/_file_test_helper_parts/__init__.py b/src/flext_cli/_utilities/_file_test_helper_parts/__init__.py index a770f61d7..9f979f11a 100644 --- a/src/flext_cli/_utilities/_file_test_helper_parts/__init__.py +++ b/src/flext_cli/_utilities/_file_test_helper_parts/__init__.py @@ -1,29 +1,4 @@ # AUTO-GENERATED FILE — Regenerate with: make gen -"""Flext Cli. Utilities. File Test Helper Parts package.""" +"""File Test Helper Parts package.""" from __future__ import annotations - -from typing import TYPE_CHECKING - -# mro-i6nq.10: The package consumes its manifest's public-export contract. -from flext_cli._utilities._file_test_helper_parts.__unit__ import ( - PUBLIC_EXPORTS as _PUBLIC_EXPORTS, -) -from flext_core.lazy import build_lazy_import_map, install_lazy_exports - -if TYPE_CHECKING: - from flext_cli._utilities._file_test_helper_parts.flextcliutilitiesfiletesthelpersmixin_part_04 import ( - FlextCliUtilitiesFileTestHelpersMixin as FlextCliUtilitiesFileTestHelpersMixin, - ) - - # mro-i6nq.10: Static declaration mirrors the installer-owned runtime binding. - __all__: tuple[str, ...] - - -_LAZY_IMPORTS = build_lazy_import_map( - _LAZY_MODULES, alias_groups=_LAZY_ALIAS_GROUPS, sort_keys=False -) - - -# mro-i6nq.10: The installer publishes __all__ from the manifest's literal ABI. -install_lazy_exports(__name__, globals(), _LAZY_IMPORTS, public_exports=_PUBLIC_EXPORTS) diff --git a/src/flext_cli/_utilities/_files_parts/__init__.py b/src/flext_cli/_utilities/_files_parts/__init__.py index e781914d8..2a51eea47 100644 --- a/src/flext_cli/_utilities/_files_parts/__init__.py +++ b/src/flext_cli/_utilities/_files_parts/__init__.py @@ -1,27 +1,4 @@ # AUTO-GENERATED FILE — Regenerate with: make gen -"""Flext Cli. Utilities. Files Parts package.""" +"""Files Parts package.""" from __future__ import annotations - -from typing import TYPE_CHECKING - -# mro-i6nq.10: The package consumes its manifest's public-export contract. -from flext_cli._utilities._files_parts.__unit__ import PUBLIC_EXPORTS as _PUBLIC_EXPORTS -from flext_core.lazy import build_lazy_import_map, install_lazy_exports - -if TYPE_CHECKING: - from flext_cli._utilities._files_parts.flextcliutilitiesfiles_part_04 import ( - FlextCliUtilitiesFiles as FlextCliUtilitiesFiles, - ) - - # mro-i6nq.10: Static declaration mirrors the installer-owned runtime binding. - __all__: tuple[str, ...] - - -_LAZY_IMPORTS = build_lazy_import_map( - _LAZY_MODULES, alias_groups=_LAZY_ALIAS_GROUPS, sort_keys=False -) - - -# mro-i6nq.10: The installer publishes __all__ from the manifest's literal ABI. -install_lazy_exports(__name__, globals(), _LAZY_IMPORTS, public_exports=_PUBLIC_EXPORTS) diff --git a/src/flext_cli/_utilities/_json/__init__.py b/src/flext_cli/_utilities/_json/__init__.py index 83dd4361b..6f49e21cd 100644 --- a/src/flext_cli/_utilities/_json/__init__.py +++ b/src/flext_cli/_utilities/_json/__init__.py @@ -1,30 +1,4 @@ # AUTO-GENERATED FILE — Regenerate with: make gen -"""Flext Cli. Utilities. Json package.""" +"""Json package.""" from __future__ import annotations - -from typing import TYPE_CHECKING - -# mro-i6nq.10: The package consumes its manifest's public-export contract. -from flext_cli._utilities._json.__unit__ import PUBLIC_EXPORTS as _PUBLIC_EXPORTS -from flext_core.lazy import build_lazy_import_map, install_lazy_exports - -if TYPE_CHECKING: - from flext_cli._utilities._json._core import ( - FlextCliUtilitiesJsonCoreMixin as FlextCliUtilitiesJsonCoreMixin, - ) - from flext_cli._utilities._json._navigate import ( - FlextCliUtilitiesJsonNavigateMixin as FlextCliUtilitiesJsonNavigateMixin, - ) - - # mro-i6nq.10: Static declaration mirrors the installer-owned runtime binding. - __all__: tuple[str, ...] - - -_LAZY_IMPORTS = build_lazy_import_map( - _LAZY_MODULES, alias_groups=_LAZY_ALIAS_GROUPS, sort_keys=False -) - - -# mro-i6nq.10: The installer publishes __all__ from the manifest's literal ABI. -install_lazy_exports(__name__, globals(), _LAZY_IMPORTS, public_exports=_PUBLIC_EXPORTS) diff --git a/src/flext_cli/_utilities/_options_parts/__init__.py b/src/flext_cli/_utilities/_options_parts/__init__.py index 9545efb8b..f08147578 100644 --- a/src/flext_cli/_utilities/_options_parts/__init__.py +++ b/src/flext_cli/_utilities/_options_parts/__init__.py @@ -1,32 +1,4 @@ # AUTO-GENERATED FILE — Regenerate with: make gen -"""Flext Cli. Utilities. Options Parts package.""" +"""Options Parts package.""" from __future__ import annotations - -from typing import TYPE_CHECKING - -# mro-i6nq.10: The package consumes its manifest's public-export contract. -from flext_cli._utilities._options_parts.__unit__ import ( - PUBLIC_EXPORTS as _PUBLIC_EXPORTS, -) -from flext_core.lazy import build_lazy_import_map, install_lazy_exports - -if TYPE_CHECKING: - from flext_cli._utilities._options_parts.flextcliutilitiesoptionbuilder_part_01 import ( - FlextCliUtilitiesOptionBuilder as FlextCliUtilitiesOptionBuilder, - ) - from flext_cli._utilities._options_parts.flextcliutilitiesoptions_part_02 import ( - FlextCliUtilitiesOptions as FlextCliUtilitiesOptions, - ) - - # mro-i6nq.10: Static declaration mirrors the installer-owned runtime binding. - __all__: tuple[str, ...] - - -_LAZY_IMPORTS = build_lazy_import_map( - _LAZY_MODULES, alias_groups=_LAZY_ALIAS_GROUPS, sort_keys=False -) - - -# mro-i6nq.10: The installer publishes __all__ from the manifest's literal ABI. -install_lazy_exports(__name__, globals(), _LAZY_IMPORTS, public_exports=_PUBLIC_EXPORTS) diff --git a/src/flext_cli/_utilities/_rules/__init__.py b/src/flext_cli/_utilities/_rules/__init__.py index 7f627a373..9038624d7 100644 --- a/src/flext_cli/_utilities/_rules/__init__.py +++ b/src/flext_cli/_utilities/_rules/__init__.py @@ -1,30 +1,4 @@ # AUTO-GENERATED FILE — Regenerate with: make gen -"""Flext Cli. Utilities. Rules package.""" +"""Rules package.""" from __future__ import annotations - -from typing import TYPE_CHECKING - -# mro-i6nq.10: The package consumes its manifest's public-export contract. -from flext_cli._utilities._rules.__unit__ import PUBLIC_EXPORTS as _PUBLIC_EXPORTS -from flext_core.lazy import build_lazy_import_map, install_lazy_exports - -if TYPE_CHECKING: - from flext_cli._utilities._rules._loaders import ( - FlextCliUtilitiesRulesLoadersMixin as FlextCliUtilitiesRulesLoadersMixin, - ) - from flext_cli._utilities._rules._matchers import ( - FlextCliUtilitiesRulesMatchersMixin as FlextCliUtilitiesRulesMatchersMixin, - ) - - # mro-i6nq.10: Static declaration mirrors the installer-owned runtime binding. - __all__: tuple[str, ...] - - -_LAZY_IMPORTS = build_lazy_import_map( - _LAZY_MODULES, alias_groups=_LAZY_ALIAS_GROUPS, sort_keys=False -) - - -# mro-i6nq.10: The installer publishes __all__ from the manifest's literal ABI. -install_lazy_exports(__name__, globals(), _LAZY_IMPORTS, public_exports=_PUBLIC_EXPORTS) diff --git a/src/flext_cli/_utilities/_toml_parts/__init__.py b/src/flext_cli/_utilities/_toml_parts/__init__.py index 923cbe0ee..008238cb8 100644 --- a/src/flext_cli/_utilities/_toml_parts/__init__.py +++ b/src/flext_cli/_utilities/_toml_parts/__init__.py @@ -1,27 +1,4 @@ # AUTO-GENERATED FILE — Regenerate with: make gen -"""Flext Cli. Utilities. Toml Parts package.""" +"""Toml Parts package.""" from __future__ import annotations - -from typing import TYPE_CHECKING - -# mro-i6nq.10: The package consumes its manifest's public-export contract. -from flext_cli._utilities._toml_parts.__unit__ import PUBLIC_EXPORTS as _PUBLIC_EXPORTS -from flext_core.lazy import build_lazy_import_map, install_lazy_exports - -if TYPE_CHECKING: - from flext_cli._utilities._toml_parts.flextcliutilitiestoml_part_07 import ( - FlextCliUtilitiesToml as FlextCliUtilitiesToml, - ) - - # mro-i6nq.10: Static declaration mirrors the installer-owned runtime binding. - __all__: tuple[str, ...] - - -_LAZY_IMPORTS = build_lazy_import_map( - _LAZY_MODULES, alias_groups=_LAZY_ALIAS_GROUPS, sort_keys=False -) - - -# mro-i6nq.10: The installer publishes __all__ from the manifest's literal ABI. -install_lazy_exports(__name__, globals(), _LAZY_IMPORTS, public_exports=_PUBLIC_EXPORTS) diff --git a/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_02.py b/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_02.py index 6b886152a..95265beba 100644 --- a/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_02.py +++ b/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_02.py @@ -65,20 +65,15 @@ def toml_item_child(container: TOMLDocument | Table, key: str) -> Item | None: @staticmethod def toml_ensure_table(parent: TOMLDocument | Table, key: str) -> Table: - """Return an explicit table child, promoting implicit super-tables when needed.""" + """Return a table child without replacing TOMLKit super-tables.""" existing: t.Cli.TomlRuntimeSource | None = None if key in parent: existing = parent[key] if isinstance(existing, Table): - table: Table = existing - if not table.is_super_table(): - return table - del parent[key] - table = tomlkit.table() - for entry_key in list(existing): - table[entry_key] = existing[entry_key] - parent[key] = table - return table + # NOTE(mro-wkii.17.26, agent codex): replacing a super-table copies + # TOMLKit trivia and adds blank lines on every conform pass. A super + # table is mutable and materializes its explicit header when needed. + return existing table = tomlkit.table() parent[key] = table return table diff --git a/src/flext_cli/_utilities/_yaml/__init__.py b/src/flext_cli/_utilities/_yaml/__init__.py index 3560f9b4a..e24437cdc 100644 --- a/src/flext_cli/_utilities/_yaml/__init__.py +++ b/src/flext_cli/_utilities/_yaml/__init__.py @@ -1,33 +1,4 @@ # AUTO-GENERATED FILE — Regenerate with: make gen -"""Flext Cli. Utilities. Yaml package.""" +"""Yaml package.""" from __future__ import annotations - -from typing import TYPE_CHECKING - -# mro-i6nq.10: The package consumes its manifest's public-export contract. -from flext_cli._utilities._yaml.__unit__ import PUBLIC_EXPORTS as _PUBLIC_EXPORTS -from flext_core.lazy import build_lazy_import_map, install_lazy_exports - -if TYPE_CHECKING: - from flext_cli._utilities._yaml._convert import ( - FlextCliUtilitiesYamlConvertMixin as FlextCliUtilitiesYamlConvertMixin, - ) - from flext_cli._utilities._yaml._editing import ( - FlextCliUtilitiesYamlEditingMixin as FlextCliUtilitiesYamlEditingMixin, - ) - from flext_cli._utilities._yaml._engine import ( - FlextCliUtilitiesYamlEngineMixin as FlextCliUtilitiesYamlEngineMixin, - ) - - # mro-i6nq.10: Static declaration mirrors the installer-owned runtime binding. - __all__: tuple[str, ...] - - -_LAZY_IMPORTS = build_lazy_import_map( - _LAZY_MODULES, alias_groups=_LAZY_ALIAS_GROUPS, sort_keys=False -) - - -# mro-i6nq.10: The installer publishes __all__ from the manifest's literal ABI. -install_lazy_exports(__name__, globals(), _LAZY_IMPORTS, public_exports=_PUBLIC_EXPORTS) diff --git a/src/flext_cli/services/__init__.py b/src/flext_cli/services/__init__.py index e4ec3030f..1a1315d37 100644 --- a/src/flext_cli/services/__init__.py +++ b/src/flext_cli/services/__init__.py @@ -1,54 +1,36 @@ # AUTO-GENERATED FILE — Regenerate with: make gen -"""Flext Cli.services package.""" +"""Services package.""" from __future__ import annotations -from typing import TYPE_CHECKING - -# mro-i6nq.10: The package consumes its manifest's public-export contract. -from flext_cli.services.__unit__ import ( - CHILD_MODULE_PATHS as _CHILD_MODULE_PATHS, - EXCLUDED_LAZY_NAMES as _EXCLUDED_LAZY_NAMES, - PUBLIC_EXPORTS as _PUBLIC_EXPORTS, -) -from flext_core.lazy import ( - build_lazy_import_map, - install_lazy_exports, - merge_lazy_imports, +from .auth import FlextCliAuth as FlextCliAuth +from .cli import FlextCliCli as FlextCliCli +from .cli_params import FlextCliCommonParams as FlextCliCommonParams +from .cmd import FlextCliCmd as FlextCliCmd +from .file_tools import FlextCliFileTools as FlextCliFileTools +from .formatters import FlextCliFormatters as FlextCliFormatters +from .output import FlextCliOutput as FlextCliOutput +from .pipeline import FlextCliPipeline as FlextCliPipeline +from .prompts import FlextCliPrompts as FlextCliPrompts +from .rules import FlextCliRules as FlextCliRules +from .runtime import FlextCliRuntime as FlextCliRuntime +from .tables import FlextCliTables as FlextCliTables +from .xlsx import FlextCliXlsx as FlextCliXlsx +from .yaml_model import FlextCliYamlModel as FlextCliYamlModel + +__all__: tuple[str, ...] = ( + "FlextCliAuth", + "FlextCliCli", + "FlextCliCmd", + "FlextCliCommonParams", + "FlextCliFileTools", + "FlextCliFormatters", + "FlextCliOutput", + "FlextCliPipeline", + "FlextCliPrompts", + "FlextCliRules", + "FlextCliRuntime", + "FlextCliTables", + "FlextCliXlsx", + "FlextCliYamlModel", ) - -if TYPE_CHECKING: - from flext_cli.services import _cli_parts as _cli_parts - from flext_cli.services.auth import FlextCliAuth as FlextCliAuth - from flext_cli.services.cli import FlextCliCli as FlextCliCli - from flext_cli.services.cli_params import ( - FlextCliCommonParams as FlextCliCommonParams, - ) - from flext_cli.services.cmd import FlextCliCmd as FlextCliCmd - from flext_cli.services.file_tools import FlextCliFileTools as FlextCliFileTools - from flext_cli.services.formatters import FlextCliFormatters as FlextCliFormatters - from flext_cli.services.output import FlextCliOutput as FlextCliOutput - from flext_cli.services.pipeline import FlextCliPipeline as FlextCliPipeline - from flext_cli.services.prompts import FlextCliPrompts as FlextCliPrompts - from flext_cli.services.rules import FlextCliRules as FlextCliRules - from flext_cli.services.runtime import FlextCliRuntime as FlextCliRuntime - from flext_cli.services.tables import FlextCliTables as FlextCliTables - from flext_cli.services.xlsx import FlextCliXlsx as FlextCliXlsx - from flext_cli.services.yaml_model import FlextCliYamlModel as FlextCliYamlModel - - # mro-i6nq.10: Static declaration mirrors the installer-owned runtime binding. - __all__: tuple[str, ...] - - -_LAZY_IMPORTS = merge_lazy_imports( - _CHILD_MODULE_PATHS, - build_lazy_import_map( - _LAZY_MODULES, alias_groups=_LAZY_ALIAS_GROUPS, sort_keys=False - ), - exclude_names=_EXCLUDED_LAZY_NAMES, - module_name=__name__, -) - - -# mro-i6nq.10: The installer publishes __all__ from the manifest's literal ABI. -install_lazy_exports(__name__, globals(), _LAZY_IMPORTS, public_exports=_PUBLIC_EXPORTS) diff --git a/src/flext_cli/services/_cli_parts/__init__.py b/src/flext_cli/services/_cli_parts/__init__.py index e1515555e..bb5132879 100644 --- a/src/flext_cli/services/_cli_parts/__init__.py +++ b/src/flext_cli/services/_cli_parts/__init__.py @@ -1,27 +1,4 @@ # AUTO-GENERATED FILE — Regenerate with: make gen -"""Flext Cli.services. Cli Parts package.""" +"""Cli Parts package.""" from __future__ import annotations - -from typing import TYPE_CHECKING - -# mro-i6nq.10: The package consumes its manifest's public-export contract. -from flext_cli.services._cli_parts.__unit__ import PUBLIC_EXPORTS as _PUBLIC_EXPORTS -from flext_core.lazy import build_lazy_import_map, install_lazy_exports - -if TYPE_CHECKING: - from flext_cli.services._cli_parts.flextclicli_part_05 import ( - FlextCliCli as FlextCliCli, - ) - - # mro-i6nq.10: Static declaration mirrors the installer-owned runtime binding. - __all__: tuple[str, ...] - - -_LAZY_IMPORTS = build_lazy_import_map( - _LAZY_MODULES, alias_groups=_LAZY_ALIAS_GROUPS, sort_keys=False -) - - -# mro-i6nq.10: The installer publishes __all__ from the manifest's literal ABI. -install_lazy_exports(__name__, globals(), _LAZY_IMPORTS, public_exports=_PUBLIC_EXPORTS) From fa8f7cb41e01175fa9bb940822bb69d6ee2a89f2 Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Tue, 14 Jul 2026 08:33:27 -0300 Subject: [PATCH 08/37] Refactor tests for improved clarity and consistency - Updated test assertions to use `tm.that` for consistency across test cases. - Enhanced docstrings for better understanding of test purposes. - Adjusted type hints and imports for clarity and correctness. - Improved handling of expected outcomes in tests, particularly for error cases. - Refactored tests to ensure they accurately reflect the intended behavior of the code. - Ensured that all tests maintain a clear structure and follow best practices for readability. --- examples/constants.py | 27 +-- examples/ex_01_getting_started.py | 41 ++-- examples/ex_05_authentication.py | 27 +-- examples/ex_12_pydantic_driven_cli.py | 64 +++--- .../flextcliprotocolsbase_part_02.py | 33 ++- .../flextcliprotocolsbase_part_03.py | 20 +- .../flextcliprotocolsbase_part_04.py | 6 +- .../flextcliutilitiestoml_part_04.py | 3 +- .../_utilities/_xlxx/xlsx_addresses.py | 26 ++- src/flext_cli/_utilities/_xlxx/xlsx_layout.py | 167 ++++++++------ .../_utilities/_xlxx/xlsx_protection.py | 92 +++++--- src/flext_cli/_utilities/_xlxx/xlsx_recalc.py | 96 +++++--- .../_utilities/_xlxx/xlsx_recalc_evidence.py | 66 +++--- .../_utilities/_xlxx/xlsx_snapshot.py | 41 ++-- .../_utilities/_xlxx/xlsx_snapshot_sheet.py | 62 ++--- .../_utilities/_xlxx/xlsx_snapshot_values.py | 110 ++++----- .../_utilities/_xlxx/xlsx_style_readers.py | 38 ++-- src/flext_cli/_utilities/_xlxx/xlsx_tables.py | 38 ++-- .../_utilities/_xlxx/xlsx_workbook_plan.py | 5 + src/flext_cli/_utilities/model_commands.py | 3 +- src/flext_cli/base.py | 8 +- .../_cli_parts/flextclicli_part_01.py | 4 +- tests/_constants_parts/tests_yaml_output.py | 16 +- tests/_exports_public.py | 1 - tests/_models_parts/__init__.py | 2 + tests/_models_parts/tests_fixtures.py | 96 ++++++++ .../testsflextclimodels_part_01.py | 2 + tests/protocols.py | 67 ++++-- .../testsflextcliservice_part_01.py | 60 ++--- .../testsflextcliservice_part_02.py | 39 ++-- .../testsflextcliservice_part_03.py | 60 ++--- .../testsflextcliservice_part_04.py | 5 + .../testsflextcliservice_part_05.py | 28 +-- .../testsflextcliexamplessmoke_part_02.py | 4 +- .../testsflextclipipeline_part_01.py | 8 +- .../testsflextclipipeline_part_02.py | 22 +- .../testsflextcliprompts_part_01.py | 23 +- ...flextclipubliccontractscoverage_part_01.py | 21 +- ...flextclipubliccontractscoverage_part_03.py | 3 +- tests/unit/conftest.py | 14 +- tests/unit/test_cli_params.py | 54 +++-- tests/unit/test_cmd.py | 49 ++-- tests/unit/test_formatters_cov.py | 42 +--- tests/unit/test_json_cov.py | 47 +++- tests/unit/test_options_cov.py | 212 ++++++++++++------ tests/unit/test_options_public_cov.py | 52 +++-- tests/unit/test_protocols.py | 35 ++- tests/unit/test_services_auth_branch_cov.py | 15 +- tests/unit/test_tables_cov.py | 24 +- tests/unit/test_typings.py | 22 +- tests/unit/test_version.py | 22 +- tests/unit/test_yaml_cov.py | 48 ++-- tests/utilities.py | 13 +- 53 files changed, 1268 insertions(+), 815 deletions(-) create mode 100644 tests/_models_parts/tests_fixtures.py diff --git a/examples/constants.py b/examples/constants.py index e4d9a54ff..7de09b74e 100644 --- a/examples/constants.py +++ b/examples/constants.py @@ -32,9 +32,7 @@ class DeploymentEnvironment(StrEnum): DeploymentEnvironment.PRODUCTION, ) EXAMPLE_DEPLOYMENT_ENVIRONMENTS_SET: Final[frozenset[DeploymentEnvironment]] = ( - frozenset( - EXAMPLE_DEPLOYMENT_ENVIRONMENTS, - ) + frozenset(EXAMPLE_DEPLOYMENT_ENVIRONMENTS) ) EXAMPLE_DEPLOYMENT_ENVIRONMENTS_SHORT: Final[t.VariadicTuple[str]] = ( "dev", @@ -62,13 +60,10 @@ class DeploymentEnvironment(StrEnum): "file4", ) EXAMPLE_TABLE_HEADERS_FIELD_VALUE: Final[t.Pair[str, str]] = ("Field", "Value") - EXAMPLE_TABLE_HEADERS_SETTING_VALUE: Final[t.Pair[str, str]] = ( - "Setting", - "Value", - ) + EXAMPLE_TABLE_HEADERS_SETTING_VALUE: Final[t.Pair[str, str]] = ("Setting", "Value") EXAMPLE_REGEX_EMAIL: Final[t.RegexPattern] = re.compile( - r"^[^@\s]+@[^@\s]+\.[^@\s]+$", + r"^[^@\s]+@[^@\s]+\.[^@\s]+$" ) EXAMPLE_REGEX_DOT: Final[t.RegexPattern] = re.compile(r"\.") @@ -84,6 +79,12 @@ class DeploymentEnvironment(StrEnum): EXAMPLE_PRODUCTION_MAX_WORKERS_CAP: Final[int] = 20 EXAMPLE_TESTING_MAX_WORKERS: Final[int] = 1 + # mro-wkii.17.26 (codex): centralize example authentication/database rules. + EXAMPLE_MIN_AUTH_TOKEN_LENGTH: Final[int] = 20 + EXAMPLE_DATABASE_DEMO_CONNECTION_POOL: Final[int] = 20 + EXAMPLE_LOCALHOST_CONNECTION_POOL_LIMIT: Final[int] = 50 + EXAMPLE_SSL_DB_PORT: Final[int] = 5433 + EXAMPLE_MIN_PORT: Final[int] = 1024 EXAMPLE_MAX_PORT: Final[int] = 65535 EXAMPLE_MAX_WORKERS: Final[int] = 32 @@ -131,10 +132,7 @@ class DeploymentEnvironment(StrEnum): "environment": EXAMPLE_ENV_KEY_ENVIRONMENT, }) - EXAMPLE_DB_URL_PREFIXES: Final[t.Pair[str, str]] = ( - "postgresql://", - "mysql://", - ) + EXAMPLE_DB_URL_PREFIXES: Final[t.Pair[str, str]] = ("postgresql://", "mysql://") EXAMPLE_REDIS_URL_PREFIX: Final[str] = "redis://" EXAMPLE_ERR_INVALID_HOST: Final[str] = "Host must be a valid hostname or IP" EXAMPLE_ERR_INVALID_DB_URL: Final[str] = "DATABASE_URL must be a valid database URL" @@ -188,7 +186,4 @@ class DeploymentEnvironment(StrEnum): c = ExamplesFlextCliConstants -__all__: t.MutableSequenceOf[str] = [ - "ExamplesFlextCliConstants", - "c", -] +__all__: t.MutableSequenceOf[str] = ["ExamplesFlextCliConstants", "c"] diff --git a/examples/ex_01_getting_started.py b/examples/ex_01_getting_started.py index 494df8c00..ac54f14df 100644 --- a/examples/ex_01_getting_started.py +++ b/examples/ex_01_getting_started.py @@ -14,9 +14,11 @@ from flext_cli import cli, settings -class ExamplesFlextCliGettingStarted(s): +class ExamplesFlextCliGettingStarted(s[t.JsonMapping]): """Minimal guided tour of flext-cli through public aliases and facades.""" + # mro-wkii.17.26 (codex): specialize the canonical service result contract. + def build_example_settings(self) -> p.Result[m.Examples.MyAppSettings]: """Build a validated application settings model through the examples facade.""" settings_payload: t.JsonMapping = { @@ -26,7 +28,7 @@ def build_example_settings(self) -> p.Result[m.Examples.MyAppSettings]: "timeout": c.EXAMPLE_DEFAULT_TIMEOUT_SECONDS, } return r[m.Examples.MyAppSettings].ok( - m.Examples.MyAppSettings.model_validate(settings_payload), + m.Examples.MyAppSettings.model_validate(settings_payload) ) @staticmethod @@ -38,23 +40,16 @@ def persist_example_settings( with TemporaryDirectory(prefix=f"{c.EXAMPLE_DEFAULT_TEMP_SUBDIR}-") as temp_dir: config_path = Path(temp_dir) / "settings.json" return cli.write_json_file( - str(config_path), - wrapped_config.model_dump(mode="json"), + str(config_path), wrapped_config.model_dump(mode="json") ).flat_map( - lambda _: cli.read_json_model(str(config_path), m.Cli.LoadedConfig), + lambda _: cli.read_json_model(str(config_path), m.Cli.LoadedConfig) ) @override def execute(self) -> p.Result[t.JsonMapping]: """Run the public getting-started flow through typed examples aliases.""" - cli.print( - "FLEXT CLI - Getting Started", - style=c.Cli.MessageStyles.BOLD_BLUE, - ) - cli.print( - "===========================", - style=c.Cli.MessageStyles.BOLD_BLUE, - ) + cli.print("FLEXT CLI - Getting Started", style=c.Cli.MessageStyles.BOLD_BLUE) + cli.print("===========================", style=c.Cli.MessageStyles.BOLD_BLUE) cli.print("\n1. Setup via s/base.py", style=c.Cli.MessageStyles.BOLD_CYAN) runtime_snapshot: t.JsonMapping = { @@ -71,12 +66,11 @@ def execute(self) -> p.Result[t.JsonMapping]: settings_result = self.build_example_settings() if settings_result.failure: return r[t.JsonMapping].fail( - settings_result.error or c.EXAMPLE_ERR_FAILED_LOAD_CONFIG, + settings_result.error or c.EXAMPLE_ERR_FAILED_LOAD_CONFIG ) cli.print( - "\n2. Pydantic 2 models via m.Examples", - style=c.Cli.MessageStyles.BOLD_CYAN, + "\n2. Pydantic 2 models via m.Examples", style=c.Cli.MessageStyles.BOLD_CYAN ) app_settings = settings_result.value app_settings.display(cli) @@ -84,12 +78,11 @@ def execute(self) -> p.Result[t.JsonMapping]: loaded_result = self.persist_example_settings(app_settings) if loaded_result.failure: return r[t.JsonMapping].fail( - loaded_result.error or c.EXAMPLE_ERR_FAILED_LOAD_CONFIG, + loaded_result.error or c.EXAMPLE_ERR_FAILED_LOAD_CONFIG ) cli.print( - "\n3. Public cli facade round-trip", - style=c.Cli.MessageStyles.BOLD_CYAN, + "\n3. Public cli facade round-trip", style=c.Cli.MessageStyles.BOLD_CYAN ) loaded_config = loaded_result.value roundtrip_summary = m.Cli.DisplayData( @@ -98,17 +91,13 @@ def execute(self) -> p.Result[t.JsonMapping]: "api_key_present": str(bool(loaded_config.content.get("api_key"))), "max_workers": str(loaded_config.content.get("max_workers")), "timeout": str(loaded_config.content.get("timeout")), - }, + } ) u.display_config_table( - roundtrip_summary, - headers=c.EXAMPLE_TABLE_HEADERS_SETTING_VALUE, + roundtrip_summary, headers=c.EXAMPLE_TABLE_HEADERS_SETTING_VALUE ) - cli.print( - "\n4. Railway result ergonomics", - style=c.Cli.MessageStyles.BOLD_CYAN, - ) + cli.print("\n4. Railway result ergonomics", style=c.Cli.MessageStyles.BOLD_CYAN) result_summary: t.JsonMapping = { "ok.success": r[str].ok(c.EXAMPLE_MSG_OPERATION_COMPLETED).success, "fail.failure": r[str].fail(c.EXAMPLE_MSG_ERROR_SOMETHING_FAILED).failure, diff --git a/examples/ex_05_authentication.py b/examples/ex_05_authentication.py index 88e006f25..f00d4d2ec 100644 --- a/examples/ex_05_authentication.py +++ b/examples/ex_05_authentication.py @@ -24,7 +24,8 @@ from __future__ import annotations -from flext_cli import c, cli, settings, u +from examples import c +from flext_cli import cli, settings, u from flext_core import p, r @@ -34,10 +35,7 @@ class Ex05Authentication: @staticmethod def login_to_service(username: str, password: str) -> p.Result[bool]: """Login and save token in YOUR CLI application.""" - auth_result = cli.authenticate({ - "username": username, - "password": password, - }) + auth_result = cli.authenticate({"username": username, "password": password}) if auth_result.failure: cli.print( f"❌ Login failed: {auth_result.error}", @@ -47,8 +45,7 @@ def login_to_service(username: str, password: str) -> p.Result[bool]: token_file_path = u.Cli.auth_token_file_path(settings.cli_token_file) cli.print("✅ Login successful!", style=c.Cli.MessageStyles.GREEN) cli.print( - f" Token saved to: {token_file_path}", - style=c.Cli.MessageStyles.CYAN, + f" Token saved to: {token_file_path}", style=c.Cli.MessageStyles.CYAN ) return r[bool].ok(True) @@ -72,16 +69,14 @@ def validate_current_token() -> p.Result[bool]: cli.print("⚠️ No token found", style=c.Cli.MessageStyles.YELLOW) return r[bool].fail(token_result.error or "No token found") token = token_result.value - if len(token) < 20: + # mro-wkii.17.26 (codex): consume the shared example token contract. + if len(token) < c.EXAMPLE_MIN_AUTH_TOKEN_LENGTH: cli.print("❌ Invalid token format", style=c.Cli.MessageStyles.BOLD_RED) return r[bool].fail("Invalid token format") token_file_path = u.Cli.auth_token_file_path(settings.cli_token_file) cli.print("✅ Token is valid", style=c.Cli.MessageStyles.GREEN) cli.print(f" Token: {token[:30]}...", style=c.Cli.MessageStyles.CYAN) - cli.print( - f" Token file: {token_file_path}", - style=c.Cli.MessageStyles.CYAN, - ) + cli.print(f" Token file: {token_file_path}", style=c.Cli.MessageStyles.CYAN) return r[bool].ok(True) @staticmethod @@ -94,14 +89,10 @@ def logout() -> p.Result[bool]: try: token_file_path.unlink() except OSError as exc: - cli.print( - f"❌ Logout failed: {exc}", - style=c.Cli.MessageStyles.BOLD_RED, - ) + cli.print(f"❌ Logout failed: {exc}", style=c.Cli.MessageStyles.BOLD_RED) return r[bool].fail(str(exc)) cli.print("✅ Logged out successfully", style=c.Cli.MessageStyles.GREEN) cli.print( - f" Token removed from: {token_file_path}", - style=c.Cli.MessageStyles.CYAN, + f" Token removed from: {token_file_path}", style=c.Cli.MessageStyles.CYAN ) return r[bool].ok(True) diff --git a/examples/ex_12_pydantic_driven_cli.py b/examples/ex_12_pydantic_driven_cli.py index 176d80455..b802362e0 100644 --- a/examples/ex_12_pydantic_driven_cli.py +++ b/examples/ex_12_pydantic_driven_cli.py @@ -26,12 +26,15 @@ from __future__ import annotations +import secrets + from examples import c, m, t, u from flext_cli import cli from flext_core import p, r # NOTE (multi-agent, mro-wkii.17 / agent: make_ssot_audit): the example enters # the railway as one validated model and retains that object through services. +# mro-wkii.17.26 (codex): source example rules from c and generate credentials. def _report_step_success[T](value: T, message: str) -> T: @@ -56,49 +59,37 @@ def create_database_config_from_cli() -> p.Result[m.Examples.AdvancedDatabaseCon ) cli_args = m.Examples.AdvancedDatabaseConfig( host="db.example.com", - port=5432, + port=c.EXAMPLE_DEFAULT_DB_PORT, name="production_db", username="example_user", - password="example_password", + password=secrets.token_urlsafe(c.EXAMPLE_MIN_PASSWORD_LENGTH), ssl_enabled=True, - connection_pool=20, + connection_pool=c.EXAMPLE_DATABASE_DEMO_CONNECTION_POOL, ) return ( r[m.Examples.AdvancedDatabaseConfig] .ok(cli_args) .map( lambda settings: _report_step_success( - settings, - "✅ Required fields validated", - ), + settings, "✅ Required fields validated" + ) ) .map( lambda settings: _report_step_success( - settings, - "✅ Pydantic validation passed", - ), - ) - .flat_map( - validate_business_rules, + settings, "✅ Pydantic validation passed" + ) ) + .flat_map(validate_business_rules) .map( lambda settings: _report_step_success( - settings, - "✅ Business rules validated", - ), - ) - .flat_map( - perform_connection_test, + settings, "✅ Business rules validated" + ) ) + .flat_map(perform_connection_test) .map( - lambda settings: _report_step_success( - settings, - "✅ Connection test passed", - ), - ) - .map( - _finish_database_config, + lambda settings: _report_step_success(settings, "✅ Connection test passed") ) + .map(_finish_database_config) ) @@ -109,11 +100,9 @@ def validate_required_fields( required = list(c.EXAMPLE_DATABASE_REQUIRED_FIELDS) missing = [field for field in required if field not in data or not data[field]] if missing: - return r[t.JsonMapping].fail( - f"Missing required fields: {missing}", - ) + return r[t.JsonMapping].fail(f"Missing required fields: {missing}") normalized_data = t.Cli.JSON_MAPPING_ADAPTER.validate_python( - u.normalize_to_json_value(data), + u.normalize_to_json_value(data) ) return r[t.JsonMapping].ok(normalized_data) @@ -124,13 +113,11 @@ def convert_and_validate_with_pydantic( """Convert raw data to validated Pydantic model.""" try: return r[m.Examples.AdvancedDatabaseConfig].ok( - m.Examples.AdvancedDatabaseConfig.model_validate( - data, - ), + m.Examples.AdvancedDatabaseConfig.model_validate(data) ) except c.ValidationError as error: return r[m.Examples.AdvancedDatabaseConfig].fail( - f"Pydantic validation failed: {error}", + f"Pydantic validation failed: {error}" ) @@ -138,11 +125,14 @@ def validate_business_rules( settings: m.Examples.AdvancedDatabaseConfig, ) -> p.Result[m.Examples.AdvancedDatabaseConfig]: """Apply custom business rules to validated database configuration.""" - if settings.ssl_enabled and settings.port == 5432: - settings = settings.model_copy(update={"port": 5433}) - if settings.connection_pool > 50 and settings.host == "localhost": + if settings.ssl_enabled and settings.port == c.EXAMPLE_DEFAULT_DB_PORT: + settings = settings.model_copy(update={"port": c.EXAMPLE_SSL_DB_PORT}) + if ( + settings.connection_pool > c.EXAMPLE_LOCALHOST_CONNECTION_POOL_LIMIT + and settings.host == c.EXAMPLE_DEFAULT_HOST + ): return r[m.Examples.AdvancedDatabaseConfig].fail( - "Localhost cannot handle large connection pools", + "Localhost cannot handle large connection pools" ) return r[m.Examples.AdvancedDatabaseConfig].ok(settings) diff --git a/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_02.py b/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_02.py index 6f0c43a94..045936c83 100644 --- a/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_02.py +++ b/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_02.py @@ -48,22 +48,47 @@ class CommandOutput(Protocol): @property def duration(self) -> float: - """Return the command duration in seconds.""" + """Command duration in seconds.""" ... @property def exit_code(self) -> int: - """Return the command exit code.""" + """Command exit status.""" ... @property def stderr(self) -> str: - """Return the command standard error.""" + """Command standard-error text.""" ... @property def stdout(self) -> str: - """Return the command standard output.""" + """Command standard-output text.""" + ... + + # mro-wkii.17.26 (codex): expose byte-exact process output structurally. + @runtime_checkable + class CommandBytesOutput(Protocol): + """Minimal byte-exact external command execution output contract.""" + + @property + def duration(self) -> float: + """Command duration in seconds.""" + ... + + @property + def exit_code(self) -> int: + """Command exit status.""" + ... + + @property + def stderr(self) -> bytes: + """Byte-exact command standard error.""" + ... + + @property + def stdout(self) -> bytes: + """Byte-exact command standard output.""" ... diff --git a/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_03.py b/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_03.py index 8e245f277..82b612ddf 100644 --- a/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_03.py +++ b/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_03.py @@ -58,6 +58,18 @@ def run_raw( """Execute a command without enforcing zero exit status.""" ... + def run_bytes( + self, + cmd: t.StrSequence, + cwd: t.Cli.TextPath | None = None, + timeout: int | None = None, + env: t.StrMapping | None = None, + remove_env_keys: t.StrSequence = (), + input_data: bytes | None = None, + ) -> p.Result[m.Cli.CommandBytesOutput]: + """Execute a command and preserve byte-exact standard streams.""" + ... + def run_checked( self, cmd: t.StrSequence, @@ -92,12 +104,12 @@ def debug(self) -> bool | None: @property def log_format(self) -> str | None: - """Get log format.""" + """Configured log format.""" ... @property def log_level(self) -> str | None: - """Get log level.""" + """Configured log level.""" ... @property @@ -107,12 +119,12 @@ def no_color(self) -> bool | None: @property def output_format(self) -> str | None: - """Get output format.""" + """Configured output format.""" ... @property def params(self) -> t.JsonMapping: - """Get configuration parameters.""" + """Configuration parameters.""" ... @property diff --git a/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_04.py b/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_04.py index b1e15fd80..1f50c27ff 100644 --- a/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_04.py +++ b/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_04.py @@ -28,17 +28,17 @@ class CliOptionSpec(Protocol): @property def declarations(self) -> t.StrSequence: - """Get the ordered option flag declarations.""" + """Ordered option flag declarations.""" ... @property def help_text(self) -> str: - """Get the human-readable option help text.""" + """Human-readable option help text.""" ... @property def default(self) -> t.Cli.CliValue | None: - """Get the normalized default value for the option.""" + """Normalized option default value.""" ... @property diff --git a/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_04.py b/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_04.py index 3305ee983..db07561b8 100644 --- a/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_04.py +++ b/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_04.py @@ -61,7 +61,8 @@ def toml_merge_string_list( FlextCliUtilitiesTomlPart03.toml_value(container, key) ) merged = sorted({*current, *required}) - if current == merged: + # mro-wkii.17.26 (codex): compare one canonical immutable sequence shape. + if tuple(current) == tuple(merged): return False container[key] = FlextCliUtilitiesTomlPart01.toml_array(merged) return True diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_addresses.py b/src/flext_cli/_utilities/_xlxx/xlsx_addresses.py index b9a855889..ded117c4b 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_addresses.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_addresses.py @@ -47,6 +47,21 @@ def _sheet_ref(name: str) -> str: def _range_failure(detail: str) -> p.Result[m.Cli.XlsxCellRange]: return r[m.Cli.XlsxCellRange].fail(f"{c.Cli.XlsxError.RANGE_INVALID}: {detail}") + # mro-wkii.17.26 (xlsx-a): keep the caught vendor boundary to one operation. + @classmethod + def _format_reference_value(cls, request: m.Cli.XlsxFormatReferenceRequest) -> str: + if request.collapse_single_cell and request.area.first == request.area.last: + reference = cls._cell_ref(request.area.first) + if request.absolute: + reference = cls._absolute_range_ref(request.area).partition(":")[0] + elif request.absolute: + reference = cls._absolute_range_ref(request.area) + else: + reference = cls._range_ref(request.area) + if request.sheet is not None: + reference = f"{cls._sheet_ref(request.sheet)}!{reference}" + return reference + @classmethod def xlsx_parse_range( cls, request: m.Cli.XlsxParseRangeRequest @@ -82,16 +97,7 @@ def xlsx_format_reference( ) -> p.Result[m.Cli.XlsxReference]: """Format one validated range as a canonical Excel reference.""" try: - if request.collapse_single_cell and request.area.first == request.area.last: - reference = cls._cell_ref(request.area.first) - if request.absolute: - reference = cls._absolute_range_ref(request.area).partition(":")[0] - elif request.absolute: - reference = cls._absolute_range_ref(request.area) - else: - reference = cls._range_ref(request.area) - if request.sheet is not None: - reference = f"{cls._sheet_ref(request.sheet)}!{reference}" + reference = cls._format_reference_value(request) except (TypeError, ValueError) as exc: detail = str(exc).strip() or exc.__class__.__name__ return r[m.Cli.XlsxReference].fail( diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_layout.py b/src/flext_cli/_utilities/_xlxx/xlsx_layout.py index ec16ea71b..0f5eb8b89 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_layout.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_layout.py @@ -6,7 +6,7 @@ from openpyxl.comments import Comment from openpyxl.worksheet.worksheet import Worksheet -from flext_cli import c, m, p, r +from flext_cli import c, m, p, r, t from .xlsx_addresses import FlextCliUtilitiesXlsxAddresses @@ -14,76 +14,113 @@ class FlextCliUtilitiesXlsxLayout(FlextCliUtilitiesXlsxAddresses): """Apply comments, links, dimensions, grouping, views, and merges.""" + # mro-wkii.17.26 (xlsx-a): preserve typed results across cohesive phases. + @classmethod + def _apply_layout_annotations( + cls, worksheet: Worksheet, plan: m.Cli.XlsxSheetLayoutPlan + ) -> p.Result[bool]: + for item in plan.comments: + comment = Comment(item.text, item.author) + if item.width is not None: + comment.width = item.width + if item.height is not None: + comment.height = item.height + cell = worksheet.cell(item.at.row, item.at.column) + if not isinstance(cell, Cell): + return r[bool].fail( + f"Cannot comment merged cell: row={item.at.row}, " + f"column={item.at.column}" + ) + cell.comment = comment + for item in plan.hyperlinks: + cell = worksheet.cell(item.at.row, item.at.column) + if not isinstance(cell, Cell): + return r[bool].fail( + f"Cannot link merged cell: row={item.at.row}, " + f"column={item.at.column}" + ) + if item.kind == "external": + cell.hyperlink = item.target + else: + destination = cls._cell_ref(item.destination) + sheet = cls._sheet_ref(item.destination_sheet) + cell.hyperlink = f"#{sheet}!{destination}" + return r[bool].ok(True) + + @classmethod + def _apply_layout_structure( + cls, worksheet: Worksheet, plan: m.Cli.XlsxSheetLayoutPlan + ) -> p.Result[bool]: + for item in plan.dimensions: + for index in range(item.first, item.last + 1): + if item.axis == "row": + dimension = worksheet.row_dimensions[index] + dimension.height = item.size + else: + dimension = worksheet.column_dimensions[cls._column_ref(index)] + if item.size is not None: + dimension.width = item.size + dimension.hidden = item.hidden + for item in plan.groups: + if item.axis == "row": + worksheet.row_dimensions.group( + item.first, + item.last, + outline_level=item.outline_level, + hidden=item.hidden, + ) + else: + worksheet.column_dimensions.group( + cls._column_ref(item.first), + cls._column_ref(item.last), + outline_level=item.outline_level, + hidden=item.hidden, + ) + return r[bool].ok(True) + + @classmethod + def _apply_layout_view( + cls, worksheet: Worksheet, plan: m.Cli.XlsxSheetLayoutPlan + ) -> p.Result[bool]: + if plan.freeze_pane is not None: + worksheet.freeze_panes = cls._cell_ref(plan.freeze_pane.at) + if plan.auto_filter is not None: + worksheet.auto_filter.ref = cls._range_ref(plan.auto_filter.area) + if plan.view is not None: + worksheet.sheet_state = plan.view.visibility + worksheet.sheet_properties.tabColor = plan.view.tab_color + return r[bool].ok(True) + + @classmethod + def _apply_layout_merges( + cls, worksheet: Worksheet, plan: m.Cli.XlsxSheetLayoutPlan + ) -> p.Result[bool]: + for item in plan.merges: + worksheet.merge_cells(cls._range_ref(item.area)) + return r[bool].ok(True) + # NOTE (multi-agent, mro-j2yt.1): merge operations run last so comments # and hyperlinks can still target every concrete cell in the plan. @classmethod def _apply_layout( cls, worksheet: Worksheet, plan: m.Cli.XlsxSheetLayoutPlan ) -> p.Result[bool]: - try: - for item in plan.comments: - comment = Comment(item.text, item.author) - if item.width is not None: - comment.width = item.width - if item.height is not None: - comment.height = item.height - cell = worksheet.cell(item.at.row, item.at.column) - if not isinstance(cell, Cell): - return r[bool].fail( - f"Cannot comment merged cell: row={item.at.row}, " - f"column={item.at.column}" - ) - cell.comment = comment - for item in plan.hyperlinks: - cell = worksheet.cell(item.at.row, item.at.column) - if not isinstance(cell, Cell): - return r[bool].fail( - f"Cannot link merged cell: row={item.at.row}, " - f"column={item.at.column}" - ) - if item.kind == "external": - cell.hyperlink = item.target - else: - destination = cls._cell_ref(item.destination) - sheet = cls._sheet_ref(item.destination_sheet) - cell.hyperlink = f"#{sheet}!{destination}" - for item in plan.dimensions: - for index in range(item.first, item.last + 1): - if item.axis == "row": - dimension = worksheet.row_dimensions[index] - dimension.height = item.size - else: - dimension = worksheet.column_dimensions[cls._column_ref(index)] - if item.size is not None: - dimension.width = item.size - dimension.hidden = item.hidden - for item in plan.groups: - if item.axis == "row": - worksheet.row_dimensions.group( - item.first, - item.last, - outline_level=item.outline_level, - hidden=item.hidden, - ) - else: - worksheet.column_dimensions.group( - cls._column_ref(item.first), - cls._column_ref(item.last), - outline_level=item.outline_level, - hidden=item.hidden, - ) - if plan.freeze_pane is not None: - worksheet.freeze_panes = cls._cell_ref(plan.freeze_pane.at) - if plan.auto_filter is not None: - worksheet.auto_filter.ref = cls._range_ref(plan.auto_filter.area) - if plan.view is not None: - worksheet.sheet_state = plan.view.visibility - worksheet.sheet_properties.tabColor = plan.view.tab_color - for item in plan.merges: - worksheet.merge_cells(cls._range_ref(item.area)) - except (AttributeError, KeyError, TypeError, ValueError) as exc: - detail = str(exc).strip() or exc.__class__.__name__ - return r[bool].fail(f"{c.Cli.XlsxError.RENDER_FAILED}: {detail}") + phases: tuple[t.Cli.NullaryOperation[p.Result[bool]], ...] = ( + lambda: cls._apply_layout_annotations(worksheet, plan), + lambda: cls._apply_layout_structure(worksheet, plan), + lambda: cls._apply_layout_view(worksheet, plan), + lambda: cls._apply_layout_merges(worksheet, plan), + ) + for phase in phases: + try: + result: p.Result[bool] = phase() + except c.EXC_ATTR_KEY_TYPE_VALUE as exc: + detail = str(exc).strip() or exc.__class__.__name__ + return r[bool].fail( + f"{c.Cli.XlsxError.RENDER_FAILED}: {detail}", exception=exc + ) + if result.failure: + return result return r[bool].ok(True) diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_protection.py b/src/flext_cli/_utilities/_xlxx/xlsx_protection.py index 33dd319e7..199396c33 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_protection.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_protection.py @@ -11,6 +11,53 @@ class FlextCliUtilitiesXlsxProtection: """Translate explicit cell rules and positive worksheet permissions.""" + # mro-wkii.17.26 (xlsx-a): keep one responsibility per vendor phase. + @staticmethod + def _apply_cell_protection( + worksheet: Worksheet, plan: m.Cli.XlsxSheetProtectionPlan + ) -> None: + for item in plan.cells: + for row in range(item.area.first.row, item.area.last.row + 1): + for column in range(item.area.first.column, item.area.last.column + 1): + worksheet.cell(row, column).protection = Protection( + locked=item.locked, hidden=item.hidden + ) + + @staticmethod + def _apply_sheet_permissions( + worksheet: Worksheet, plan: m.Cli.XlsxSheetProtectionPlan + ) -> None: + permissions = plan.permissions + protection = worksheet.protection + protection.sheet = True + protection.selectLockedCells = not permissions.allow_select_locked + protection.selectUnlockedCells = not permissions.allow_select_unlocked + protection.formatCells = not permissions.allow_format_cells + protection.formatColumns = not permissions.allow_format_columns + protection.formatRows = not permissions.allow_format_rows + protection.insertColumns = not permissions.allow_insert_columns + protection.insertRows = not permissions.allow_insert_rows + protection.insertHyperlinks = not permissions.allow_insert_hyperlinks + protection.deleteColumns = not permissions.allow_delete_columns + protection.deleteRows = not permissions.allow_delete_rows + protection.sort = not permissions.allow_sort + protection.autoFilter = not permissions.allow_auto_filter + protection.pivotTables = not permissions.allow_pivot_tables + protection.objects = not permissions.allow_edit_objects + protection.scenarios = not permissions.allow_edit_scenarios + + @staticmethod + def _apply_protection_credential( + worksheet: Worksheet, plan: m.Cli.XlsxSheetProtectionPlan + ) -> None: + credential = plan.credential + if credential is None: + return + if credential.kind == "legacy_hash": + worksheet.protection.set_password(credential.value, already_hashed=True) + else: + worksheet.protection.set_password(credential.value) + # NOTE (multi-agent, mro-j2yt.1): SheetProtection booleans express denied # actions, so positive allow_* model flags are inverted exactly once here. @classmethod @@ -19,43 +66,16 @@ def _apply_protection( ) -> p.Result[bool]: if plan is None: return r[bool].ok(True) + if any( + item.area.first.row > item.area.last.row + or item.area.first.column > item.area.last.column + for item in plan.cells + ): + return r[bool].fail("Cell protection range is inverted") try: - for item in plan.cells: - if ( - item.area.first.row > item.area.last.row - or item.area.first.column > item.area.last.column - ): - return r[bool].fail("Cell protection range is inverted") - for row in range(item.area.first.row, item.area.last.row + 1): - for column in range( - item.area.first.column, item.area.last.column + 1 - ): - worksheet.cell(row, column).protection = Protection( - locked=item.locked, hidden=item.hidden - ) - permissions = plan.permissions - protection = worksheet.protection - protection.sheet = True - protection.selectLockedCells = not permissions.allow_select_locked - protection.selectUnlockedCells = not permissions.allow_select_unlocked - protection.formatCells = not permissions.allow_format_cells - protection.formatColumns = not permissions.allow_format_columns - protection.formatRows = not permissions.allow_format_rows - protection.insertColumns = not permissions.allow_insert_columns - protection.insertRows = not permissions.allow_insert_rows - protection.insertHyperlinks = not permissions.allow_insert_hyperlinks - protection.deleteColumns = not permissions.allow_delete_columns - protection.deleteRows = not permissions.allow_delete_rows - protection.sort = not permissions.allow_sort - protection.autoFilter = not permissions.allow_auto_filter - protection.pivotTables = not permissions.allow_pivot_tables - protection.objects = not permissions.allow_edit_objects - protection.scenarios = not permissions.allow_edit_scenarios - if plan.credential is not None: - if plan.credential.kind == "legacy_hash": - protection.set_password(plan.credential.value, already_hashed=True) - else: - protection.set_password(plan.credential.value) + cls._apply_cell_protection(worksheet, plan) + cls._apply_sheet_permissions(worksheet, plan) + cls._apply_protection_credential(worksheet, plan) except (TypeError, ValueError) as exc: detail = str(exc).strip() or exc.__class__.__name__ return r[bool].fail(f"{c.Cli.XlsxError.RENDER_FAILED}: {detail}") diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_recalc.py b/src/flext_cli/_utilities/_xlxx/xlsx_recalc.py index ff1f585d3..3fd63bf49 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_recalc.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_recalc.py @@ -17,6 +17,63 @@ class FlextCliUtilitiesXlsxRecalc( ): """Recalculate formula caches and prove parity through typed evidence.""" + # mro-wkii.17.26 (xlsx-a): isolate filesystem and process failure boundaries. + @staticmethod + def _recalc_error(detail: str) -> str: + return f"{c.Cli.XlsxError.RECALC_FAILED}: {detail}" + + @classmethod + def _recalc_in_workspace( + cls, request: m.Cli.XlsxRecalcRequest, workdir: Path + ) -> p.Result[m.Cli.XlsxRecalcResult]: + input_dir = workdir / "input" + output_dir = workdir / "output" + source_path = input_dir / c.Cli.XLSX_RECALC_SOURCE_NAME + try: + input_dir.mkdir() + output_dir.mkdir() + source_path.write_bytes(request.source) + except (OSError, ValueError) as exc: + detail = str(exc).strip() or exc.__class__.__name__ + return r[m.Cli.XlsxRecalcResult].fail(cls._recalc_error(detail)) + try: + started = FlextCliUtilitiesProcesses.process_start( + (*c.Cli.XLSX_RECALC_COMMAND, str(output_dir), str(source_path)), + cwd=workdir, + ) + except (OSError, ValueError) as exc: + detail = str(exc).strip() or exc.__class__.__name__ + return r[m.Cli.XlsxRecalcResult].fail(cls._recalc_error(detail)) + if started.failure: + return r[m.Cli.XlsxRecalcResult].fail(cls._recalc_error(f"{started.error}")) + process = started.value + try: + completed = process.wait(timeout=c.Cli.XLSX_RECALC_TIMEOUT_SECONDS) + except (OSError, ValueError) as exc: + detail = str(exc).strip() or exc.__class__.__name__ + return r[m.Cli.XlsxRecalcResult].fail(cls._recalc_error(detail)) + if completed.failure: + try: + killed = process.kill() + except (OSError, ValueError) as exc: + detail = str(exc).strip() or exc.__class__.__name__ + return r[m.Cli.XlsxRecalcResult].fail(cls._recalc_error(detail)) + detail = completed.error or "process wait failed" + if killed.failure: + detail = f"{detail}; kill failed: {killed.error}" + return r[m.Cli.XlsxRecalcResult].fail(cls._recalc_error(detail)) + if completed.value != 0: + detail = process.stderr.strip() or process.stdout.strip() + return r[m.Cli.XlsxRecalcResult].fail( + cls._recalc_error(f"exit={completed.value}: {detail}") + ) + try: + content = (output_dir / c.Cli.XLSX_RECALC_SOURCE_NAME).read_bytes() + except (OSError, ValueError) as exc: + detail = str(exc).strip() or exc.__class__.__name__ + return r[m.Cli.XlsxRecalcResult].fail(cls._recalc_error(detail)) + return r[m.Cli.XlsxRecalcResult].ok(m.Cli.XlsxRecalcResult(content=content)) + # NOTE (multi-agent, mro-j2yt.1): the headless engine process terminates # at this private adapter; process spawning is consumed from the generic # processes facade without polluting the XLSX composition order. @@ -29,44 +86,11 @@ def xlsx_recalc( with tempfile.TemporaryDirectory( prefix=c.Cli.XLSX_RECALC_TEMP_PREFIX ) as workspace: - workdir = Path(workspace) - input_dir = workdir / "input" - output_dir = workdir / "output" - input_dir.mkdir() - output_dir.mkdir() - source_path = input_dir / c.Cli.XLSX_RECALC_SOURCE_NAME - source_path.write_bytes(request.source) - started = FlextCliUtilitiesProcesses.process_start( - (*c.Cli.XLSX_RECALC_COMMAND, str(output_dir), str(source_path)), - cwd=workdir, - ) - if started.failure: - return r[m.Cli.XlsxRecalcResult].fail( - f"{c.Cli.XlsxError.RECALC_FAILED}: {started.error}" - ) - process = started.value - completed = process.wait(timeout=c.Cli.XLSX_RECALC_TIMEOUT_SECONDS) - if completed.failure: - killed = process.kill() - detail = completed.error or "process wait failed" - if killed.failure: - detail = f"{detail}; kill failed: {killed.error}" - return r[m.Cli.XlsxRecalcResult].fail( - f"{c.Cli.XlsxError.RECALC_FAILED}: {detail}" - ) - if completed.value != 0: - detail = process.stderr.strip() or process.stdout.strip() - return r[m.Cli.XlsxRecalcResult].fail( - f"{c.Cli.XlsxError.RECALC_FAILED}: " - f"exit={completed.value}: {detail}" - ) - content = (output_dir / c.Cli.XLSX_RECALC_SOURCE_NAME).read_bytes() + result = cls._recalc_in_workspace(request, Path(workspace)) except (OSError, ValueError) as exc: detail = str(exc).strip() or exc.__class__.__name__ - return r[m.Cli.XlsxRecalcResult].fail( - f"{c.Cli.XlsxError.RECALC_FAILED}: {detail}" - ) - return r[m.Cli.XlsxRecalcResult].ok(m.Cli.XlsxRecalcResult(content=content)) + return r[m.Cli.XlsxRecalcResult].fail(cls._recalc_error(detail)) + return result @classmethod def xlsx_recalc_parity( diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_recalc_evidence.py b/src/flext_cli/_utilities/_xlxx/xlsx_recalc_evidence.py index b241212c7..d4c6c5a89 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_recalc_evidence.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_recalc_evidence.py @@ -63,6 +63,40 @@ def _worksheet_targets( targets = (*targets, (name, member)) return targets + # mro-wkii.17.26 (xlsx-a): keep ZIP exception translation at its boundary. + @classmethod + def _collect_formula_cache_evidence( + cls, archive: p.Cli.XlsxArchiveReader + ) -> tuple[tuple[str, ...], tuple[str, ...]]: + workbook_root = cls._require_xml(archive, c.Cli.XLSX_WORKBOOK_MEMBER) + rels_root = cls._require_xml(archive, c.Cli.XLSX_WORKBOOK_RELS_MEMBER) + uncached: tuple[str, ...] = () + empty: tuple[str, ...] = () + for sheet_name, member in cls._worksheet_targets(workbook_root, rels_root): + root = cls._require_xml(archive, member) + for element in root.iter(): + if cls._local_name(element.tag) != "c": + continue + has_formula = False + value_element: p.Cli.XlsxXmlElement | None = None + for child in element.iter(): + local = cls._local_name(child.tag) + if local == "f": + has_formula = True + elif local == "v" and value_element is None: + value_element = child + if not has_formula: + continue + coordinate = element.get("r") + if coordinate is None: + msg = f"Formula cell without coordinate in {member}" + raise ValueError(msg) + if value_element is None: + uncached = (*uncached, f"{sheet_name}!{coordinate}") + elif not (value_element.text or "").strip(): + empty = (*empty, f"{sheet_name}!{coordinate}") + return uncached, empty + @classmethod def _formula_cache_evidence( cls, source: bytes @@ -70,41 +104,13 @@ def _formula_cache_evidence( """Classify formula cells as uncached or empty-string cached.""" try: with ZipFile(BytesIO(source)) as archive: - workbook_root = cls._require_xml(archive, c.Cli.XLSX_WORKBOOK_MEMBER) - rels_root = cls._require_xml(archive, c.Cli.XLSX_WORKBOOK_RELS_MEMBER) - uncached: tuple[str, ...] = () - empty: tuple[str, ...] = () - for sheet_name, member in cls._worksheet_targets( - workbook_root, rels_root - ): - root = cls._require_xml(archive, member) - for element in root.iter(): - if cls._local_name(element.tag) != "c": - continue - has_formula = False - value_element: p.Cli.XlsxXmlElement | None = None - for child in element.iter(): - local = cls._local_name(child.tag) - if local == "f": - has_formula = True - elif local == "v" and value_element is None: - value_element = child - if not has_formula: - continue - coordinate = element.get("r") - if coordinate is None: - msg = f"Formula cell without coordinate in {member}" - raise ValueError(msg) - if value_element is None: - uncached = (*uncached, f"{sheet_name}!{coordinate}") - elif not (value_element.text or "").strip(): - empty = (*empty, f"{sheet_name}!{coordinate}") + evidence = cls._collect_formula_cache_evidence(archive) except (BadZipFile, LargeZipFile, OSError, ValueError) as exc: detail = str(exc).strip() or exc.__class__.__name__ return r[tuple[tuple[str, ...], tuple[str, ...]]].fail( f"{c.Cli.XlsxError.PARITY_FAILED}: {detail}" ) - return r[tuple[tuple[str, ...], tuple[str, ...]]].ok((uncached, empty)) + return r[tuple[tuple[str, ...], tuple[str, ...]]].ok(evidence) __all__: tuple[str, ...] = ("FlextCliUtilitiesXlsxRecalcEvidence",) diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_snapshot.py b/src/flext_cli/_utilities/_xlxx/xlsx_snapshot.py index e0218142a..2f9fd9d07 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_snapshot.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_snapshot.py @@ -15,8 +15,8 @@ class FlextCliUtilitiesXlsxSnapshot( ): """Expose vendor-independent workbook parity evidence.""" - # NOTE (multi-agent, mro-j2yt.1): the formula view owns structure and - # counts; a second data-only view supplies cached values only when asked. + # NOTE (multi-agent, mro-wkii.17.26): the formula view owns structure and + # narrow phases; a data-only view supplies cached values only when requested. @classmethod def xlsx_snapshot( cls, request: m.Cli.XlsxSnapshotRequest @@ -31,20 +31,30 @@ def xlsx_snapshot( if request.data_only else formula_workbook ) - if len(formula_workbook.worksheets) != len(value_workbook.worksheets): - msg = "Formula and value workbook views have different sheet counts" - raise ValueError(msg) - sheets: tuple[m.Cli.XlsxSheetSnapshot, ...] = () - for position, (formula_sheet, value_sheet) in enumerate( - zip( - formula_workbook.worksheets, value_workbook.worksheets, strict=True - ), - start=1, - ): - sheet = cls._require_success( + except (TypeError, ValidationError, ValueError) as exc: + return r[m.Cli.XlsxWorkbookSnapshot].fail( + f"Workbook snapshot failed ({exc.__class__.__name__}): {exc}", + exception=exc, + ) + if len(formula_workbook.worksheets) != len(value_workbook.worksheets): + return r[m.Cli.XlsxWorkbookSnapshot].fail( + "Workbook snapshot failed (ValueError): Formula and value workbook " + "views have different sheet counts" + ) + try: + sheets = tuple( + cls._require_success( cls._snapshot_sheet(formula_sheet, value_sheet, position=position) ) - sheets = (*sheets, sheet) + for position, (formula_sheet, value_sheet) in enumerate( + zip( + formula_workbook.worksheets, + value_workbook.worksheets, + strict=True, + ), + start=1, + ) + ) defined_names = cls._require_success(cls._snapshot_names(formula_workbook)) snapshot = m.Cli.XlsxWorkbookSnapshot( data_only=request.data_only, @@ -56,7 +66,8 @@ def xlsx_snapshot( ) except (TypeError, ValidationError, ValueError) as exc: return r[m.Cli.XlsxWorkbookSnapshot].fail( - f"Workbook snapshot failed ({exc.__class__.__name__}): {exc}" + f"Workbook snapshot failed ({exc.__class__.__name__}): {exc}", + exception=exc, ) return r[m.Cli.XlsxWorkbookSnapshot].ok(snapshot) diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_sheet.py b/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_sheet.py index 60f590e8d..c2c658db3 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_sheet.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_sheet.py @@ -18,8 +18,8 @@ class FlextCliUtilitiesXlsxSnapshotSheet( ): """Build one immutable worksheet snapshot from formula and value views.""" - # NOTE (multi-agent, mro-j2yt.1): formula structure remains authoritative - # while data_only selects only the typed value exposed for each cell. + # NOTE (multi-agent, mro-wkii.17.26): formula structure stays authoritative; + # vendor aggregation and model validation use narrow exception boundaries. @staticmethod def _snapshot_state( worksheet: Worksheet, @@ -38,35 +38,46 @@ def _snapshot_state( def _snapshot_sheet( cls, formula_sheet: Worksheet, value_sheet: Worksheet, *, position: int ) -> p.Result[m.Cli.XlsxSheetSnapshot]: + formula_title = formula_sheet.title + value_title = value_sheet.title + if formula_title != value_title: + return r[m.Cli.XlsxSheetSnapshot].fail( + "Worksheet snapshot failed (ValueError): Worksheet view mismatch: " + f"{formula_title} != {value_title}" + ) try: - if formula_sheet.title != value_sheet.title: - msg = ( - "Worksheet view mismatch: " - f"{formula_sheet.title} != {value_sheet.title}" - ) - raise ValueError(msg) - state = cls._require_success(cls._snapshot_state(formula_sheet)) - cells = cls._require_success( - cls._snapshot_cells( - formula_sheet, - value_sheet, - data_only=formula_sheet is not value_sheet, - ) + state, cells, tables, rows, columns = ( + cls._require_success(cls._snapshot_state(formula_sheet)), + cls._require_success( + cls._snapshot_cells( + formula_sheet, + value_sheet, + data_only=formula_sheet is not value_sheet, + ) + ), + cls._require_success(cls._snapshot_tables(formula_sheet)), + cls._require_success(cls._snapshot_rows(formula_sheet)), + cls._require_success(cls._snapshot_columns(formula_sheet)), ) - tables = cls._require_success(cls._snapshot_tables(formula_sheet)) - rows = cls._require_success(cls._snapshot_rows(formula_sheet)) - columns = cls._require_success(cls._snapshot_columns(formula_sheet)) merged_ranges = tuple( sorted(str(item) for item in formula_sheet.merged_cells.ranges) ) legacy_password_hash = formula_sheet.protection.password - if legacy_password_hash is not None and not isinstance( - legacy_password_hash, str - ): - msg = "Worksheet legacy protection hash is not textual" - raise TypeError(msg) + except (TypeError, ValidationError, ValueError) as exc: + return r[m.Cli.XlsxSheetSnapshot].fail( + f"Worksheet snapshot failed ({exc.__class__.__name__}): {exc}", + exception=exc, + ) + if legacy_password_hash is not None and not isinstance( + legacy_password_hash, str + ): + return r[m.Cli.XlsxSheetSnapshot].fail( + "Worksheet snapshot failed (TypeError): Worksheet legacy protection " + "hash is not textual" + ) + try: snapshot = m.Cli.XlsxSheetSnapshot( - name=formula_sheet.title, + name=formula_title, position=position, state=state, max_row=formula_sheet.max_row, @@ -100,7 +111,8 @@ def _snapshot_sheet( ) except (TypeError, ValidationError, ValueError) as exc: return r[m.Cli.XlsxSheetSnapshot].fail( - f"Worksheet snapshot failed ({exc.__class__.__name__}): {exc}" + f"Worksheet snapshot failed ({exc.__class__.__name__}): {exc}", + exception=exc, ) return r[m.Cli.XlsxSheetSnapshot].ok(snapshot) diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_values.py b/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_values.py index bb605bf9d..e66cf0bab 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_values.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_values.py @@ -17,12 +17,11 @@ class FlextCliUtilitiesXlsxSnapshotValues: # NOTE (multi-agent, mro-j2yt.1): external cell primitives are validated # once into XlsxCellValue and vendor instances never leave this utility. + # NOTE (multi-agent, mro-wkii.17.26): narrow exception boundaries retain + # the exact failing vendor/model operation and never default missing data. @staticmethod def _snapshot_style_name(cell: Cell) -> str | None: - try: - return cell.style - except IndexError: - return None + return cell.style @staticmethod def _require_success[T](result: p.Result[T]) -> T: @@ -38,33 +37,38 @@ def _require_success[T](result: p.Result[T]) -> T: def _snapshot_value( value: t.Cli.XlsxCellPrimitive, *, formula_view: bool ) -> p.Result[m.Cli.XlsxCellValue]: + formula = ( + value + if formula_view and isinstance(value, str) and value.startswith("=") + else None + ) + if formula_view and formula is None: + return r[m.Cli.XlsxCellValue].fail( + f"{c.Cli.XlsxError.CELL_VALUE_UNSUPPORTED}: " + "formula cell has no formula expression" + ) try: - if formula_view: - if isinstance(value, str) and value.startswith("="): - converted: m.Cli.XlsxCellValue = m.Cli.XlsxFormulaValue(value=value) - return r[m.Cli.XlsxCellValue].ok(converted) - return r[m.Cli.XlsxCellValue].fail( - f"{c.Cli.XlsxError.CELL_VALUE_UNSUPPORTED}: " - "formula cell has no formula expression" - ) - if value is None: - converted = m.Cli.XlsxBlankValue() - elif isinstance(value, bool): - converted = m.Cli.XlsxBooleanValue(value=value) - elif isinstance(value, int): - converted = m.Cli.XlsxIntegerValue(value=value) - elif isinstance(value, (float, Decimal)): - converted = m.Cli.XlsxDecimalValue(value=Decimal(str(value))) - elif isinstance(value, dt.datetime): - converted = m.Cli.XlsxDateTimeValue(value=value) - elif isinstance(value, dt.date): - converted = m.Cli.XlsxDateValue(value=value) - else: - converted = m.Cli.XlsxTextValue(value=value) + converted: m.Cli.XlsxCellValue = ( + m.Cli.XlsxFormulaValue(value=formula) + if formula is not None + else m.Cli.XlsxBlankValue() + if value is None + else m.Cli.XlsxBooleanValue(value=value) + if isinstance(value, bool) + else m.Cli.XlsxIntegerValue(value=value) + if isinstance(value, int) + else m.Cli.XlsxDecimalValue(value=Decimal(str(value))) + if isinstance(value, (float, Decimal)) + else m.Cli.XlsxDateTimeValue(value=value) + if isinstance(value, dt.datetime) + else m.Cli.XlsxDateValue(value=value) + if isinstance(value, dt.date) + else m.Cli.XlsxTextValue(value=value) + ) except (InvalidOperation, ValidationError, ValueError) as exc: detail = str(exc).strip() or exc.__class__.__name__ return r[m.Cli.XlsxCellValue].fail( - f"{c.Cli.XlsxError.CELL_VALUE_UNSUPPORTED}: {detail}" + f"{c.Cli.XlsxError.CELL_VALUE_UNSUPPORTED}: {detail}", exception=exc ) return r[m.Cli.XlsxCellValue].ok(converted) @@ -101,18 +105,22 @@ def _snapshot_cell( if data_only else formula_cell ) - if not isinstance(selected, Cell): - return r[m.Cli.XlsxCellSnapshot].fail( - f"Unsupported selected cell: {formula_cell.coordinate}" - ) - selected_value = selected.value - if selected_value is not None and not isinstance( - selected_value, (str, int, float, bool, Decimal, dt.date, dt.datetime) - ): - return r[m.Cli.XlsxCellSnapshot].fail( - f"{c.Cli.XlsxError.CELL_VALUE_UNSUPPORTED}: " - f"{selected_value.__class__.__name__} at {formula_cell.coordinate}" - ) + except (IndexError, TypeError, ValidationError, ValueError) as exc: + detail = str(exc).strip() or exc.__class__.__name__ + return r[m.Cli.XlsxCellSnapshot].fail(detail, exception=exc) + if not isinstance(selected, Cell): + return r[m.Cli.XlsxCellSnapshot].fail( + f"Unsupported selected cell: {formula_cell.coordinate}" + ) + selected_value = selected.value + if selected_value is not None and not isinstance( + selected_value, (str, int, float, bool, Decimal, dt.date, dt.datetime) + ): + return r[m.Cli.XlsxCellSnapshot].fail( + f"{c.Cli.XlsxError.CELL_VALUE_UNSUPPORTED}: " + f"{selected_value.__class__.__name__} at {formula_cell.coordinate}" + ) + try: value = cls._require_success( cls._snapshot_value( selected_value, formula_view=formula is not None and not data_only @@ -133,29 +141,31 @@ def _snapshot_cell( ) except (IndexError, TypeError, ValidationError, ValueError) as exc: detail = str(exc).strip() or exc.__class__.__name__ - return r[m.Cli.XlsxCellSnapshot].fail(detail) + return r[m.Cli.XlsxCellSnapshot].fail(detail, exception=exc) return r[m.Cli.XlsxCellSnapshot].ok(snapshot) @classmethod def _snapshot_cells( cls, formula_sheet: Worksheet, value_sheet: Worksheet, *, data_only: bool ) -> p.Result[tuple[m.Cli.XlsxCellSnapshot, ...]]: + cells: tuple[m.Cli.XlsxCellSnapshot, ...] = () try: - cells: tuple[m.Cli.XlsxCellSnapshot, ...] = () for row in formula_sheet.iter_rows(): for formula_cell in row: - if isinstance(formula_cell, MergedCell): - continue - if not cls._has_snapshot_content(formula_cell): + if isinstance( + formula_cell, MergedCell + ) or not cls._has_snapshot_content(formula_cell): continue - cell = cls._require_success( - cls._snapshot_cell( - formula_cell, value_sheet, data_only=data_only - ) + cells = ( + *cells, + cls._require_success( + cls._snapshot_cell( + formula_cell, value_sheet, data_only=data_only + ) + ), ) - cells = (*cells, cell) except ValueError as exc: - return r[tuple[m.Cli.XlsxCellSnapshot, ...]].fail(str(exc)) + return r[tuple[m.Cli.XlsxCellSnapshot, ...]].fail(str(exc), exception=exc) return r[tuple[m.Cli.XlsxCellSnapshot, ...]].ok(cells) diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_style_readers.py b/src/flext_cli/_utilities/_xlxx/xlsx_style_readers.py index 971067a05..687f8b8aa 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_style_readers.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_style_readers.py @@ -16,8 +16,8 @@ class FlextCliUtilitiesXlsxStyleReaders: """Validate external style proxies into the canonical visual models.""" - # NOTE (multi-agent, mro-j2yt.1): copy() is the documented openpyxl proxy - # boundary; each copied component is runtime-checked before model ingress. + # NOTE (multi-agent, mro-wkii.17.26): copy() is the openpyxl proxy boundary; + # proxy reads and Pydantic composition fail through distinct typed phases. @staticmethod def _color_spec(color: Color | None) -> m.Cli.XlsxColor | None: if color is None: @@ -131,18 +131,26 @@ def _visual_from_styleable( fill = copy(value.fill) border = copy(value.border) alignment = copy(value.alignment) - if not isinstance(font, Font): - msg = "openpyxl font proxy copy is not Font" - raise TypeError(msg) - if not isinstance(fill, Fill): - msg = "openpyxl fill proxy copy is not Fill" - raise TypeError(msg) - if not isinstance(border, Border): - msg = "openpyxl border proxy copy is not Border" - raise TypeError(msg) - if not isinstance(alignment, Alignment): - msg = "openpyxl alignment proxy copy is not Alignment" - raise TypeError(msg) + except (TypeError, ValidationError, ValueError) as exc: + detail = str(exc).strip() or exc.__class__.__name__ + return r[m.Cli.XlsxVisualStyleSpec].fail(detail, exception=exc) + if not isinstance(font, Font): + return r[m.Cli.XlsxVisualStyleSpec].fail( + "openpyxl font proxy copy is not Font" + ) + if not isinstance(fill, Fill): + return r[m.Cli.XlsxVisualStyleSpec].fail( + "openpyxl fill proxy copy is not Fill" + ) + if not isinstance(border, Border): + return r[m.Cli.XlsxVisualStyleSpec].fail( + "openpyxl border proxy copy is not Border" + ) + if not isinstance(alignment, Alignment): + return r[m.Cli.XlsxVisualStyleSpec].fail( + "openpyxl alignment proxy copy is not Alignment" + ) + try: visual = m.Cli.XlsxVisualStyleSpec( font=cls._font_spec(font), fill=cls._fill_spec(fill), @@ -152,7 +160,7 @@ def _visual_from_styleable( ) except (TypeError, ValidationError, ValueError) as exc: detail = str(exc).strip() or exc.__class__.__name__ - return r[m.Cli.XlsxVisualStyleSpec].fail(detail) + return r[m.Cli.XlsxVisualStyleSpec].fail(detail, exception=exc) return r[m.Cli.XlsxVisualStyleSpec].ok(visual) diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_tables.py b/src/flext_cli/_utilities/_xlxx/xlsx_tables.py index c0b5a9d2a..c2da5e519 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_tables.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_tables.py @@ -18,6 +18,8 @@ class FlextCliUtilitiesXlsxTables(FlextCliUtilitiesXlsxAddresses): # NOTE (multi-agent, mro-j2yt.1): table/name uniqueness and header validity # are checked before external objects mutate the workbook. + # NOTE (multi-agent, mro-wkii.17.26): header reads and table mutation use + # separate exception boundaries; domain validation remains explicit. @classmethod def _apply_tables( cls, @@ -26,18 +28,24 @@ def _apply_tables( used_names: frozenset[str], ) -> p.Result[frozenset[str]]: names = used_names - try: - for plan in plans: - if plan.name in names: + for plan in plans: + if plan.name in names: + return r[frozenset[str]].fail( + f"{c.Cli.XlsxError.DUPLICATE_TABLE}: {plan.name}" + ) + for column in range(plan.area.first.column, plan.area.last.column + 1): + try: + header = worksheet.cell(plan.area.first.row, column).value + except (KeyError, TypeError, ValueError) as exc: + detail = str(exc).strip() or exc.__class__.__name__ return r[frozenset[str]].fail( - f"{c.Cli.XlsxError.DUPLICATE_TABLE}: {plan.name}" + f"{c.Cli.XlsxError.RENDER_FAILED}: {detail}", exception=exc ) - for column in range(plan.area.first.column, plan.area.last.column + 1): - header = worksheet.cell(plan.area.first.row, column).value - if not isinstance(header, str) or not header: - return r[frozenset[str]].fail( - f"Invalid table header: {plan.name} column {column}" - ) + if not isinstance(header, str) or not header: + return r[frozenset[str]].fail( + f"Invalid table header: {plan.name} column {column}" + ) + try: table = Table(displayName=plan.name, ref=cls._range_ref(plan.area)) table.tableStyleInfo = TableStyleInfo( name=plan.style, @@ -47,10 +55,12 @@ def _apply_tables( showColumnStripes=plan.show_column_stripes, ) worksheet.add_table(table) - names = names.union((plan.name,)) - except (KeyError, TypeError, ValueError) as exc: - detail = str(exc).strip() or exc.__class__.__name__ - return r[frozenset[str]].fail(f"{c.Cli.XlsxError.RENDER_FAILED}: {detail}") + except (KeyError, TypeError, ValueError) as exc: + detail = str(exc).strip() or exc.__class__.__name__ + return r[frozenset[str]].fail( + f"{c.Cli.XlsxError.RENDER_FAILED}: {detail}", exception=exc + ) + names = names.union((plan.name,)) return r[frozenset[str]].ok(names) @classmethod diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_workbook_plan.py b/src/flext_cli/_utilities/_xlxx/xlsx_workbook_plan.py index 329cd386c..31481dfea 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_workbook_plan.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_workbook_plan.py @@ -66,6 +66,7 @@ def _workbook_for_request( loaded.error or str(c.Cli.XlsxError.WORKBOOK_LOAD_FAILED) ) workbook = loaded.value + # mro-wkii.17.26 (codex): isolate vendor mutations by workbook phase. try: for worksheet in tuple(workbook.worksheets): workbook.remove(worksheet) @@ -75,6 +76,10 @@ def _workbook_for_request( for spec in request.plan.named_styles: if spec.name not in workbook.named_styles: workbook.add_named_style(cls._named_style(spec)) + except (KeyError, TypeError, ValueError) as exc: + detail = str(exc).strip() or exc.__class__.__name__ + return r[Workbook].fail(f"{c.Cli.XlsxError.RENDER_FAILED}: {detail}") + try: for sheet in request.plan.sheets: created = workbook.create_sheet(sheet.name) if not isinstance(created, Worksheet): diff --git a/src/flext_cli/_utilities/model_commands.py b/src/flext_cli/_utilities/model_commands.py index 26d583154..95e136a00 100644 --- a/src/flext_cli/_utilities/model_commands.py +++ b/src/flext_cli/_utilities/model_commands.py @@ -98,7 +98,8 @@ def model_source_data( if isinstance(source, Mapping): raw_source = source else: - raw_source = source.model_dump(exclude_none=True) + # mro-wkii.17.26 (codex): explicit source fields alone override targets. + raw_source = source.model_dump(exclude_none=True, exclude_unset=True) filtered_payload = { field_name: raw_source[field_name] for field_name in model_cls.model_fields diff --git a/src/flext_cli/base.py b/src/flext_cli/base.py index eb6edffda..75368000f 100644 --- a/src/flext_cli/base.py +++ b/src/flext_cli/base.py @@ -10,16 +10,20 @@ from __future__ import annotations from flext_cli import m, t -from flext_core import s +from flext_core import p, s -class FlextCliServiceBase(s[m.Cli.RuntimeStatus]): +class FlextCliServiceBase[TDomainResult: p.Base = m.Cli.RuntimeStatus]( + s[TDomainResult] +): """Base class for flext-cli services with typed configuration access. Note: This is an abstract base class. Subclasses must implement the `execute` method from s. """ + # mro-wkii.17.26 (codex): preserve the domain result through the service MRO. + s = FlextCliServiceBase diff --git a/src/flext_cli/services/_cli_parts/flextclicli_part_01.py b/src/flext_cli/services/_cli_parts/flextclicli_part_01.py index b53587bd0..ff4a2007e 100644 --- a/src/flext_cli/services/_cli_parts/flextclicli_part_01.py +++ b/src/flext_cli/services/_cli_parts/flextclicli_part_01.py @@ -42,7 +42,9 @@ def __init__( self._model_cls = model_cls def __call__(self, **kwargs: t.Cli.CliValue) -> t.JsonValue: - model = self._model_cls.model_validate(kwargs) + # mro-wkii.17.26 (codex): the adapter supplies field names while + # external callers may use declared aliases at this single boundary. + model = self._model_cls.model_validate(kwargs, by_alias=True, by_name=True) return self._handler(model) @classmethod diff --git a/tests/_constants_parts/tests_yaml_output.py b/tests/_constants_parts/tests_yaml_output.py index 8e55e439f..ca34455df 100644 --- a/tests/_constants_parts/tests_yaml_output.py +++ b/tests/_constants_parts/tests_yaml_output.py @@ -18,13 +18,13 @@ class TestsFlextCliConstantsYamlOutput: YAML_INVALID_CONTENT: Final[str] = "key: [unterminated" YAML_NON_MAPPING_CONTENT: Final[str] = "- item1\n- item2\n" - # parse(text) → (text, expect_ok, expect_empty_dict) - YAML_PARSE_CASES: Final[tuple[tuple[str, bool, bool], ...]] = ( - (YAML_VALID_CONTENT, True, False), - ("", True, True), - ("null\n", True, True), - (YAML_INVALID_CONTENT, False, False), - (YAML_NON_MAPPING_CONTENT, False, False), + # parse(text) → (text, expect_ok) + YAML_PARSE_CASES: Final[tuple[tuple[str, bool], ...]] = ( + (YAML_VALID_CONTENT, True), + ("", False), + ("null\n", False), + (YAML_INVALID_CONTENT, False), + (YAML_NON_MAPPING_CONTENT, False), ) # dump: (data, sort_keys, expect_ok) @@ -66,8 +66,6 @@ class TestsFlextCliConstantsYamlOutput: ) # ── FORMATTERS ───────────────────────────────────────────────── - FORMATTER_TREE_LABELS: Final[t.StrSequence] = ("Root", "Branch", "") - # (columns, rows, title) FORMATTER_TABLE_CASES: Final[ tuple[tuple[t.StrSequence, tuple[t.StrSequence, ...], str], ...] diff --git a/tests/_exports_public.py b/tests/_exports_public.py index aab25afee..fd0df500a 100644 --- a/tests/_exports_public.py +++ b/tests/_exports_public.py @@ -68,7 +68,6 @@ "make_prompts", "p", "r", - "reset_settings", "s", "t", "td", diff --git a/tests/_models_parts/__init__.py b/tests/_models_parts/__init__.py index 9cbd30bc1..6a7447859 100644 --- a/tests/_models_parts/__init__.py +++ b/tests/_models_parts/__init__.py @@ -7,6 +7,8 @@ _LAZY_IMPORTS = build_lazy_import_map({ ".tests_cli": ("TestsFlextCliModelsCli",), + # mro-wkii.17.26 (models): publish concrete fixture-model ownership. + ".tests_fixtures": ("TestsFlextCliModelsFixtures",), ".tests_runtime": ("TestsFlextCliModelsRuntime",), ".tests_version": ("TestsFlextCliModelsVersion",), ".testsflextclimodels_part_01": ("TestsFlextCliModels",), diff --git a/tests/_models_parts/tests_fixtures.py b/tests/_models_parts/tests_fixtures.py new file mode 100644 index 000000000..154d171dc --- /dev/null +++ b/tests/_models_parts/tests_fixtures.py @@ -0,0 +1,96 @@ +"""Concrete field-only models for flext-cli public contract fixtures.""" + +from __future__ import annotations + +from typing import Annotated + +from flext_cli import m + + +class TestsFlextCliModelsFixtures: + """Consumer-owned immutable records used by public integration flows.""" + + # mro-wkii.17.26 (codex): own CLI field-metadata fixtures as validated data. + + class CustomDeclarationInput(m.FrozenModel): + """Validated command input with explicit CLI option declarations.""" + + flag: Annotated[ + bool, + m.Field( + description="Custom boolean option", + validate_default=True, + json_schema_extra={"typer_param_decls": ("-f", "--flaggy")}, + ), + ] = False + + class ExcludedFieldInput(m.FrozenModel): + """Validated command input with one excluded internal field.""" + + visible: Annotated[str, m.Field(description="Visible command value")] + hidden: Annotated[ + str, + m.Field( + description="Internal value excluded from command options", + exclude=True, + validate_default=True, + ), + ] = "secret" + + class TemplateEmpty(m.FrozenModel): + """Validated empty template context.""" + + class TemplateValue(m.FrozenModel): + """Validated scalar template context.""" + + value: Annotated[int, m.Field(description="Rendered test value")] + + class TemplateServer(m.FrozenModel): + """Validated server data rendered by template tests.""" + + port: Annotated[int, m.Field(description="Server port")] + + class TemplateServerContext(m.FrozenModel): + """Validated nested server template context.""" + + server: Annotated[ + TestsFlextCliModelsFixtures.TemplateServer, + m.Field(description="Server rendered by the template"), + ] + + class SampleInputPatch(m.FrozenModel): + """Canonical source patch for model derivation tests.""" + + name: Annotated[str, m.Field(description="Patched target name")] + count: Annotated[int, m.Field(description="Patched repetition count")] + + class ReportRow(m.FrozenModel): + """Serializable row consumed by the output example.""" + + id: Annotated[int, m.Field(description="Report row identifier")] + name: Annotated[str, m.Field(description="Report row name")] + status: Annotated[str, m.Field(description="Report row status")] + + class UserPreferences(m.FrozenModel): + """User preference payload persisted by the file example.""" + + theme: Annotated[str, m.Field(description="Selected visual theme")] + notifications: Annotated[ + bool, m.Field(description="Notification activation flag") + ] + + class DeploymentConfig(m.FrozenModel): + """Deployment payload persisted by the YAML example.""" + + environment: Annotated[str, m.Field(description="Deployment environment")] + replicas: Annotated[int, m.Field(description="Requested replica count")] + + class ImportRecord(m.FrozenModel): + """Validated record consumed by the JSON import example.""" + + id: Annotated[int, m.Field(description="Imported record identifier")] + name: Annotated[str, m.Field(description="Imported record name")] + value: Annotated[str, m.Field(description="Imported record value")] + + +__all__: tuple[str, ...] = ("TestsFlextCliModelsFixtures",) diff --git a/tests/_models_parts/testsflextclimodels_part_01.py b/tests/_models_parts/testsflextclimodels_part_01.py index f5676eade..a9959d9ea 100644 --- a/tests/_models_parts/testsflextclimodels_part_01.py +++ b/tests/_models_parts/testsflextclimodels_part_01.py @@ -5,6 +5,7 @@ from flext_tests import m from tests._models_parts.tests_cli import TestsFlextCliModelsCli +from tests._models_parts.tests_fixtures import TestsFlextCliModelsFixtures from tests._models_parts.tests_runtime import TestsFlextCliModelsRuntime from tests._models_parts.tests_version import TestsFlextCliModelsVersion @@ -13,6 +14,7 @@ class TestsFlextCliModels: """Implementation part for TestsFlextCliModels.""" class Tests( + TestsFlextCliModelsFixtures, TestsFlextCliModelsRuntime, TestsFlextCliModelsVersion, TestsFlextCliModelsCli, diff --git a/tests/protocols.py b/tests/protocols.py index 6c1e25d77..559864362 100644 --- a/tests/protocols.py +++ b/tests/protocols.py @@ -13,6 +13,7 @@ from flext_cli import p if TYPE_CHECKING: + from flext_cli import m from tests import t @@ -25,52 +26,82 @@ class Tests(FlextTestsProtocols.Tests): class ScriptedPrompts(Protocol): """Prompt test double contract exposed through the canonical `p`.""" - def override_test_env(self, enabled: bool | None = True) -> Self: ... + def override_test_env(self, *, enabled: bool | None = True) -> Self: + """Override test-environment detection for the prompt instance.""" + ... - def use_input_values(self, values: t.StrSequence) -> Self: ... + def use_input_values(self, values: t.StrSequence) -> Self: + """Queue text values returned by subsequent prompt calls.""" + ... - def use_input_error(self, error: Exception) -> Self: ... + def use_input_error(self, error: Exception) -> Self: + """Configure the next text prompt to raise the supplied error.""" + ... - def use_password(self, password: str) -> Self: ... + def use_password(self, password: str) -> Self: + """Configure the password returned by the prompt boundary.""" + ... - def use_password_error(self, error: Exception) -> Self: ... + def use_password_error(self, error: Exception) -> Self: + """Configure the next password prompt to raise an error.""" + ... def configure_state( self, *, interactive: bool = True, quiet: bool = False - ) -> Self: ... + ) -> Self: + """Set the observable interactive and quiet prompt state.""" + ... - def execute(self) -> p.Result[t.MappingKV[str, t.JsonValue]]: ... + def execute(self) -> p.Result[m.Cli.RuntimeStatus]: + """Return the canonical typed CLI runtime status.""" + ... - def prompt(self, message: str, default: str = "") -> p.Result[str]: ... + def prompt(self, message: str, default: str = "") -> p.Result[str]: + """Read a text value or return the configured default.""" + ... - def confirm( - self, message: str, *, default: bool = False - ) -> p.Result[bool]: ... + def confirm(self, message: str, *, default: bool = False) -> p.Result[bool]: + """Read a yes-or-no confirmation through the public result contract.""" + ... def prompt_choice( self, message: str, choices: t.StrSequence, default: str | None = None - ) -> p.Result[str]: ... + ) -> p.Result[str]: + """Read one validated value from the available choices.""" + ... def prompt_password( self, message: str, min_length: int = 8 - ) -> p.Result[str]: ... + ) -> p.Result[str]: + """Read a password satisfying the minimum length.""" + ... - def print_success(self, message: str) -> p.Result[None]: ... + def print_success(self, message: str) -> p.Result[None]: + """Emit a success message through the prompt service.""" + ... - def print_error(self, message: str) -> p.Result[None]: ... + def print_error(self, message: str) -> p.Result[None]: + """Emit an error message through the prompt service.""" + ... - def print_warning(self, message: str) -> p.Result[None]: ... + def print_warning(self, message: str) -> p.Result[None]: + """Emit a warning message through the prompt service.""" + ... class CaptureLogPrompts(ScriptedPrompts, Protocol): """Prompt test double that exposes captured log records.""" @property - def records(self) -> list[tuple[str, str]]: ... + def records(self) -> list[tuple[str, str]]: + """Captured log-level and message pairs.""" + ... class FailingLogPrompts(ScriptedPrompts, Protocol): """Prompt test double that can fail a selected log call.""" - def fail_on_log(self, *, level: str, message: str) -> Self: ... + def fail_on_log(self, *, level: str, message: str) -> Self: + """Configure one matching log emission to fail.""" + ... p = TestsFlextCliProtocols diff --git a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_01.py b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_01.py index 585395d8d..3192bc650 100644 --- a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_01.py +++ b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_01.py @@ -11,6 +11,7 @@ from flext_cli import cli # NOTE (multi-agent, mro-wkii.19.4): app creation owns the settings singleton. +# mro-wkii.17.26 (codex): exercise CLI flows through the public invocation facade. if TYPE_CHECKING: from collections.abc import MutableSequence @@ -21,21 +22,22 @@ class TestsFlextCliService: """Implementation part for TestsFlextCliService.""" - def test_model_command_updates_runtime_settings_fields(self) -> None: - class RuntimeSettings(m.BaseModel): - debug: bool = False - - settings = RuntimeSettings() + def test_model_command_validates_runtime_settings_fields(self) -> None: + """Validate runtime CLI parameters through the model command.""" + command_settings = m.Cli.CliParamsConfig() def handle(params: m.Cli.CliParamsConfig) -> t.JsonValue: return params.debug is True - command = cli.model_command(m.Cli.CliParamsConfig, handle, settings=settings) + command = cli.model_command( + m.Cli.CliParamsConfig, handle, settings=command_settings + ) result = command(debug=True) tm.that(result, eq=True) - def test_create_app_with_common_params_applies_settings(self) -> None: + def test_create_app_with_common_params_accepts_debug_flag(self) -> None: + """Accept the public debug flag through a real CLI invocation.""" app = cli.create_app_with_common_params( name="sample", help_text="Sample application" ) @@ -43,13 +45,14 @@ def test_create_app_with_common_params_applies_settings(self) -> None: app, name="inspect", help_text="Inspect settings", command=lambda: True ) - runner_result = cli.create_cli_runner() - tm.ok(runner_result) - result = runner_result.value.invoke(app, ["--debug", "inspect"]) + result = cli.invoke_app(app, args=("--debug", "inspect")) - tm.that(result.exit_code, eq=0) + tm.ok(result) + invocation = result.value + tm.that(invocation.exit_code, eq=0) - def test_create_app_with_common_params_applies_log_level(self) -> None: + def test_create_app_with_common_params_accepts_log_level_flag(self) -> None: + """Accept an explicit log level through a real CLI invocation.""" app = cli.create_app_with_common_params( name="sample", help_text="Sample application" ) @@ -57,15 +60,14 @@ def test_create_app_with_common_params_applies_log_level(self) -> None: app, name="inspect", help_text="Inspect settings", command=lambda: True ) - runner_result = cli.create_cli_runner() - tm.ok(runner_result) - result = runner_result.value.invoke( - app, ["--log-level", c.LogLevel.DEBUG, "inspect"] - ) + result = cli.invoke_app(app, args=("--log-level", c.LogLevel.DEBUG, "inspect")) - tm.that(result.exit_code, eq=0) + tm.ok(result) + invocation = result.value + tm.that(invocation.exit_code, eq=0) def test_model_command_generates_real_typer_options(self) -> None: + """Generate and execute real Typer options from the request model.""" captured: MutableSequence[m.Tests.SampleInput] = [] app = cli.create_app_with_common_params( name="root", help_text="Root application" @@ -81,12 +83,10 @@ def handle(params: m.Tests.SampleInput) -> t.JsonValue: group, name="run", help_text="Run sample command", command=command ) cli.add_group(app, name="sample", group=group) - runner_result = cli.create_cli_runner() - tm.ok(runner_result) - help_result = runner_result.value.invoke(app, ["sample", "run", "--help"]) - exec_result = runner_result.value.invoke( + help_result = cli.invoke_app(app, args=("sample", "run", "--help")) + exec_result = cli.invoke_app( app, - [ + args=( "sample", "run", "--name", @@ -96,13 +96,17 @@ def handle(params: m.Tests.SampleInput) -> t.JsonValue: "--dry-run", "--output-format", c.Cli.OutputFormats.JSON, - ], + ), ) - tm.that(help_result.exit_code, eq=0) - tm.that(help_result.stdout, has="Target name") - tm.that(help_result.stdout, has="Dry-run mode") - tm.that(exec_result.exit_code, eq=0) + tm.ok(help_result) + tm.ok(exec_result) + help_invocation = help_result.value + exec_invocation = exec_result.value + tm.that(help_invocation.exit_code, eq=0) + tm.that(help_invocation.stdout, has="Target name") + tm.that(help_invocation.stdout, has="Dry-run mode") + tm.that(exec_invocation.exit_code, eq=0) tm.that(len(captured), eq=1) tm.that(captured[0].name, eq="alice") tm.that(captured[0].count, eq=3) diff --git a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_02.py b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_02.py index aec25c4b8..8d5fa6cf2 100644 --- a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_02.py +++ b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_02.py @@ -11,6 +11,7 @@ from flext_cli import cli # NOTE (multi-agent, mro-wkii.19.4): app creation owns the settings singleton. +# mro-wkii.17.26 (codex): exercise CLI flows through the public invocation facade. if TYPE_CHECKING: from collections.abc import MutableSequence @@ -22,6 +23,7 @@ class TestsFlextCliService: """Implementation part for TestsFlextCliService.""" def test_model_command_accepts_repeatable_list_options(self) -> None: + """Parse repeatable CLI options into one validated model.""" captured: MutableSequence[m.Tests.RepeatableInput] = [] app = cli.create_app_with_common_params( name="root", help_text="Root application" @@ -40,25 +42,27 @@ def handle(params: m.Tests.RepeatableInput) -> t.JsonValue: command=command, ) cli.add_group(app, name="sample", group=group) - runner_result = cli.create_cli_runner() - tm.ok(runner_result) - exec_result = runner_result.value.invoke( + exec_result = cli.invoke_app( app, - [ + args=( "sample", "repeat", "--make-arg", "FILES=a b c.py", "--make-arg", "VERBOSE=1", - ], + ), ) - tm.that(exec_result.exit_code, eq=0) + tm.ok(exec_result) + invocation = exec_result.value + tm.that(invocation.exit_code, eq=0) tm.that(len(captured), eq=1) tm.that(captured[0].make_arg, eq=["FILES=a b c.py", "VERBOSE=1"]) def test_model_command_returns_handler_value(self) -> None: + """Return the handler value from the model-generated command.""" + def handle(params: m.Tests.SampleInput) -> t.JsonValue: return { "name": params.name, @@ -83,27 +87,22 @@ def handle(params: m.Tests.SampleInput) -> t.JsonValue: ) def test_model_command_uses_custom_param_decls_from_field_extra(self) -> None: - class CustomDeclModel(m.BaseModel): - flag: bool = m.Field( - False, - validate_default=True, - description="Custom flag", - json_schema_extra={"typer_param_decls": ["-f", "--flaggy"]}, - ) - + """Expose custom option declarations from validated field metadata.""" app = cli.create_app_with_common_params(name="decl-app", help_text="Decl app") cli.register_command( app, name="run", help_text="Run", - command=cli.model_command(CustomDeclModel, lambda _params: True), + command=cli.model_command( + m.Tests.CustomDeclarationInput, lambda _params: True + ), ) - runner_result = cli.create_cli_runner() - tm.ok(runner_result) - help_result = runner_result.value.invoke(app, ["run", "--help"]) + help_result = cli.invoke_app(app, args=("run", "--help")) - tm.that(help_result.exit_code, eq=0) - tm.that(help_result.stdout, has="--flaggy") + tm.ok(help_result) + invocation = help_result.value + tm.that(invocation.exit_code, eq=0) + tm.that(invocation.stdout, has="--flaggy") __all__: list[str] = ["TestsFlextCliService"] diff --git a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_03.py b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_03.py index 7715ee14f..ab98c92a9 100644 --- a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_03.py +++ b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_03.py @@ -11,16 +11,14 @@ # NOTE (multi-agent, mro-wkii.19.4): app creation owns the settings singleton. # NOTE (multi-agent, mro-wkii.17 / agent: make_ssot_audit): derive_model tests # compose canonical source models without JSON-shaped intermediaries. +# mro-wkii.17.26 (codex): exercise CLI flows through the public invocation facade. class TestsFlextCliService: """Implementation part for TestsFlextCliService.""" def test_model_command_skips_excluded_fields(self) -> None: - class ExcludedFieldModel(m.BaseModel): - visible: str = m.Field(..., description="Visible", validate_default=True) - hidden: str = m.Field("secret", exclude=True, validate_default=True) - + """Exclude hidden model fields from generated CLI options.""" app = cli.create_app_with_common_params( name="exclude-app", help_text="Exclude app" ) @@ -28,49 +26,46 @@ class ExcludedFieldModel(m.BaseModel): app, name="run", help_text="Run", - command=cli.model_command(ExcludedFieldModel, lambda _params: True), + command=cli.model_command(m.Tests.ExcludedFieldInput, lambda _params: True), ) - runner_result = cli.create_cli_runner() - tm.ok(runner_result) - help_result = runner_result.value.invoke(app, ["run", "--help"]) + help_result = cli.invoke_app(app, args=("run", "--help")) - tm.that(help_result.exit_code, eq=0) - tm.that(help_result.stdout, has="--visible") - tm.that("--hidden" in help_result.stdout, eq=False) + tm.ok(help_result) + invocation = help_result.value + tm.that(invocation.exit_code, eq=0) + tm.that(invocation.stdout, has="--visible") + tm.that("--hidden" in invocation.stdout, eq=False) def test_create_app_with_common_params_handles_invalid_trace_without_debug( self, ) -> None: + """Keep trace disabled when debug mode is not active.""" app = cli.create_app_with_common_params(name="warn-app", help_text="Warn app") cli.register_command(app, name="ok", help_text="OK", command=lambda: True) - runner_result = cli.create_cli_runner() - tm.ok(runner_result) - invoke_result = runner_result.value.invoke(app, ["--trace", "ok"]) + invoke_result = cli.invoke_app(app, args=("--trace", "ok")) - tm.that(invoke_result.exit_code, eq=0) + tm.ok(invoke_result) + invocation = invoke_result.value + tm.that(invocation.exit_code, eq=0) tm.that(settings.trace, eq=False) def test_create_app_with_common_params_no_flags_keeps_settings(self) -> None: + """Preserve shared settings when no global flags are provided.""" app = cli.create_app_with_common_params( name="identity-app", help_text="Identity app" ) cli.register_command(app, name="ok", help_text="OK", command=lambda: True) - runner_result = cli.create_cli_runner() - tm.ok(runner_result) - invoke_result = runner_result.value.invoke(app, ["ok"]) + invoke_result = cli.invoke_app(app, args=("ok",)) - tm.that(invoke_result.exit_code, eq=0) + tm.ok(invoke_result) + invocation = invoke_result.value + tm.that(invocation.exit_code, eq=0) tm.that(settings.debug, eq=False) - def test_create_cli_runner_fails_loud_for_unsupported_echo_stdin(self) -> None: - result = cli.create_cli_runner(echo_stdin=True) - - tm.fail(result) - tm.that(result.error, has=c.Cli.ERR_CLI_RUNNER_ECHO_STDIN_UNSUPPORTED) - def test_derive_model_merges_canonical_model_sources(self) -> None: + """Merge canonical model sources in declaration order.""" first_source = m.Tests.SampleInputPatch(name="alice", count=2) model_from_instance = m.Tests.SampleInput( name="bob", count=7, dry_run=True, output_format=c.Cli.OutputFormats.JSON @@ -85,21 +80,8 @@ def test_derive_model_merges_canonical_model_sources(self) -> None: tm.that(derived.count, eq=9) tm.that(derived.dry_run, eq=True) - def test_execute_app_handles_abort_exception(self) -> None: - app = cli.create_app_with_common_params(name="abort-app", help_text="Abort app") - cli.register_command( - app, - name="abort", - help_text="Abort command", - command=lambda: (_ for _ in ()).throw(c.Cli.CliAbortError()), - ) - - result = cli.execute_app(app, prog_name="abort-app", args=["abort"]) - - tm.fail(result) - tm.that(result.error, has="Abort") - def test_execute_app_handles_unexpected_exception(self) -> None: + """Propagate an unexpected application exception with context.""" app = cli.create_app_with_common_params(name="error-app", help_text="Error app") cli.register_command( app, diff --git a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_04.py b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_04.py index 662c66232..1e3703b32 100644 --- a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_04.py +++ b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_04.py @@ -19,6 +19,7 @@ class TestsFlextCliService: """Implementation part for TestsFlextCliService.""" def test_execute_app_handles_nonzero_int_result(self) -> None: + """Report a nonzero integer command result as a CLI failure.""" app = cli.create_app_with_common_params(name="int-app", help_text="Int app") cli.register_command( app, name="return-two", help_text="Return int", command=lambda: 2 @@ -30,6 +31,7 @@ def test_execute_app_handles_nonzero_int_result(self) -> None: tm.that(result.error, has="CLI exited with code 2") def test_execute_app_handles_typer_exit_zero_branch(self) -> None: + """Treat an explicit zero exit as successful execution.""" app = cli.create_app_with_common_params(name="zero-app", help_text="Zero app") cli.register_command( app, @@ -43,6 +45,7 @@ def test_execute_app_handles_typer_exit_zero_branch(self) -> None: tm.ok(result) def test_execute_app_handles_typer_exit_nonzero_branch_real(self) -> None: + """Report an explicit nonzero exit as a CLI failure.""" app = cli.create_app_with_common_params( name="nonzero-app", help_text="Non-zero app" ) @@ -56,6 +59,7 @@ def test_execute_app_handles_typer_exit_nonzero_branch_real(self) -> None: tm.that(result.error, has="CLI exited with code 1") def test_execute_app_prefers_real_failure_message(self) -> None: + """Preserve the real exit code in a command failure message.""" app = cli.create_app_with_common_params( name="sample", help_text="Failure group" ) @@ -80,6 +84,7 @@ def fail_handler(_params: m.Tests.SampleInput) -> t.JsonValue: tm.that(result.error, has="CLI exited with code 1") def test_execute_app_preserves_click_usage_errors(self) -> None: + """Preserve Click usage details for an unknown command.""" app = cli.create_app_with_common_params( name="sample", help_text="Failure group" ) diff --git a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_05.py b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_05.py index 943556eab..14f037cb5 100644 --- a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_05.py +++ b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_05.py @@ -11,6 +11,7 @@ from flext_cli import cli, r # NOTE (multi-agent, mro-wkii.19.4): app creation owns the settings singleton. +# mro-wkii.17.26 (codex): exercise CLI flows through the public invocation facade. if TYPE_CHECKING: from tests import p @@ -20,6 +21,7 @@ class TestsFlextCliService: """Implementation part for TestsFlextCliService.""" def test_register_result_command_renders_success_and_failure(self) -> None: + """Render successful and failed result commands through real CLI routes.""" app = cli.create_app_with_common_params( name="result-app", help_text="Result application" ) @@ -56,19 +58,20 @@ def build_fail_route() -> m.Cli.ResultCommandRoute: cli.register_result_route(app, route=build_ok_route()) cli.register_result_route(group, route=build_fail_route()) cli.add_group(app, name="group", group=group) - runner_result = cli.create_cli_runner() - tm.ok(runner_result) - ok_result = runner_result.value.invoke(app, ["ok", "--name", "alice"]) - fail_result = runner_result.value.invoke( - app, ["group", "fail", "--name", "alice"] - ) - - tm.that(ok_result.exit_code, eq=0) - tm.that(ok_result.stdout, has="processed alice") - tm.that(fail_result.exit_code, eq=1) - tm.that(fail_result.stdout, has="Username cannot be empty") + ok_result = cli.invoke_app(app, args=("ok", "--name", "alice")) + fail_result = cli.invoke_app(app, args=("group", "fail", "--name", "alice")) + + tm.ok(ok_result) + tm.ok(fail_result) + ok_invocation = ok_result.value + fail_invocation = fail_result.value + tm.that(ok_invocation.exit_code, eq=0) + tm.that(ok_invocation.stdout, has="processed alice") + tm.that(fail_invocation.exit_code, eq=1) + tm.that(fail_invocation.stdout, has="Username cannot be empty") def test_register_result_routes_propagates_real_failure(self) -> None: + """Preserve structured failures from registered result routes.""" app = cli.create_app_with_common_params( name="result-app", help_text="Result application" ) @@ -99,8 +102,7 @@ def fail_handler(params: m.Tests.SampleInput) -> p.Result[m.Tests.SampleOutput]: tm.fail(fail_result) tm.that(fail_result.error, has="Password cannot be resolved") tm.that(fail_result.error_code, eq="secret_unavailable") - assert fail_result.error_data is not None - tm.that(fail_result.error_data["field"], eq="password") + tm.that(fail_result.error_data, eq={"field": "password", "name": "alice"}) tm.that(fail_result.exception, is_=ValueError) tm.that(cli.finalize_result(fail_result), eq=c.Cli.EXIT_CODE_FAILURE) diff --git a/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_02.py b/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_02.py index 875f0fc4b..35288d58e 100644 --- a/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_02.py +++ b/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_02.py @@ -17,6 +17,8 @@ from flext_cli import cli, settings +# mro-wkii.17.26 (codex): assert authentication against the shared example rule. + if TYPE_CHECKING: from collections.abc import Iterator from pathlib import Path @@ -81,7 +83,7 @@ def test_authentication_and_settings_examples(self, tmp_path: Path) -> None: token_result = Ex05Authentication.fetch_saved_token() tm.ok(token_result) - tm.that(len(token_result.value) >= 20, eq=True) + tm.that(len(token_result.value) >= ec.EXAMPLE_MIN_AUTH_TOKEN_LENGTH, eq=True) validation_result = Ex05Authentication.validate_current_token() tm.ok(validation_result) diff --git a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_01.py b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_01.py index 863ce3308..e3644971b 100644 --- a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_01.py +++ b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_01.py @@ -39,7 +39,7 @@ def _fail_handler(stage_id: str) -> t.Cli.PipelineHandler: """Build a handler that fails.""" def handler( - ctx: p.Cli.PipelineStageContext, + _ctx: p.Cli.PipelineStageContext, ) -> p.Result[m.Cli.PipelineStageResult]: return r[m.Cli.PipelineStageResult].fail(f"{stage_id} failed") @@ -55,7 +55,7 @@ def test_single_stage_ok(self, tmp_path: Path) -> None: result = cli.pipeline(stages, context=cli.stage_context(tmp_path)) tm.ok(result) pipeline = result.value - tm.ok(pipeline) + tm.that(pipeline.success, eq=True) tm.that(len(pipeline.stages), eq=1) tm.that(pipeline.stages[0].stage_id, eq="alpha") tm.that(pipeline.stages[0].status, eq=c.Cli.PipelineStageStatus.OK) @@ -116,7 +116,7 @@ def test_fail_fast_stops_on_failure(self, tmp_path: Path) -> None: ) tm.ok(result) pipeline = result.value - tm.fail(pipeline) + tm.that(pipeline.success, eq=False) tm.that(len(pipeline.failed_stages), eq=1) tm.that(pipeline.failed_stages[0].stage_id, eq="a") @@ -132,7 +132,7 @@ def test_skip_predicate(self, tmp_path: Path) -> None: result = cli.pipeline(stages, context=cli.stage_context(tmp_path)) tm.ok(result) pipeline = result.value - tm.ok(pipeline) + tm.that(pipeline.success, eq=True) tm.that(pipeline.stages[0].status, eq=c.Cli.PipelineStageStatus.SKIPPED) diff --git a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_02.py b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_02.py index f8ac095f1..df0d91f2d 100644 --- a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_02.py +++ b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_02.py @@ -46,23 +46,24 @@ def test_cycle_detection(self, tmp_path: Path) -> None: def test_retry_on_failure(self, tmp_path: Path) -> None: """Stage retries up to retry count before succeeding.""" call_count = 0 + expected_attempts = 3 def flaky( - ctx: p.Cli.PipelineStageContext, + _ctx: p.Cli.PipelineStageContext, ) -> p.Result[m.Cli.PipelineStageResult]: nonlocal call_count call_count += 1 - if call_count < 3: + if call_count < expected_attempts: return r[m.Cli.PipelineStageResult].fail("transient") return r[m.Cli.PipelineStageResult].ok( cli.stage_result("flaky", status=c.Cli.PipelineStageStatus.OK) ) - stages = [cli.stage("flaky", handler=flaky, retry=3)] + stages = [cli.stage("flaky", handler=flaky, retry=expected_attempts)] result = cli.pipeline(stages, context=cli.stage_context(tmp_path)) tm.ok(result) - tm.ok(result.value) - tm.that(call_count, eq=3) + tm.that(result.value.success, eq=True) + tm.that(call_count, eq=expected_attempts) def test_retry_on_safe_exception_marks_stage_failed(self, tmp_path: Path) -> None: """Safe stage exceptions are retried and end as failed stage results.""" @@ -83,17 +84,18 @@ def exploding( ) tm.ok(result) - tm.fail(result.value) + tm.that(result.value.success, eq=False) tm.that(call_count, eq=2) - assert ( - result.value.failed_stages[0].error == f"stage boom raised: {error_message}" + tm.that( + result.value.failed_stages[0].error, + eq=f"stage boom raised: {error_message}", ) def test_empty_pipeline(self, tmp_path: Path) -> None: """Empty pipeline returns ok with no stages.""" result = cli.pipeline([], context=cli.stage_context(tmp_path)) tm.ok(result) - tm.ok(result.value) + tm.that(result.value.success, eq=True) tm.that(len(result.value.stages), eq=0) def test_total_duration_tracked(self, tmp_path: Path) -> None: @@ -101,7 +103,7 @@ def test_total_duration_tracked(self, tmp_path: Path) -> None: stages = [cli.stage("a", handler=self._ok_handler("a"))] result = cli.pipeline(stages, context=cli.stage_context(tmp_path)) tm.ok(result) - assert result.value.total_duration_ms >= 0.0 + tm.that(result.value.total_duration_ms, gte=0.0) __all__: list[str] = ["TestsFlextCliPipeline"] diff --git a/tests/unit/_cases/test_prompts/testsflextcliprompts_part_01.py b/tests/unit/_cases/test_prompts/testsflextcliprompts_part_01.py index ad86083a4..6022d5492 100644 --- a/tests/unit/_cases/test_prompts/testsflextcliprompts_part_01.py +++ b/tests/unit/_cases/test_prompts/testsflextcliprompts_part_01.py @@ -5,6 +5,7 @@ from typing import TYPE_CHECKING import pytest +from flext_cli import m from flext_tests import tm from tests import c @@ -20,25 +21,30 @@ class TestsFlextCliPrompts: def test_execute_success( self, make_prompts: Callable[..., p.Tests.ScriptedPrompts] ) -> None: + """Return the canonical runtime status in non-interactive mode.""" prompts = make_prompts(interactive_mode=False) result = prompts.execute() - tm.ok(result) - tm.that(result.value[c.Cli.DICT_KEY_STATUS], eq=c.Cli.ServiceStatus.OPERATIONAL) - tm.that(result.value[c.Cli.DICT_KEY_SERVICE], eq=c.Cli.FLEXT_CLI) + tm.ok(result, is_=m.Cli.RuntimeStatus) + status = result.value + tm.that(status.status, eq=c.Cli.ServiceStatus.OPERATIONAL) + tm.that(status.service, eq=c.Cli.FLEXT_CLI) def test_execute_uses_public_cmd_status_even_when_prompt_logger_would_fail( self, make_failing_prompts: Callable[..., p.Tests.FailingLogPrompts] ) -> None: + """Return public runtime status independently of prompt logging.""" prompts = make_failing_prompts(interactive_mode=False) prompts.fail_on_log(level=c.LogLevel.DEBUG, message="Execute error") result = prompts.execute() - tm.ok(result) - tm.that(result.value[c.Cli.DICT_KEY_STATUS], eq=c.Cli.ServiceStatus.OPERATIONAL) - tm.that(result.value[c.Cli.DICT_KEY_SERVICE], eq=c.Cli.FLEXT_CLI) + tm.ok(result, is_=m.Cli.RuntimeStatus) + status = result.value + tm.that(status.status, eq=c.Cli.ServiceStatus.OPERATIONAL) + tm.that(status.service, eq=c.Cli.FLEXT_CLI) def test_prompt_returns_default_in_quiet_and_non_interactive_modes( self, make_prompts: Callable[..., p.Tests.ScriptedPrompts] ) -> None: + """Return configured defaults when prompting cannot be interactive.""" quiet_prompts = make_prompts(quiet=True) tm.that( quiet_prompts.prompt("Enter value", default="default").value, eq="default" @@ -52,6 +58,7 @@ def test_prompt_returns_default_in_quiet_and_non_interactive_modes( def test_prompt_reads_input_and_uses_default_for_empty_text( self, make_prompts: Callable[..., p.Tests.ScriptedPrompts] ) -> None: + """Normalize entered text and use the default for empty input.""" prompts = make_prompts().use_input_values([" typed ", ""]) typed_result = prompts.prompt("Enter value") tm.ok(typed_result) @@ -63,6 +70,7 @@ def test_prompt_reads_input_and_uses_default_for_empty_text( def test_prompt_handles_input_failure( self, make_prompts: Callable[..., p.Tests.ScriptedPrompts] ) -> None: + """Expose input failures through the public result contract.""" prompts = make_prompts().use_input_error(ValueError("Input error")) result = prompts.prompt("Enter value") tm.fail(result, has="Input error") @@ -70,6 +78,7 @@ def test_prompt_handles_input_failure( def test_confirm_returns_defaults_when_not_interactive( self, make_prompts: Callable[..., p.Tests.ScriptedPrompts] ) -> None: + """Return confirmation defaults outside interactive mode.""" quiet_prompts = make_prompts(quiet=True) tm.that(quiet_prompts.confirm("Continue?", default=True).value, eq=True) non_interactive_prompts = make_prompts(interactive_mode=False) @@ -80,6 +89,7 @@ def test_confirm_returns_defaults_when_not_interactive( def test_confirm_accepts_yes_no_default_and_invalid_retry( self, make_capture_prompts: Callable[..., p.Tests.CaptureLogPrompts] ) -> None: + """Accept confirmation variants and retry after invalid input.""" prompts = make_capture_prompts() prompts.use_input_values(["", "y", "n", "maybe", "yes"]) tm.that(prompts.confirm("Continue?", default=True).value, eq=True) @@ -105,6 +115,7 @@ def test_confirm_handles_failures( error: Exception, expected: str, ) -> None: + """Map confirmation boundary failures to public error messages.""" prompts = make_prompts().use_input_error(error) result = prompts.confirm("Continue?", default=False) tm.fail(result, has=expected) diff --git a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_01.py b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_01.py index 6ecebe059..f4dec31d8 100644 --- a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_01.py +++ b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_01.py @@ -28,6 +28,7 @@ class _CommandSource(m.BaseModel): debug: bool | None = None def test_public_facade_and_settings_contract(self) -> None: + """Expose settings behavior and typed runtime status through public facades.""" # NOTE (multi-agent): flat cli_* settings (§2.6) — fresh instances come # from ``settings.clone()`` and test-runtime detection lives in # ``u.Cli.cli_test_env`` (behavior moved off the settings model). @@ -52,19 +53,17 @@ def test_public_facade_and_settings_contract(self) -> None: FlextCliSettings.reset_for_testing() - facade_result = cli.execute() + result = cli.execute() + tm.ok(result, is_=m.Cli.RuntimeStatus) + status = result.value - tm.ok(facade_result) - tm.that( - facade_result.value[c.Cli.DICT_KEY_STATUS], - eq=(c.Cli.ServiceStatus.OPERATIONAL), - ) - tm.that(facade_result.value[c.Cli.DICT_KEY_SERVICE], eq=c.Cli.FLEXT_CLI) - components = facade_result.value.get("components") - tm.that(components, is_=dict) - tm.that(components["prompts"], eq="available") + tm.that(status.status, eq=c.Cli.ServiceStatus.OPERATIONAL) + tm.that(status.service, eq=c.Cli.FLEXT_CLI) + tm.that(status.components, is_=m.Cli.RuntimeComponents) + tm.that(status.components.prompts, eq="available") def test_public_model_command_utility_contract(self) -> None: + """Build and execute model commands through the public utility contract.""" command_settings = self._CommandModel(label="configured", debug=True) def handler(model: TestsFlextCliPublicContractsCoverage._CommandModel) -> str: @@ -78,7 +77,7 @@ def handler(model: TestsFlextCliPublicContractsCoverage._CommandModel) -> str: # NOTE (multi-agent): ``u.Cli.build_model_command`` renders model-field # defaults into the signature; settings-seeded defaults are the # ``cli.model_command`` contract, not this utility's. - assert signature.parameters["label"].default is inspect.Parameter.empty + tm.that(signature.parameters["label"].default, eq=inspect.Parameter.empty) tm.that(signature.parameters["debug"].default, eq=False) tm.that( u.Cli.model_source_data( diff --git a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_03.py b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_03.py index cffb559b0..cd9d1a9ce 100644 --- a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_03.py +++ b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_03.py @@ -18,6 +18,7 @@ class TestsFlextCliPublicContractsCoverage: """Implementation part for TestsFlextCliPublicContractsCoverage.""" def test_public_pipeline_model_contracts(self, tmp_path: Path) -> None: + """Exercise the public pipeline models and service contract.""" context = cli.stage_context(tmp_path, settings={"mode": "test"}) def stage_handler( @@ -56,7 +57,7 @@ def stage_handler( tm.ok(stage_result) tm.that(stage_result.value.output, eq={"workspace": str(tmp_path)}) tm.ok(pipeline_run) - tm.ok(pipeline_run.value) + tm.that(pipeline_run.value.success, eq=True) __all__: list[str] = ["TestsFlextCliPublicContractsCoverage"] diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py index 4e2847168..90028d25e 100644 --- a/tests/unit/conftest.py +++ b/tests/unit/conftest.py @@ -5,7 +5,6 @@ from typing import TYPE_CHECKING, Self, override import pytest -from flext_tests import reset_settings from flext_cli import FlextCliSettings from flext_cli.services.prompts import FlextCliPrompts @@ -20,16 +19,20 @@ class TestsFlextCliScriptedPrompts(FlextCliPrompts): """Prompt service with typed scripting helpers for tests.""" - def override_test_env(self, enabled: bool | None = True) -> Self: + def override_test_env(self, *, enabled: bool | None = True) -> Self: + """Select the explicit test-environment override.""" self._test_env_override = enabled return self def use_input_values(self, values: t.StrSequence) -> Self: + """Script successive prompt input values.""" values_iter = iter(values) self._input_reader = lambda _prompt: next(values_iter) return self def use_input_error(self, error: Exception) -> Self: + """Script an input-reader failure.""" + def raise_input(_prompt: str) -> str: raise error @@ -37,10 +40,13 @@ def raise_input(_prompt: str) -> str: return self def use_password(self, password: str) -> Self: + """Script a password response.""" self._password_reader = lambda _prompt: password return self def use_password_error(self, error: Exception) -> Self: + """Script a password-reader failure.""" + def raise_password(_prompt: str) -> str: raise error @@ -48,6 +54,7 @@ def raise_password(_prompt: str) -> str: return self def configure_state(self, *, interactive: bool = True, quiet: bool = False) -> Self: + """Configure the observable prompt runtime state.""" self.configure(m.Cli.PromptRuntimeState(interactive=interactive, quiet=quiet)) return self @@ -59,6 +66,7 @@ class TestsFlextCliCaptureLogPrompts(TestsFlextCliScriptedPrompts): @property def records(self) -> list[tuple[str, str]]: + """Captured log-level and message pairs.""" return self._records @override @@ -73,6 +81,7 @@ class TestsFlextCliFailingLogPrompts(TestsFlextCliScriptedPrompts): _failure_message: str = m.PrivateAttr(default_factory=lambda: "logger failure") def fail_on_log(self, *, level: str, message: str) -> Self: + """Select the log call that raises the scripted failure.""" self._failure_level = level self._failure_message = message return self @@ -134,5 +143,4 @@ def pytest_runtest_teardown(item: pytest.Item, nextitem: pytest.Item | None) -> "make_capture_prompts", "make_failing_prompts", "make_prompts", - "reset_settings", ] diff --git a/tests/unit/test_cli_params.py b/tests/unit/test_cli_params.py index a5ac97cdd..e0881d2a1 100644 --- a/tests/unit/test_cli_params.py +++ b/tests/unit/test_cli_params.py @@ -16,7 +16,6 @@ from flext_cli import cli from tests import c from tests import p -from tests import t from tests import u @@ -128,54 +127,51 @@ def test_apply_to_config_rejects_invalid_enum_value( # ── decorator wiring: observable CLI behavior ──────────────────── @pytest.fixture - def runner_and_app(self) -> tuple[t.Cli.TyperRunner, t.Cli.CliApp]: - """Build a CLI runner plus an app carrying the common-params decorated command.""" + def app(self) -> p.Cli.Application: + """Build an app carrying the common-params decorated command.""" app_result = u.Tests.create_cli_app() tm.ok(app_result) app = app_result.value tm.ok(u.Tests.create_decorated_command(app, "test")) - runner_result = cli.create_cli_runner() - tm.ok(runner_result) - return runner_result.value, app + return app - def test_help_exposes_common_options( - self, runner_and_app: tuple[t.Cli.TyperRunner, t.Cli.CliApp] - ) -> None: + def test_help_exposes_common_options(self, app: p.Cli.Application) -> None: """--help lists every common parameter the decorator promises to add.""" - runner, app = runner_and_app - result = runner.invoke(app, ["test", "--help"]) + result = cli.invoke_app(app, args=("test", "--help")) + tm.ok(result) + invocation = result.value - tm.that(result.exit_code, eq=0) + tm.that(invocation.exit_code, eq=0) for flag in ("--verbose", "--debug", "--log-level", "--output-format"): - tm.that(result.stdout, has=flag) + tm.that(invocation.stdout, has=flag) def test_boolean_flags_toggle_command_behavior( - self, runner_and_app: tuple[t.Cli.TyperRunner, t.Cli.CliApp] + self, app: p.Cli.Application ) -> None: """Passing --verbose/--debug flips the command's observable output.""" - runner, app = runner_and_app - result = runner.invoke(app, ["test", "--verbose", "--debug"]) + result = cli.invoke_app(app, args=("test", "--verbose", "--debug")) + tm.ok(result) + invocation = result.value - tm.that(result.exit_code, eq=0) - tm.that(result.stdout, has="Verbose: enabled") - tm.that(result.stdout, has="Debug: enabled") + tm.that(invocation.exit_code, eq=0) + tm.that(invocation.stdout, has="Verbose: enabled") + tm.that(invocation.stdout, has="Debug: enabled") - def test_value_parameters_flow_to_command( - self, runner_and_app: tuple[t.Cli.TyperRunner, t.Cli.CliApp] - ) -> None: + def test_value_parameters_flow_to_command(self, app: p.Cli.Application) -> None: """Choice-valued options are parsed and surfaced in command output.""" - runner, app = runner_and_app - result = runner.invoke( + result = cli.invoke_app( app, - [ + args=( "test", "--log-level", c.LogLevel.WARNING, "--output-format", c.Cli.OutputFormats.JSON, - ], + ), ) + tm.ok(result) + invocation = result.value - tm.that(result.exit_code, eq=0) - tm.that(result.stdout, has="Log level: WARNING") - tm.that(result.stdout, has="Output format: json") + tm.that(invocation.exit_code, eq=0) + tm.that(invocation.stdout, has="Log level: WARNING") + tm.that(invocation.stdout, has="Output format: json") diff --git a/tests/unit/test_cmd.py b/tests/unit/test_cmd.py index aac705b40..81a82c837 100644 --- a/tests/unit/test_cmd.py +++ b/tests/unit/test_cmd.py @@ -40,26 +40,33 @@ def test_cli_satisfies_cmd_service_contract(self) -> None: def test_execute_reports_operational_runtime_payload(self) -> None: """execute() must succeed and expose the canonical status payload.""" - data = tm.ok(cli.execute(), is_=dict) + result = cli.execute() + tm.ok(result, is_=m.Cli.RuntimeStatus) + status = result.value tm.that( - data, - kv={ - c.Cli.DICT_KEY_STATUS: c.Cli.ServiceStatus.OPERATIONAL, - c.Cli.DICT_KEY_SERVICE: c.Cli.FLEXT_CLI, + status, + attr_eq={ + "status": c.Cli.ServiceStatus.OPERATIONAL, + "service": c.Cli.FLEXT_CLI, "version": c.Cli.CLI_VERSION, }, - keys=("timestamp", "components"), ) + tm.that(status.timestamp, is_=str) + tm.that(status.components, is_=m.Cli.RuntimeComponents) def test_execute_is_deterministic_across_calls(self) -> None: """Repeated execute() calls must report identical stable identity fields.""" - first = tm.ok(cli.execute()) - second = tm.ok(cli.execute()) + first_result = cli.execute() + second_result = cli.execute() + tm.ok(first_result, is_=m.Cli.RuntimeStatus) + tm.ok(second_result, is_=m.Cli.RuntimeStatus) + first = first_result.value + second = second_result.value - tm.that(first[c.Cli.DICT_KEY_STATUS], eq=second[c.Cli.DICT_KEY_STATUS]) - tm.that(first[c.Cli.DICT_KEY_SERVICE], eq=second[c.Cli.DICT_KEY_SERVICE]) - tm.that(first["version"], eq=second["version"]) + tm.that(first.status, eq=second.status) + tm.that(first.service, eq=second.service) + tm.that(first.version, eq=second.version) def test_settings_snapshot_reports_absent_home_state( self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch @@ -67,7 +74,9 @@ def test_settings_snapshot_reports_absent_home_state( """A missing settings dir must yield a fully-negative snapshot.""" monkeypatch.setenv("HOME", str(tmp_path)) - info = tm.ok(cli.settings_snapshot()) + result = cli.settings_snapshot() + tm.ok(result) + info = result.value tm.that( info, @@ -87,7 +96,9 @@ def test_settings_snapshot_reports_present_home_state( settings_dir.mkdir() monkeypatch.setenv("HOME", str(tmp_path)) - info = tm.ok(cli.settings_snapshot()) + result = cli.settings_snapshot() + tm.ok(result) + info = result.value tm.that( info, @@ -105,7 +116,9 @@ def test_settings_snapshot_timestamp_is_iso8601( """The snapshot timestamp must be a parseable ISO-8601 instant.""" monkeypatch.setenv("HOME", str(tmp_path)) - info = tm.ok(cli.settings_snapshot()) + result = cli.settings_snapshot() + tm.ok(result) + info = result.value parsed = datetime.fromisoformat(info.timestamp) tm.that(parsed, is_=datetime) @@ -148,8 +161,12 @@ def test_show_settings_reflects_snapshot_presence( (tmp_path / c.Cli.PATH_FLEXT_DIR_NAME).mkdir() monkeypatch.setenv("HOME", str(tmp_path)) - displayed = tm.ok(cli.show_settings()) - snapshot = tm.ok(cli.settings_snapshot()) + displayed_result = cli.show_settings() + snapshot_result = cli.settings_snapshot() + tm.ok(displayed_result) + tm.ok(snapshot_result) + displayed = displayed_result.value + snapshot = snapshot_result.value tm.that(displayed, eq=True) tm.that(snapshot.settings_exists, eq=True) diff --git a/tests/unit/test_formatters_cov.py b/tests/unit/test_formatters_cov.py index caabb3ac4..cf0868fe7 100644 --- a/tests/unit/test_formatters_cov.py +++ b/tests/unit/test_formatters_cov.py @@ -1,10 +1,9 @@ """Behavioral tests for the CLI formatters public contract. Exercises the observable behavior promised by ``FlextCli`` formatter methods -(``create_tree``/``print``/``render_rule``/``render_panel``/``render_table``), -which delegate through ``FlextCliFormatters`` and ``FlextCliUtilitiesFormatters``: +(``print``/``render_rule``/``render_panel``/``render_table``), which delegate +through ``FlextCliFormatters`` and ``FlextCliUtilitiesFormatters``: -- ``create_tree`` returns ``r[RichTree]`` whose value carries the given label. - ``print``/``render_rule``/``render_panel``/``render_table`` render their content to the console (observable on stdout). @@ -17,7 +16,6 @@ from typing import TYPE_CHECKING import pytest -from rich.tree import Tree as RichTree from flext_cli import cli from tests import c @@ -30,44 +28,13 @@ class TestsFlextCliFormattersCov: """Behavioral tests for the public CLI formatter contract.""" - # ── create_tree: fallible contract (r[RichTree]) ───────────────── - - @pytest.mark.parametrize("label", c.Tests.FORMATTER_TREE_LABELS) - def test_create_tree_succeeds_and_preserves_label(self, label: str) -> None: - result = cli.create_tree(label) - - tm.ok(result) - tree = result.unwrap() - tm.that(tree, is_=RichTree) - tm.that(tree.label, eq=label) - - def test_create_tree_value_matches_unwrap(self) -> None: - result = cli.create_tree("Root") - - tm.ok(result) - assert result.value is result.unwrap() - - def test_create_tree_result_maps_to_label(self) -> None: - # r[T] monadic contract: map projects the success value. - mapped = cli.create_tree("Branch").map(lambda tree: tree.label) - - tm.ok(mapped) - tm.that(mapped.unwrap(), eq="Branch") - - def test_create_tree_children_can_be_attached(self) -> None: - # Public Rich Tree contract: the returned root accepts children. - root = cli.create_tree("Root").unwrap() - child = root.add("Leaf") - - tm.that(child.label, eq="Leaf") - assert root.children[0] is child - # ── print: message rendered to stdout ──────────────────────────── @pytest.mark.parametrize(("msg", "style"), c.Tests.FORMATTERS_PRINT_CASES) def test_print_renders_message_to_stdout( self, capsys: pytest.CaptureFixture[str], msg: str, style: str | None ) -> None: + """Render each message and optional style to standard output.""" if style is not None: cli.print(msg, style) else: @@ -82,6 +49,7 @@ def test_print_renders_message_to_stdout( def test_render_rule_renders_label_to_stdout( self, capsys: pytest.CaptureFixture[str], label: str ) -> None: + """Render a visible horizontal rule carrying the supplied label.""" cli.render_rule(label) out = capsys.readouterr().out @@ -95,6 +63,7 @@ def test_render_rule_renders_label_to_stdout( def test_render_panel_renders_content_to_stdout( self, capsys: pytest.CaptureFixture[str], content: str, title: str ) -> None: + """Render panel content and its title through the public facade.""" cli.render_panel(content, title=title) out = capsys.readouterr().out @@ -112,6 +81,7 @@ def test_render_table_renders_columns_and_cells( rows: tuple[t.StrSequence, ...], title: str, ) -> None: + """Render every declared column and cell through the public facade.""" cli.render_table( columns=list(columns), rows=[list(row) for row in rows], title=title ) diff --git a/tests/unit/test_json_cov.py b/tests/unit/test_json_cov.py index 07a5a299e..d9e2b1249 100644 --- a/tests/unit/test_json_cov.py +++ b/tests/unit/test_json_cov.py @@ -21,20 +21,23 @@ class TestsFlextCliJsonCov: # ----- normalize ------------------------------------------------------- def test_normalize_json_value_preserves_mapping(self) -> None: + """Preserve a JSON-compatible mapping during normalization.""" tm.that(u.Cli.normalize_json_value({"key": "value"}), eq={"key": "value"}) # ----- json_read (fallible, r[JsonMapping]) ---------------------------- - def test_json_read_missing_file_succeeds_with_empty_mapping( - self, tmp_path: Path - ) -> None: - result = u.Cli.json_read(tmp_path / "missing.json") - tm.ok(result) - tm.that(result.value, eq={}) + def test_json_read_missing_file_fails_loudly(self, tmp_path: Path) -> None: + """Reject a missing JSON file with its path in the public error.""" + missing = tmp_path / "missing.json" + result = u.Cli.json_read(missing) + tm.fail(result) + tm.that(result.error, has="file not found") + tm.that(result.error, has=str(missing)) def test_json_read_valid_object_returns_parsed_mapping( self, tmp_path: Path ) -> None: + """Return a parsed mapping for a valid JSON object file.""" path = tmp_path / "data.json" path.write_text('{"key": "value"}', encoding="utf-8") result = u.Cli.json_read(path) @@ -42,22 +45,24 @@ def test_json_read_valid_object_returns_parsed_mapping( tm.that(result.value, eq={"key": "value"}) @pytest.mark.parametrize( - ("content", "reason"), - [("not json!!", "malformed json"), ("[1, 2, 3]", "non-object root")], + ("content", "expected_error"), + [("not json!!", "json_read"), ("[1, 2, 3]", "root must be an object")], ) def test_json_read_rejects_invalid_content( - self, tmp_path: Path, content: str, reason: str + self, tmp_path: Path, content: str, expected_error: str ) -> None: + """Reject malformed JSON and non-object roots with context.""" path = tmp_path / "bad.json" path.write_text(content, encoding="utf-8") result = u.Cli.json_read(path) tm.fail(result) tm.that(result.error, none=False) - tm.that(result.error, has="json_read") + tm.that(result.error, has=expected_error) # ----- json_write roundtrip / options ---------------------------------- def test_json_write_then_read_roundtrips_payload(self, tmp_path: Path) -> None: + """Round-trip a mapping through the public file helpers.""" path = tmp_path / "out.json" write_result = u.Cli.json_write(path, {"a": 1, "b": [1, 2]}) tm.ok(write_result) @@ -66,6 +71,7 @@ def test_json_write_then_read_roundtrips_payload(self, tmp_path: Path) -> None: tm.that(read_result.value, eq={"a": 1, "b": [1, 2]}) def test_json_write_sort_keys_orders_nested_keys(self, tmp_path: Path) -> None: + """Sort keys recursively when the write option is enabled.""" path = tmp_path / "sorted.json" payload: t.JsonPayload = { "z": t.Cli.JSON_MAPPING_ADAPTER.validate_python({"b": 2, "a": 1}), @@ -89,6 +95,7 @@ def test_json_write_sort_keys_orders_nested_keys(self, tmp_path: Path) -> None: def test_json_write_serializes_pydantic_model_as_object( self, tmp_path: Path ) -> None: + """Serialize a Pydantic model as a JSON object.""" path = tmp_path / "model.json" result = u.Cli.json_write(path, m.Cli.TableConfig()) tm.ok(result) @@ -99,10 +106,12 @@ def test_json_write_serializes_pydantic_model_as_object( # ----- json_parse (fallible) ------------------------------------------- def test_json_parse_valid_text_succeeds(self) -> None: + """Parse valid JSON text successfully.""" result = u.Cli.json_parse('{"x": 1}') tm.ok(result) def test_json_parse_invalid_text_fails(self) -> None: + """Reject malformed JSON text.""" result = u.Cli.json_parse("not json") tm.fail(result) tm.that(result.error, none=False) @@ -115,6 +124,7 @@ def test_json_parse_invalid_text_fails(self) -> None: def test_json_as_mapping_coerces_to_mapping_or_empty( self, value: t.JsonValue | None, expected: t.JsonMapping ) -> None: + """Coerce mapping values and return empty for other shapes.""" tm.that(u.Cli.json_as_mapping(value), eq=expected) @pytest.mark.parametrize( @@ -123,6 +133,7 @@ def test_json_as_mapping_coerces_to_mapping_or_empty( def test_json_as_sequence_coerces_to_list_or_empty( self, value: t.JsonValue | None, expected: list[t.JsonValue] ) -> None: + """Coerce sequence values and return empty for other shapes.""" tm.that(list(u.Cli.json_as_sequence(value)), eq=expected) @pytest.mark.parametrize( @@ -131,11 +142,13 @@ def test_json_as_sequence_coerces_to_list_or_empty( def test_json_as_mapping_list_filters_to_mappings( self, value: t.JsonValue | None, expected_len: int ) -> None: + """Retain only mappings from a JSON sequence.""" tm.that(len(u.Cli.json_as_mapping_list(value)), eq=expected_len) # ----- json_walk_path -------------------------------------------------- def test_json_walk_path_returns_leaf_for_existing_path(self) -> None: + """Return the leaf value for an existing mapping path.""" data = u.Cli.json_as_mapping(u.Cli.json_loads('{"a": {"b": {"c": 42}}}').value) tm.that(u.Cli.json_walk_path(data, ("a", "b", "c")), eq=42) @@ -145,21 +158,25 @@ def test_json_walk_path_returns_leaf_for_existing_path(self) -> None: def test_json_walk_path_returns_none_when_unreachable( self, keys: tuple[str, ...], raw: str ) -> None: + """Return none when a mapping path cannot be traversed.""" data = u.Cli.json_as_mapping(u.Cli.json_loads(raw).value) tm.that(u.Cli.json_walk_path(data, keys), none=True) # ----- deep mapping helpers -------------------------------------------- def test_json_deep_mapping_descends_into_nested_object(self) -> None: + """Return a nested mapping reached by successive keys.""" data = u.Cli.json_as_mapping( u.Cli.json_loads('{"outer": {"inner": {"x": 1}}}').value ) tm.that(u.Cli.json_deep_mapping(data, "outer", "inner"), eq={"x": 1}) def test_json_deep_mapping_without_keys_returns_same_mapping(self) -> None: + """Return the original mapping when no keys are supplied.""" tm.that(u.Cli.json_deep_mapping({"a": 1}), eq={"a": 1}) def test_json_deep_mapping_list_returns_nested_list(self) -> None: + """Return nested mapping items from a sequence field.""" data = u.Cli.json_as_mapping( u.Cli.json_loads('{"items": [{"a": 1}, {"b": 2}]}').value ) @@ -168,6 +185,7 @@ def test_json_deep_mapping_list_returns_nested_list(self) -> None: # ----- typed pickers --------------------------------------------------- def test_json_pick_str_trims_and_falls_back(self) -> None: + """Trim string values and use the explicit default when absent.""" tm.that(u.Cli.json_pick_str({"k": " val "}, "k"), eq="val") tm.that(u.Cli.json_pick_str({}, "k", default="default"), eq="default") tm.that(u.Cli.json_pick_str({"k": None}, "k", default="fb"), eq="fb") @@ -179,6 +197,7 @@ def test_json_pick_str_trims_and_falls_back(self) -> None: def test_json_pick_int_coerces_scalar_variants( self, key: str, expected: int ) -> None: + """Coerce supported scalar variants to integers.""" data = u.Cli.json_as_mapping( u.Cli.json_loads( '{"n": 5, "s": "7", "f": 3.9, "b": true, "none": null, "bad": []}' @@ -204,8 +223,9 @@ def test_json_pick_int_coerces_scalar_variants( ], ) def test_json_pick_bool_coerces_truthy_variants( - self, key: str, expected: bool + self, key: str, *, expected: bool ) -> None: + """Coerce supported scalar variants to booleans.""" data = u.Cli.json_as_mapping( u.Cli.json_loads( '{"t": true, "f": false, "s_true": "true", "s_false": "false",' @@ -213,18 +233,21 @@ def test_json_pick_bool_coerces_truthy_variants( ' "s_on": "on", "s_off": "off", "n": 1, "n0": 0, "missing": null}' ).value ) - assert u.Cli.json_pick_bool(data, key) is expected + tm.that(u.Cli.json_pick_bool(data, key), eq=expected) def test_json_pick_bool_uses_default_for_missing_key(self) -> None: + """Use the explicit boolean default for a missing value.""" data = u.Cli.json_as_mapping(u.Cli.json_loads('{"missing": null}').value) tm.that(u.Cli.json_pick_bool(data, "missing", default=True), eq=True) def test_json_nested_int_reads_nested_value_or_default(self) -> None: + """Read a nested integer or use the explicit default.""" data = u.Cli.json_as_mapping(u.Cli.json_loads('{"a": {"b": 42}}').value) tm.that(u.Cli.json_nested_int(data, "a", "b"), eq=42) tm.that(u.Cli.json_nested_int(data, "a", "missing", default=99), eq=99) def test_json_get_str_key_trims_value(self) -> None: + """Return a trimmed string from a mapping key.""" tm.that(u.Cli.json_get_str_key({"name": " Hello "}, "name"), eq="Hello") diff --git a/tests/unit/test_options_cov.py b/tests/unit/test_options_cov.py index 03a67ac42..d7bc8292c 100644 --- a/tests/unit/test_options_cov.py +++ b/tests/unit/test_options_cov.py @@ -23,64 +23,64 @@ from flext_cli import cli, m from tests import c -from tests import p from tests import t +from tests import u from flext_tests import tm class TestsFlextCliOptionsUtilsCov: """Behavioral coverage for ``cli.model_command`` public behavior.""" - class StringAnnotationModel(m.BaseModel): + class _StringAnnotationModel(m.BaseModel): value: str - class OptionalStringAnnotationModel(m.BaseModel): + class _OptionalStringAnnotationModel(m.BaseModel): value: t.Tests.OptionalStringAlias - class UnionAnnotationModel(m.BaseModel): + class _UnionAnnotationModel(m.BaseModel): value: str | int - class ListAnnotationModel(m.BaseModel): + class _ListAnnotationModel(m.BaseModel): value: list[str] - class TupleAnnotationModel(m.BaseModel): + class _TupleAnnotationModel(m.BaseModel): value: t.StrSequence - class SetAnnotationModel(m.BaseModel): + class _SetAnnotationModel(m.BaseModel): value: set[str] - class FrozenSetAnnotationModel(m.BaseModel): + class _FrozenSetAnnotationModel(m.BaseModel): value: frozenset[str] - class DictAnnotationModel(m.BaseModel): + class _DictAnnotationModel(m.BaseModel): value: dict[str, int] - class AnnotatedStringModel(m.BaseModel): + class _AnnotatedStringModel(m.BaseModel): value: Annotated[str, "meta"] - class StringListAliasModel(m.BaseModel): + class _StringListAliasModel(m.BaseModel): value: t.Tests.StringListAlias - class AliasOptionsModel(m.BaseModel): + class _AliasOptionsModel(m.BaseModel): project_name: str = m.Field(..., alias="project", validate_default=True) - class CustomDeclModel(m.BaseModel): + class _CustomDeclModel(m.BaseModel): custom_name: str = m.Field( ..., json_schema_extra={"typer_param_decls": ["--custom-name", "--projects"]}, validate_default=True, ) - class BoolToggleModel(m.BaseModel): + class _BoolToggleModel(m.BaseModel): debug: bool = False - class GreetModel(m.BaseModel): + class _GreetModel(m.BaseModel): """Simple request model used to exercise command invocation.""" name: str shout: bool = False - class OptionsDefaultsModel(m.BaseModel): + class _OptionsDefaultsModel(m.BaseModel): """Model used to exercise field-default normalization paths.""" name: str = "default-name" @@ -94,99 +94,159 @@ class OptionsDefaultsModel(m.BaseModel): ) _ANNOTATION_CASES: ClassVar[ - tuple[tuple[t.Cli.ModelType[m.BaseModel], t.Cli.RuntimeAnnotation], ...] + tuple[tuple[t.ModelClass[m.BaseModel], t.Cli.RuntimeAnnotation], ...] ] = ( - (StringAnnotationModel, str), - (OptionalStringAnnotationModel, str), - (UnionAnnotationModel, str), - (ListAnnotationModel, list[str]), - (TupleAnnotationModel, list[str]), - (SetAnnotationModel, set), - (FrozenSetAnnotationModel, frozenset), - (DictAnnotationModel, dict), - (AnnotatedStringModel, str), - (StringListAliasModel, list[str]), + (_StringAnnotationModel, str), + (_OptionalStringAnnotationModel, str), + (_UnionAnnotationModel, str), + (_ListAnnotationModel, list[str]), + (_TupleAnnotationModel, list[str]), + (_SetAnnotationModel, set), + (_FrozenSetAnnotationModel, frozenset), + (_DictAnnotationModel, dict), + (_AnnotatedStringModel, str), + (_StringListAliasModel, list[str]), ) @staticmethod def _noop_handler(_params: t.Cli.ModelLike) -> bool: return True - @staticmethod - def _option_spec(command: t.Cli.CliCommand, param_name: str) -> p.Cli.CliOptionSpec: - """Return the public option spec the builder produced for a field.""" - spec = inspect.signature(command).parameters[param_name].default - tm.that(spec, is_=p.Cli.CliOptionSpec) - return spec - # ---- generated-command contract ------------------------------------- def test_model_command_uses_field_alias_as_option_name(self) -> None: - command = cli.model_command(self.AliasOptionsModel, self._noop_handler) - spec = self._option_spec(command, "project_name") - tm.that(spec.param_decls, none=False) - tm.that(spec.param_decls, has="--project") + """Accept a field alias through a real CLI invocation.""" + received: list[TestsFlextCliOptionsUtilsCov._AliasOptionsModel] = [] + + def _capture(params: TestsFlextCliOptionsUtilsCov._AliasOptionsModel) -> bool: + received.append(params) + return True + + app = cli.create_group(name="alias-options", help_text="Alias options") + cli.register_command( + app, + name="run", + help_text="Run alias options", + command=cli.model_command(self._AliasOptionsModel, _capture), + ) + result = cli.invoke_app(app, args=("--project", "flext")) + + tm.ok(result) + tm.that(result.value.exit_code, eq=0) + tm.that(received[0].project_name, eq="flext") def test_model_command_honors_custom_param_decls(self) -> None: - command = cli.model_command(self.CustomDeclModel, self._noop_handler) - spec = self._option_spec(command, "custom_name") - tm.that(spec.param_decls, none=False) - tm.that(spec.param_decls, has="--custom-name") - tm.that(spec.param_decls, has="--projects") + """Accept configured custom declarations through the public CLI.""" + received: list[TestsFlextCliOptionsUtilsCov._CustomDeclModel] = [] + + def _capture(params: TestsFlextCliOptionsUtilsCov._CustomDeclModel) -> bool: + received.append(params) + return True + + app = cli.create_group(name="custom-options", help_text="Custom options") + cli.register_command( + app, + name="run", + help_text="Run custom options", + command=cli.model_command(self._CustomDeclModel, _capture), + ) + result = cli.invoke_app(app, args=("--projects", "flext")) + + tm.ok(result) + tm.that(result.value.exit_code, eq=0) + tm.that(received[0].custom_name, eq="flext") def test_model_command_renders_bool_field_as_toggle_flag(self) -> None: - command = cli.model_command(self.BoolToggleModel, self._noop_handler) - spec = self._option_spec(command, "debug") - tm.that(spec.param_decls, eq=["--debug/--no-debug"]) + """Enable a boolean option through its generated positive flag.""" + received: list[TestsFlextCliOptionsUtilsCov._BoolToggleModel] = [] + + def _capture(params: TestsFlextCliOptionsUtilsCov._BoolToggleModel) -> bool: + received.append(params) + return True + + app = cli.create_group(name="bool-options", help_text="Boolean options") + cli.register_command( + app, + name="run", + help_text="Run boolean options", + command=cli.model_command(self._BoolToggleModel, _capture), + ) + result = cli.invoke_app(app, args=("--debug",)) + + tm.ok(result) + tm.that(result.value.exit_code, eq=0) + tm.that(received[0].debug, eq=True) @pytest.mark.parametrize(("model_cls", "expected"), _ANNOTATION_CASES) def test_model_command_normalizes_runtime_annotations( self, - model_cls: t.Cli.ModelType[t.Cli.ModelLike], + model_cls: t.ModelClass[t.Cli.ModelLike], expected: t.Cli.RuntimeAnnotation, ) -> None: + """Expose each supported field annotation in canonical runtime form.""" command = cli.model_command(model_cls, self._noop_handler) resolved = inspect.signature(command).parameters["value"].annotation tm.that(resolved, eq=expected) def test_model_command_marks_required_field_default_as_ellipsis(self) -> None: - command = cli.model_command(self.AliasOptionsModel, self._noop_handler) - spec = self._option_spec(command, "project_name") - assert spec.default is ... + """Reject a real invocation that omits a required model field.""" + app = cli.create_group(name="required-options", help_text="Required options") + cli.register_command( + app, + name="run", + help_text="Run required options", + command=cli.model_command(self._AliasOptionsModel, self._noop_handler), + ) + + result = cli.invoke_app(app, args=()) + + tm.ok(result) + tm.that(result.value.exit_code, eq=2) def test_field_default_prefers_settings_value_over_model_default(self) -> None: - settings = self.OptionsDefaultsModel(name="override-name") - command = cli.model_command( - self.OptionsDefaultsModel, self._noop_handler, settings=settings + """Prefer the validated settings value over field metadata.""" + settings = self._OptionsDefaultsModel(name="override-name") + default = u.Cli.field_default( + "name", self._OptionsDefaultsModel.model_fields["name"], settings ) - spec = self._option_spec(command, "name") - tm.that(spec.default, eq="override-name") + tm.that(default, eq="override-name") def test_field_default_normalizes_sequence_default_to_tuple(self) -> None: - command = cli.model_command(self.OptionsDefaultsModel, self._noop_handler) - spec = self._option_spec(command, "generated") - tm.that(spec.default, eq=("gen", "value")) + """Normalize a generated sequence default to an immutable tuple.""" + default = u.Cli.field_default( + "generated", self._OptionsDefaultsModel.model_fields["generated"], None + ) + tm.that(default, eq=("gen", "value")) def test_field_default_preserves_normalizable_mapping(self) -> None: - command = cli.model_command(self.OptionsDefaultsModel, self._noop_handler) - spec = self._option_spec(command, "valid_mapping") - tm.that(spec.default, eq=dict(c.Tests.OPTIONS_FIELD_DEFAULT_VALID_MAPPING)) + """Preserve a mapping containing only supported CLI atoms.""" + default = u.Cli.field_default( + "valid_mapping", + self._OptionsDefaultsModel.model_fields["valid_mapping"], + None, + ) + tm.that(default, eq=dict(c.Tests.OPTIONS_FIELD_DEFAULT_VALID_MAPPING)) def test_field_default_drops_non_normalizable_mapping_to_none(self) -> None: - command = cli.model_command(self.OptionsDefaultsModel, self._noop_handler) - spec = self._option_spec(command, "invalid_mapping") - tm.that(spec.default, none=True) + """Reject a mapping containing values unsupported by the CLI.""" + default = u.Cli.field_default( + "invalid_mapping", + self._OptionsDefaultsModel.model_fields["invalid_mapping"], + None, + ) + tm.that(default, none=True) # ---- end-to-end command invocation ---------------------------------- def test_invoking_command_passes_validated_model_to_handler(self) -> None: - received: dict[str, TestsFlextCliOptionsUtilsCov.GreetModel] = {} + """Pass one validated request model to the registered handler.""" + received: dict[str, TestsFlextCliOptionsUtilsCov._GreetModel] = {} - def _capture(params: TestsFlextCliOptionsUtilsCov.GreetModel) -> str: + def _capture(params: TestsFlextCliOptionsUtilsCov._GreetModel) -> str: received["model"] = params return f"handled:{params.name}" - command = cli.model_command(self.GreetModel, _capture) + command = cli.model_command(self._GreetModel, _capture) result = command(name="ada", shout=True) tm.that(result, eq="handled:ada") @@ -194,34 +254,38 @@ def _capture(params: TestsFlextCliOptionsUtilsCov.GreetModel) -> str: tm.that(received["model"].shout, eq=True) def test_invoking_command_coerces_raw_values_through_model_validation(self) -> None: - def _handler(params: TestsFlextCliOptionsUtilsCov.GreetModel) -> bool: + """Validate raw command values before the handler receives them.""" + + def _handler(params: TestsFlextCliOptionsUtilsCov._GreetModel) -> bool: return params.shout - command = cli.model_command(self.GreetModel, _handler) + command = cli.model_command(self._GreetModel, _handler) result = command(name="grace", shout="true") tm.that(result, eq=True) def test_invoking_command_rejects_missing_required_field(self) -> None: - command = cli.model_command(self.GreetModel, self._noop_handler) + """Reject direct calls missing a required request field.""" + command = cli.model_command(self._GreetModel, self._noop_handler) with pytest.raises(m.ValidationError): command(shout=True) def test_invoking_command_uses_parsed_values_without_mutating_settings( self, ) -> None: + """Keep source settings immutable while passing parsed values onward.""" # Write-back into the settings model was removed (commit f5f83dee); # the observable contract is now: parsed values reach the handler # through the validated model and the settings instance stays intact. - settings = self.OptionsDefaultsModel(name="start-name") - received: dict[str, TestsFlextCliOptionsUtilsCov.OptionsDefaultsModel] = {} + settings = self._OptionsDefaultsModel(name="start-name") + received: dict[str, TestsFlextCliOptionsUtilsCov._OptionsDefaultsModel] = {} - def _capture(params: TestsFlextCliOptionsUtilsCov.OptionsDefaultsModel) -> str: + def _capture(params: TestsFlextCliOptionsUtilsCov._OptionsDefaultsModel) -> str: received["model"] = params return params.name command = cli.model_command( - self.OptionsDefaultsModel, _capture, settings=settings + self._OptionsDefaultsModel, _capture, settings=settings ) result = command(name="parsed-name") diff --git a/tests/unit/test_options_public_cov.py b/tests/unit/test_options_public_cov.py index 3073dfb18..9597805ef 100644 --- a/tests/unit/test_options_public_cov.py +++ b/tests/unit/test_options_public_cov.py @@ -26,7 +26,7 @@ class _OptionSettings(m.BaseModel): output_path: Path = Path("reports/output.json") tags: t.StrSequence = ("lint", "typecheck") - flags: dict[str, bool] = {"debug": True} + flags: dict[str, bool] = m.Field(default_factory=lambda: {"debug": True}) @pytest.mark.parametrize( ("annotation", "expected"), @@ -42,9 +42,11 @@ class _OptionSettings(m.BaseModel): def test_resolve_typer_annotation_maps_scalars_unions_and_collections( self, annotation: t.Cli.RuntimeAnnotation, expected: type ) -> None: - assert u.Cli.resolve_typer_annotation(annotation) is expected + """Resolve scalar, union, and collection annotations canonically.""" + tm.that(u.Cli.resolve_typer_annotation(annotation), eq=expected) def test_resolve_typer_annotation_maps_string_sequence_to_list_of_str(self) -> None: + """Map the canonical string sequence alias to a repeatable CLI list.""" tm.that(u.Cli.resolve_typer_annotation(t.StrSequence), eq=list[str]) @pytest.mark.parametrize( @@ -63,6 +65,7 @@ def test_resolve_typer_annotation_maps_string_sequence_to_list_of_str(self) -> N def test_normalize_cli_atom_returns_typer_ready_value_or_none( self, value: t.Cli.CliDefaultSource, expected: t.Cli.DefaultAtom | None ) -> None: + """Normalize supported CLI atoms and reject unsupported values.""" tm.that(u.Cli.normalize_cli_atom(value), eq=expected) @pytest.mark.parametrize( @@ -78,20 +81,23 @@ def test_normalize_cli_atom_returns_typer_ready_value_or_none( ], ) def test_is_string_sequence_recognizes_only_str_sequences( - self, value: t.Cli.CliDefaultSource, expected: bool + self, value: t.Cli.CliDefaultSource, *, expected: bool ) -> None: - assert u.Cli.is_string_sequence(value) is expected + """Recognize only sequences whose every member is a string.""" + tm.that(u.Cli.is_string_sequence(value), eq=expected) def test_field_default_prefers_settings_scalar_over_field_metadata(self) -> None: + """Prefer a scalar sourced from validated settings.""" settings = self._OptionSettings() fields = self._OptionSettings.model_fields - assert ( - u.Cli.field_default("output_path", fields["output_path"], settings) - == "reports/output.json" + tm.that( + u.Cli.field_default("output_path", fields["output_path"], settings), + eq="reports/output.json", ) def test_field_default_normalizes_sequence_field_to_tuple(self) -> None: + """Normalize a settings sequence to an immutable tuple.""" settings = self._OptionSettings() fields = self._OptionSettings.model_fields @@ -101,6 +107,7 @@ def test_field_default_normalizes_sequence_field_to_tuple(self) -> None: ) def test_field_default_normalizes_mapping_field_preserving_entries(self) -> None: + """Preserve supported entries from a settings mapping.""" settings = self._OptionSettings() fields = self._OptionSettings.model_fields @@ -109,30 +116,30 @@ def test_field_default_normalizes_mapping_field_preserving_entries(self) -> None ) def test_field_default_falls_back_to_field_metadata_without_settings(self) -> None: + """Use field metadata when no settings object is supplied.""" fields = self._OptionSettings.model_fields - assert ( - u.Cli.field_default("output_path", fields["output_path"], None) - == "reports/output.json" + tm.that( + u.Cli.field_default("output_path", fields["output_path"], None), + eq="reports/output.json", ) def test_build_option_registers_aliases_and_short_flag_from_spec(self) -> None: + """Build ordered long, plural, and short declarations from metadata.""" option = u.Cli.build_option("project", {"project": {"short": "p"}}) - param_decls = option.param_decls - tm.that(param_decls, none=False) - tm.that(param_decls, has="--project") - tm.that(param_decls, has="--projects") - tm.that(param_decls, has="-p") + tm.that(option.declarations, has="--project") + tm.that(option.declarations, has="--projects") + tm.that(option.declarations, has="-p") def test_build_option_reads_canonical_registry_contract(self) -> None: + """Build an option from the canonical CLI parameter registry.""" option = u.Cli.build_option("debug", c.Cli.CLI_PARAM_REGISTRY) - param_decls = option.param_decls - tm.that(param_decls, none=False) - tm.that(param_decls, has="--debug") + tm.that(option.declarations, has="--debug") def test_reorder_prefixed_options_moves_shared_flags_after_subcommand(self) -> None: + """Move shared prefix flags immediately after the subcommand.""" reordered = u.Cli.reorder_prefixed_options( ["--debug", "--log-level", "DEBUG", "check", "--all"], bool_options=("--debug",), @@ -142,6 +149,7 @@ def test_reorder_prefixed_options_moves_shared_flags_after_subcommand(self) -> N tm.that(reordered, eq=["check", "--debug", "--log-level", "DEBUG", "--all"]) def test_reorder_prefixed_options_handles_equals_joined_value_option(self) -> None: + """Preserve an equals-joined value while reordering its option.""" reordered = u.Cli.reorder_prefixed_options( ["--log-level=DEBUG", "check", "--all"], bool_options=("--debug",), @@ -154,14 +162,16 @@ def test_reorder_prefixed_options_handles_equals_joined_value_option(self) -> No def test_reorder_prefixed_options_is_identity_without_leading_prefixes( self, args: list[str] ) -> None: - assert ( + """Preserve argument order when no shared option precedes the command.""" + tm.that( u.Cli.reorder_prefixed_options( args, bool_options=("--debug",), value_options=("--log-level",) - ) - == args + ), + eq=args, ) def test_reorder_prefixed_options_is_idempotent(self) -> None: + """Return the same ordering when applied repeatedly.""" once = u.Cli.reorder_prefixed_options( ["--debug", "check", "--all"], bool_options=("--debug",), diff --git a/tests/unit/test_protocols.py b/tests/unit/test_protocols.py index d73342cd9..9dee3002a 100644 --- a/tests/unit/test_protocols.py +++ b/tests/unit/test_protocols.py @@ -15,12 +15,13 @@ from __future__ import annotations +import sys from pathlib import Path import pytest from flext_cli import t -from tests import p +from tests import p, u from flext_tests import tm @@ -44,7 +45,8 @@ class _PartialSummary: class _ConformingYamlModule: """Object structurally conforming to ``YamlModule``.""" - def dump(self, data: object, *, default_flow_style: bool = True) -> str: + def dump(self, data: t.JsonPayload, *, default_flow_style: bool = True) -> str: + _ = data, default_flow_style return "" @@ -73,7 +75,7 @@ def test_data_protocol_accepts_structurally_conforming_object(self) -> None: def test_data_protocol_rejects_object_missing_required_attributes(self) -> None: """An object missing declared attributes fails the protocol check.""" - assert not isinstance(_PartialSummary(), p.Cli.SummaryStats) + tm.that(isinstance(_PartialSummary(), p.Cli.SummaryStats), eq=False) def test_method_protocol_accepts_object_exposing_method(self) -> None: """An object exposing ``dump`` satisfies ``YamlModule``.""" @@ -81,7 +83,7 @@ def test_method_protocol_accepts_object_exposing_method(self) -> None: def test_method_protocol_rejects_object_without_method(self) -> None: """An object lacking ``dump`` is rejected by ``YamlModule``.""" - assert not isinstance(object(), p.Cli.YamlModule) + tm.that(isinstance(_PartialSummary(), p.Cli.YamlModule), eq=False) def test_callable_protocol_accepts_plain_callable(self) -> None: """Any single-arg callable conforms to ``JsonValueProcessor``.""" @@ -96,12 +98,24 @@ def test_property_protocol_rejects_object_missing_a_property(self) -> None: class _MissingSettings: @property - def workspace_root(self) -> object: ... + def workspace_root(self) -> Path: + return Path() @property - def shared(self) -> object: ... + def shared(self) -> t.MutableJsonMapping: + return {} - assert not isinstance(_MissingSettings(), p.Cli.PipelineStageContext) + tm.that(isinstance(_MissingSettings(), p.Cli.PipelineStageContext), eq=False) + + def test_command_runner_preserves_byte_exact_output(self) -> None: + """The public runner returns its byte-output structural contract.""" + result = u.Cli.run_bytes((sys.executable, "-c", "print('bytes')")) + tm.that(result.success, eq=True) + payload = result.value + tm.that(payload, is_=p.Cli.CommandBytesOutput) + tm.that(u.Cli, is_=p.Cli.CommandRunner) + tm.that(payload.stdout, eq=b"bytes\n") + tm.that(payload.stderr, eq=b"") @pytest.mark.parametrize( "protocol_name", @@ -134,11 +148,12 @@ def test_cli_protocols_are_runtime_checkable(self, protocol_name: str) -> None: "PipelineService", ], ) - def test_top_level_protocol_is_same_object_as_cli_namespace( + def test_protocol_is_exposed_only_by_cli_namespace( self, protocol_name: str ) -> None: - """MRO exposure guarantees one shared protocol object across namespaces.""" - assert getattr(p, protocol_name) is getattr(p.Cli, protocol_name) + """CLI protocols stay namespaced without flat compatibility aliases.""" + tm.that(hasattr(p, protocol_name), eq=False) + tm.that(getattr(p.Cli, protocol_name), is_=type) def test_result_protocol_inherited_from_core_facade(self) -> None: """The CLI facade re-exposes the core ``Result`` protocol contract.""" diff --git a/tests/unit/test_services_auth_branch_cov.py b/tests/unit/test_services_auth_branch_cov.py index fffa35ad7..a90236627 100644 --- a/tests/unit/test_services_auth_branch_cov.py +++ b/tests/unit/test_services_auth_branch_cov.py @@ -45,6 +45,7 @@ def _point_token_file(path: Path) -> None: def test_authenticate_with_token_persists_and_round_trips( self, service: FlextCli, tmp_path: Path ) -> None: + """Persist a supplied token and load the same token publicly.""" # Arrange self._point_token_file(tmp_path / "token.json") @@ -58,6 +59,7 @@ def test_authenticate_with_token_persists_and_round_trips( def test_authenticate_with_username_password_returns_reloadable_token( self, service: FlextCli, tmp_path: Path ) -> None: + """Generate and persist a reloadable token from valid credentials.""" # Arrange self._point_token_file(tmp_path / "token.json") @@ -70,7 +72,7 @@ def test_authenticate_with_username_password_returns_reloadable_token( # Assert: a non-empty token is generated and persisted for reload. generated = tm.ok(authenticated) tm.that(generated, is_=str) - assert generated + tm.that(generated, empty=False) tm.that(tm.ok(service.fetch_auth_token()), eq=generated) @pytest.mark.parametrize( @@ -86,6 +88,7 @@ def test_authenticate_with_username_password_returns_reloadable_token( def test_authenticate_rejects_malformed_credentials_payload( self, service: FlextCli, tmp_path: Path, credentials: dict[str, str] ) -> None: + """Reject malformed credential payloads at the validation boundary.""" # Arrange self._point_token_file(tmp_path / "token.json") @@ -116,6 +119,7 @@ def test_authenticate_reports_missing_credential_field( credentials: dict[str, str], missing_field: str, ) -> None: + """Report each required credential field that is absent.""" # Arrange self._point_token_file(tmp_path / "token.json") @@ -140,6 +144,7 @@ def test_authenticate_reports_missing_credential_field( def test_authenticate_fails_when_token_cannot_be_persisted( self, service: FlextCli, tmp_path: Path, credentials: dict[str, str] ) -> None: + """Propagate the canonical JSON write failure when persistence fails.""" # Arrange: point token_file at a directory so the write cannot succeed. token_dir = tmp_path / "token-as-dir" token_dir.mkdir() @@ -150,11 +155,12 @@ def test_authenticate_fails_when_token_cannot_be_persisted( # Assert: persistence failure surfaces as a write error, not success. tm.fail(result) - tm.that(result.error, has="json_write:") + tm.that(result.error, has="json_write failed:") def test_save_auth_token_rejects_blank_token( self, service: FlextCli, tmp_path: Path ) -> None: + """Reject blank authentication tokens before filesystem access.""" # Arrange self._point_token_file(tmp_path / "token.json") @@ -169,6 +175,7 @@ def test_save_auth_token_rejects_blank_token( def test_validate_credentials_rejects_empty_password( self, service: FlextCli ) -> None: + """Reject credentials whose password is empty.""" # Act result = service.validate_credentials("user", "") @@ -179,6 +186,7 @@ def test_validate_credentials_rejects_empty_password( def test_fetch_auth_token_fails_when_file_missing( self, service: FlextCli, tmp_path: Path ) -> None: + """Fail loudly when the configured token file is absent.""" # Arrange self._point_token_file(tmp_path / "missing-token.json") @@ -192,6 +200,7 @@ def test_fetch_auth_token_fails_when_file_missing( def test_fetch_auth_token_fails_when_path_is_directory( self, service: FlextCli, tmp_path: Path ) -> None: + """Fail loudly when the configured token path is a directory.""" # Arrange token_dir = tmp_path / "read-as-dir" token_dir.mkdir() @@ -207,6 +216,7 @@ def test_fetch_auth_token_fails_when_path_is_directory( def test_clear_auth_tokens_is_ok_when_file_missing( self, service: FlextCli, tmp_path: Path ) -> None: + """Treat clearing an already absent token as idempotent success.""" # Arrange self._point_token_file(tmp_path / "missing-token.json") @@ -220,6 +230,7 @@ def test_clear_auth_tokens_is_ok_when_file_missing( def test_clear_auth_tokens_removes_persisted_token_and_is_idempotent( self, service: FlextCli, tmp_path: Path ) -> None: + """Remove a persisted token and preserve idempotency on repetition.""" # Arrange: persist a token first. self._point_token_file(tmp_path / "token.json") tm.ok(service.authenticate({c.Cli.DICT_KEY_AUTH_TOKEN: "token-123"})) diff --git a/tests/unit/test_tables_cov.py b/tests/unit/test_tables_cov.py index 9043e723f..79666fc81 100644 --- a/tests/unit/test_tables_cov.py +++ b/tests/unit/test_tables_cov.py @@ -29,15 +29,18 @@ class TestsFlextCliTables: # ── tables_normalize_mapping_row ────────────────────────────────── def test_normalize_mapping_row_preserves_keys_and_json_values(self) -> None: + """Preserve mapping keys and JSON-native values.""" row: t.Cli.TableMappingRow = {"a": 1, "b": "hello"} result = u.Cli.tables_normalize_mapping_row(row) tm.that(result, eq={"a": 1, "b": "hello"}) - def test_normalize_mapping_row_renders_none_as_empty_string(self) -> None: + def test_normalize_mapping_row_preserves_json_null(self) -> None: + """Preserve JSON null instead of inventing an empty string.""" result = u.Cli.tables_normalize_mapping_row({"key": None}) - tm.that(result, eq={"key": ""}) + tm.that(result, eq={"key": None}) def test_normalize_mapping_row_is_idempotent_on_json_values(self) -> None: + """Remain idempotent for already normalized JSON values.""" row: t.Cli.TableMappingRow = {"a": 1, "b": "x"} once = u.Cli.tables_normalize_mapping_row(row) twice = u.Cli.tables_normalize_mapping_row(once) @@ -46,30 +49,36 @@ def test_normalize_mapping_row_is_idempotent_on_json_values(self) -> None: # ── tables_normalize_sequence_row ───────────────────────────────── def test_normalize_sequence_row_preserves_length_and_order(self) -> None: + """Preserve sequence length, order, and JSON-native values.""" result = u.Cli.tables_normalize_sequence_row([1, "text", True]) tm.that(result, eq=[1, "text", True]) def test_normalize_sequence_row_empty_yields_empty_list(self) -> None: + """Return an empty list for an empty row.""" tm.that(u.Cli.tables_normalize_sequence_row([]), eq=[]) # ── tables_resolve_config ───────────────────────────────────────── def test_resolve_config_no_args_returns_default_model(self) -> None: + """Return a default table configuration when no input is supplied.""" result = u.Cli.tables_resolve_config() tm.ok(result) tm.that(result.unwrap(), is_=m.Cli.TableConfig) def test_resolve_config_returns_same_instance_when_only_model_given(self) -> None: + """Reuse the validated configuration instance without rebuilding it.""" config = m.Cli.TableConfig() result = u.Cli.tables_resolve_config(config) - assert result.unwrap() is config + tm.that(result.unwrap() is config, eq=True) def test_resolve_config_applies_kwarg_override(self) -> None: + """Apply an explicit keyword override to the default configuration.""" result = u.Cli.tables_resolve_config(table_format=c.Cli.TabularFormat.PLAIN) tm.ok(result) tm.that(result.unwrap().table_format, eq=c.Cli.TabularFormat.PLAIN) def test_resolve_config_merges_model_with_kwargs(self) -> None: + """Merge explicit overrides with a validated configuration model.""" base = m.Cli.TableConfig(title="orig") result = u.Cli.tables_resolve_config( base, table_format=c.Cli.TabularFormat.PLAIN @@ -79,6 +88,7 @@ def test_resolve_config_merges_model_with_kwargs(self) -> None: tm.that(resolved.table_format, eq=c.Cli.TabularFormat.PLAIN) def test_resolve_config_invalid_kwarg_fails_with_config_message(self) -> None: + """Reject an unknown configuration field with context.""" result = u.Cli.tables_resolve_config(not_a_field="oops") tm.fail(result) tm.that((result.error or ""), has="Invalid table configuration") @@ -86,20 +96,24 @@ def test_resolve_config_invalid_kwarg_fails_with_config_message(self) -> None: # ── tables_normalize_data ───────────────────────────────────────── def test_normalize_data_mapping_becomes_key_value_rows(self) -> None: + """Convert a mapping into ordered key and value rows.""" data: t.JsonMapping = {"key": "val", "num": 42} rows = list(u.Cli.tables_normalize_data(data).unwrap()) tm.that(rows, eq=[{"Key": "key", "Value": "val"}, {"Key": "num", "Value": 42}]) def test_normalize_data_list_of_dicts_preserves_rows(self) -> None: + """Preserve mapping rows supplied as a list.""" data = [{"col1": "a", "col2": 1}, {"col1": "b", "col2": 2}] rows = list(u.Cli.tables_normalize_data(data).unwrap()) tm.that(rows, eq=data) def test_normalize_data_list_of_lists_preserves_rows(self) -> None: + """Preserve sequence rows supplied as a list.""" rows = list(u.Cli.tables_normalize_data([["a", "b"], ["c", "d"]]).unwrap()) tm.that(rows, eq=[["a", "b"], ["c", "d"]]) def test_normalize_data_empty_list_yields_no_rows(self) -> None: + """Return no normalized rows for an empty data source.""" tm.that(list(u.Cli.tables_normalize_data([]).unwrap()), eq=[]) # NOTE: The malformed-input failure branch of ``tables_normalize_data`` @@ -112,6 +126,7 @@ def test_normalize_data_empty_list_yields_no_rows(self) -> None: # ── tables_render ───────────────────────────────────────────────── def test_render_mapping_rows_includes_cell_values(self) -> None: + """Render every observable value from mapping rows.""" config = m.Cli.TableConfig(table_format=c.Cli.TabularFormat.PLAIN) rows: list[t.JsonMapping] = [{"Name": "x", "Age": 1}, {"Name": "y", "Age": 2}] rendered = u.Cli.tables_render(rows, config).unwrap() @@ -119,6 +134,7 @@ def test_render_mapping_rows_includes_cell_values(self) -> None: tm.that(rendered, has="y") def test_render_sequence_rows_includes_cell_values(self) -> None: + """Render every observable value from sequence rows.""" config = m.Cli.TableConfig(table_format=c.Cli.TabularFormat.PLAIN) rows: list[list[t.JsonValue]] = [["a", 1], ["b", 2]] rendered = u.Cli.tables_render(rows, config).unwrap() @@ -126,6 +142,7 @@ def test_render_sequence_rows_includes_cell_values(self) -> None: tm.that(rendered, has="b") def test_render_empty_rows_yields_string(self) -> None: + """Return a string when rendering an empty row collection.""" config = m.Cli.TableConfig() result = u.Cli.tables_render([], config) tm.ok(result) @@ -142,6 +159,7 @@ def test_render_empty_rows_yields_string(self) -> None: def test_render_succeeds_across_formats( self, table_format: c.Cli.TabularFormat ) -> None: + """Render successfully through each supported table format.""" config = m.Cli.TableConfig(table_format=table_format) rows: list[t.JsonMapping] = [{"K": "v"}] result = u.Cli.tables_render(rows, config) diff --git a/tests/unit/test_typings.py b/tests/unit/test_typings.py index 77f9436b0..f7c94bbca 100644 --- a/tests/unit/test_typings.py +++ b/tests/unit/test_typings.py @@ -11,7 +11,7 @@ from __future__ import annotations from collections.abc import Sequence -from pathlib import Path +from typing import TYPE_CHECKING import pytest from flext_tests import tm @@ -19,6 +19,9 @@ from tests import m from tests import t +if TYPE_CHECKING: + from pathlib import Path + class TestsFlextCliTypings: """Behavioural contract of flext_cli.typings.FlextCliTypes.""" @@ -73,13 +76,7 @@ def test_json_list_adapter_accepts_json_arrays(self, payload: list[object]) -> N @pytest.mark.parametrize( ("payload", "expected"), - [ - ("plain", "plain"), - (7, 7), - (True, True), - (Path("/tmp/x"), Path("/tmp/x")), - (["a", "b"], ["a", "b"]), - ], + [("plain", "plain"), (7, 7), (True, True), (["a", "b"], ["a", "b"])], ) def test_cli_default_source_adapter_accepts_cli_value_kinds( self, payload: object, expected: object @@ -88,6 +85,15 @@ def test_cli_default_source_adapter_accepts_cli_value_kinds( result = t.Cli.CLI_DEFAULT_SOURCE_ADAPTER.validate_python(payload) tm.that(result, eq=expected) + def test_cli_default_source_adapter_accepts_real_paths( + self, tmp_path: Path + ) -> None: + """Validate a pytest-managed path through the public CLI adapter.""" + # mro-wkii.17.26 (codex): use the isolated filesystem fixture, never /tmp. + source = tmp_path / "source" + result = t.Cli.CLI_DEFAULT_SOURCE_ADAPTER.validate_python(source) + tm.that(result, eq=source) + # --- Published type-tuple ClassVars --------------------------------- def test_primitive_types_expose_scalar_primitives(self) -> None: diff --git a/tests/unit/test_version.py b/tests/unit/test_version.py index 0be51c8cc..6bb09d5f3 100644 --- a/tests/unit/test_version.py +++ b/tests/unit/test_version.py @@ -16,7 +16,7 @@ from flext_tests import tm import flext_cli -from flext_cli import cli +from flext_cli import cli, m from flext_cli.__version__ import FlextCliVersion from tests import c @@ -95,20 +95,20 @@ def test_cli_version_constant_exposes_major_minor_patch(self) -> None: def test_execute_publishes_cli_version_in_runtime_payload(self) -> None: """``cli.execute()`` succeeds and reports the CLI version string.""" result = cli.execute() - tm.ok(result) - payload = result.value - tm.that("version" in payload, eq=True) - version = payload["version"] - tm.that(version, is_=str) - tm.that(version, eq=c.Cli.CLI_VERSION) + tm.ok(result, is_=m.Cli.RuntimeStatus) + status = result.value + tm.that(status.version, is_=str) + tm.that(status.version, eq=c.Cli.CLI_VERSION) def test_execute_reports_version_deterministically(self) -> None: """Repeated ``cli.execute()`` calls report an identical version.""" first = cli.execute() second = cli.execute() - tm.ok(first) - tm.ok(second) - tm.that(first.value["version"], eq=second.value["version"]) + tm.ok(first, is_=m.Cli.RuntimeStatus) + tm.ok(second, is_=m.Cli.RuntimeStatus) + first_status = first.value + second_status = second.value + tm.that(first_status.version, eq=second_status.version) @pytest.mark.parametrize( ("candidate", "is_valid"), @@ -126,7 +126,7 @@ def test_execute_reports_version_deterministically(self) -> None: ("not-a-version", False), ], ) - def test_semver_pattern_contract(self, candidate: str, is_valid: bool) -> None: + def test_semver_pattern_contract(self, candidate: str, *, is_valid: bool) -> None: """The published semver pattern accepts valid and rejects invalid strings.""" matched = c.PATTERN_SEMVER_RE.match(candidate) is not None tm.that(matched, eq=is_valid) diff --git a/tests/unit/test_yaml_cov.py b/tests/unit/test_yaml_cov.py index 9033ddff9..7165d51a2 100644 --- a/tests/unit/test_yaml_cov.py +++ b/tests/unit/test_yaml_cov.py @@ -34,28 +34,29 @@ class TestsFlextCliYamlCov: # ── yaml_parse ────────────────────────────────────────────────── - @pytest.mark.parametrize( - ("text", "expect_ok", "expect_empty"), c.Tests.YAML_PARSE_CASES - ) + @pytest.mark.parametrize(("text", "expect_ok"), c.Tests.YAML_PARSE_CASES) def test_yaml_parse_reports_outcome_per_input( - self, text: str, expect_ok: bool, expect_empty: bool + self, text: str, *, expect_ok: bool ) -> None: + """Accept mappings and fail loudly for empty or non-mapping input.""" result = u.Cli.yaml_parse(text) tm.that(result.success, eq=expect_ok) if expect_ok: - assert result.value == {} if expect_empty else result.value != {} + tm.that(result.value, empty=False) else: - # Failure carries a descriptive, non-empty error message. - assert result.error + tm.fail(result) + tm.that(result.error, empty=False) def test_yaml_parse_preserves_nested_mapping_values(self) -> None: + """Preserve nested mapping values during parsing.""" result = u.Cli.yaml_parse(c.Tests.YAML_VALID_CONTENT) tm.ok(result) tm.that(result.unwrap(), eq={"key": "value", "nested": {"foo": "bar"}}) def test_yaml_parse_top_level_list_is_rejected_as_non_mapping(self) -> None: + """Reject a top-level sequence when a mapping is required.""" result = u.Cli.yaml_parse(c.Tests.YAML_NON_MAPPING_CONTENT) tm.fail(result) @@ -63,6 +64,7 @@ def test_yaml_parse_top_level_list_is_rejected_as_non_mapping(self) -> None: tm.that(result.error, has="not a mapping") def test_yaml_parse_malformed_yaml_fails_with_parse_error(self) -> None: + """Report malformed YAML as a parse failure.""" result = u.Cli.yaml_parse(c.Tests.YAML_INVALID_CONTENT) tm.fail(result) @@ -72,6 +74,7 @@ def test_yaml_parse_malformed_yaml_fails_with_parse_error(self) -> None: # ── yaml_safe_load ─────────────────────────────────────────────── def test_yaml_safe_load_returns_parsed_mapping(self, tmp_path: Path) -> None: + """Load a valid YAML mapping from a file.""" yaml_file = tmp_path / "valid.yml" yaml_file.write_text(c.Tests.YAML_VALID_CONTENT, encoding="utf-8") @@ -83,6 +86,7 @@ def test_yaml_safe_load_returns_parsed_mapping(self, tmp_path: Path) -> None: def test_yaml_safe_load_missing_file_reports_not_found( self, tmp_path: Path ) -> None: + """Report a missing YAML file with its path.""" missing = tmp_path / "nonexistent.yml" result = u.Cli.yaml_safe_load(missing) @@ -93,6 +97,7 @@ def test_yaml_safe_load_missing_file_reports_not_found( tm.that(result.error, has=str(missing)) def test_yaml_safe_load_invalid_yaml_fails(self, tmp_path: Path) -> None: + """Fail when a YAML file contains malformed content.""" bad_file = tmp_path / "bad.yml" bad_file.write_text(c.Tests.YAML_INVALID_CONTENT, encoding="utf-8") @@ -103,6 +108,7 @@ def test_yaml_safe_load_invalid_yaml_fails(self, tmp_path: Path) -> None: tm.that(result.error, has="parse error") def test_yaml_safe_load_non_mapping_file_fails(self, tmp_path: Path) -> None: + """Fail when a YAML file contains a top-level sequence.""" list_file = tmp_path / "list.yml" list_file.write_text(c.Tests.YAML_NON_MAPPING_CONTENT, encoding="utf-8") @@ -112,20 +118,20 @@ def test_yaml_safe_load_non_mapping_file_fails(self, tmp_path: Path) -> None: tm.that(result.error, none=False) tm.that(result.error, has="not a mapping") - def test_yaml_safe_load_empty_file_yields_empty_mapping( - self, tmp_path: Path - ) -> None: + def test_yaml_safe_load_empty_file_fails_loudly(self, tmp_path: Path) -> None: + """Reject an empty YAML file with a descriptive failure.""" empty_file = tmp_path / "empty.yml" empty_file.write_text("", encoding="utf-8") result = u.Cli.yaml_safe_load(empty_file) - tm.ok(result) - tm.that(result.unwrap(), eq={}) + tm.fail(result) + tm.that(result.error, has="empty") # ── yaml_load_mapping ──────────────────────────────────────────── def test_yaml_load_mapping_returns_full_mapping(self, tmp_path: Path) -> None: + """Return the complete mapping from the compatibility helper.""" yaml_file = tmp_path / "m.yml" yaml_file.write_text(c.Tests.YAML_VALID_CONTENT, encoding="utf-8") @@ -134,6 +140,7 @@ def test_yaml_load_mapping_returns_full_mapping(self, tmp_path: Path) -> None: tm.that(result, eq={"key": "value", "nested": {"foo": "bar"}}) def test_yaml_load_mapping_missing_defaults_to_empty(self, tmp_path: Path) -> None: + """Expose the current empty default for a missing mapping file.""" result = u.Cli.yaml_load_mapping(tmp_path / "missing.yml") tm.that(result, eq={}) @@ -141,6 +148,7 @@ def test_yaml_load_mapping_missing_defaults_to_empty(self, tmp_path: Path) -> No def test_yaml_load_mapping_missing_uses_provided_default( self, tmp_path: Path ) -> None: + """Expose the current explicit default for a missing mapping file.""" default: t.JsonMapping = {"fallback": True} result = u.Cli.yaml_load_mapping(tmp_path / "missing.yml", default=default) @@ -148,6 +156,7 @@ def test_yaml_load_mapping_missing_uses_provided_default( tm.that(result, eq=default) def test_yaml_load_mapping_invalid_yaml_uses_default(self, tmp_path: Path) -> None: + """Expose the current explicit default for malformed YAML.""" bad_file = tmp_path / "bad.yml" bad_file.write_text(c.Tests.YAML_INVALID_CONTENT, encoding="utf-8") @@ -159,8 +168,9 @@ def test_yaml_load_mapping_invalid_yaml_uses_default(self, tmp_path: Path) -> No @pytest.mark.parametrize(("content", "expect_list"), c.Tests.YAML_LIST_CASES) def test_yaml_load_list_returns_list_only_for_sequences( - self, tmp_path: Path, content: str, expect_list: bool + self, tmp_path: Path, content: str, *, expect_list: bool ) -> None: + """Return sequence values only for top-level YAML lists.""" data_file = tmp_path / "data.yml" data_file.write_text(content, encoding="utf-8") @@ -172,11 +182,13 @@ def test_yaml_load_list_returns_list_only_for_sequences( tm.that(list(result), eq=[]) def test_yaml_load_list_missing_file_returns_empty(self, tmp_path: Path) -> None: + """Expose the current empty sequence for a missing list file.""" result = u.Cli.yaml_load_list(tmp_path / "nope.yml") tm.that(list(result), eq=[]) def test_yaml_load_list_invalid_yaml_returns_empty(self, tmp_path: Path) -> None: + """Expose the current empty sequence for malformed list YAML.""" bad_file = tmp_path / "bad.yml" bad_file.write_text(c.Tests.YAML_INVALID_CONTENT, encoding="utf-8") @@ -190,8 +202,9 @@ def test_yaml_load_list_invalid_yaml_returns_empty(self, tmp_path: Path) -> None ("data", "sort_keys", "expect_ok"), c.Tests.YAML_DUMP_CASES ) def test_yaml_dump_writes_roundtrippable_file( - self, tmp_path: Path, data: t.JsonMapping, sort_keys: bool, expect_ok: bool + self, tmp_path: Path, data: t.JsonMapping, *, sort_keys: bool, expect_ok: bool ) -> None: + """Write a mapping that round-trips through the public loader.""" outfile = tmp_path / "out.yml" result = u.Cli.yaml_dump(outfile, data, sort_keys=sort_keys) @@ -202,6 +215,7 @@ def test_yaml_dump_writes_roundtrippable_file( tm.that(u.Cli.yaml_safe_load(outfile).unwrap(), eq=data) def test_yaml_dump_creates_missing_parent_directories(self, tmp_path: Path) -> None: + """Create missing parent directories before writing YAML.""" deep = tmp_path / "a" / "b" / "c" / "out.yml" result = u.Cli.yaml_dump(deep, {"x": 1}) @@ -212,6 +226,7 @@ def test_yaml_dump_creates_missing_parent_directories(self, tmp_path: Path) -> N # ── yaml_dump_str ──────────────────────────────────────────────── def test_yaml_dump_str_roundtrips_through_parse(self) -> None: + """Round-trip an in-memory mapping through YAML text.""" payload: t.JsonMapping = {"hello": "world", "count": 3} text = u.Cli.yaml_dump_str(payload) @@ -219,16 +234,19 @@ def test_yaml_dump_str_roundtrips_through_parse(self) -> None: tm.that(u.Cli.yaml_parse(text).unwrap(), eq=payload) def test_yaml_dump_str_sort_keys_orders_output(self) -> None: + """Order serialized mapping keys when requested.""" text = u.Cli.yaml_dump_str({"b": 2, "a": 1}, sort_keys=True) - assert text.index("a:") < text.index("b:") + tm.that(text.index("a:") < text.index("b:"), eq=True) def test_yaml_dump_str_empty_mapping_parses_back_to_empty(self) -> None: + """Round-trip an empty mapping without changing its value.""" text = u.Cli.yaml_dump_str({}) tm.that(u.Cli.yaml_parse(text).unwrap(), eq={}) def test_yaml_dump_str_serializes_pydantic_model_fields(self) -> None: + """Serialize the public fields of a Pydantic model.""" model = m.Cli.TableConfig() text = u.Cli.yaml_dump_str(model) diff --git a/tests/utilities.py b/tests/utilities.py index baa7a7d38..c975751d6 100644 --- a/tests/utilities.py +++ b/tests/utilities.py @@ -18,7 +18,6 @@ from tests import c from tests import p from tests.settings import TestsFlextCliSettings -from tests import t class TestsFlextCliUtilities(FlextTestsUtilities, u): @@ -32,6 +31,7 @@ class VersionTestFactory: @staticmethod def validate_version_string(version: str) -> p.Result[str]: + """Validate one semantic-version string.""" if not version: return r[str].fail(c.Tests.VERSION_EMPTY_MSG) if not c.PATTERN_SEMVER_RE.match(version): @@ -44,7 +44,8 @@ def validate_version_string(version: str) -> p.Result[str]: def validate_version_info( version_info: tuple[int | str, ...], ) -> p.Result[tuple[int | str, ...]]: - if len(version_info) < 3: + """Validate one structured semantic-version tuple.""" + if len(version_info) < len(c.Tests.VERSION_INFO_VALID_TUPLE): return r[tuple[int | str, ...]].fail( c.Tests.VERSION_INFO_TOO_SHORT_MSG ) @@ -67,6 +68,7 @@ def validate_version_info( def validate_consistency( cls, version_string: str, version_info: tuple[int | str, ...] ) -> p.Result[tuple[str, tuple[int | str, ...]]]: + """Validate matching string and tuple version representations.""" pair_t = tuple[str, tuple[int | str, ...]] string_check = cls.validate_version_string(version_string) if string_check.failure: @@ -103,10 +105,10 @@ def create_test_settings() -> p.Result[p.Cli.Settings]: return r[p.Cli.Settings].ok(TestsFlextCliSettings()) @staticmethod - def create_cli_app() -> p.Result[t.Cli.CliApp]: + def create_cli_app() -> p.Result[p.Cli.Application]: """Create CLI app via Railway pattern.""" # NOTE (multi-agent, mro-wkii.19.4): the CLI owns global settings. - return r[t.Cli.CliApp].ok( + return r[p.Cli.Application].ok( cli.create_app_with_common_params( name="tests-cli", help_text="Test CLI app" ) @@ -114,11 +116,12 @@ def create_cli_app() -> p.Result[t.Cli.CliApp]: @staticmethod def create_decorated_command( - app: t.Cli.CliApp, command_name: str = "test" + app: p.Cli.Application, command_name: str = "test" ) -> p.Result[Callable[..., None]]: """Register a real flag-driven command on ``app`` for tests.""" def command( + *, verbose: Annotated[bool, cli.create_option("verbose")] = False, debug: Annotated[bool, cli.create_option("debug")] = False, log_level: Annotated[ From 42b1889f93ed6c624fd5b2ffa55e2def3401051a Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Tue, 14 Jul 2026 11:48:55 -0300 Subject: [PATCH 09/37] fix: format generated cli settings import --- src/flext_cli/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flext_cli/__init__.py b/src/flext_cli/__init__.py index 41444876e..8f93befae 100644 --- a/src/flext_cli/__init__.py +++ b/src/flext_cli/__init__.py @@ -19,7 +19,7 @@ if TYPE_CHECKING: from flext_cli._config import FlextCliConfig as FlextCliConfig, config as config - from flext_cli._settings import FlextCliSettings,settings + from flext_cli._settings import FlextCliSettings, settings from flext_cli.api import FlextCli as FlextCli, cli as cli from flext_cli import services as services from flext_cli.base import FlextCliServiceBase as FlextCliServiceBase, s as s From b75b352db4edd499324f60f5c3d73f342e246b21 Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Tue, 14 Jul 2026 12:03:32 -0300 Subject: [PATCH 10/37] fixes --- src/flext_cli/_utilities/formatters.py | 4 ++-- tests/unit/test_services_output_cov.py | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/flext_cli/_utilities/formatters.py b/src/flext_cli/_utilities/formatters.py index 9a756feaf..c991aed6e 100644 --- a/src/flext_cli/_utilities/formatters.py +++ b/src/flext_cli/_utilities/formatters.py @@ -18,8 +18,8 @@ class FlextCliUtilitiesFormatters: @classmethod def formatters_print(cls, message: str, style: str | None = None) -> None: - """Print one message via Rich.""" - cls._console.print(message, style=style) + """Print literal diagnostic text through Rich with an optional style.""" + cls._console.print(message, style=style, markup=False) @classmethod def formatters_render_rule(cls, text: str) -> None: diff --git a/tests/unit/test_services_output_cov.py b/tests/unit/test_services_output_cov.py index 18ea9cbf1..1b5cb3a4b 100644 --- a/tests/unit/test_services_output_cov.py +++ b/tests/unit/test_services_output_cov.py @@ -79,6 +79,12 @@ def test_print_message_emits_message_with_or_without_style( tm.that(capsys.readouterr().out, has="raw message") + def test_print_message_preserves_literal_brackets(self, capsys: Capture) -> None: + """Diagnostic glob patterns are output literally, not parsed as Rich markup.""" + cli.print_message("ignored: [path/**/*.py]") + + tm.that(capsys.readouterr().out, has="[path/**/*.py]") + # ── display_header ──────────────────────────────────────────────── @pytest.mark.parametrize("label", ["Setup", "Results", "Done"]) From da1cd80c0d8da7003a6344e7f93e700af31f03fb Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Tue, 14 Jul 2026 19:35:49 -0300 Subject: [PATCH 11/37] fixes --- examples/_models_parts/examples_advanced.py | 4 +- examples/constants.py | 4 +- examples/ex_04_file_operations.py | 4 +- examples/protocols.py | 8 +- examples/utilities.py | 8 +- src/flext_cli/__init__.py | 151 ++++++++++-------- src/flext_cli/_config.py | 9 +- src/flext_cli/_constants/__init__.py | 33 +--- src/flext_cli/_constants/base.py | 5 +- src/flext_cli/_constants/errors.py | 7 +- src/flext_cli/_constants/files.py | 5 +- src/flext_cli/_constants/output.py | 8 +- src/flext_cli/_constants/pipeline.py | 5 +- src/flext_cli/_models/__init__.py | 49 +----- src/flext_cli/_models/_base_parts/__init__.py | 5 +- src/flext_cli/_protocols/__init__.py | 31 +--- .../_protocols/_base_parts/__init__.py | 7 +- .../flextcliprotocolsbase_part_03.py | 5 +- .../flextcliprotocolsbase_part_04.py | 9 +- .../flextcliprotocolsbase_part_05.py | 9 +- src/flext_cli/_protocols/pipeline.py | 7 +- src/flext_cli/_protocols/xlsx.py | 7 +- src/flext_cli/_protocols/xlsx_snapshot.py | 7 +- src/flext_cli/_typings/__init__.py | 13 +- src/flext_cli/_typings/pipeline.py | 5 +- src/flext_cli/_utilities/__init__.py | 57 +------ .../_file_test_helper_parts/__init__.py | 7 +- ...liutilitiesfiletesthelpersmixin_part_02.py | 4 +- ...liutilitiesfiletesthelpersmixin_part_03.py | 4 +- ...liutilitiesfiletesthelpersmixin_part_04.py | 4 +- .../_utilities/_files_parts/__init__.py | 7 +- src/flext_cli/_utilities/_json/__init__.py | 11 +- src/flext_cli/_utilities/_json/_navigate.py | 4 +- .../_utilities/_options_parts/__init__.py | 13 +- src/flext_cli/_utilities/_rules/__init__.py | 14 +- src/flext_cli/_utilities/_rules/_loaders.py | 4 +- src/flext_cli/_utilities/_rules/_matchers.py | 6 +- .../_utilities/_toml_parts/__init__.py | 7 +- .../flextcliutilitiestoml_part_02.py | 5 +- .../flextcliutilitiestoml_part_04.py | 8 +- .../flextcliutilitiestoml_part_05.py | 4 +- .../flextcliutilitiestoml_part_06.py | 4 +- .../flextcliutilitiestoml_part_07.py | 4 +- src/flext_cli/_utilities/_xlxx/__init__.py | 89 +---------- src/flext_cli/_utilities/_yaml/__init__.py | 17 +- src/flext_cli/_utilities/_yaml/_engine.py | 5 +- src/flext_cli/_utilities/commands.py | 4 +- src/flext_cli/_utilities/framework.py | 5 +- src/flext_cli/_utilities/model_commands.py | 31 ++-- src/flext_cli/services/__init__.py | 33 +--- src/flext_cli/services/_cli_parts/__init__.py | 5 +- .../_cli_parts/flextclicli_part_03.py | 12 +- .../_cli_parts/flextclicli_part_05.py | 4 +- src/flext_cli/services/_prompts_support.py | 5 +- tests/_constants_parts/tests_core.py | 4 +- tests/_constants_parts/tests_rules_options.py | 4 +- tests/_constants_parts/tests_yaml_output.py | 4 +- tests/_models_parts/tests_version.py | 4 +- tests/conftest.py | 4 +- tests/protocols.py | 6 +- tests/test_yaml_model_write.py | 4 +- .../testsflextcliservice_part_01.py | 6 +- .../testsflextcliservice_part_02.py | 6 +- .../testsflextcliservice_part_04.py | 4 +- .../testsflextcliservice_part_05.py | 4 +- .../testsflextcliexamplessmoke_part_01.py | 4 +- .../testsflextcliexamplessmoke_part_02.py | 6 +- .../testsflextcliexamplessmoke_part_03.py | 4 +- .../testsflextcliexamplessmoke_part_04.py | 6 +- .../testsflextclifilescov_part_01.py | 6 +- .../testsflextclifilescov_part_02.py | 4 +- .../testsflextclijsoncov_part_01.py | 4 +- .../testsflextclioutputcov_part_02.py | 4 +- .../testsflextclipipeline_part_01.py | 8 +- .../testsflextclipipeline_part_02.py | 8 +- .../testsflextclipipeline_part_03.py | 10 +- .../testsflextcliprompts_part_01.py | 6 +- .../testsflextcliprompts_part_02.py | 6 +- ...flextclipubliccontractscoverage_part_02.py | 6 +- ...flextclipubliccontractscoverage_part_03.py | 4 +- .../testsflextclirulescov_part_01.py | 4 +- .../testsflextclirulescov_part_03.py | 4 +- .../testsflextclirulescov_part_04.py | 4 +- .../testsflextclitomlutilities_part_01.py | 6 +- .../testsflextclitomlutilities_part_02.py | 4 +- .../testsflextclitomlutilities_part_03.py | 6 +- tests/unit/conftest.py | 8 +- tests/unit/test_auth_utils_cov.py | 4 +- tests/unit/test_cmd.py | 4 +- tests/unit/test_cmd_cov.py | 6 +- tests/unit/test_conversion_cov.py | 4 +- tests/unit/test_files_cov.py | 6 +- tests/unit/test_formatters_cov.py | 4 +- tests/unit/test_json_cov.py | 4 +- tests/unit/test_matching_cov.py | 4 +- tests/unit/test_prompts_cov.py | 6 +- tests/unit/test_rules_cov.py | 6 +- tests/unit/test_runtime_utilities_core.py | 6 +- tests/unit/test_runtime_utilities_extra.py | 4 +- tests/unit/test_services_auth_branch_cov.py | 6 +- tests/unit/test_services_auth_cov.py | 8 +- tests/unit/test_services_tables_branch_cov.py | 4 +- tests/unit/test_tables.py | 4 +- tests/unit/test_tables_cov.py | 4 +- tests/unit/test_toml_cov.py | 4 +- tests/unit/test_toml_sync_cov.py | 6 +- tests/unit/test_toml_utilities.py | 4 +- tests/unit/test_typings.py | 4 +- tests/unit/test_yaml_cov.py | 6 +- tests/unit/test_yaml_roundtrip.py | 4 +- 110 files changed, 334 insertions(+), 732 deletions(-) diff --git a/examples/_models_parts/examples_advanced.py b/examples/_models_parts/examples_advanced.py index 9acb32e17..d651c5a92 100644 --- a/examples/_models_parts/examples_advanced.py +++ b/examples/_models_parts/examples_advanced.py @@ -9,8 +9,8 @@ from examples._models_parts.examples_common import ExamplesFlextCliModelsExamplesCommon from flext_cli import m, u -if TYPE_CHECKING: - from collections.abc import MutableSequence +from collections.abc import MutableSequence + class ExamplesFlextCliModelsExamplesAdvanced: diff --git a/examples/constants.py b/examples/constants.py index 7de09b74e..1fd1cc072 100644 --- a/examples/constants.py +++ b/examples/constants.py @@ -9,8 +9,8 @@ from flext_cli import c -if TYPE_CHECKING: - from examples import t +from examples import t + class ExamplesFlextCliConstants(c): diff --git a/examples/ex_04_file_operations.py b/examples/ex_04_file_operations.py index 91bf954b6..2013b5258 100644 --- a/examples/ex_04_file_operations.py +++ b/examples/ex_04_file_operations.py @@ -14,8 +14,8 @@ from flext_cli import c, cli, m, p, r, t, u -if TYPE_CHECKING: - from pathlib import Path +from pathlib import Path + _EXAMPLE_REQUIRED_DATA_FIELDS: t.VariadicTuple[str] = ("id", "name", "value") diff --git a/examples/protocols.py b/examples/protocols.py index 2a278f804..ff8abe1c9 100644 --- a/examples/protocols.py +++ b/examples/protocols.py @@ -6,10 +6,10 @@ from flext_cli import p -if TYPE_CHECKING: - from collections.abc import ( - Callable, - ) +from collections.abc import ( + Callable, +) + class ExamplesFlextCliProtocols(p): diff --git a/examples/utilities.py b/examples/utilities.py index 62c94350a..e36d91f67 100644 --- a/examples/utilities.py +++ b/examples/utilities.py @@ -16,10 +16,10 @@ from examples import c, m, t from flext_cli import cli, u -if TYPE_CHECKING: - from collections.abc import ( - MutableSequence, - ) +from collections.abc import ( + MutableSequence, +) + class ExamplesFlextCliUtilities(u): diff --git a/src/flext_cli/__init__.py b/src/flext_cli/__init__.py index f5080dcea..1a8c0078d 100644 --- a/src/flext_cli/__init__.py +++ b/src/flext_cli/__init__.py @@ -6,48 +6,56 @@ from typing import TYPE_CHECKING from flext_cli.__version__ import ( - __author__ as __author__, - __author_email__ as __author_email__, - __description__ as __description__, - __license__ as __license__, - __title__ as __title__, - __url__ as __url__, - __version__ as __version__, - __version_info__ as __version_info__, + __author__, + __author_email__, + __description__, + __license__, + __title__, + __url__, + __version__, + __version_info__, ) from flext_core.lazy import build_lazy_import_map, install_lazy_exports if TYPE_CHECKING: - from flext_cli import services as services - from flext_cli._config import FlextCliConfig as FlextCliConfig, config as config - from flext_cli._settings import ( - FlextCliSettings as FlextCliSettings, - settings as settings, - ) - from flext_cli.api import FlextCli as FlextCli, cli as cli - from flext_cli.base import FlextCliServiceBase as FlextCliServiceBase, s as s - from flext_cli.constants import FlextCliConstants as FlextCliConstants, c as c - from flext_cli.models import FlextCliModels as FlextCliModels, m as m - from flext_cli.protocols import FlextCliProtocols as FlextCliProtocols, p as p - from flext_cli.services.auth import FlextCliAuth as FlextCliAuth - from flext_cli.services.cli import FlextCliCli as FlextCliCli - from flext_cli.services.cli_params import ( - FlextCliCommonParams as FlextCliCommonParams, + from flext_core import d, e, h, r, x + + from ._config import FlextCliConfig, config + from ._settings import FlextCliSettings, settings + from .api import FlextCli, cli + from .base import FlextCliServiceBase, s + from .constants import FlextCliConstants, FlextCliConstants as c + from .models import FlextCliModels, FlextCliModels as m + from .protocols import FlextCliProtocols, FlextCliProtocols as p + from .typings import FlextCliTypes, FlextCliTypes as t + from .utilities import FlextCliUtilities, FlextCliUtilities as u + + _ = ( + c, + FlextCliConstants, + t, + FlextCliTypes, + p, + FlextCliProtocols, + m, + FlextCliModels, + u, + FlextCliUtilities, + d, + e, + h, + r, + x, + s, + FlextCliServiceBase, + FlextCliConfig, + config, + FlextCliSettings, + settings, + FlextCli, + cli, ) - from flext_cli.services.cmd import FlextCliCmd as FlextCliCmd - from flext_cli.services.file_tools import FlextCliFileTools as FlextCliFileTools - from flext_cli.services.formatters import FlextCliFormatters as FlextCliFormatters - from flext_cli.services.output import FlextCliOutput as FlextCliOutput - from flext_cli.services.pipeline import FlextCliPipeline as FlextCliPipeline - from flext_cli.services.prompts import FlextCliPrompts as FlextCliPrompts - from flext_cli.services.rules import FlextCliRules as FlextCliRules - from flext_cli.services.runtime import FlextCliRuntime as FlextCliRuntime - from flext_cli.services.tables import FlextCliTables as FlextCliTables - from flext_cli.services.xlsx import FlextCliXlsx as FlextCliXlsx - from flext_cli.services.yaml_model import FlextCliYamlModel as FlextCliYamlModel - from flext_cli.typings import FlextCliTypes as FlextCliTypes, t as t - from flext_cli.utilities import FlextCliUtilities as FlextCliUtilities, u as u - from flext_core import d as d, e as e, h as h, r as r, x as x + _LAZY_MODULES: dict[str, tuple[str, ...]] = { "._config": ("FlextCliConfig", "config"), @@ -57,56 +65,65 @@ ".constants": ("FlextCliConstants", "c"), ".models": ("FlextCliModels", "m"), ".protocols": ("FlextCliProtocols", "p"), - ".services": ("services",), - ".services.auth": ("FlextCliAuth",), - ".services.cli": ("FlextCliCli",), - ".services.cli_params": ("FlextCliCommonParams",), - ".services.cmd": ("FlextCliCmd",), - ".services.file_tools": ("FlextCliFileTools",), - ".services.formatters": ("FlextCliFormatters",), - ".services.output": ("FlextCliOutput",), - ".services.pipeline": ("FlextCliPipeline",), - ".services.prompts": ("FlextCliPrompts",), - ".services.rules": ("FlextCliRules",), - ".services.runtime": ("FlextCliRuntime",), - ".services.tables": ("FlextCliTables",), - ".services.xlsx": ("FlextCliXlsx",), - ".services.yaml_model": ("FlextCliYamlModel",), ".typings": ("FlextCliTypes", "t"), ".utilities": ("FlextCliUtilities", "u"), "flext_core": ("d", "e", "h", "r", "x"), } + _LAZY_ALIAS_GROUPS: dict[str, tuple[tuple[str, str], ...]] = {} + _LAZY_IMPORTS = build_lazy_import_map( _LAZY_MODULES, alias_groups=_LAZY_ALIAS_GROUPS, sort_keys=False ) +_DIRECT_IMPORTS: tuple[str, ...] = ( + "FlextCli", + "FlextCliConfig", + "FlextCliConstants", + "FlextCliModels", + "FlextCliProtocols", + "FlextCliServiceBase", + "FlextCliSettings", + "FlextCliTypes", + "FlextCliUtilities", + "__author__", + "__author_email__", + "__description__", + "__license__", + "__title__", + "__url__", + "__version__", + "__version_info__", + "build_lazy_import_map", + "c", + "cli", + "config", + "d", + "e", + "h", + "install_lazy_exports", + "m", + "p", + "r", + "s", + "settings", + "t", + "u", + "x", +) + __all__: tuple[str, ...] = ( "FlextCli", - "FlextCliAuth", - "FlextCliCli", - "FlextCliCmd", - "FlextCliCommonParams", "FlextCliConfig", "FlextCliConstants", - "FlextCliFileTools", - "FlextCliFormatters", "FlextCliModels", - "FlextCliOutput", - "FlextCliPipeline", - "FlextCliPrompts", "FlextCliProtocols", - "FlextCliRules", - "FlextCliRuntime", "FlextCliServiceBase", "FlextCliSettings", - "FlextCliTables", "FlextCliTypes", "FlextCliUtilities", - "FlextCliXlsx", - "FlextCliYamlModel", "__author__", "__author_email__", "__description__", @@ -125,11 +142,11 @@ "p", "r", "s", - "services", "settings", "t", "u", "x", ) + install_lazy_exports(__name__, globals(), _LAZY_IMPORTS, public_exports=__all__) diff --git a/src/flext_cli/_config.py b/src/flext_cli/_config.py index 670287bc5..e537e63fb 100644 --- a/src/flext_cli/_config.py +++ b/src/flext_cli/_config.py @@ -14,15 +14,14 @@ from functools import cached_property from pathlib import Path -from typing import TYPE_CHECKING, ClassVar +from typing import ClassVar from flext_cli._models.config import FlextCliConfigModels from flext_core import FlextConfig -if TYPE_CHECKING: - # NOTE (multi-agent): accessor typed by PROTOCOL (p), never the model - # class; the protocol module enters under TYPE_CHECKING only (§2.5/§3.4). - from flext_cli._protocols.config import FlextCliProtocolsConfig +# NOTE (multi-agent): accessor typed by PROTOCOL (p), never the model +# class; the protocol module enters under TYPE_CHECKING only (§2.5/§3.4). +from flext_cli._protocols.config import FlextCliProtocolsConfig class FlextCliConfig(FlextConfig): diff --git a/src/flext_cli/_constants/__init__.py b/src/flext_cli/_constants/__init__.py index 72cb63d95..cfdd749f0 100644 --- a/src/flext_cli/_constants/__init__.py +++ b/src/flext_cli/_constants/__init__.py @@ -3,35 +3,4 @@ from __future__ import annotations -from .base import FlextCliConstantsBase as FlextCliConstantsBase -from .config import FlextCliConstantsConfig as FlextCliConstantsConfig -from .enums import FlextCliConstantsEnums as FlextCliConstantsEnums -from .errors import FlextCliConstantsErrors as FlextCliConstantsErrors -from .exceptions import CliDefinitionError as CliDefinitionError -from .exceptions import CliValidationError as CliValidationError -from .exceptions import FlextCliConstantsExceptions as FlextCliConstantsExceptions -from .files import FlextCliConstantsFiles as FlextCliConstantsFiles -from .output import FlextCliConstantsOutput as FlextCliConstantsOutput -from .pipeline import FlextCliConstantsPipeline as FlextCliConstantsPipeline -from .settings import FlextCliConstantsSettings as FlextCliConstantsSettings -from .xlsx import FlextCliConstantsXlsx as FlextCliConstantsXlsx -from .xlsx_future_functions import ( - FlextCliConstantsXlsxFutureFunctions as FlextCliConstantsXlsxFutureFunctions, -) - - -__all__: tuple[str, ...] = ( - "CliDefinitionError", - "CliValidationError", - "FlextCliConstantsBase", - "FlextCliConstantsConfig", - "FlextCliConstantsEnums", - "FlextCliConstantsErrors", - "FlextCliConstantsExceptions", - "FlextCliConstantsFiles", - "FlextCliConstantsOutput", - "FlextCliConstantsPipeline", - "FlextCliConstantsSettings", - "FlextCliConstantsXlsx", - "FlextCliConstantsXlsxFutureFunctions", -) +__all__: tuple[str, ...] = () diff --git a/src/flext_cli/_constants/base.py b/src/flext_cli/_constants/base.py index 60453fc40..92cfb4bfa 100644 --- a/src/flext_cli/_constants/base.py +++ b/src/flext_cli/_constants/base.py @@ -8,10 +8,9 @@ from __future__ import annotations import re -from typing import TYPE_CHECKING, ClassVar, Final +from typing import ClassVar, Final -if TYPE_CHECKING: - from flext_core import t +from flext_core import t class FlextCliConstantsBase: diff --git a/src/flext_cli/_constants/errors.py b/src/flext_cli/_constants/errors.py index d42101aa6..7665fc897 100644 --- a/src/flext_cli/_constants/errors.py +++ b/src/flext_cli/_constants/errors.py @@ -2,10 +2,7 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Final - -if TYPE_CHECKING: - from flext_cli import t +from typing import Final class FlextCliConstantsErrors: @@ -99,4 +96,4 @@ class FlextCliConstantsErrors: ) -__all__: t.MutableSequenceOf[str] = ["FlextCliConstantsErrors"] +__all__: tuple[str, ...] = ("FlextCliConstantsErrors",) diff --git a/src/flext_cli/_constants/files.py b/src/flext_cli/_constants/files.py index b6d66d711..a6196ebba 100644 --- a/src/flext_cli/_constants/files.py +++ b/src/flext_cli/_constants/files.py @@ -8,10 +8,9 @@ from enum import StrEnum, unique from types import MappingProxyType -from typing import TYPE_CHECKING, Final +from typing import Final -if TYPE_CHECKING: - from flext_core import t +from flext_core import t class FlextCliConstantsFiles: diff --git a/src/flext_cli/_constants/output.py b/src/flext_cli/_constants/output.py index 602faa42d..adacebec9 100644 --- a/src/flext_cli/_constants/output.py +++ b/src/flext_cli/_constants/output.py @@ -3,13 +3,13 @@ from __future__ import annotations from types import MappingProxyType -from typing import TYPE_CHECKING, ClassVar, Final +from typing import ClassVar, Final from flext_cli._constants.enums import FlextCliConstantsEnums as ce -from flext_core import c, t -if TYPE_CHECKING: - from flext_cli import t +# mro-wkii.17.26 (codex): constants may consume only the upstream typing +# facade while the local constants facade is still being composed. +from flext_core import c, t class FlextCliConstantsOutput: diff --git a/src/flext_cli/_constants/pipeline.py b/src/flext_cli/_constants/pipeline.py index 3ec574ae7..b140bbf68 100644 --- a/src/flext_cli/_constants/pipeline.py +++ b/src/flext_cli/_constants/pipeline.py @@ -2,10 +2,9 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Final +from typing import Final -if TYPE_CHECKING: - from flext_core import t +from flext_core import t class FlextCliConstantsPipeline: diff --git a/src/flext_cli/_models/__init__.py b/src/flext_cli/_models/__init__.py index 86bb83522..2b7f3c142 100644 --- a/src/flext_cli/_models/__init__.py +++ b/src/flext_cli/_models/__init__.py @@ -3,51 +3,4 @@ from __future__ import annotations -from .config import FlextCliConfigModels as FlextCliConfigModels -from .pipeline import FlextCliModelsPipeline as FlextCliModelsPipeline -from .rules import FlextCliModelsRules as FlextCliModelsRules -from .template import FlextCliModelsTemplate as FlextCliModelsTemplate -from .xlsx import FlextCliModelsXlsx as FlextCliModelsXlsx -from .xlsx_archive import FlextCliModelsXlsxArchive as FlextCliModelsXlsxArchive -from .xlsx_cells import FlextCliModelsXlsxCells as FlextCliModelsXlsxCells -from .xlsx_layout import FlextCliModelsXlsxLayout as FlextCliModelsXlsxLayout -from .xlsx_recalc import FlextCliModelsXlsxRecalc as FlextCliModelsXlsxRecalc -from .xlsx_rules import FlextCliModelsXlsxRules as FlextCliModelsXlsxRules -from .xlsx_snapshot import FlextCliModelsXlsxSnapshot as FlextCliModelsXlsxSnapshot -from .xlsx_style_catalog import ( - FlextCliModelsXlsxStyleCatalog as FlextCliModelsXlsxStyleCatalog, -) -from .xlsx_style_fills import ( - FlextCliModelsXlsxStyleFills as FlextCliModelsXlsxStyleFills, -) -from .xlsx_style_primitives import ( - FlextCliModelsXlsxStylePrimitives as FlextCliModelsXlsxStylePrimitives, -) -from .xlsx_styles import FlextCliModelsXlsxStyles as FlextCliModelsXlsxStyles -from .xlsx_tables import FlextCliModelsXlsxTables as FlextCliModelsXlsxTables -from .xlsx_validation import ( - FlextCliModelsXlsxValidation as FlextCliModelsXlsxValidation, -) -from .xlsx_workbook import FlextCliModelsXlsxWorkbook as FlextCliModelsXlsxWorkbook - - -__all__: tuple[str, ...] = ( - "FlextCliConfigModels", - "FlextCliModelsPipeline", - "FlextCliModelsRules", - "FlextCliModelsTemplate", - "FlextCliModelsXlsx", - "FlextCliModelsXlsxArchive", - "FlextCliModelsXlsxCells", - "FlextCliModelsXlsxLayout", - "FlextCliModelsXlsxRecalc", - "FlextCliModelsXlsxRules", - "FlextCliModelsXlsxSnapshot", - "FlextCliModelsXlsxStyleCatalog", - "FlextCliModelsXlsxStyleFills", - "FlextCliModelsXlsxStylePrimitives", - "FlextCliModelsXlsxStyles", - "FlextCliModelsXlsxTables", - "FlextCliModelsXlsxValidation", - "FlextCliModelsXlsxWorkbook", -) +__all__: tuple[str, ...] = () diff --git a/src/flext_cli/_models/_base_parts/__init__.py b/src/flext_cli/_models/_base_parts/__init__.py index 9c1c5d196..9880a96e9 100644 --- a/src/flext_cli/_models/_base_parts/__init__.py +++ b/src/flext_cli/_models/_base_parts/__init__.py @@ -3,7 +3,4 @@ from __future__ import annotations -from .flextclimodelsbase_part_07 import FlextCliModelsBase as FlextCliModelsBase - - -__all__: tuple[str, ...] = ("FlextCliModelsBase",) +__all__: tuple[str, ...] = () diff --git a/src/flext_cli/_protocols/__init__.py b/src/flext_cli/_protocols/__init__.py index 83191299f..4bce4741f 100644 --- a/src/flext_cli/_protocols/__init__.py +++ b/src/flext_cli/_protocols/__init__.py @@ -3,33 +3,4 @@ from __future__ import annotations -from .config import FlextCliProtocolsConfig as FlextCliProtocolsConfig -from .domain import FlextCliProtocolsDomain as FlextCliProtocolsDomain -from .framework import FlextCliProtocolsFramework as FlextCliProtocolsFramework -from .pipeline import FlextCliProtocolsPipeline as FlextCliProtocolsPipeline -from .xlsx import FlextCliProtocolsXlsx as FlextCliProtocolsXlsx -from .xlsx_archive import FlextCliProtocolsXlsxArchive as FlextCliProtocolsXlsxArchive -from .xlsx_rules import FlextCliProtocolsXlsxRules as FlextCliProtocolsXlsxRules -from .xlsx_snapshot import ( - FlextCliProtocolsXlsxSnapshot as FlextCliProtocolsXlsxSnapshot, -) -from .xlsx_snapshot_structure import ( - FlextCliProtocolsXlsxSnapshotStructure as FlextCliProtocolsXlsxSnapshotStructure, -) -from .xlsx_workbook import ( - FlextCliProtocolsXlsxWorkbook as FlextCliProtocolsXlsxWorkbook, -) - - -__all__: tuple[str, ...] = ( - "FlextCliProtocolsConfig", - "FlextCliProtocolsDomain", - "FlextCliProtocolsFramework", - "FlextCliProtocolsPipeline", - "FlextCliProtocolsXlsx", - "FlextCliProtocolsXlsxArchive", - "FlextCliProtocolsXlsxRules", - "FlextCliProtocolsXlsxSnapshot", - "FlextCliProtocolsXlsxSnapshotStructure", - "FlextCliProtocolsXlsxWorkbook", -) +__all__: tuple[str, ...] = () diff --git a/src/flext_cli/_protocols/_base_parts/__init__.py b/src/flext_cli/_protocols/_base_parts/__init__.py index 2f4affd32..9880a96e9 100644 --- a/src/flext_cli/_protocols/_base_parts/__init__.py +++ b/src/flext_cli/_protocols/_base_parts/__init__.py @@ -3,9 +3,4 @@ from __future__ import annotations -from .flextcliprotocolsbase_part_05 import ( - FlextCliProtocolsBase as FlextCliProtocolsBase, -) - - -__all__: tuple[str, ...] = ("FlextCliProtocolsBase",) +__all__: tuple[str, ...] = () diff --git a/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_03.py b/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_03.py index a6aabd627..75eddf105 100644 --- a/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_03.py +++ b/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_03.py @@ -6,14 +6,13 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Protocol, runtime_checkable +from typing import Protocol, runtime_checkable from flext_cli._protocols._base_parts.flextcliprotocolsbase_part_02 import ( FlextCliProtocolsBase as FlextCliProtocolsBasePart02, ) -if TYPE_CHECKING: - from flext_cli import p, t +from flext_cli import p, t class FlextCliProtocolsBase(FlextCliProtocolsBasePart02): diff --git a/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_04.py b/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_04.py index 1f50c27ff..46c99a376 100644 --- a/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_04.py +++ b/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_04.py @@ -6,17 +6,16 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Protocol, runtime_checkable +from typing import Protocol, runtime_checkable from flext_cli._protocols._base_parts.flextcliprotocolsbase_part_03 import ( FlextCliProtocolsBase as FlextCliProtocolsBasePart03, ) from flext_core import p -if TYPE_CHECKING: - # Why (multi-agent): defer flext_cli import to break the __init__-time - # circular import; t is annotation-only (PEP 563). Matches sibling part_03. - from flext_cli import m, t +# Why (multi-agent): defer flext_cli import to break the __init__-time +# circular import; t is annotation-only (PEP 563). Matches sibling part_03. +from flext_cli import m, t class FlextCliProtocolsBase(FlextCliProtocolsBasePart03): diff --git a/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_05.py b/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_05.py index 2cff030ff..d7f14b389 100644 --- a/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_05.py +++ b/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_05.py @@ -6,16 +6,15 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Protocol, runtime_checkable +from typing import Protocol, runtime_checkable from flext_cli._protocols._base_parts.flextcliprotocolsbase_part_04 import ( FlextCliProtocolsBase as FlextCliProtocolsBasePart04, ) -if TYPE_CHECKING: - # Why (multi-agent): defer flext_cli import to break the __init__-time - # circular import; t is annotation-only (PEP 563). Matches sibling part_03. - from flext_cli import t +# Why (multi-agent): defer flext_cli import to break the __init__-time +# circular import; t is annotation-only (PEP 563). Matches sibling part_03. +from flext_cli import t class FlextCliProtocolsBase(FlextCliProtocolsBasePart04): diff --git a/src/flext_cli/_protocols/pipeline.py b/src/flext_cli/_protocols/pipeline.py index c6c4a0828..5e62abf22 100644 --- a/src/flext_cli/_protocols/pipeline.py +++ b/src/flext_cli/_protocols/pipeline.py @@ -4,14 +4,13 @@ from collections.abc import Callable from pathlib import Path -from typing import TYPE_CHECKING, Protocol, runtime_checkable +from typing import Protocol, runtime_checkable from flext_cli import t from flext_core import p -if TYPE_CHECKING: - # mro-j47u (codex): p -> m is a reverse facade edge; keep it type-only. - from flext_cli import m +# mro-j47u (codex): p -> m is a reverse facade edge; keep it type-only. +from flext_cli import m class FlextCliProtocolsPipeline: diff --git a/src/flext_cli/_protocols/xlsx.py b/src/flext_cli/_protocols/xlsx.py index 172f56309..65648bf22 100644 --- a/src/flext_cli/_protocols/xlsx.py +++ b/src/flext_cli/_protocols/xlsx.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Protocol, runtime_checkable +from typing import Protocol, runtime_checkable from flext_core import p @@ -11,9 +11,8 @@ from .xlsx_snapshot import FlextCliProtocolsXlsxSnapshot from .xlsx_workbook import FlextCliProtocolsXlsxWorkbook -if TYPE_CHECKING: - # mro-j47u (codex): p -> m stays type-only through the canonical facade. - from flext_cli import m +# mro-j47u (codex): p -> m stays type-only through the canonical facade. +from flext_cli import m class FlextCliProtocolsXlsx( diff --git a/src/flext_cli/_protocols/xlsx_snapshot.py b/src/flext_cli/_protocols/xlsx_snapshot.py index 42bbde9aa..b68e3b748 100644 --- a/src/flext_cli/_protocols/xlsx_snapshot.py +++ b/src/flext_cli/_protocols/xlsx_snapshot.py @@ -2,15 +2,14 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Protocol, runtime_checkable +from typing import Protocol, runtime_checkable from flext_core import p from .xlsx_snapshot_structure import FlextCliProtocolsXlsxSnapshotStructure -if TYPE_CHECKING: - # mro-j47u (codex): p -> m stays type-only through the canonical facade. - from flext_cli import m +# mro-j47u (codex): p -> m stays type-only through the canonical facade. +from flext_cli import m class FlextCliProtocolsXlsxSnapshot(FlextCliProtocolsXlsxSnapshotStructure): diff --git a/src/flext_cli/_typings/__init__.py b/src/flext_cli/_typings/__init__.py index fb06386ef..7e509b92c 100644 --- a/src/flext_cli/_typings/__init__.py +++ b/src/flext_cli/_typings/__init__.py @@ -3,15 +3,4 @@ from __future__ import annotations -from .base import FlextCliTypesBase as FlextCliTypesBase -from .domain import FlextCliTypesDomain as FlextCliTypesDomain -from .pipeline import FlextCliTypesPipeline as FlextCliTypesPipeline -from .xlsx import FlextCliTypesXlsx as FlextCliTypesXlsx - - -__all__: tuple[str, ...] = ( - "FlextCliTypesBase", - "FlextCliTypesDomain", - "FlextCliTypesPipeline", - "FlextCliTypesXlsx", -) +__all__: tuple[str, ...] = () diff --git a/src/flext_cli/_typings/pipeline.py b/src/flext_cli/_typings/pipeline.py index 39ff30838..7613db430 100644 --- a/src/flext_cli/_typings/pipeline.py +++ b/src/flext_cli/_typings/pipeline.py @@ -3,13 +3,12 @@ from __future__ import annotations from collections.abc import Callable -from typing import TYPE_CHECKING, Literal +from typing import Literal from flext_cli import c from flext_core import p, t -if TYPE_CHECKING: - from flext_cli import m +from flext_cli import m class FlextCliTypesPipeline: diff --git a/src/flext_cli/_utilities/__init__.py b/src/flext_cli/_utilities/__init__.py index c38b5c132..f059cf2f9 100644 --- a/src/flext_cli/_utilities/__init__.py +++ b/src/flext_cli/_utilities/__init__.py @@ -3,59 +3,4 @@ from __future__ import annotations -from ._cli_namespace import FlextCliUtilitiesCli as FlextCliUtilitiesCli -from .auth import FlextCliUtilitiesAuth as FlextCliUtilitiesAuth -from .cmd import FlextCliUtilitiesCmd as FlextCliUtilitiesCmd -from .commands import FlextCliUtilitiesCommands as FlextCliUtilitiesCommands -from .config import FlextCliUtilitiesConfig as FlextCliUtilitiesConfig -from .conversion import FlextCliUtilitiesConversion as FlextCliUtilitiesConversion -from .formatters import FlextCliUtilitiesFormatters as FlextCliUtilitiesFormatters -from .framework import FlextCliUtilitiesFramework as FlextCliUtilitiesFramework -from .json import FlextCliUtilitiesJson as FlextCliUtilitiesJson -from .matching import FlextCliUtilitiesMatching as FlextCliUtilitiesMatching -from .model_commands import ( - FlextCliUtilitiesModelCommands as FlextCliUtilitiesModelCommands, -) -from .output import FlextCliUtilitiesOutput as FlextCliUtilitiesOutput -from .params import FlextCliUtilitiesParams as FlextCliUtilitiesParams -from .pipeline import FlextCliUtilitiesPipeline as FlextCliUtilitiesPipeline -from .processes import FlextCliUtilitiesProcesses as FlextCliUtilitiesProcesses -from .prompts import FlextCliUtilitiesPrompts as FlextCliUtilitiesPrompts -from .rules import FlextCliUtilitiesRules as FlextCliUtilitiesRules -from .runtime import FlextCliUtilitiesRuntime as FlextCliUtilitiesRuntime -from .settings import FlextCliUtilitiesSettings as FlextCliUtilitiesSettings -from .tables import FlextCliUtilitiesTables as FlextCliUtilitiesTables -from .template import FlextCliUtilitiesTemplate as FlextCliUtilitiesTemplate -from .validation import FlextCliUtilitiesValidation as FlextCliUtilitiesValidation -from .xlsx import FlextCliUtilitiesXlsx as FlextCliUtilitiesXlsx -from .yaml import FlextCliUtilitiesYaml as FlextCliUtilitiesYaml -from .yaml_model import FlextCliUtilitiesYamlModel as FlextCliUtilitiesYamlModel - - -__all__: tuple[str, ...] = ( - "FlextCliUtilitiesAuth", - "FlextCliUtilitiesCli", - "FlextCliUtilitiesCmd", - "FlextCliUtilitiesCommands", - "FlextCliUtilitiesConfig", - "FlextCliUtilitiesConversion", - "FlextCliUtilitiesFormatters", - "FlextCliUtilitiesFramework", - "FlextCliUtilitiesJson", - "FlextCliUtilitiesMatching", - "FlextCliUtilitiesModelCommands", - "FlextCliUtilitiesOutput", - "FlextCliUtilitiesParams", - "FlextCliUtilitiesPipeline", - "FlextCliUtilitiesProcesses", - "FlextCliUtilitiesPrompts", - "FlextCliUtilitiesRules", - "FlextCliUtilitiesRuntime", - "FlextCliUtilitiesSettings", - "FlextCliUtilitiesTables", - "FlextCliUtilitiesTemplate", - "FlextCliUtilitiesValidation", - "FlextCliUtilitiesXlsx", - "FlextCliUtilitiesYaml", - "FlextCliUtilitiesYamlModel", -) +__all__: tuple[str, ...] = () diff --git a/src/flext_cli/_utilities/_file_test_helper_parts/__init__.py b/src/flext_cli/_utilities/_file_test_helper_parts/__init__.py index 26e9d9b9d..e1b9db66c 100644 --- a/src/flext_cli/_utilities/_file_test_helper_parts/__init__.py +++ b/src/flext_cli/_utilities/_file_test_helper_parts/__init__.py @@ -3,9 +3,4 @@ from __future__ import annotations -from .flextcliutilitiesfiletesthelpersmixin_part_04 import ( - FlextCliUtilitiesFileTestHelpersMixin as FlextCliUtilitiesFileTestHelpersMixin, -) - - -__all__: tuple[str, ...] = ("FlextCliUtilitiesFileTestHelpersMixin",) +__all__: tuple[str, ...] = () diff --git a/src/flext_cli/_utilities/_file_test_helper_parts/flextcliutilitiesfiletesthelpersmixin_part_02.py b/src/flext_cli/_utilities/_file_test_helper_parts/flextcliutilitiesfiletesthelpersmixin_part_02.py index af932d2a8..ff1a49fdf 100644 --- a/src/flext_cli/_utilities/_file_test_helper_parts/flextcliutilitiesfiletesthelpersmixin_part_02.py +++ b/src/flext_cli/_utilities/_file_test_helper_parts/flextcliutilitiesfiletesthelpersmixin_part_02.py @@ -9,10 +9,8 @@ from __future__ import annotations import os -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from pathlib import Path +from pathlib import Path class FlextCliUtilitiesFileTestHelpersMixin: diff --git a/src/flext_cli/_utilities/_file_test_helper_parts/flextcliutilitiesfiletesthelpersmixin_part_03.py b/src/flext_cli/_utilities/_file_test_helper_parts/flextcliutilitiesfiletesthelpersmixin_part_03.py index a4230ab6d..bc63180fc 100644 --- a/src/flext_cli/_utilities/_file_test_helper_parts/flextcliutilitiesfiletesthelpersmixin_part_03.py +++ b/src/flext_cli/_utilities/_file_test_helper_parts/flextcliutilitiesfiletesthelpersmixin_part_03.py @@ -9,7 +9,6 @@ from __future__ import annotations from collections.abc import Mapping, MutableMapping -from typing import TYPE_CHECKING from flext_cli import c, p, r from flext_cli._utilities._file_test_helper_parts.flextcliutilitiesfiletesthelpersmixin_part_04 import ( @@ -17,8 +16,7 @@ ) from flext_cli._utilities.files import FlextCliUtilitiesFiles -if TYPE_CHECKING: - from pathlib import Path +from pathlib import Path class FlextCliUtilitiesFileTestHelpersMixin: diff --git a/src/flext_cli/_utilities/_file_test_helper_parts/flextcliutilitiesfiletesthelpersmixin_part_04.py b/src/flext_cli/_utilities/_file_test_helper_parts/flextcliutilitiesfiletesthelpersmixin_part_04.py index 1d1050504..277ae706b 100644 --- a/src/flext_cli/_utilities/_file_test_helper_parts/flextcliutilitiesfiletesthelpersmixin_part_04.py +++ b/src/flext_cli/_utilities/_file_test_helper_parts/flextcliutilitiesfiletesthelpersmixin_part_04.py @@ -8,15 +8,13 @@ from __future__ import annotations -from typing import TYPE_CHECKING from flext_cli import c, p, r from flext_cli._utilities.json import FlextCliUtilitiesJson as uj from flext_cli._utilities.toml import FlextCliUtilitiesToml as ut from flext_cli._utilities.yaml import FlextCliUtilitiesYaml as uy -if TYPE_CHECKING: - from pathlib import Path +from pathlib import Path class FlextCliUtilitiesFileTestHelpersMixin: diff --git a/src/flext_cli/_utilities/_files_parts/__init__.py b/src/flext_cli/_utilities/_files_parts/__init__.py index f0644a9c8..8cd7456a8 100644 --- a/src/flext_cli/_utilities/_files_parts/__init__.py +++ b/src/flext_cli/_utilities/_files_parts/__init__.py @@ -3,9 +3,4 @@ from __future__ import annotations -from .flextcliutilitiesfiles_part_04 import ( - FlextCliUtilitiesFiles as FlextCliUtilitiesFiles, -) - - -__all__: tuple[str, ...] = ("FlextCliUtilitiesFiles",) +__all__: tuple[str, ...] = () diff --git a/src/flext_cli/_utilities/_json/__init__.py b/src/flext_cli/_utilities/_json/__init__.py index a26ef0b46..f1b944ab2 100644 --- a/src/flext_cli/_utilities/_json/__init__.py +++ b/src/flext_cli/_utilities/_json/__init__.py @@ -3,13 +3,4 @@ from __future__ import annotations -from ._core import FlextCliUtilitiesJsonCoreMixin as FlextCliUtilitiesJsonCoreMixin -from ._navigate import ( - FlextCliUtilitiesJsonNavigateMixin as FlextCliUtilitiesJsonNavigateMixin, -) - - -__all__: tuple[str, ...] = ( - "FlextCliUtilitiesJsonCoreMixin", - "FlextCliUtilitiesJsonNavigateMixin", -) +__all__: tuple[str, ...] = () diff --git a/src/flext_cli/_utilities/_json/_navigate.py b/src/flext_cli/_utilities/_json/_navigate.py index 6b3faf476..def33acfe 100644 --- a/src/flext_cli/_utilities/_json/_navigate.py +++ b/src/flext_cli/_utilities/_json/_navigate.py @@ -10,14 +10,12 @@ from __future__ import annotations -from typing import TYPE_CHECKING from flext_core import u from ._core import FlextCliUtilitiesJsonCoreMixin -if TYPE_CHECKING: - from flext_cli import t +from flext_cli import t class FlextCliUtilitiesJsonNavigateMixin(FlextCliUtilitiesJsonCoreMixin): diff --git a/src/flext_cli/_utilities/_options_parts/__init__.py b/src/flext_cli/_utilities/_options_parts/__init__.py index 3918ec75a..82c7ccfac 100644 --- a/src/flext_cli/_utilities/_options_parts/__init__.py +++ b/src/flext_cli/_utilities/_options_parts/__init__.py @@ -3,15 +3,4 @@ from __future__ import annotations -from .flextcliutilitiesoptionbuilder_part_01 import ( - FlextCliUtilitiesOptionBuilder as FlextCliUtilitiesOptionBuilder, -) -from .flextcliutilitiesoptions_part_02 import ( - FlextCliUtilitiesOptions as FlextCliUtilitiesOptions, -) - - -__all__: tuple[str, ...] = ( - "FlextCliUtilitiesOptionBuilder", - "FlextCliUtilitiesOptions", -) +__all__: tuple[str, ...] = () diff --git a/src/flext_cli/_utilities/_rules/__init__.py b/src/flext_cli/_utilities/_rules/__init__.py index 82055dce9..89da3c6f2 100644 --- a/src/flext_cli/_utilities/_rules/__init__.py +++ b/src/flext_cli/_utilities/_rules/__init__.py @@ -3,16 +3,4 @@ from __future__ import annotations - -from ._loaders import ( - FlextCliUtilitiesRulesLoadersMixin as FlextCliUtilitiesRulesLoadersMixin, -) -from ._matchers import ( - FlextCliUtilitiesRulesMatchersMixin as FlextCliUtilitiesRulesMatchersMixin, -) - - -__all__: tuple[str, ...] = ( - "FlextCliUtilitiesRulesLoadersMixin", - "FlextCliUtilitiesRulesMatchersMixin", -) +__all__: tuple[str, ...] = () diff --git a/src/flext_cli/_utilities/_rules/_loaders.py b/src/flext_cli/_utilities/_rules/_loaders.py index dcd7c09cf..fab7606ad 100644 --- a/src/flext_cli/_utilities/_rules/_loaders.py +++ b/src/flext_cli/_utilities/_rules/_loaders.py @@ -11,7 +11,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING from flext_cli import c, m, p, r, t from flext_cli._utilities.json import FlextCliUtilitiesJson as uj @@ -19,8 +18,7 @@ from ._matchers import FlextCliUtilitiesRulesMatchersMixin -if TYPE_CHECKING: - from pathlib import Path +from pathlib import Path class FlextCliUtilitiesRulesLoadersMixin(FlextCliUtilitiesRulesMatchersMixin): diff --git a/src/flext_cli/_utilities/_rules/_matchers.py b/src/flext_cli/_utilities/_rules/_matchers.py index bbf1f0177..aa3183e6a 100644 --- a/src/flext_cli/_utilities/_rules/_matchers.py +++ b/src/flext_cli/_utilities/_rules/_matchers.py @@ -13,14 +13,12 @@ import fnmatch from collections.abc import Mapping, MutableSequence -from typing import TYPE_CHECKING from flext_cli._utilities.json import FlextCliUtilitiesJson as uj -if TYPE_CHECKING: - from pathlib import Path +from pathlib import Path - from flext_cli import t +from flext_cli import t class FlextCliUtilitiesRulesMatchersMixin: diff --git a/src/flext_cli/_utilities/_toml_parts/__init__.py b/src/flext_cli/_utilities/_toml_parts/__init__.py index 8aa76b05b..5d099c342 100644 --- a/src/flext_cli/_utilities/_toml_parts/__init__.py +++ b/src/flext_cli/_utilities/_toml_parts/__init__.py @@ -3,9 +3,4 @@ from __future__ import annotations -from .flextcliutilitiestoml_part_07 import ( - FlextCliUtilitiesToml as FlextCliUtilitiesToml, -) - - -__all__: tuple[str, ...] = ("FlextCliUtilitiesToml",) +__all__: tuple[str, ...] = () diff --git a/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_02.py b/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_02.py index 95265beba..d85b3ee68 100644 --- a/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_02.py +++ b/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_02.py @@ -2,14 +2,13 @@ from __future__ import annotations -from typing import TYPE_CHECKING, TypeIs +from typing import TypeIs import tomlkit from tomlkit.items import AoT, Item, Table from tomlkit.toml_document import TOMLDocument -if TYPE_CHECKING: - from flext_cli import t +from flext_cli import t class FlextCliUtilitiesToml: diff --git a/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_04.py b/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_04.py index b31bc1768..f0eb87893 100644 --- a/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_04.py +++ b/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_04.py @@ -2,7 +2,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING from flext_cli._utilities._toml_parts.flextcliutilitiestoml_part_01 import ( FlextCliUtilitiesToml as FlextCliUtilitiesTomlPart01, @@ -12,11 +11,10 @@ ) from flext_core import u -if TYPE_CHECKING: - from tomlkit.items import Table - from tomlkit.toml_document import TOMLDocument +from tomlkit.items import Table +from tomlkit.toml_document import TOMLDocument - from flext_cli import t +from flext_cli import t class FlextCliUtilitiesToml: diff --git a/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_05.py b/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_05.py index b245ae482..d8be3f6a1 100644 --- a/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_05.py +++ b/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_05.py @@ -3,7 +3,6 @@ from __future__ import annotations from collections.abc import Mapping -from typing import TYPE_CHECKING from tomlkit.items import Item, Table from tomlkit.toml_document import TOMLDocument @@ -19,8 +18,7 @@ ) from flext_core import u -if TYPE_CHECKING: - from flext_cli import t +from flext_cli import t class FlextCliUtilitiesToml: diff --git a/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_06.py b/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_06.py index 8d4cbc70f..cd6a18527 100644 --- a/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_06.py +++ b/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_06.py @@ -2,7 +2,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING import tomlkit from tomlkit.toml_document import TOMLDocument @@ -14,8 +13,7 @@ from flext_cli._utilities.runtime import FlextCliUtilitiesRuntime as ur from flext_core import u -if TYPE_CHECKING: - from pathlib import Path +from pathlib import Path class FlextCliUtilitiesToml: diff --git a/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_07.py b/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_07.py index f9ae59c76..4c76a69ac 100644 --- a/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_07.py +++ b/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_07.py @@ -2,7 +2,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING from flext_cli import c, e, p, r, t from flext_cli._utilities._toml_parts.flextcliutilitiestoml_part_01 import ( @@ -12,8 +11,7 @@ FlextCliUtilitiesToml as FlextCliUtilitiesTomlPart06, ) -if TYPE_CHECKING: - from pathlib import Path +from pathlib import Path class FlextCliUtilitiesToml: diff --git a/src/flext_cli/_utilities/_xlxx/__init__.py b/src/flext_cli/_utilities/_xlxx/__init__.py index 21180f24f..e2f75d0b9 100644 --- a/src/flext_cli/_utilities/_xlxx/__init__.py +++ b/src/flext_cli/_utilities/_xlxx/__init__.py @@ -3,91 +3,4 @@ from __future__ import annotations -from .xlsx_addresses import ( - FlextCliUtilitiesXlsxAddresses as FlextCliUtilitiesXlsxAddresses, -) -from .xlsx_archive import FlextCliUtilitiesXlsxArchive as FlextCliUtilitiesXlsxArchive -from .xlsx_archive_checks import ( - FlextCliUtilitiesXlsxArchiveChecks as FlextCliUtilitiesXlsxArchiveChecks, -) -from .xlsx_cells import FlextCliUtilitiesXlsxCells as FlextCliUtilitiesXlsxCells -from .xlsx_conditional import ( - FlextCliUtilitiesXlsxConditional as FlextCliUtilitiesXlsxConditional, -) -from .xlsx_formula_codec import ( - FlextCliUtilitiesXlsxFormulaCodec as FlextCliUtilitiesXlsxFormulaCodec, -) -from .xlsx_layout import FlextCliUtilitiesXlsxLayout as FlextCliUtilitiesXlsxLayout -from .xlsx_protection import ( - FlextCliUtilitiesXlsxProtection as FlextCliUtilitiesXlsxProtection, -) -from .xlsx_recalc import FlextCliUtilitiesXlsxRecalc as FlextCliUtilitiesXlsxRecalc -from .xlsx_recalc_evidence import ( - FlextCliUtilitiesXlsxRecalcEvidence as FlextCliUtilitiesXlsxRecalcEvidence, -) -from .xlsx_renderer import ( - FlextCliUtilitiesXlsxRenderer as FlextCliUtilitiesXlsxRenderer, -) -from .xlsx_rules import FlextCliUtilitiesXlsxRules as FlextCliUtilitiesXlsxRules -from .xlsx_snapshot import ( - FlextCliUtilitiesXlsxSnapshot as FlextCliUtilitiesXlsxSnapshot, -) -from .xlsx_snapshot_sheet import ( - FlextCliUtilitiesXlsxSnapshotSheet as FlextCliUtilitiesXlsxSnapshotSheet, -) -from .xlsx_snapshot_structure import ( - FlextCliUtilitiesXlsxSnapshotStructure as FlextCliUtilitiesXlsxSnapshotStructure, -) -from .xlsx_snapshot_values import ( - FlextCliUtilitiesXlsxSnapshotValues as FlextCliUtilitiesXlsxSnapshotValues, -) -from .xlsx_style_builders import ( - FlextCliUtilitiesXlsxStyleBuilders as FlextCliUtilitiesXlsxStyleBuilders, -) -from .xlsx_style_catalog import ( - FlextCliUtilitiesXlsxStyleCatalog as FlextCliUtilitiesXlsxStyleCatalog, -) -from .xlsx_style_codec import ( - FlextCliUtilitiesXlsxStyleCodec as FlextCliUtilitiesXlsxStyleCodec, -) -from .xlsx_style_readers import ( - FlextCliUtilitiesXlsxStyleReaders as FlextCliUtilitiesXlsxStyleReaders, -) -from .xlsx_tables import FlextCliUtilitiesXlsxTables as FlextCliUtilitiesXlsxTables -from .xlsx_validations import ( - FlextCliUtilitiesXlsxValidations as FlextCliUtilitiesXlsxValidations, -) -from .xlsx_workbook_io import ( - FlextCliUtilitiesXlsxWorkbookIo as FlextCliUtilitiesXlsxWorkbookIo, -) -from .xlsx_workbook_plan import ( - FlextCliUtilitiesXlsxWorkbookPlan as FlextCliUtilitiesXlsxWorkbookPlan, -) - - -__all__: tuple[str, ...] = ( - "FlextCliUtilitiesXlsxAddresses", - "FlextCliUtilitiesXlsxArchive", - "FlextCliUtilitiesXlsxArchiveChecks", - "FlextCliUtilitiesXlsxCells", - "FlextCliUtilitiesXlsxConditional", - "FlextCliUtilitiesXlsxFormulaCodec", - "FlextCliUtilitiesXlsxLayout", - "FlextCliUtilitiesXlsxProtection", - "FlextCliUtilitiesXlsxRecalc", - "FlextCliUtilitiesXlsxRecalcEvidence", - "FlextCliUtilitiesXlsxRenderer", - "FlextCliUtilitiesXlsxRules", - "FlextCliUtilitiesXlsxSnapshot", - "FlextCliUtilitiesXlsxSnapshotSheet", - "FlextCliUtilitiesXlsxSnapshotStructure", - "FlextCliUtilitiesXlsxSnapshotValues", - "FlextCliUtilitiesXlsxStyleBuilders", - "FlextCliUtilitiesXlsxStyleCatalog", - "FlextCliUtilitiesXlsxStyleCodec", - "FlextCliUtilitiesXlsxStyleReaders", - "FlextCliUtilitiesXlsxTables", - "FlextCliUtilitiesXlsxValidations", - "FlextCliUtilitiesXlsxWorkbookIo", - "FlextCliUtilitiesXlsxWorkbookPlan", -) +__all__: tuple[str, ...] = () diff --git a/src/flext_cli/_utilities/_yaml/__init__.py b/src/flext_cli/_utilities/_yaml/__init__.py index 9fc343907..c9102a7ec 100644 --- a/src/flext_cli/_utilities/_yaml/__init__.py +++ b/src/flext_cli/_utilities/_yaml/__init__.py @@ -3,19 +3,4 @@ from __future__ import annotations -from ._convert import ( - FlextCliUtilitiesYamlConvertMixin as FlextCliUtilitiesYamlConvertMixin, -) -from ._editing import ( - FlextCliUtilitiesYamlEditingMixin as FlextCliUtilitiesYamlEditingMixin, -) -from ._engine import ( - FlextCliUtilitiesYamlEngineMixin as FlextCliUtilitiesYamlEngineMixin, -) - - -__all__: tuple[str, ...] = ( - "FlextCliUtilitiesYamlConvertMixin", - "FlextCliUtilitiesYamlEditingMixin", - "FlextCliUtilitiesYamlEngineMixin", -) +__all__: tuple[str, ...] = () diff --git a/src/flext_cli/_utilities/_yaml/_engine.py b/src/flext_cli/_utilities/_yaml/_engine.py index bceb6938f..37a94cdbd 100644 --- a/src/flext_cli/_utilities/_yaml/_engine.py +++ b/src/flext_cli/_utilities/_yaml/_engine.py @@ -16,7 +16,7 @@ from __future__ import annotations import io -from typing import TYPE_CHECKING, TextIO +from typing import TextIO import ruamel.yaml from ruamel.yaml.comments import CommentedMap @@ -25,8 +25,7 @@ from ._convert import FlextCliUtilitiesYamlConvertMixin -if TYPE_CHECKING: - from pathlib import Path +from pathlib import Path class _YamlRoundtripEngine: diff --git a/src/flext_cli/_utilities/commands.py b/src/flext_cli/_utilities/commands.py index 946e61dcc..a7c1e1de2 100644 --- a/src/flext_cli/_utilities/commands.py +++ b/src/flext_cli/_utilities/commands.py @@ -3,15 +3,13 @@ from __future__ import annotations import traceback -from typing import TYPE_CHECKING # mro-j47u (codex): formatter contracts are owned once by the t facade. from flext_cli import c, r, t from flext_cli._utilities.output import FlextCliUtilitiesOutput as uo from flext_core import u -if TYPE_CHECKING: - from flext_cli import p +from flext_cli import p class FlextCliUtilitiesCommands: diff --git a/src/flext_cli/_utilities/framework.py b/src/flext_cli/_utilities/framework.py index 5dfdb7359..c46081d40 100644 --- a/src/flext_cli/_utilities/framework.py +++ b/src/flext_cli/_utilities/framework.py @@ -7,7 +7,7 @@ from contextvars import ContextVar from inspect import Parameter from types import EllipsisType, GenericAlias -from typing import TYPE_CHECKING, Never +from typing import Never import click import typer @@ -17,8 +17,7 @@ # mro-j47u (codex): consume every public facade through the package root. from flext_cli import c, e, r, t -if TYPE_CHECKING: - from flext_cli import m, p +from flext_cli import m, p class _TyperApplication: diff --git a/src/flext_cli/_utilities/model_commands.py b/src/flext_cli/_utilities/model_commands.py index 95e136a00..dfea5b013 100644 --- a/src/flext_cli/_utilities/model_commands.py +++ b/src/flext_cli/_utilities/model_commands.py @@ -14,7 +14,7 @@ from collections.abc import Callable, Mapping from typing import cast -from flext_cli import p, settings, t +from flext_cli import settings, t from flext_core import m @@ -25,16 +25,12 @@ class Builder[M: t.Cli.ModelLike]: """Thin builder for direct model-backed command callables.""" def __init__( - self, - model_class: t.ModelClass[M], - handler: Callable[[M], t.JsonValue], - settings: t.Cli.ModelLike | None = None, + self, model_class: t.ModelClass[M], handler: Callable[[M], t.JsonValue] ) -> None: """Store the canonical inputs for deferred command construction.""" super().__init__() self.model_class = model_class self.handler = handler - self.settings = settings def _resolve_default(self, field_info: m.FieldInfo) -> t.Cli.CliValue | type: if field_info.is_required(): @@ -61,24 +57,21 @@ def build(self) -> t.Cli.CliCommand: ] signature = inspect.Signature(parameters) - # NOTE (multi-agent): ``self.settings`` (per-command, may be any + # NOTE (multi-agent): ``settings`` (per-command, may be any # model or None) falls back to the module settings singleton. # Overrides apply only when the effective settings is a full # Settings protocol (has update_global) — a plain model skips them. - effective_settings = ( - self.settings if self.settings is not None else settings - ) + effective_settings = settings def command(**kwargs: t.Cli.CliValue) -> t.JsonValue: - if isinstance(effective_settings, p.Cli.Settings): - settings_fields = effective_settings.model_dump() - applicable_overrides = { - field_name: field_value - for field_name, field_value in kwargs.items() - if field_name in settings_fields - } - if applicable_overrides: - effective_settings.update_global(**applicable_overrides) + settings_fields = effective_settings.model_dump() + applicable_overrides = { + field_name: field_value + for field_name, field_value in kwargs.items() + if field_name in settings_fields + } + if applicable_overrides: + effective_settings.update_global(**applicable_overrides) model = self.model_class.model_validate(kwargs) return self.handler(model) diff --git a/src/flext_cli/services/__init__.py b/src/flext_cli/services/__init__.py index 7ca91216c..f4dc05e8b 100644 --- a/src/flext_cli/services/__init__.py +++ b/src/flext_cli/services/__init__.py @@ -3,35 +3,4 @@ from __future__ import annotations -from .auth import FlextCliAuth as FlextCliAuth -from .cli import FlextCliCli as FlextCliCli -from .cli_params import FlextCliCommonParams as FlextCliCommonParams -from .cmd import FlextCliCmd as FlextCliCmd -from .file_tools import FlextCliFileTools as FlextCliFileTools -from .formatters import FlextCliFormatters as FlextCliFormatters -from .output import FlextCliOutput as FlextCliOutput -from .pipeline import FlextCliPipeline as FlextCliPipeline -from .prompts import FlextCliPrompts as FlextCliPrompts -from .rules import FlextCliRules as FlextCliRules -from .runtime import FlextCliRuntime as FlextCliRuntime -from .tables import FlextCliTables as FlextCliTables -from .xlsx import FlextCliXlsx as FlextCliXlsx -from .yaml_model import FlextCliYamlModel as FlextCliYamlModel - - -__all__: tuple[str, ...] = ( - "FlextCliAuth", - "FlextCliCli", - "FlextCliCmd", - "FlextCliCommonParams", - "FlextCliFileTools", - "FlextCliFormatters", - "FlextCliOutput", - "FlextCliPipeline", - "FlextCliPrompts", - "FlextCliRules", - "FlextCliRuntime", - "FlextCliTables", - "FlextCliXlsx", - "FlextCliYamlModel", -) +__all__: tuple[str, ...] = () diff --git a/src/flext_cli/services/_cli_parts/__init__.py b/src/flext_cli/services/_cli_parts/__init__.py index 9f7b4c94d..45aa2f42e 100644 --- a/src/flext_cli/services/_cli_parts/__init__.py +++ b/src/flext_cli/services/_cli_parts/__init__.py @@ -3,7 +3,4 @@ from __future__ import annotations -from .flextclicli_part_05 import FlextCliCli as FlextCliCli - - -__all__: tuple[str, ...] = ("FlextCliCli",) +__all__: tuple[str, ...] = () diff --git a/src/flext_cli/services/_cli_parts/flextclicli_part_03.py b/src/flext_cli/services/_cli_parts/flextclicli_part_03.py index d59303dfd..960863c4a 100644 --- a/src/flext_cli/services/_cli_parts/flextclicli_part_03.py +++ b/src/flext_cli/services/_cli_parts/flextclicli_part_03.py @@ -7,19 +7,17 @@ from __future__ import annotations from inspect import Parameter -from typing import TYPE_CHECKING from flext_cli import c, m, p, r, t, u from flext_cli.services._cli_parts.flextclicli_part_02 import ( FlextCliCli as FlextCliCliPart02, ) -if TYPE_CHECKING: - # mro-j47u (codex): the earlier MRO part is referenced only by annotation; - # inspect.Parameter remains runtime because it constructs the CLI signature. - from flext_cli.services._cli_parts.flextclicli_part_01 import ( - FlextCliCli as FlextCliCliPart01, - ) +# mro-j47u (codex): the earlier MRO part is referenced only by annotation; +# inspect.Parameter remains runtime because it constructs the CLI signature. +from flext_cli.services._cli_parts.flextclicli_part_01 import ( + FlextCliCli as FlextCliCliPart01, +) class FlextCliCli(FlextCliCliPart02): diff --git a/src/flext_cli/services/_cli_parts/flextclicli_part_05.py b/src/flext_cli/services/_cli_parts/flextclicli_part_05.py index 1965c3d7e..6cecabc94 100644 --- a/src/flext_cli/services/_cli_parts/flextclicli_part_05.py +++ b/src/flext_cli/services/_cli_parts/flextclicli_part_05.py @@ -6,15 +6,13 @@ from __future__ import annotations -from typing import TYPE_CHECKING from flext_cli import c, r, settings, t, u from flext_cli.services._cli_parts.flextclicli_part_04 import ( FlextCliCli as FlextCliCliPart04, ) -if TYPE_CHECKING: - from flext_cli import p +from flext_cli import p class FlextCliCli(FlextCliCliPart04): diff --git a/src/flext_cli/services/_prompts_support.py b/src/flext_cli/services/_prompts_support.py index fed126ca7..d4f949bd0 100644 --- a/src/flext_cli/services/_prompts_support.py +++ b/src/flext_cli/services/_prompts_support.py @@ -10,12 +10,11 @@ from __future__ import annotations import getpass -from typing import TYPE_CHECKING, Annotated, Self +from typing import Annotated, Self from flext_cli import c, m, p, r, s, settings, t, u -if TYPE_CHECKING: - from collections.abc import Callable +from collections.abc import Callable class FlextCliPromptsSupport(s): diff --git a/tests/_constants_parts/tests_core.py b/tests/_constants_parts/tests_core.py index 04261fd38..f02498f59 100644 --- a/tests/_constants_parts/tests_core.py +++ b/tests/_constants_parts/tests_core.py @@ -9,8 +9,8 @@ from flext_cli import c -if TYPE_CHECKING: - from tests import t +from tests import t + class TestsFlextCliConstantsCore: diff --git a/tests/_constants_parts/tests_rules_options.py b/tests/_constants_parts/tests_rules_options.py index 979d2932b..cbadcfb8c 100644 --- a/tests/_constants_parts/tests_rules_options.py +++ b/tests/_constants_parts/tests_rules_options.py @@ -5,8 +5,8 @@ from types import MappingProxyType from typing import TYPE_CHECKING, Final -if TYPE_CHECKING: - from tests import t +from tests import t + class TestsFlextCliConstantsRulesOptions: diff --git a/tests/_constants_parts/tests_yaml_output.py b/tests/_constants_parts/tests_yaml_output.py index ca34455df..6c3ab56b7 100644 --- a/tests/_constants_parts/tests_yaml_output.py +++ b/tests/_constants_parts/tests_yaml_output.py @@ -6,8 +6,8 @@ from flext_cli import c -if TYPE_CHECKING: - from tests import t +from tests import t + class TestsFlextCliConstantsYamlOutput: diff --git a/tests/_models_parts/tests_version.py b/tests/_models_parts/tests_version.py index eed18433b..7ce192509 100644 --- a/tests/_models_parts/tests_version.py +++ b/tests/_models_parts/tests_version.py @@ -7,8 +7,8 @@ from flext_cli import m from tests import c -if TYPE_CHECKING: - from tests import t +from tests import t + class TestsFlextCliModelsVersion: diff --git a/tests/conftest.py b/tests/conftest.py index 8ac931259..7d40a07e4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -6,8 +6,8 @@ import pytest -if TYPE_CHECKING: - from tests import t +from tests import t + def pytest_collection_modifyitems( diff --git a/tests/protocols.py b/tests/protocols.py index 559864362..15170f7f1 100644 --- a/tests/protocols.py +++ b/tests/protocols.py @@ -12,9 +12,9 @@ from flext_cli import p -if TYPE_CHECKING: - from flext_cli import m - from tests import t +from flext_cli import m +from tests import t + class TestsFlextCliProtocols(FlextTestsProtocols, p): diff --git a/tests/test_yaml_model_write.py b/tests/test_yaml_model_write.py index d3efd6d61..fe0f31307 100644 --- a/tests/test_yaml_model_write.py +++ b/tests/test_yaml_model_write.py @@ -8,8 +8,8 @@ from flext_cli import cli, m -if TYPE_CHECKING: - from pathlib import Path +from pathlib import Path + def test_write_yaml_model_round_trips_the_same_model_contract(tmp_path: Path) -> None: diff --git a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_01.py b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_01.py index 3192bc650..7d7092163 100644 --- a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_01.py +++ b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_01.py @@ -13,10 +13,10 @@ # NOTE (multi-agent, mro-wkii.19.4): app creation owns the settings singleton. # mro-wkii.17.26 (codex): exercise CLI flows through the public invocation facade. -if TYPE_CHECKING: - from collections.abc import MutableSequence +from collections.abc import MutableSequence + +from tests import t - from tests import t class TestsFlextCliService: diff --git a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_02.py b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_02.py index 8d5fa6cf2..71b21785b 100644 --- a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_02.py +++ b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_02.py @@ -13,10 +13,10 @@ # NOTE (multi-agent, mro-wkii.19.4): app creation owns the settings singleton. # mro-wkii.17.26 (codex): exercise CLI flows through the public invocation facade. -if TYPE_CHECKING: - from collections.abc import MutableSequence +from collections.abc import MutableSequence + +from tests import t - from tests import t class TestsFlextCliService: diff --git a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_04.py b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_04.py index 338c367b7..7c3de222a 100644 --- a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_04.py +++ b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_04.py @@ -11,8 +11,8 @@ # NOTE (multi-agent, mro-wkii.19.4): app creation owns the settings singleton. -if TYPE_CHECKING: - from tests import t +from tests import t + class TestsFlextCliService: diff --git a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_05.py b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_05.py index 63a59921f..31d489c22 100644 --- a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_05.py +++ b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_05.py @@ -13,8 +13,8 @@ # NOTE (multi-agent, mro-wkii.19.4): app creation owns the settings singleton. # mro-wkii.17.26 (codex): exercise CLI flows through the public invocation facade. -if TYPE_CHECKING: - from tests import p +from tests import p + class TestsFlextCliService: diff --git a/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_01.py b/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_01.py index 98a85b0fb..1680000e6 100644 --- a/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_01.py +++ b/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_01.py @@ -18,8 +18,8 @@ from flext_cli import cli -if TYPE_CHECKING: - from pathlib import Path +from pathlib import Path + # NOTE (multi-agent, mro-wkii.17 / agent: make_ssot_audit): file fixtures are # validated models, serialized once at egress and validated once at ingress. diff --git a/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_02.py b/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_02.py index 35288d58e..6de4b1e4b 100644 --- a/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_02.py +++ b/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_02.py @@ -19,9 +19,9 @@ # mro-wkii.17.26 (codex): assert authentication against the shared example rule. -if TYPE_CHECKING: - from collections.abc import Iterator - from pathlib import Path +from collections.abc import Iterator +from pathlib import Path + class TestsFlextCliExamplesSmoke: diff --git a/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_03.py b/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_03.py index 827fcdf6e..4449cbd78 100644 --- a/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_03.py +++ b/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_03.py @@ -11,8 +11,8 @@ from flext_cli import cli, settings -if TYPE_CHECKING: - from collections.abc import Iterator +from collections.abc import Iterator + class TestsFlextCliExamplesSmoke: diff --git a/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_04.py b/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_04.py index 1cd58db87..01e4ebc93 100644 --- a/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_04.py +++ b/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_04.py @@ -10,10 +10,10 @@ from flext_cli import cli -if TYPE_CHECKING: - from pathlib import Path +from pathlib import Path + +from tests import p - from tests import p class TestsFlextCliExamplesSmoke: diff --git a/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_01.py b/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_01.py index 20ad742c6..bdb578aad 100644 --- a/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_01.py +++ b/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_01.py @@ -12,10 +12,10 @@ from flext_cli import cli -if TYPE_CHECKING: - from pathlib import Path +from pathlib import Path + +from tests import t - from tests import t class TestsFlextCliFilesCov: diff --git a/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_02.py b/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_02.py index 06f7da0d2..309f35467 100644 --- a/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_02.py +++ b/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_02.py @@ -9,8 +9,8 @@ from flext_cli import cli -if TYPE_CHECKING: - from pathlib import Path +from pathlib import Path + class TestsFlextCliFilesCov: diff --git a/tests/unit/_cases/test_json_cov/testsflextclijsoncov_part_01.py b/tests/unit/_cases/test_json_cov/testsflextclijsoncov_part_01.py index e1da78018..372964258 100644 --- a/tests/unit/_cases/test_json_cov/testsflextclijsoncov_part_01.py +++ b/tests/unit/_cases/test_json_cov/testsflextclijsoncov_part_01.py @@ -9,8 +9,8 @@ from tests import u from flext_tests import tm -if TYPE_CHECKING: - from pathlib import Path +from pathlib import Path + class TestsFlextCliJsonCov: diff --git a/tests/unit/_cases/test_output_cov/testsflextclioutputcov_part_02.py b/tests/unit/_cases/test_output_cov/testsflextclioutputcov_part_02.py index 782de9b8f..56498f2aa 100644 --- a/tests/unit/_cases/test_output_cov/testsflextclioutputcov_part_02.py +++ b/tests/unit/_cases/test_output_cov/testsflextclioutputcov_part_02.py @@ -9,8 +9,8 @@ from tests import u from flext_tests import tm -if TYPE_CHECKING: - import pytest +import pytest + class TestsFlextCliOutputCov: diff --git a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_01.py b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_01.py index e3644971b..a923adca1 100644 --- a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_01.py +++ b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_01.py @@ -10,11 +10,11 @@ from flext_cli import cli, r from flext_tests import tm -if TYPE_CHECKING: - from pathlib import Path +from pathlib import Path + +from tests import p +from tests import t - from tests import p - from tests import t class TestsFlextCliPipeline: diff --git a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_02.py b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_02.py index df0d91f2d..2048f6788 100644 --- a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_02.py +++ b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_02.py @@ -10,11 +10,11 @@ from flext_cli import cli, r from flext_tests import tm -if TYPE_CHECKING: - from pathlib import Path +from pathlib import Path + +from tests import p +from tests import t - from tests import p - from tests import t class TestsFlextCliPipeline: diff --git a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_03.py b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_03.py index 952fb6cae..edec52791 100644 --- a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_03.py +++ b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_03.py @@ -7,12 +7,12 @@ from flext_cli import cli from flext_tests import tm -if TYPE_CHECKING: - from pathlib import Path +from pathlib import Path + +from tests import m +from tests import p +from tests import t - from tests import m - from tests import p - from tests import t # ── Fixtures ──────────────────────────────────────────────────────── diff --git a/tests/unit/_cases/test_prompts/testsflextcliprompts_part_01.py b/tests/unit/_cases/test_prompts/testsflextcliprompts_part_01.py index ff3619f7f..0a65a3772 100644 --- a/tests/unit/_cases/test_prompts/testsflextcliprompts_part_01.py +++ b/tests/unit/_cases/test_prompts/testsflextcliprompts_part_01.py @@ -9,10 +9,10 @@ from flext_tests import tm from tests import c -if TYPE_CHECKING: - from collections.abc import Callable +from collections.abc import Callable + +from tests import p - from tests import p class TestsFlextCliPrompts: diff --git a/tests/unit/_cases/test_prompts/testsflextcliprompts_part_02.py b/tests/unit/_cases/test_prompts/testsflextcliprompts_part_02.py index 43ef0e1af..8805f8e0c 100644 --- a/tests/unit/_cases/test_prompts/testsflextcliprompts_part_02.py +++ b/tests/unit/_cases/test_prompts/testsflextcliprompts_part_02.py @@ -9,10 +9,10 @@ from flext_tests import tm from tests import c -if TYPE_CHECKING: - from collections.abc import Callable +from collections.abc import Callable + +from tests import p - from tests import p class TestsFlextCliPrompts: diff --git a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_02.py b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_02.py index 064b045c2..5fed033d8 100644 --- a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_02.py +++ b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_02.py @@ -10,10 +10,10 @@ from flext_cli import r from flext_tests import tm -if TYPE_CHECKING: - from pathlib import Path +from pathlib import Path + +from tests import p - from tests import p class TestsFlextCliPublicContractsCoverage: diff --git a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_03.py b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_03.py index cd9d1a9ce..c962d460b 100644 --- a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_03.py +++ b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_03.py @@ -10,8 +10,8 @@ from flext_cli import cli, m, r from flext_tests import tm -if TYPE_CHECKING: - from pathlib import Path +from pathlib import Path + class TestsFlextCliPublicContractsCoverage: diff --git a/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_01.py b/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_01.py index 4a2ea28e9..7df8fb843 100644 --- a/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_01.py +++ b/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_01.py @@ -11,8 +11,8 @@ from tests import u from flext_tests import tm -if TYPE_CHECKING: - from tests import t +from tests import t + class TestsFlextCliRulesCov: diff --git a/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_03.py b/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_03.py index c2060aedd..7a1eb6057 100644 --- a/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_03.py +++ b/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_03.py @@ -11,8 +11,8 @@ from tests import u from flext_tests import tm -if TYPE_CHECKING: - from tests import t +from tests import t + class TestsFlextCliRulesCov: diff --git a/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_04.py b/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_04.py index d8bd3d980..6a989ba14 100644 --- a/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_04.py +++ b/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_04.py @@ -8,8 +8,8 @@ from tests import u from flext_tests import tm -if TYPE_CHECKING: - from tests import t +from tests import t + class TestsFlextCliRulesCov: diff --git a/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_01.py b/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_01.py index 2c9e18ded..d11b217b3 100644 --- a/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_01.py +++ b/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_01.py @@ -11,10 +11,10 @@ from flext_tests import tm from tests import u -if TYPE_CHECKING: - from collections.abc import Generator +from collections.abc import Generator + +from tests import t - from tests import t class TestsFlextCliTomlUtilities: diff --git a/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_02.py b/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_02.py index b090b4da3..821d024fe 100644 --- a/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_02.py +++ b/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_02.py @@ -7,8 +7,8 @@ from flext_tests import tm from tests import u -if TYPE_CHECKING: - from tests import t +from tests import t + class TestsFlextCliTomlUtilities: diff --git a/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_03.py b/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_03.py index dd422aa89..f5b1ae9f1 100644 --- a/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_03.py +++ b/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_03.py @@ -8,10 +8,10 @@ from flext_tests import tm from tests import u -if TYPE_CHECKING: - from pathlib import Path +from pathlib import Path + +from tests import t - from tests import t class TestsFlextCliTomlUtilities: diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py index 90028d25e..10f5c9e48 100644 --- a/tests/unit/conftest.py +++ b/tests/unit/conftest.py @@ -10,10 +10,10 @@ from flext_cli.services.prompts import FlextCliPrompts from tests import m -if TYPE_CHECKING: - from collections.abc import Callable +from collections.abc import Callable + +from tests import t - from tests import t class TestsFlextCliScriptedPrompts(FlextCliPrompts): @@ -55,7 +55,7 @@ def raise_password(_prompt: str) -> str: def configure_state(self, *, interactive: bool = True, quiet: bool = False) -> Self: """Configure the observable prompt runtime state.""" - self.configure(m.Cli.PromptRuntimeState(interactive=interactive, quiet=quiet)) + settingsure(m.Cli.PromptRuntimeState(interactive=interactive, quiet=quiet)) return self diff --git a/tests/unit/test_auth_utils_cov.py b/tests/unit/test_auth_utils_cov.py index 3cc5a38c7..aabc207f0 100644 --- a/tests/unit/test_auth_utils_cov.py +++ b/tests/unit/test_auth_utils_cov.py @@ -23,8 +23,8 @@ from tests import u from flext_tests import tm -if TYPE_CHECKING: - from tests import t +from tests import t + class TestsFlextCliAuthUtilsCov: diff --git a/tests/unit/test_cmd.py b/tests/unit/test_cmd.py index 81a82c837..83cd62dbf 100644 --- a/tests/unit/test_cmd.py +++ b/tests/unit/test_cmd.py @@ -27,8 +27,8 @@ from tests import c from tests import p -if TYPE_CHECKING: - from pathlib import Path +from pathlib import Path + class TestsFlextCliCmd: diff --git a/tests/unit/test_cmd_cov.py b/tests/unit/test_cmd_cov.py index ca41da3f2..96f33b2da 100644 --- a/tests/unit/test_cmd_cov.py +++ b/tests/unit/test_cmd_cov.py @@ -19,9 +19,9 @@ from flext_cli import cli from tests import c -if TYPE_CHECKING: - from collections.abc import Generator - from pathlib import Path +from collections.abc import Generator +from pathlib import Path + class TestsFlextCliCmdCov: diff --git a/tests/unit/test_conversion_cov.py b/tests/unit/test_conversion_cov.py index c7df6fc93..0991d5f83 100644 --- a/tests/unit/test_conversion_cov.py +++ b/tests/unit/test_conversion_cov.py @@ -12,8 +12,8 @@ from tests import m from tests import u -if TYPE_CHECKING: - from tests import t +from tests import t + class TestsFlextCliConversion: diff --git a/tests/unit/test_files_cov.py b/tests/unit/test_files_cov.py index 902995b71..caba423e3 100644 --- a/tests/unit/test_files_cov.py +++ b/tests/unit/test_files_cov.py @@ -19,10 +19,10 @@ from tests import m from tests import u -if TYPE_CHECKING: - from pathlib import Path +from pathlib import Path + +from tests import t - from tests import t class TestsFlextCliFilesCov: diff --git a/tests/unit/test_formatters_cov.py b/tests/unit/test_formatters_cov.py index cf0868fe7..d37316025 100644 --- a/tests/unit/test_formatters_cov.py +++ b/tests/unit/test_formatters_cov.py @@ -21,8 +21,8 @@ from tests import c from flext_tests import tm -if TYPE_CHECKING: - from tests import t +from tests import t + class TestsFlextCliFormattersCov: diff --git a/tests/unit/test_json_cov.py b/tests/unit/test_json_cov.py index d9e2b1249..b193761f1 100644 --- a/tests/unit/test_json_cov.py +++ b/tests/unit/test_json_cov.py @@ -11,8 +11,8 @@ from tests import u from flext_tests import tm -if TYPE_CHECKING: - from pathlib import Path +from pathlib import Path + class TestsFlextCliJsonCov: diff --git a/tests/unit/test_matching_cov.py b/tests/unit/test_matching_cov.py index 5bdba77a2..47556c72c 100644 --- a/tests/unit/test_matching_cov.py +++ b/tests/unit/test_matching_cov.py @@ -20,8 +20,8 @@ from tests import u from flext_tests import tm -if TYPE_CHECKING: - from tests import t +from tests import t + class TestsFlextCliMatchingCov: diff --git a/tests/unit/test_prompts_cov.py b/tests/unit/test_prompts_cov.py index 9886c189b..152e483f8 100644 --- a/tests/unit/test_prompts_cov.py +++ b/tests/unit/test_prompts_cov.py @@ -15,10 +15,10 @@ from tests import c -if TYPE_CHECKING: - from collections.abc import Callable +from collections.abc import Callable + +from tests import p - from tests import p class TestsFlextCliPromptsCov: diff --git a/tests/unit/test_rules_cov.py b/tests/unit/test_rules_cov.py index 3ecd77eaa..d3af02b40 100644 --- a/tests/unit/test_rules_cov.py +++ b/tests/unit/test_rules_cov.py @@ -17,10 +17,10 @@ from tests import u from flext_tests import tm -if TYPE_CHECKING: - from pathlib import Path +from pathlib import Path + +from tests import t - from tests import t class TestsFlextCliRulesCov: diff --git a/tests/unit/test_runtime_utilities_core.py b/tests/unit/test_runtime_utilities_core.py index 9082da6a4..5c6919a4b 100644 --- a/tests/unit/test_runtime_utilities_core.py +++ b/tests/unit/test_runtime_utilities_core.py @@ -11,10 +11,10 @@ from tests import m from tests import u -if TYPE_CHECKING: - from pathlib import Path +from pathlib import Path + +from tests import t - from tests import t class TestsFlextCliRuntimeUtilitiesCore: diff --git a/tests/unit/test_runtime_utilities_extra.py b/tests/unit/test_runtime_utilities_extra.py index 123e5a56e..e63e047b8 100644 --- a/tests/unit/test_runtime_utilities_extra.py +++ b/tests/unit/test_runtime_utilities_extra.py @@ -15,8 +15,8 @@ from tests import m from tests import u -if TYPE_CHECKING: - from pathlib import Path +from pathlib import Path + class TestsFlextCliRuntimeUtilitiesExtra: diff --git a/tests/unit/test_services_auth_branch_cov.py b/tests/unit/test_services_auth_branch_cov.py index a90236627..5800c89e1 100644 --- a/tests/unit/test_services_auth_branch_cov.py +++ b/tests/unit/test_services_auth_branch_cov.py @@ -17,9 +17,9 @@ from flext_cli import FlextCli, cli, settings from tests import c -if TYPE_CHECKING: - from collections.abc import Iterator - from pathlib import Path +from collections.abc import Iterator +from pathlib import Path + class TestsFlextCliServicesAuth: diff --git a/tests/unit/test_services_auth_cov.py b/tests/unit/test_services_auth_cov.py index 8c9ad13ba..efb59c69a 100644 --- a/tests/unit/test_services_auth_cov.py +++ b/tests/unit/test_services_auth_cov.py @@ -21,11 +21,11 @@ from tests import c from flext_tests import tm -if TYPE_CHECKING: - from collections.abc import Iterator - from pathlib import Path +from collections.abc import Iterator +from pathlib import Path + +from tests import p - from tests import p class TestsFlextCliServicesAuthCov: diff --git a/tests/unit/test_services_tables_branch_cov.py b/tests/unit/test_services_tables_branch_cov.py index 5288f97e6..738013e42 100644 --- a/tests/unit/test_services_tables_branch_cov.py +++ b/tests/unit/test_services_tables_branch_cov.py @@ -15,8 +15,8 @@ from tests import c from flext_tests import tm -if TYPE_CHECKING: - from flext_cli import t +from flext_cli import t + class TestsFlextCliServicesTablesBranchCov: diff --git a/tests/unit/test_tables.py b/tests/unit/test_tables.py index 0ee1aae80..20198dbd7 100644 --- a/tests/unit/test_tables.py +++ b/tests/unit/test_tables.py @@ -16,8 +16,8 @@ from flext_cli import cli from tests import c -if TYPE_CHECKING: - from flext_cli import t +from flext_cli import t + class TestsFlextCliTables: diff --git a/tests/unit/test_tables_cov.py b/tests/unit/test_tables_cov.py index 79666fc81..ad9d4eac9 100644 --- a/tests/unit/test_tables_cov.py +++ b/tests/unit/test_tables_cov.py @@ -19,8 +19,8 @@ from tests import u from flext_tests import tm -if TYPE_CHECKING: - from tests import t +from tests import t + class TestsFlextCliTables: diff --git a/tests/unit/test_toml_cov.py b/tests/unit/test_toml_cov.py index 9c3d24e76..e90a138a8 100644 --- a/tests/unit/test_toml_cov.py +++ b/tests/unit/test_toml_cov.py @@ -20,8 +20,8 @@ from tests import u from flext_tests import tm -if TYPE_CHECKING: - from pathlib import Path +from pathlib import Path + class TestsFlextCliTomlCov: diff --git a/tests/unit/test_toml_sync_cov.py b/tests/unit/test_toml_sync_cov.py index 2d3c50ad1..bcd2f3d1e 100644 --- a/tests/unit/test_toml_sync_cov.py +++ b/tests/unit/test_toml_sync_cov.py @@ -22,10 +22,10 @@ from tests import u from flext_tests import tm -if TYPE_CHECKING: - from tomlkit.items import Table +from tomlkit.items import Table + +from tests import t - from tests import t class TestsFlextCliTomlSyncCoverage: diff --git a/tests/unit/test_toml_utilities.py b/tests/unit/test_toml_utilities.py index 3369a08db..14a1cb788 100644 --- a/tests/unit/test_toml_utilities.py +++ b/tests/unit/test_toml_utilities.py @@ -19,8 +19,8 @@ from tests import u -if TYPE_CHECKING: - from tests import t +from tests import t + class TestsFlextCliTomlUtilities: diff --git a/tests/unit/test_typings.py b/tests/unit/test_typings.py index f7c94bbca..475949f58 100644 --- a/tests/unit/test_typings.py +++ b/tests/unit/test_typings.py @@ -19,8 +19,8 @@ from tests import m from tests import t -if TYPE_CHECKING: - from pathlib import Path +from pathlib import Path + class TestsFlextCliTypings: diff --git a/tests/unit/test_yaml_cov.py b/tests/unit/test_yaml_cov.py index 7165d51a2..14e3d5d78 100644 --- a/tests/unit/test_yaml_cov.py +++ b/tests/unit/test_yaml_cov.py @@ -23,10 +23,10 @@ from tests import u from flext_tests import tm -if TYPE_CHECKING: - from pathlib import Path +from pathlib import Path + +from tests import t - from tests import t class TestsFlextCliYamlCov: diff --git a/tests/unit/test_yaml_roundtrip.py b/tests/unit/test_yaml_roundtrip.py index 18a3b220f..c1ef0f148 100644 --- a/tests/unit/test_yaml_roundtrip.py +++ b/tests/unit/test_yaml_roundtrip.py @@ -18,8 +18,8 @@ from tests import u from flext_tests import tm -if TYPE_CHECKING: - from pathlib import Path +from pathlib import Path + class TestsFlextCliYamlRoundtripLoad: From 9503257c67594c35ee7f6627c44078cef37c0d0f Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Tue, 14 Jul 2026 19:50:50 -0300 Subject: [PATCH 12/37] fix: remove protocol facade import cycles --- .../flextcliprotocolsbase_part_03.py | 27 ++-- .../flextcliprotocolsbase_part_04.py | 58 +++++-- .../flextcliprotocolsbase_part_05.py | 8 +- src/flext_cli/_protocols/pipeline.py | 150 +++++++++++++++--- src/flext_cli/_protocols/xlsx.py | 119 ++++++++++++-- src/flext_cli/_protocols/xlsx_snapshot.py | 50 ++++-- src/flext_cli/_typings/pipeline.py | 9 +- 7 files changed, 339 insertions(+), 82 deletions(-) diff --git a/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_03.py b/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_03.py index 75eddf105..9f8a4f02b 100644 --- a/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_03.py +++ b/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_03.py @@ -6,18 +6,21 @@ from __future__ import annotations +from pathlib import Path from typing import Protocol, runtime_checkable from flext_cli._protocols._base_parts.flextcliprotocolsbase_part_02 import ( FlextCliProtocolsBase as FlextCliProtocolsBasePart02, ) -from flext_cli import p, t +from flext_core import p, t class FlextCliProtocolsBase(FlextCliProtocolsBasePart02): """Implementation part for FlextCliProtocolsBase.""" + # mro-wkii.17.26 (codex): this p fragment consumes only upstream aliases + # and contracts inherited from the preceding fragment, never its own facade. @runtime_checkable class CommandRunner(Protocol): """Contract for generic command execution services.""" @@ -25,18 +28,18 @@ class CommandRunner(Protocol): def run( self, cmd: t.StrSequence, - cwd: t.Cli.TextPath | None = None, + cwd: str | Path | None = None, timeout: int | None = None, env: t.StrMapping | None = None, remove_env_keys: t.StrSequence = (), - ) -> p.Result[p.Cli.CommandOutput]: + ) -> p.Result[FlextCliProtocolsBasePart02.CommandOutput]: """Execute a command and require zero exit status.""" ... def capture( self, cmd: t.StrSequence, - cwd: t.Cli.TextPath | None = None, + cwd: str | Path | None = None, timeout: int | None = None, env: t.StrMapping | None = None, remove_env_keys: t.StrSequence = (), @@ -47,12 +50,12 @@ def capture( def run_raw( self, cmd: t.StrSequence, - cwd: t.Cli.TextPath | None = None, + cwd: str | Path | None = None, timeout: int | None = None, env: t.StrMapping | None = None, remove_env_keys: t.StrSequence = (), input_data: bytes | None = None, - ) -> p.Result[p.Cli.CommandOutput]: + ) -> p.Result[FlextCliProtocolsBasePart02.CommandOutput]: """Execute a command without enforcing zero exit status.""" ... @@ -60,19 +63,19 @@ def run_raw( def run_bytes( self, cmd: t.StrSequence, - cwd: t.Cli.TextPath | None = None, + cwd: str | Path | None = None, timeout: int | None = None, env: t.StrMapping | None = None, remove_env_keys: t.StrSequence = (), input_data: bytes | None = None, - ) -> p.Result[p.Cli.CommandBytesOutput]: + ) -> p.Result[FlextCliProtocolsBasePart02.CommandBytesOutput]: """Execute a command and preserve byte-exact output.""" ... def run_checked( self, cmd: t.StrSequence, - cwd: t.Cli.TextPath | None = None, + cwd: str | Path | None = None, timeout: int | None = None, env: t.StrMapping | None = None, remove_env_keys: t.StrSequence = (), @@ -83,8 +86,8 @@ def run_checked( def run_to_file( self, cmd: t.StrSequence, - output_file: t.Cli.TextPath, - cwd: t.Cli.TextPath | None = None, + output_file: str | Path, + cwd: str | Path | None = None, timeout: int | None = None, env: t.StrMapping | None = None, remove_env_keys: t.StrSequence = (), @@ -142,4 +145,4 @@ def verbose(self) -> bool | None: ... -__all__: list[str] = ["FlextCliProtocolsBase"] +__all__: tuple[str, ...] = ("FlextCliProtocolsBase",) diff --git a/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_04.py b/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_04.py index 46c99a376..3decf18cb 100644 --- a/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_04.py +++ b/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_04.py @@ -12,15 +12,49 @@ FlextCliProtocolsBase as FlextCliProtocolsBasePart03, ) from flext_core import p - -# Why (multi-agent): defer flext_cli import to break the __init__-time -# circular import; t is annotation-only (PEP 563). Matches sibling part_03. -from flext_cli import m, t +from flext_core import t class FlextCliProtocolsBase(FlextCliProtocolsBasePart03): """Implementation part for FlextCliProtocolsBase.""" + # mro-wkii.17.26 (codex): public status results are structural p contracts; + # importing local m/t here re-enters facades that p is still composing. + @runtime_checkable + class RuntimeComponents(Protocol): + """Observable CLI runtime component states.""" + + @property + def settings(self) -> str: ... + + @property + def formatters(self) -> str: ... + + @property + def prompts(self) -> str: ... + + @property + def rules(self) -> str: ... + + @runtime_checkable + class RuntimeStatus(Protocol): + """Observable public CLI runtime status.""" + + @property + def status(self) -> str: ... + + @property + def service(self) -> str: ... + + @property + def timestamp(self) -> str: ... + + @property + def version(self) -> str: ... + + @property + def components(self) -> FlextCliProtocolsBase.RuntimeComponents: ... + @runtime_checkable class CliOptionSpec(Protocol): """Framework-neutral option model contract returned by the CLI DSL.""" @@ -36,7 +70,11 @@ def help_text(self) -> str: ... @property - def default(self) -> t.Cli.CliValue | None: + def default( + self, + ) -> ( + t.Scalar | t.StrSequence | t.MappingKV[str, t.Scalar | t.StrSequence] | None + ): """Normalized option default value.""" ... @@ -49,7 +87,7 @@ def required(self) -> bool: class CmdService(Protocol): """Protocol for the public command/settings service surface on ``cli``.""" - def execute(self) -> p.Result[m.Cli.RuntimeStatus]: + def execute(self) -> p.Result[FlextCliProtocolsBase.RuntimeStatus]: """Return the public operational status payload.""" ... @@ -96,9 +134,7 @@ def __call__( ... @runtime_checkable - class ResultCommandHandler[TParams: t.Cli.ModelLike, TResult: t.Cli.ResultValue]( - Protocol - ): + class ResultCommandHandler[TParams: t.BaseModel, TResult: t.JsonPayload](Protocol): """Protocol for model-driven CLI handlers returning `r[...]`.""" def __call__(self, params: TParams, /) -> p.Result[TResult]: @@ -120,11 +156,11 @@ def error(self) -> str | None: ... @property - def value(self) -> t.Cli.ResultValue: + def value(self) -> t.JsonPayload: """Expose the successful payload for message formatting.""" ... # mro-j47u (codex): formatter callables have one owner in t.Cli. -__all__: list[str] = ["FlextCliProtocolsBase"] +__all__: tuple[str, ...] = ("FlextCliProtocolsBase",) diff --git a/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_05.py b/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_05.py index d7f14b389..3cbfa26b9 100644 --- a/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_05.py +++ b/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_05.py @@ -12,9 +12,9 @@ FlextCliProtocolsBase as FlextCliProtocolsBasePart04, ) -# Why (multi-agent): defer flext_cli import to break the __init__-time -# circular import; t is annotation-only (PEP 563). Matches sibling part_03. -from flext_cli import t +# mro-wkii.17.26 (codex): YAML protocol data is defined by the upstream JSON +# alias; importing the local t facade would re-enter its own p composition. +from flext_core import t class FlextCliProtocolsBase(FlextCliProtocolsBasePart04): @@ -29,4 +29,4 @@ def dump(self, data: t.JsonPayload, *, default_flow_style: bool = True) -> str: ... -__all__: list[str] = ["FlextCliProtocolsBase"] +__all__: tuple[str, ...] = ("FlextCliProtocolsBase",) diff --git a/src/flext_cli/_protocols/pipeline.py b/src/flext_cli/_protocols/pipeline.py index 5e62abf22..12967b369 100644 --- a/src/flext_cli/_protocols/pipeline.py +++ b/src/flext_cli/_protocols/pipeline.py @@ -6,16 +6,15 @@ from pathlib import Path from typing import Protocol, runtime_checkable -from flext_cli import t -from flext_core import p - -# mro-j47u (codex): p -> m is a reverse facade edge; keep it type-only. -from flext_cli import m +from flext_cli._constants.enums import FlextCliConstantsEnums as ce +from flext_core import p, t class FlextCliProtocolsPipeline: """Pipeline protocol namespace.""" + # mro-wkii.17.26 (codex): pipeline contracts are owned by p so the t + # facade never imports concrete m models while either facade is composed. @runtime_checkable class PipelineStageContext(Protocol): """Contract for stage execution context — carries shared state between stages.""" @@ -35,13 +34,111 @@ def settings(self) -> t.JsonMapping: """Immutable configuration for the pipeline run.""" ... + @runtime_checkable + class PipelineStageResult(Protocol): + """Observable result of one executed pipeline stage.""" + + @property + def stage_id(self) -> str: + """Stage identifier.""" + ... + + @property + def status(self) -> ce.PipelineStageStatus: + """Stage execution status.""" + ... + + @property + def output(self) -> t.JsonMapping: + """Stage output payload.""" + ... + + @property + def duration_ms(self) -> float: + """Stage execution duration in milliseconds.""" + ... + + @property + def error(self) -> str | None: + """Stage error message.""" + ... + + @runtime_checkable + class PipelineStageSpec(Protocol): + """Declarative pipeline stage contract.""" + + @property + def stage_id(self) -> str: + """Stage identifier.""" + ... + + @property + def depends_on(self) -> frozenset[str]: + """Identifiers of prerequisite stages.""" + ... + + @property + def handler( + self, + ) -> Callable[ + [FlextCliProtocolsPipeline.PipelineStageContext], + p.Result[FlextCliProtocolsPipeline.PipelineStageResult], + ]: + """Stage execution handler.""" + ... + + @property + def skip_if( + self, + ) -> Callable[[FlextCliProtocolsPipeline.PipelineStageContext], bool] | None: + """Optional stage skip predicate.""" + ... + + @property + def retry(self) -> int: + """Maximum retry count.""" + ... + + @runtime_checkable + class PipelineResult(Protocol): + """Observable aggregate pipeline result.""" + + @property + def stages(self) -> t.SequenceOf[FlextCliProtocolsPipeline.PipelineStageResult]: + """Results from executed stages.""" + ... + + @property + def total_duration_ms(self) -> float: + """Total execution duration in milliseconds.""" + ... + + @property + def success(self) -> bool: + """Whether every executed stage succeeded.""" + ... + + @property + def failed_stages( + self, + ) -> t.SequenceOf[FlextCliProtocolsPipeline.PipelineStageResult]: + """Failed stage results.""" + ... + + @property + def skipped_stages( + self, + ) -> t.SequenceOf[FlextCliProtocolsPipeline.PipelineStageResult]: + """Skipped stage results.""" + ... + @runtime_checkable class PipelineStage(Protocol): """Contract for a callable pipeline stage handler.""" def __call__( self, ctx: FlextCliProtocolsPipeline.PipelineStageContext - ) -> p.Result[m.Cli.PipelineStageResult]: + ) -> p.Result[FlextCliProtocolsPipeline.PipelineStageResult]: """Execute stage and return typed result.""" ... @@ -51,11 +148,11 @@ class PipelineExecutor(Protocol): def execute( self, - stages: t.SequenceOf[m.Cli.PipelineStageSpec], + stages: t.SequenceOf[FlextCliProtocolsPipeline.PipelineStageSpec], context: FlextCliProtocolsPipeline.PipelineStageContext, *, fail_fast: bool = True, - ) -> p.Result[m.Cli.PipelineResult]: + ) -> p.Result[FlextCliProtocolsPipeline.PipelineResult]: """Execute stages in dependency order.""" ... @@ -69,7 +166,7 @@ def stage_context( *, shared: t.MutableJsonMapping | None = None, settings: t.JsonMapping | None = None, - ) -> m.Cli.PipelineStageContext: + ) -> FlextCliProtocolsPipeline.PipelineStageContext: """Build the canonical pipeline execution context.""" ... @@ -79,13 +176,13 @@ def stage( *, handler: Callable[ [FlextCliProtocolsPipeline.PipelineStageContext], - p.Result[m.Cli.PipelineStageResult], + p.Result[FlextCliProtocolsPipeline.PipelineStageResult], ], depends_on: t.SequenceOf[str] | frozenset[str] = (), skip_if: Callable[[FlextCliProtocolsPipeline.PipelineStageContext], bool] | None = None, retry: int = 0, - ) -> m.Cli.PipelineStageSpec: + ) -> FlextCliProtocolsPipeline.PipelineStageSpec: """Build one declarative pipeline stage spec.""" ... @@ -93,11 +190,11 @@ def stage_result( self, stage_id: str, *, - status: t.Cli.PipelineStageStatus, + status: ce.PipelineStageStatus, output: t.JsonMapping | None = None, duration_ms: float = 0.0, error: str | None = None, - ) -> m.Cli.PipelineStageResult: + ) -> FlextCliProtocolsPipeline.PipelineStageResult: """Build one typed pipeline stage result payload.""" ... @@ -107,31 +204,40 @@ def ok_stage( *, output: t.JsonMapping | None = None, duration_ms: float = 0.0, - ) -> p.Result[m.Cli.PipelineStageResult]: + ) -> p.Result[FlextCliProtocolsPipeline.PipelineStageResult]: """Return a successful typed stage result via ``r``.""" ... def pipeline( self, - stages: t.SequenceOf[m.Cli.PipelineStageSpec], + stages: t.SequenceOf[FlextCliProtocolsPipeline.PipelineStageSpec], *, - context: m.Cli.PipelineStageContext, + context: FlextCliProtocolsPipeline.PipelineStageContext, fail_fast: bool = True, logger: p.Logger | None = None, - ) -> p.Result[m.Cli.PipelineResult]: + ) -> p.Result[FlextCliProtocolsPipeline.PipelineResult]: """Execute a pipeline from the public service DSL.""" ... def linear_pipeline( self, stage_order: t.StrSequence, - handlers: t.Cli.PipelineHandlerMap, + handlers: t.MappingKV[ + str, + Callable[ + [FlextCliProtocolsPipeline.PipelineStageContext], + p.Result[FlextCliProtocolsPipeline.PipelineStageResult], + ], + ], *, - retry_by_stage: t.Cli.PipelineRetryMap | None = None, - skip_by_stage: t.Cli.PipelineSkipMap | None = None, - ) -> t.SequenceOf[m.Cli.PipelineStageSpec]: + retry_by_stage: t.MappingKV[str, int] | None = None, + skip_by_stage: t.MappingKV[ + str, Callable[[FlextCliProtocolsPipeline.PipelineStageContext], bool] + ] + | None = None, + ) -> t.SequenceOf[FlextCliProtocolsPipeline.PipelineStageSpec]: """Build a linear dependency chain with canonical previous-stage deps.""" ... -__all__: list[str] = ["FlextCliProtocolsPipeline"] +__all__: tuple[str, ...] = ("FlextCliProtocolsPipeline",) diff --git a/src/flext_cli/_protocols/xlsx.py b/src/flext_cli/_protocols/xlsx.py index 65648bf22..6206341a6 100644 --- a/src/flext_cli/_protocols/xlsx.py +++ b/src/flext_cli/_protocols/xlsx.py @@ -4,6 +4,7 @@ from typing import Protocol, runtime_checkable +from flext_cli._typings.xlsx import FlextCliTypesXlsx as tx from flext_core import p from .xlsx_archive import FlextCliProtocolsXlsxArchive @@ -11,9 +12,6 @@ from .xlsx_snapshot import FlextCliProtocolsXlsxSnapshot from .xlsx_workbook import FlextCliProtocolsXlsxWorkbook -# mro-j47u (codex): p -> m stays type-only through the canonical facade. -from flext_cli import m - class FlextCliProtocolsXlsx( FlextCliProtocolsXlsxArchive, @@ -23,6 +21,8 @@ class FlextCliProtocolsXlsx( ): """Consumer protocols for plans, requests, results, and services.""" + # mro-wkii.17.26 (codex): all public XLSX relationships are expressed by + # sibling p contracts; concrete m models never participate in p composition. # NOTE (multi-agent, mro-j2yt.1): protocol properties retain the exact # source model objects; no dump, mapping, or adapter DTO is introduced. @runtime_checkable @@ -33,7 +33,7 @@ def name(self) -> str: ... @runtime_checkable class XlsxWorkbookPlan(Protocol): @property - def sheets(self) -> tuple[m.Cli.XlsxSheetPlan, ...]: ... + def sheets(self) -> tuple[FlextCliProtocolsXlsx.XlsxSheetPlan, ...]: ... @property def full_calculation_on_load(self) -> bool: ... @@ -44,7 +44,7 @@ class XlsxRenderRequest(Protocol): def template(self) -> bytes | None: ... @property - def plan(self) -> m.Cli.XlsxWorkbookPlan: ... + def plan(self) -> FlextCliProtocolsXlsx.XlsxWorkbookPlan: ... @runtime_checkable class XlsxRenderResult(Protocol): @@ -52,18 +52,26 @@ class XlsxRenderResult(Protocol): def content(self) -> bytes: ... @property - def plan(self) -> m.Cli.XlsxWorkbookPlan: ... + def plan(self) -> FlextCliProtocolsXlsx.XlsxWorkbookPlan: ... @runtime_checkable class XlsxParseRangeRequest(Protocol): @property def reference(self) -> str: ... + @runtime_checkable + class XlsxCellRange(Protocol): + @property + def first(self) -> FlextCliProtocolsXlsx.XlsxCellAddress: ... + + @property + def last(self) -> FlextCliProtocolsXlsx.XlsxCellAddress: ... + # mro-j2yt.1 (xlsx_reference_api): public structural formatting boundary. @runtime_checkable class XlsxFormatReferenceRequest(Protocol): @property - def area(self) -> m.Cli.XlsxCellRange: ... + def area(self) -> FlextCliProtocolsXlsx.XlsxCellRange: ... @property def sheet(self) -> str | None: ... @@ -79,13 +87,78 @@ class XlsxReference(Protocol): @property def reference(self) -> str: ... + @runtime_checkable + class XlsxArchivePolicy(Protocol): + @property + def max_members(self) -> int: ... + + @property + def max_member_uncompressed_bytes(self) -> int: ... + + @property + def max_total_uncompressed_bytes(self) -> int: ... + + @property + def forbidden_members(self) -> frozenset[str]: ... + + @property + def forbidden_prefixes(self) -> tuple[str, ...]: ... + + @property + def forbidden_worksheet_tags(self) -> frozenset[str]: ... + + @property + def required_worksheet_count(self) -> int | None: ... + + @property + def reject_defined_names(self) -> bool: ... + + @property + def reject_style_protection(self) -> bool: ... + + @property + def allowed_locked_tokens(self) -> frozenset[str | None]: ... + + @property + def allowed_hidden_tokens(self) -> frozenset[str | None]: ... + + @runtime_checkable + class XlsxArchiveViolation(Protocol): + @property + def kind(self) -> tx.XlsxArchiveViolationKind: ... + + @property + def location(self) -> str: ... + + @property + def detail(self) -> str: ... + + @runtime_checkable + class XlsxArchiveInspection(Protocol): + @property + def member_count(self) -> int: ... + + @property + def worksheet_count(self) -> int: ... + + @property + def total_uncompressed_bytes(self) -> int: ... + + @property + def violations( + self, + ) -> tuple[FlextCliProtocolsXlsx.XlsxArchiveViolation, ...]: ... + + @property + def clean(self) -> bool: ... + @runtime_checkable class XlsxArchiveInspectionRequest(Protocol): @property def source(self) -> bytes: ... @property - def policy(self) -> m.Cli.XlsxArchivePolicy: ... + def policy(self) -> FlextCliProtocolsXlsx.XlsxArchivePolicy: ... @runtime_checkable class XlsxStyleCatalogRequest(Protocol): @@ -106,39 +179,55 @@ def source_style_id(self) -> int: ... @property def style_name(self) -> str: ... + @runtime_checkable + class XlsxNamedStyleSpec(Protocol): + @property + def name(self) -> str: ... + + @property + def visual(self) -> p.Model: ... + + @runtime_checkable + class XlsxStyleCatalog(Protocol): + @property + def style_map(self) -> tuple[FlextCliProtocolsXlsx.XlsxStyleMapEntry, ...]: ... + + @property + def styles(self) -> tuple[FlextCliProtocolsXlsx.XlsxNamedStyleSpec, ...]: ... + @runtime_checkable class XlsxStyleTemplateResult(Protocol): @property def content(self) -> bytes: ... @property - def style_map(self) -> tuple[m.Cli.XlsxStyleMapEntry, ...]: ... + def style_map(self) -> tuple[FlextCliProtocolsXlsx.XlsxStyleMapEntry, ...]: ... @runtime_checkable class XlsxService(FlextCliProtocolsXlsxSnapshot.XlsxSnapshotService, Protocol): def xlsx_parse_range( self, request: FlextCliProtocolsXlsx.XlsxParseRangeRequest - ) -> p.Result[m.Cli.XlsxCellRange]: ... + ) -> p.Result[FlextCliProtocolsXlsx.XlsxCellRange]: ... def xlsx_format_reference( self, request: FlextCliProtocolsXlsx.XlsxFormatReferenceRequest - ) -> p.Result[m.Cli.XlsxReference]: ... + ) -> p.Result[FlextCliProtocolsXlsx.XlsxReference]: ... def xlsx_render( self, request: FlextCliProtocolsXlsx.XlsxRenderRequest - ) -> p.Result[m.Cli.XlsxRenderResult]: ... + ) -> p.Result[FlextCliProtocolsXlsx.XlsxRenderResult]: ... def xlsx_inspect( self, request: FlextCliProtocolsXlsx.XlsxArchiveInspectionRequest - ) -> p.Result[m.Cli.XlsxArchiveInspection]: ... + ) -> p.Result[FlextCliProtocolsXlsx.XlsxArchiveInspection]: ... def xlsx_style_catalog( self, request: FlextCliProtocolsXlsx.XlsxStyleCatalogRequest - ) -> p.Result[m.Cli.XlsxStyleCatalog]: ... + ) -> p.Result[FlextCliProtocolsXlsx.XlsxStyleCatalog]: ... def xlsx_style_template( self, request: FlextCliProtocolsXlsx.XlsxStyleTemplateRequest - ) -> p.Result[m.Cli.XlsxStyleTemplateResult]: ... + ) -> p.Result[FlextCliProtocolsXlsx.XlsxStyleTemplateResult]: ... __all__: tuple[str, ...] = ("FlextCliProtocolsXlsx",) diff --git a/src/flext_cli/_protocols/xlsx_snapshot.py b/src/flext_cli/_protocols/xlsx_snapshot.py index b68e3b748..6236e24a5 100644 --- a/src/flext_cli/_protocols/xlsx_snapshot.py +++ b/src/flext_cli/_protocols/xlsx_snapshot.py @@ -8,13 +8,25 @@ from .xlsx_snapshot_structure import FlextCliProtocolsXlsxSnapshotStructure -# mro-j47u (codex): p -> m stays type-only through the canonical facade. -from flext_cli import m - class FlextCliProtocolsXlsxSnapshot(FlextCliProtocolsXlsxSnapshotStructure): """Consumer-facing protocols for workbook parity evidence.""" + # mro-wkii.17.26 (codex): snapshot relations stay structural inside p; + # concrete XLSX models are construction outputs and cannot be p dependencies. + @runtime_checkable + class XlsxCellAddress(Protocol): + @property + def row(self) -> int: ... + + @property + def column(self) -> int: ... + + @runtime_checkable + class XlsxCellValue(Protocol): + @property + def kind(self) -> str: ... + # NOTE (multi-agent, mro-j2yt.1): protocols expose the original immutable # snapshot models directly; no mapping or revalidation boundary is added. @runtime_checkable @@ -31,10 +43,10 @@ class XlsxCellSnapshot(Protocol): def coordinate(self) -> str: ... @property - def position(self) -> m.Cli.XlsxCellAddress: ... + def position(self) -> FlextCliProtocolsXlsxSnapshot.XlsxCellAddress: ... @property - def value(self) -> m.Cli.XlsxCellValue: ... + def value(self) -> FlextCliProtocolsXlsxSnapshot.XlsxCellValue: ... @property def formula(self) -> str | None: ... @@ -100,18 +112,24 @@ def max_row(self) -> int: ... def max_column(self) -> int: ... @property - def cells(self) -> tuple[m.Cli.XlsxCellSnapshot, ...]: ... + def cells( + self, + ) -> tuple[FlextCliProtocolsXlsxSnapshot.XlsxCellSnapshot, ...]: ... @property - def tables(self) -> tuple[m.Cli.XlsxTableSnapshot, ...]: ... + def tables( + self, + ) -> tuple[FlextCliProtocolsXlsxSnapshot.XlsxTableSnapshot, ...]: ... @property - def row_dimensions(self) -> tuple[m.Cli.XlsxRowDimensionSnapshot, ...]: ... + def row_dimensions( + self, + ) -> tuple[FlextCliProtocolsXlsxSnapshot.XlsxRowDimensionSnapshot, ...]: ... @property def column_dimensions( self, - ) -> tuple[m.Cli.XlsxColumnDimensionSnapshot, ...]: ... + ) -> tuple[FlextCliProtocolsXlsxSnapshot.XlsxColumnDimensionSnapshot, ...]: ... @property def merged_ranges(self) -> tuple[str, ...]: ... @@ -123,7 +141,9 @@ def freeze_pane(self) -> str | None: ... def auto_filter(self) -> str | None: ... @property - def protection(self) -> m.Cli.XlsxSheetProtectionSnapshot: ... + def protection( + self, + ) -> FlextCliProtocolsXlsxSnapshot.XlsxSheetProtectionSnapshot: ... @property def formula_count(self) -> int: ... @@ -146,10 +166,14 @@ class XlsxWorkbookSnapshot(Protocol): def data_only(self) -> bool: ... @property - def sheets(self) -> tuple[m.Cli.XlsxSheetSnapshot, ...]: ... + def sheets( + self, + ) -> tuple[FlextCliProtocolsXlsxSnapshot.XlsxSheetSnapshot, ...]: ... @property - def defined_names(self) -> tuple[m.Cli.XlsxDefinedNameSnapshot, ...]: ... + def defined_names( + self, + ) -> tuple[FlextCliProtocolsXlsxSnapshot.XlsxDefinedNameSnapshot, ...]: ... @property def named_styles(self) -> tuple[str, ...]: ... @@ -164,7 +188,7 @@ def literal_count(self) -> int: ... class XlsxSnapshotService(Protocol): def xlsx_snapshot( self, request: FlextCliProtocolsXlsxSnapshot.XlsxSnapshotRequest - ) -> p.Result[m.Cli.XlsxWorkbookSnapshot]: ... + ) -> p.Result[FlextCliProtocolsXlsxSnapshot.XlsxWorkbookSnapshot]: ... __all__: tuple[str, ...] = ("FlextCliProtocolsXlsxSnapshot",) diff --git a/src/flext_cli/_typings/pipeline.py b/src/flext_cli/_typings/pipeline.py index 7613db430..ac42819c8 100644 --- a/src/flext_cli/_typings/pipeline.py +++ b/src/flext_cli/_typings/pipeline.py @@ -6,10 +6,9 @@ from typing import Literal from flext_cli import c +from flext_cli._protocols.pipeline import FlextCliProtocolsPipeline as pp from flext_core import p, t -from flext_cli import m - class FlextCliTypesPipeline: """Pipeline type aliases namespace.""" @@ -20,12 +19,12 @@ class FlextCliTypesPipeline: c.Cli.PipelineStageStatus.FAILED, ] type PipelineHandler = Callable[ - [m.Cli.PipelineStageContext], p.Result[m.Cli.PipelineStageResult] + [pp.PipelineStageContext], p.Result[pp.PipelineStageResult] ] - type PipelineSkipPredicate = Callable[[m.Cli.PipelineStageContext], bool] + type PipelineSkipPredicate = Callable[[pp.PipelineStageContext], bool] type PipelineHandlerMap = t.MappingKV[str, PipelineHandler] type PipelineRetryMap = t.MappingKV[str, int] type PipelineSkipMap = t.MappingKV[str, PipelineSkipPredicate] -__all__: list[str] = ["FlextCliTypesPipeline"] +__all__: tuple[str, ...] = ("FlextCliTypesPipeline",) From 208cb7bf0951b9fc87bac4e512cbb54946690655 Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Tue, 14 Jul 2026 20:16:51 -0300 Subject: [PATCH 13/37] fixes --- .../{_base_parts => _base}/__init__.py | 0 .../flextclimodelsbase_part_01.py | 0 .../flextclimodelsbase_part_02.py | 0 .../flextclimodelsbase_part_03.py | 0 .../flextclimodelsbase_part_04.py | 0 .../flextclimodelsbase_part_05.py | 0 .../flextclimodelsbase_part_06.py | 0 .../flextclimodelsbase_part_07.py | 0 .../_models/{_base_parts => _base}/py.typed | 0 .../_models/{ => _xlx}/xlsx_archive.py | 0 .../_models/{ => _xlx}/xlsx_cells.py | 0 .../_models/{ => _xlx}/xlsx_layout.py | 0 .../_models/{ => _xlx}/xlsx_recalc.py | 0 .../_models/{ => _xlx}/xlsx_rules.py | 0 .../_models/{ => _xlx}/xlsx_snapshot.py | 0 .../_models/{ => _xlx}/xlsx_style_catalog.py | 0 .../_models/{ => _xlx}/xlsx_style_fills.py | 0 .../{ => _xlx}/xlsx_style_primitives.py | 0 .../_models/{ => _xlx}/xlsx_styles.py | 0 .../_models/{ => _xlx}/xlsx_tables.py | 0 .../_models/{ => _xlx}/xlsx_validation.py | 0 .../_models/{ => _xlx}/xlsx_workbook.py | 0 src/flext_cli/_models/base.py | 14 ++++++------ src/flext_cli/_models/xlsx.py | 22 +++++++++---------- .../{_base_parts => _base}/__init__.py | 0 .../flextcliprotocolsbase_part_01.py | 0 .../flextcliprotocolsbase_part_02.py | 2 +- .../flextcliprotocolsbase_part_03.py | 2 +- .../flextcliprotocolsbase_part_04.py | 2 +- .../flextcliprotocolsbase_part_05.py | 2 +- .../{_base_parts => _base}/py.typed | 0 src/flext_cli/_protocols/_xlx/__init__.py | 6 +++++ .../_protocols/{ => _xlx}/xlsx_archive.py | 0 .../_protocols/{ => _xlx}/xlsx_rules.py | 0 .../_protocols/{ => _xlx}/xlsx_snapshot.py | 0 .../{ => _xlx}/xlsx_snapshot_structure.py | 0 .../_protocols/{ => _xlx}/xlsx_workbook.py | 0 src/flext_cli/_protocols/base.py | 2 +- src/flext_cli/_protocols/xlsx.py | 8 +++---- src/flext_cli/_typings/domain.py | 3 ++- src/flext_cli/_utilities/_cli_namespace.py | 2 +- .../__init__.py | 0 ...liutilitiesfiletesthelpersmixin_part_01.py | 0 ...liutilitiesfiletesthelpersmixin_part_02.py | 0 ...liutilitiesfiletesthelpersmixin_part_03.py | 2 +- ...liutilitiesfiletesthelpersmixin_part_04.py | 0 .../py.typed | 0 .../{_files_parts => _files}/__init__.py | 0 .../flextcliutilitiesfiles_part_01.py | 2 +- .../flextcliutilitiesfiles_part_02.py | 0 .../flextcliutilitiesfiles_part_03.py | 2 +- .../flextcliutilitiesfiles_part_04.py | 4 ++-- .../{_files_parts => _files}/py.typed | 0 .../{_options_parts => _options}/__init__.py | 0 .../flextcliutilitiesoptionbuilder_part_01.py | 0 .../flextcliutilitiesoptions_part_01.py | 0 .../flextcliutilitiesoptions_part_02.py | 4 ++-- .../{_options_parts => _options}/py.typed | 0 .../{_toml_parts => _toml}/__init__.py | 0 .../flextcliutilitiestoml_part_01.py | 2 +- .../flextcliutilitiestoml_part_02.py | 0 .../flextcliutilitiestoml_part_03.py | 4 ++-- .../flextcliutilitiestoml_part_04.py | 4 ++-- .../flextcliutilitiestoml_part_05.py | 6 ++--- .../flextcliutilitiestoml_part_06.py | 2 +- .../flextcliutilitiestoml_part_07.py | 4 ++-- .../{_toml_parts => _toml}/py.typed | 0 src/flext_cli/_utilities/config.py | 2 +- src/flext_cli/_utilities/file_test_helpers.py | 8 +++---- src/flext_cli/_utilities/files.py | 8 +++---- src/flext_cli/_utilities/toml.py | 14 ++++++------ .../services/{_cli_parts => _cli}/__init__.py | 0 .../flextclicli_part_01.py | 0 .../flextclicli_part_02.py | 4 +--- .../flextclicli_part_03.py | 8 ++----- .../flextclicli_part_04.py | 4 +--- .../flextclicli_part_05.py | 4 +--- .../services/{_cli_parts => _cli}/py.typed | 0 src/flext_cli/services/cli.py | 4 +--- tests/unit/conftest.py | 2 +- 80 files changed, 77 insertions(+), 82 deletions(-) rename src/flext_cli/_models/{_base_parts => _base}/__init__.py (100%) rename src/flext_cli/_models/{_base_parts => _base}/flextclimodelsbase_part_01.py (100%) rename src/flext_cli/_models/{_base_parts => _base}/flextclimodelsbase_part_02.py (100%) rename src/flext_cli/_models/{_base_parts => _base}/flextclimodelsbase_part_03.py (100%) rename src/flext_cli/_models/{_base_parts => _base}/flextclimodelsbase_part_04.py (100%) rename src/flext_cli/_models/{_base_parts => _base}/flextclimodelsbase_part_05.py (100%) rename src/flext_cli/_models/{_base_parts => _base}/flextclimodelsbase_part_06.py (100%) rename src/flext_cli/_models/{_base_parts => _base}/flextclimodelsbase_part_07.py (100%) rename src/flext_cli/_models/{_base_parts => _base}/py.typed (100%) rename src/flext_cli/_models/{ => _xlx}/xlsx_archive.py (100%) rename src/flext_cli/_models/{ => _xlx}/xlsx_cells.py (100%) rename src/flext_cli/_models/{ => _xlx}/xlsx_layout.py (100%) rename src/flext_cli/_models/{ => _xlx}/xlsx_recalc.py (100%) rename src/flext_cli/_models/{ => _xlx}/xlsx_rules.py (100%) rename src/flext_cli/_models/{ => _xlx}/xlsx_snapshot.py (100%) rename src/flext_cli/_models/{ => _xlx}/xlsx_style_catalog.py (100%) rename src/flext_cli/_models/{ => _xlx}/xlsx_style_fills.py (100%) rename src/flext_cli/_models/{ => _xlx}/xlsx_style_primitives.py (100%) rename src/flext_cli/_models/{ => _xlx}/xlsx_styles.py (100%) rename src/flext_cli/_models/{ => _xlx}/xlsx_tables.py (100%) rename src/flext_cli/_models/{ => _xlx}/xlsx_validation.py (100%) rename src/flext_cli/_models/{ => _xlx}/xlsx_workbook.py (100%) rename src/flext_cli/_protocols/{_base_parts => _base}/__init__.py (100%) rename src/flext_cli/_protocols/{_base_parts => _base}/flextcliprotocolsbase_part_01.py (100%) rename src/flext_cli/_protocols/{_base_parts => _base}/flextcliprotocolsbase_part_02.py (97%) rename src/flext_cli/_protocols/{_base_parts => _base}/flextcliprotocolsbase_part_03.py (98%) rename src/flext_cli/_protocols/{_base_parts => _base}/flextcliprotocolsbase_part_04.py (98%) rename src/flext_cli/_protocols/{_base_parts => _base}/flextcliprotocolsbase_part_05.py (92%) rename src/flext_cli/_protocols/{_base_parts => _base}/py.typed (100%) create mode 100644 src/flext_cli/_protocols/_xlx/__init__.py rename src/flext_cli/_protocols/{ => _xlx}/xlsx_archive.py (100%) rename src/flext_cli/_protocols/{ => _xlx}/xlsx_rules.py (100%) rename src/flext_cli/_protocols/{ => _xlx}/xlsx_snapshot.py (100%) rename src/flext_cli/_protocols/{ => _xlx}/xlsx_snapshot_structure.py (100%) rename src/flext_cli/_protocols/{ => _xlx}/xlsx_workbook.py (100%) rename src/flext_cli/_utilities/{_file_test_helper_parts => _file_test_helper}/__init__.py (100%) rename src/flext_cli/_utilities/{_file_test_helper_parts => _file_test_helper}/flextcliutilitiesfiletesthelpersmixin_part_01.py (100%) rename src/flext_cli/_utilities/{_file_test_helper_parts => _file_test_helper}/flextcliutilitiesfiletesthelpersmixin_part_02.py (100%) rename src/flext_cli/_utilities/{_file_test_helper_parts => _file_test_helper}/flextcliutilitiesfiletesthelpersmixin_part_03.py (97%) rename src/flext_cli/_utilities/{_file_test_helper_parts => _file_test_helper}/flextcliutilitiesfiletesthelpersmixin_part_04.py (100%) rename src/flext_cli/_utilities/{_file_test_helper_parts => _file_test_helper}/py.typed (100%) rename src/flext_cli/_utilities/{_files_parts => _files}/__init__.py (100%) rename src/flext_cli/_utilities/{_files_parts => _files}/flextcliutilitiesfiles_part_01.py (98%) rename src/flext_cli/_utilities/{_files_parts => _files}/flextcliutilitiesfiles_part_02.py (100%) rename src/flext_cli/_utilities/{_files_parts => _files}/flextcliutilitiesfiles_part_03.py (97%) rename src/flext_cli/_utilities/{_files_parts => _files}/flextcliutilitiesfiles_part_04.py (97%) rename src/flext_cli/_utilities/{_files_parts => _files}/py.typed (100%) rename src/flext_cli/_utilities/{_options_parts => _options}/__init__.py (100%) rename src/flext_cli/_utilities/{_options_parts => _options}/flextcliutilitiesoptionbuilder_part_01.py (100%) rename src/flext_cli/_utilities/{_options_parts => _options}/flextcliutilitiesoptions_part_01.py (100%) rename src/flext_cli/_utilities/{_options_parts => _options}/flextcliutilitiesoptions_part_02.py (95%) rename src/flext_cli/_utilities/{_options_parts => _options}/py.typed (100%) rename src/flext_cli/_utilities/{_toml_parts => _toml}/__init__.py (100%) rename src/flext_cli/_utilities/{_toml_parts => _toml}/flextcliutilitiestoml_part_01.py (98%) rename src/flext_cli/_utilities/{_toml_parts => _toml}/flextcliutilitiestoml_part_02.py (100%) rename src/flext_cli/_utilities/{_toml_parts => _toml}/flextcliutilitiestoml_part_03.py (96%) rename src/flext_cli/_utilities/{_toml_parts => _toml}/flextcliutilitiestoml_part_04.py (96%) rename src/flext_cli/_utilities/{_toml_parts => _toml}/flextcliutilitiestoml_part_05.py (95%) rename src/flext_cli/_utilities/{_toml_parts => _toml}/flextcliutilitiestoml_part_06.py (98%) rename src/flext_cli/_utilities/{_toml_parts => _toml}/flextcliutilitiestoml_part_07.py (85%) rename src/flext_cli/_utilities/{_toml_parts => _toml}/py.typed (100%) rename src/flext_cli/services/{_cli_parts => _cli}/__init__.py (100%) rename src/flext_cli/services/{_cli_parts => _cli}/flextclicli_part_01.py (100%) rename src/flext_cli/services/{_cli_parts => _cli}/flextclicli_part_02.py (97%) rename src/flext_cli/services/{_cli_parts => _cli}/flextclicli_part_03.py (93%) rename src/flext_cli/services/{_cli_parts => _cli}/flextclicli_part_04.py (94%) rename src/flext_cli/services/{_cli_parts => _cli}/flextclicli_part_05.py (98%) rename src/flext_cli/services/{_cli_parts => _cli}/py.typed (100%) diff --git a/src/flext_cli/_models/_base_parts/__init__.py b/src/flext_cli/_models/_base/__init__.py similarity index 100% rename from src/flext_cli/_models/_base_parts/__init__.py rename to src/flext_cli/_models/_base/__init__.py diff --git a/src/flext_cli/_models/_base_parts/flextclimodelsbase_part_01.py b/src/flext_cli/_models/_base/flextclimodelsbase_part_01.py similarity index 100% rename from src/flext_cli/_models/_base_parts/flextclimodelsbase_part_01.py rename to src/flext_cli/_models/_base/flextclimodelsbase_part_01.py diff --git a/src/flext_cli/_models/_base_parts/flextclimodelsbase_part_02.py b/src/flext_cli/_models/_base/flextclimodelsbase_part_02.py similarity index 100% rename from src/flext_cli/_models/_base_parts/flextclimodelsbase_part_02.py rename to src/flext_cli/_models/_base/flextclimodelsbase_part_02.py diff --git a/src/flext_cli/_models/_base_parts/flextclimodelsbase_part_03.py b/src/flext_cli/_models/_base/flextclimodelsbase_part_03.py similarity index 100% rename from src/flext_cli/_models/_base_parts/flextclimodelsbase_part_03.py rename to src/flext_cli/_models/_base/flextclimodelsbase_part_03.py diff --git a/src/flext_cli/_models/_base_parts/flextclimodelsbase_part_04.py b/src/flext_cli/_models/_base/flextclimodelsbase_part_04.py similarity index 100% rename from src/flext_cli/_models/_base_parts/flextclimodelsbase_part_04.py rename to src/flext_cli/_models/_base/flextclimodelsbase_part_04.py diff --git a/src/flext_cli/_models/_base_parts/flextclimodelsbase_part_05.py b/src/flext_cli/_models/_base/flextclimodelsbase_part_05.py similarity index 100% rename from src/flext_cli/_models/_base_parts/flextclimodelsbase_part_05.py rename to src/flext_cli/_models/_base/flextclimodelsbase_part_05.py diff --git a/src/flext_cli/_models/_base_parts/flextclimodelsbase_part_06.py b/src/flext_cli/_models/_base/flextclimodelsbase_part_06.py similarity index 100% rename from src/flext_cli/_models/_base_parts/flextclimodelsbase_part_06.py rename to src/flext_cli/_models/_base/flextclimodelsbase_part_06.py diff --git a/src/flext_cli/_models/_base_parts/flextclimodelsbase_part_07.py b/src/flext_cli/_models/_base/flextclimodelsbase_part_07.py similarity index 100% rename from src/flext_cli/_models/_base_parts/flextclimodelsbase_part_07.py rename to src/flext_cli/_models/_base/flextclimodelsbase_part_07.py diff --git a/src/flext_cli/_models/_base_parts/py.typed b/src/flext_cli/_models/_base/py.typed similarity index 100% rename from src/flext_cli/_models/_base_parts/py.typed rename to src/flext_cli/_models/_base/py.typed diff --git a/src/flext_cli/_models/xlsx_archive.py b/src/flext_cli/_models/_xlx/xlsx_archive.py similarity index 100% rename from src/flext_cli/_models/xlsx_archive.py rename to src/flext_cli/_models/_xlx/xlsx_archive.py diff --git a/src/flext_cli/_models/xlsx_cells.py b/src/flext_cli/_models/_xlx/xlsx_cells.py similarity index 100% rename from src/flext_cli/_models/xlsx_cells.py rename to src/flext_cli/_models/_xlx/xlsx_cells.py diff --git a/src/flext_cli/_models/xlsx_layout.py b/src/flext_cli/_models/_xlx/xlsx_layout.py similarity index 100% rename from src/flext_cli/_models/xlsx_layout.py rename to src/flext_cli/_models/_xlx/xlsx_layout.py diff --git a/src/flext_cli/_models/xlsx_recalc.py b/src/flext_cli/_models/_xlx/xlsx_recalc.py similarity index 100% rename from src/flext_cli/_models/xlsx_recalc.py rename to src/flext_cli/_models/_xlx/xlsx_recalc.py diff --git a/src/flext_cli/_models/xlsx_rules.py b/src/flext_cli/_models/_xlx/xlsx_rules.py similarity index 100% rename from src/flext_cli/_models/xlsx_rules.py rename to src/flext_cli/_models/_xlx/xlsx_rules.py diff --git a/src/flext_cli/_models/xlsx_snapshot.py b/src/flext_cli/_models/_xlx/xlsx_snapshot.py similarity index 100% rename from src/flext_cli/_models/xlsx_snapshot.py rename to src/flext_cli/_models/_xlx/xlsx_snapshot.py diff --git a/src/flext_cli/_models/xlsx_style_catalog.py b/src/flext_cli/_models/_xlx/xlsx_style_catalog.py similarity index 100% rename from src/flext_cli/_models/xlsx_style_catalog.py rename to src/flext_cli/_models/_xlx/xlsx_style_catalog.py diff --git a/src/flext_cli/_models/xlsx_style_fills.py b/src/flext_cli/_models/_xlx/xlsx_style_fills.py similarity index 100% rename from src/flext_cli/_models/xlsx_style_fills.py rename to src/flext_cli/_models/_xlx/xlsx_style_fills.py diff --git a/src/flext_cli/_models/xlsx_style_primitives.py b/src/flext_cli/_models/_xlx/xlsx_style_primitives.py similarity index 100% rename from src/flext_cli/_models/xlsx_style_primitives.py rename to src/flext_cli/_models/_xlx/xlsx_style_primitives.py diff --git a/src/flext_cli/_models/xlsx_styles.py b/src/flext_cli/_models/_xlx/xlsx_styles.py similarity index 100% rename from src/flext_cli/_models/xlsx_styles.py rename to src/flext_cli/_models/_xlx/xlsx_styles.py diff --git a/src/flext_cli/_models/xlsx_tables.py b/src/flext_cli/_models/_xlx/xlsx_tables.py similarity index 100% rename from src/flext_cli/_models/xlsx_tables.py rename to src/flext_cli/_models/_xlx/xlsx_tables.py diff --git a/src/flext_cli/_models/xlsx_validation.py b/src/flext_cli/_models/_xlx/xlsx_validation.py similarity index 100% rename from src/flext_cli/_models/xlsx_validation.py rename to src/flext_cli/_models/_xlx/xlsx_validation.py diff --git a/src/flext_cli/_models/xlsx_workbook.py b/src/flext_cli/_models/_xlx/xlsx_workbook.py similarity index 100% rename from src/flext_cli/_models/xlsx_workbook.py rename to src/flext_cli/_models/_xlx/xlsx_workbook.py diff --git a/src/flext_cli/_models/base.py b/src/flext_cli/_models/base.py index c9570d628..0bee01a7b 100644 --- a/src/flext_cli/_models/base.py +++ b/src/flext_cli/_models/base.py @@ -2,25 +2,25 @@ from __future__ import annotations -from flext_cli._models._base_parts.flextclimodelsbase_part_01 import ( +from flext_cli._models._base.flextclimodelsbase_part_01 import ( FlextCliModelsBase as FlextCliModelsBasePart01, ) -from flext_cli._models._base_parts.flextclimodelsbase_part_02 import ( +from flext_cli._models._base.flextclimodelsbase_part_02 import ( FlextCliModelsBase as FlextCliModelsBasePart02, ) -from flext_cli._models._base_parts.flextclimodelsbase_part_03 import ( +from flext_cli._models._base.flextclimodelsbase_part_03 import ( FlextCliModelsBase as FlextCliModelsBasePart03, ) -from flext_cli._models._base_parts.flextclimodelsbase_part_04 import ( +from flext_cli._models._base.flextclimodelsbase_part_04 import ( FlextCliModelsBase as FlextCliModelsBasePart04, ) -from flext_cli._models._base_parts.flextclimodelsbase_part_05 import ( +from flext_cli._models._base.flextclimodelsbase_part_05 import ( FlextCliModelsBase as FlextCliModelsBasePart05, ) -from flext_cli._models._base_parts.flextclimodelsbase_part_06 import ( +from flext_cli._models._base.flextclimodelsbase_part_06 import ( FlextCliModelsBase as FlextCliModelsBasePart06, ) -from flext_cli._models._base_parts.flextclimodelsbase_part_07 import ( +from flext_cli._models._base.flextclimodelsbase_part_07 import ( FlextCliModelsBase as FlextCliModelsBasePart07, ) diff --git a/src/flext_cli/_models/xlsx.py b/src/flext_cli/_models/xlsx.py index e45636e66..24ba73545 100644 --- a/src/flext_cli/_models/xlsx.py +++ b/src/flext_cli/_models/xlsx.py @@ -2,17 +2,17 @@ from __future__ import annotations -from .xlsx_archive import FlextCliModelsXlsxArchive -from .xlsx_cells import FlextCliModelsXlsxCells -from .xlsx_layout import FlextCliModelsXlsxLayout -from .xlsx_recalc import FlextCliModelsXlsxRecalc -from .xlsx_rules import FlextCliModelsXlsxRules -from .xlsx_snapshot import FlextCliModelsXlsxSnapshot -from .xlsx_style_catalog import FlextCliModelsXlsxStyleCatalog -from .xlsx_styles import FlextCliModelsXlsxStyles -from .xlsx_tables import FlextCliModelsXlsxTables -from .xlsx_validation import FlextCliModelsXlsxValidation -from .xlsx_workbook import FlextCliModelsXlsxWorkbook +from ._xlx.xlsx_archive import FlextCliModelsXlsxArchive +from ._xlx.xlsx_cells import FlextCliModelsXlsxCells +from ._xlx.xlsx_layout import FlextCliModelsXlsxLayout +from ._xlx.xlsx_recalc import FlextCliModelsXlsxRecalc +from ._xlx.xlsx_rules import FlextCliModelsXlsxRules +from ._xlx.xlsx_snapshot import FlextCliModelsXlsxSnapshot +from ._xlx.xlsx_style_catalog import FlextCliModelsXlsxStyleCatalog +from ._xlx.xlsx_styles import FlextCliModelsXlsxStyles +from ._xlx.xlsx_tables import FlextCliModelsXlsxTables +from ._xlx.xlsx_validation import FlextCliModelsXlsxValidation +from ._xlx.xlsx_workbook import FlextCliModelsXlsxWorkbook class FlextCliModelsXlsx( diff --git a/src/flext_cli/_protocols/_base_parts/__init__.py b/src/flext_cli/_protocols/_base/__init__.py similarity index 100% rename from src/flext_cli/_protocols/_base_parts/__init__.py rename to src/flext_cli/_protocols/_base/__init__.py diff --git a/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_01.py b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_01.py similarity index 100% rename from src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_01.py rename to src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_01.py diff --git a/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_02.py b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_02.py similarity index 97% rename from src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_02.py rename to src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_02.py index 045936c83..6d19f4e10 100644 --- a/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_02.py +++ b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_02.py @@ -8,7 +8,7 @@ from typing import Protocol, runtime_checkable -from flext_cli._protocols._base_parts.flextcliprotocolsbase_part_01 import ( +from flext_cli._protocols._base.flextcliprotocolsbase_part_01 import ( FlextCliProtocolsBase as FlextCliProtocolsBasePart01, ) from flext_core import p diff --git a/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_03.py b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_03.py similarity index 98% rename from src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_03.py rename to src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_03.py index 9f8a4f02b..53668c6cc 100644 --- a/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_03.py +++ b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_03.py @@ -9,7 +9,7 @@ from pathlib import Path from typing import Protocol, runtime_checkable -from flext_cli._protocols._base_parts.flextcliprotocolsbase_part_02 import ( +from flext_cli._protocols._base.flextcliprotocolsbase_part_02 import ( FlextCliProtocolsBase as FlextCliProtocolsBasePart02, ) diff --git a/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_04.py b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_04.py similarity index 98% rename from src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_04.py rename to src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_04.py index 3decf18cb..260e17144 100644 --- a/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_04.py +++ b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_04.py @@ -8,7 +8,7 @@ from typing import Protocol, runtime_checkable -from flext_cli._protocols._base_parts.flextcliprotocolsbase_part_03 import ( +from flext_cli._protocols._base.flextcliprotocolsbase_part_03 import ( FlextCliProtocolsBase as FlextCliProtocolsBasePart03, ) from flext_core import p diff --git a/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_05.py b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_05.py similarity index 92% rename from src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_05.py rename to src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_05.py index 3cbfa26b9..0aac684b1 100644 --- a/src/flext_cli/_protocols/_base_parts/flextcliprotocolsbase_part_05.py +++ b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_05.py @@ -8,7 +8,7 @@ from typing import Protocol, runtime_checkable -from flext_cli._protocols._base_parts.flextcliprotocolsbase_part_04 import ( +from flext_cli._protocols._base.flextcliprotocolsbase_part_04 import ( FlextCliProtocolsBase as FlextCliProtocolsBasePart04, ) diff --git a/src/flext_cli/_protocols/_base_parts/py.typed b/src/flext_cli/_protocols/_base/py.typed similarity index 100% rename from src/flext_cli/_protocols/_base_parts/py.typed rename to src/flext_cli/_protocols/_base/py.typed diff --git a/src/flext_cli/_protocols/_xlx/__init__.py b/src/flext_cli/_protocols/_xlx/__init__.py new file mode 100644 index 000000000..4bce4741f --- /dev/null +++ b/src/flext_cli/_protocols/_xlx/__init__.py @@ -0,0 +1,6 @@ +# AUTO-GENERATED FILE — Regenerate with: make gen +"""Protocols package.""" + +from __future__ import annotations + +__all__: tuple[str, ...] = () diff --git a/src/flext_cli/_protocols/xlsx_archive.py b/src/flext_cli/_protocols/_xlx/xlsx_archive.py similarity index 100% rename from src/flext_cli/_protocols/xlsx_archive.py rename to src/flext_cli/_protocols/_xlx/xlsx_archive.py diff --git a/src/flext_cli/_protocols/xlsx_rules.py b/src/flext_cli/_protocols/_xlx/xlsx_rules.py similarity index 100% rename from src/flext_cli/_protocols/xlsx_rules.py rename to src/flext_cli/_protocols/_xlx/xlsx_rules.py diff --git a/src/flext_cli/_protocols/xlsx_snapshot.py b/src/flext_cli/_protocols/_xlx/xlsx_snapshot.py similarity index 100% rename from src/flext_cli/_protocols/xlsx_snapshot.py rename to src/flext_cli/_protocols/_xlx/xlsx_snapshot.py diff --git a/src/flext_cli/_protocols/xlsx_snapshot_structure.py b/src/flext_cli/_protocols/_xlx/xlsx_snapshot_structure.py similarity index 100% rename from src/flext_cli/_protocols/xlsx_snapshot_structure.py rename to src/flext_cli/_protocols/_xlx/xlsx_snapshot_structure.py diff --git a/src/flext_cli/_protocols/xlsx_workbook.py b/src/flext_cli/_protocols/_xlx/xlsx_workbook.py similarity index 100% rename from src/flext_cli/_protocols/xlsx_workbook.py rename to src/flext_cli/_protocols/_xlx/xlsx_workbook.py diff --git a/src/flext_cli/_protocols/base.py b/src/flext_cli/_protocols/base.py index 067f89587..097282b1d 100644 --- a/src/flext_cli/_protocols/base.py +++ b/src/flext_cli/_protocols/base.py @@ -6,7 +6,7 @@ from __future__ import annotations -from flext_cli._protocols._base_parts.flextcliprotocolsbase_part_05 import ( +from flext_cli._protocols._base.flextcliprotocolsbase_part_05 import ( FlextCliProtocolsBase as FlextCliProtocolsBasePart05, ) diff --git a/src/flext_cli/_protocols/xlsx.py b/src/flext_cli/_protocols/xlsx.py index 6206341a6..b4c8774e9 100644 --- a/src/flext_cli/_protocols/xlsx.py +++ b/src/flext_cli/_protocols/xlsx.py @@ -7,10 +7,10 @@ from flext_cli._typings.xlsx import FlextCliTypesXlsx as tx from flext_core import p -from .xlsx_archive import FlextCliProtocolsXlsxArchive -from .xlsx_rules import FlextCliProtocolsXlsxRules -from .xlsx_snapshot import FlextCliProtocolsXlsxSnapshot -from .xlsx_workbook import FlextCliProtocolsXlsxWorkbook +from ._xlx.xlsx_archive import FlextCliProtocolsXlsxArchive +from ._xlx.xlsx_rules import FlextCliProtocolsXlsxRules +from ._xlx.xlsx_snapshot import FlextCliProtocolsXlsxSnapshot +from ._xlx.xlsx_workbook import FlextCliProtocolsXlsxWorkbook class FlextCliProtocolsXlsx( diff --git a/src/flext_cli/_typings/domain.py b/src/flext_cli/_typings/domain.py index 456ab1a0f..5165d4809 100644 --- a/src/flext_cli/_typings/domain.py +++ b/src/flext_cli/_typings/domain.py @@ -74,7 +74,8 @@ class FlextCliTypesDomain: type CliCommand = Callable[..., t.JsonPayload] # mro-j47u (codex): one generic alias owns formatter data and call contracts. type JsonCommandFn = Callable[..., p.Result[t.JsonPayload]] - type ResultRouteHandler = Callable[..., p.Result[ResultValue]] + # NOTE (multi-agent): route outputs are observation-only so payloads covary. + type ResultRouteHandler = Callable[..., p.ResultObservable[ResultValue]] type SuccessMessageFormatter[TResult: ResultValue = ResultValue] = Callable[ [TResult], str ] diff --git a/src/flext_cli/_utilities/_cli_namespace.py b/src/flext_cli/_utilities/_cli_namespace.py index 12991b089..59cd6bab6 100644 --- a/src/flext_cli/_utilities/_cli_namespace.py +++ b/src/flext_cli/_utilities/_cli_namespace.py @@ -2,7 +2,7 @@ from __future__ import annotations -from flext_cli._utilities._options_parts.flextcliutilitiesoptions_part_02 import ( +from flext_cli._utilities._options.flextcliutilitiesoptions_part_02 import ( FlextCliUtilitiesOptions, ) from flext_cli._utilities.auth import FlextCliUtilitiesAuth diff --git a/src/flext_cli/_utilities/_file_test_helper_parts/__init__.py b/src/flext_cli/_utilities/_file_test_helper/__init__.py similarity index 100% rename from src/flext_cli/_utilities/_file_test_helper_parts/__init__.py rename to src/flext_cli/_utilities/_file_test_helper/__init__.py diff --git a/src/flext_cli/_utilities/_file_test_helper_parts/flextcliutilitiesfiletesthelpersmixin_part_01.py b/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_01.py similarity index 100% rename from src/flext_cli/_utilities/_file_test_helper_parts/flextcliutilitiesfiletesthelpersmixin_part_01.py rename to src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_01.py diff --git a/src/flext_cli/_utilities/_file_test_helper_parts/flextcliutilitiesfiletesthelpersmixin_part_02.py b/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_02.py similarity index 100% rename from src/flext_cli/_utilities/_file_test_helper_parts/flextcliutilitiesfiletesthelpersmixin_part_02.py rename to src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_02.py diff --git a/src/flext_cli/_utilities/_file_test_helper_parts/flextcliutilitiesfiletesthelpersmixin_part_03.py b/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_03.py similarity index 97% rename from src/flext_cli/_utilities/_file_test_helper_parts/flextcliutilitiesfiletesthelpersmixin_part_03.py rename to src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_03.py index bc63180fc..3374a45b7 100644 --- a/src/flext_cli/_utilities/_file_test_helper_parts/flextcliutilitiesfiletesthelpersmixin_part_03.py +++ b/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_03.py @@ -11,7 +11,7 @@ from collections.abc import Mapping, MutableMapping from flext_cli import c, p, r -from flext_cli._utilities._file_test_helper_parts.flextcliutilitiesfiletesthelpersmixin_part_04 import ( +from flext_cli._utilities._file_test_helper.flextcliutilitiesfiletesthelpersmixin_part_04 import ( FlextCliUtilitiesFileTestHelpersMixin as FlextCliUtilitiesFileTestHelpersMixinPart04, ) from flext_cli._utilities.files import FlextCliUtilitiesFiles diff --git a/src/flext_cli/_utilities/_file_test_helper_parts/flextcliutilitiesfiletesthelpersmixin_part_04.py b/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_04.py similarity index 100% rename from src/flext_cli/_utilities/_file_test_helper_parts/flextcliutilitiesfiletesthelpersmixin_part_04.py rename to src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_04.py diff --git a/src/flext_cli/_utilities/_file_test_helper_parts/py.typed b/src/flext_cli/_utilities/_file_test_helper/py.typed similarity index 100% rename from src/flext_cli/_utilities/_file_test_helper_parts/py.typed rename to src/flext_cli/_utilities/_file_test_helper/py.typed diff --git a/src/flext_cli/_utilities/_files_parts/__init__.py b/src/flext_cli/_utilities/_files/__init__.py similarity index 100% rename from src/flext_cli/_utilities/_files_parts/__init__.py rename to src/flext_cli/_utilities/_files/__init__.py diff --git a/src/flext_cli/_utilities/_files_parts/flextcliutilitiesfiles_part_01.py b/src/flext_cli/_utilities/_files/flextcliutilitiesfiles_part_01.py similarity index 98% rename from src/flext_cli/_utilities/_files_parts/flextcliutilitiesfiles_part_01.py rename to src/flext_cli/_utilities/_files/flextcliutilitiesfiles_part_01.py index 49266a4bf..aeff2c9c5 100644 --- a/src/flext_cli/_utilities/_files_parts/flextcliutilitiesfiles_part_01.py +++ b/src/flext_cli/_utilities/_files/flextcliutilitiesfiles_part_01.py @@ -10,7 +10,7 @@ import flext_core from flext_cli import c, p, r, t -from flext_cli._utilities._files_parts.flextcliutilitiesfiles_part_02 import ( +from flext_cli._utilities._files.flextcliutilitiesfiles_part_02 import ( FlextCliUtilitiesFiles as FlextCliUtilitiesFilesPart02, ) from flext_cli._utilities.yaml import FlextCliUtilitiesYaml as uy diff --git a/src/flext_cli/_utilities/_files_parts/flextcliutilitiesfiles_part_02.py b/src/flext_cli/_utilities/_files/flextcliutilitiesfiles_part_02.py similarity index 100% rename from src/flext_cli/_utilities/_files_parts/flextcliutilitiesfiles_part_02.py rename to src/flext_cli/_utilities/_files/flextcliutilitiesfiles_part_02.py diff --git a/src/flext_cli/_utilities/_files_parts/flextcliutilitiesfiles_part_03.py b/src/flext_cli/_utilities/_files/flextcliutilitiesfiles_part_03.py similarity index 97% rename from src/flext_cli/_utilities/_files_parts/flextcliutilitiesfiles_part_03.py rename to src/flext_cli/_utilities/_files/flextcliutilitiesfiles_part_03.py index ccea863ab..72feb6dd6 100644 --- a/src/flext_cli/_utilities/_files_parts/flextcliutilitiesfiles_part_03.py +++ b/src/flext_cli/_utilities/_files/flextcliutilitiesfiles_part_03.py @@ -7,7 +7,7 @@ from pathlib import Path from flext_cli import c, p, r, t -from flext_cli._utilities._files_parts.flextcliutilitiesfiles_part_02 import ( +from flext_cli._utilities._files.flextcliutilitiesfiles_part_02 import ( FlextCliUtilitiesFiles as FlextCliUtilitiesFilesPart02, ) diff --git a/src/flext_cli/_utilities/_files_parts/flextcliutilitiesfiles_part_04.py b/src/flext_cli/_utilities/_files/flextcliutilitiesfiles_part_04.py similarity index 97% rename from src/flext_cli/_utilities/_files_parts/flextcliutilitiesfiles_part_04.py rename to src/flext_cli/_utilities/_files/flextcliutilitiesfiles_part_04.py index 8e6c57634..ebecd6f3b 100644 --- a/src/flext_cli/_utilities/_files_parts/flextcliutilitiesfiles_part_04.py +++ b/src/flext_cli/_utilities/_files/flextcliutilitiesfiles_part_04.py @@ -9,10 +9,10 @@ from pathlib import Path from flext_cli import c, m, p, r, t -from flext_cli._utilities._files_parts.flextcliutilitiesfiles_part_01 import ( +from flext_cli._utilities._files.flextcliutilitiesfiles_part_01 import ( FlextCliUtilitiesFiles as FlextCliUtilitiesFilesPart01, ) -from flext_cli._utilities._files_parts.flextcliutilitiesfiles_part_02 import ( +from flext_cli._utilities._files.flextcliutilitiesfiles_part_02 import ( FlextCliUtilitiesFiles as FlextCliUtilitiesFilesPart02, ) from flext_cli._utilities.json import FlextCliUtilitiesJson as uj diff --git a/src/flext_cli/_utilities/_files_parts/py.typed b/src/flext_cli/_utilities/_files/py.typed similarity index 100% rename from src/flext_cli/_utilities/_files_parts/py.typed rename to src/flext_cli/_utilities/_files/py.typed diff --git a/src/flext_cli/_utilities/_options_parts/__init__.py b/src/flext_cli/_utilities/_options/__init__.py similarity index 100% rename from src/flext_cli/_utilities/_options_parts/__init__.py rename to src/flext_cli/_utilities/_options/__init__.py diff --git a/src/flext_cli/_utilities/_options_parts/flextcliutilitiesoptionbuilder_part_01.py b/src/flext_cli/_utilities/_options/flextcliutilitiesoptionbuilder_part_01.py similarity index 100% rename from src/flext_cli/_utilities/_options_parts/flextcliutilitiesoptionbuilder_part_01.py rename to src/flext_cli/_utilities/_options/flextcliutilitiesoptionbuilder_part_01.py diff --git a/src/flext_cli/_utilities/_options_parts/flextcliutilitiesoptions_part_01.py b/src/flext_cli/_utilities/_options/flextcliutilitiesoptions_part_01.py similarity index 100% rename from src/flext_cli/_utilities/_options_parts/flextcliutilitiesoptions_part_01.py rename to src/flext_cli/_utilities/_options/flextcliutilitiesoptions_part_01.py diff --git a/src/flext_cli/_utilities/_options_parts/flextcliutilitiesoptions_part_02.py b/src/flext_cli/_utilities/_options/flextcliutilitiesoptions_part_02.py similarity index 95% rename from src/flext_cli/_utilities/_options_parts/flextcliutilitiesoptions_part_02.py rename to src/flext_cli/_utilities/_options/flextcliutilitiesoptions_part_02.py index 7264c86d3..de313ae3f 100644 --- a/src/flext_cli/_utilities/_options_parts/flextcliutilitiesoptions_part_02.py +++ b/src/flext_cli/_utilities/_options/flextcliutilitiesoptions_part_02.py @@ -5,10 +5,10 @@ from collections.abc import Mapping from flext_cli import c, m, t -from flext_cli._utilities._options_parts.flextcliutilitiesoptionbuilder_part_01 import ( +from flext_cli._utilities._options.flextcliutilitiesoptionbuilder_part_01 import ( FlextCliUtilitiesOptionBuilder, ) -from flext_cli._utilities._options_parts.flextcliutilitiesoptions_part_01 import ( +from flext_cli._utilities._options.flextcliutilitiesoptions_part_01 import ( FlextCliUtilitiesOptions as FlextCliUtilitiesOptionsPart01, ) diff --git a/src/flext_cli/_utilities/_options_parts/py.typed b/src/flext_cli/_utilities/_options/py.typed similarity index 100% rename from src/flext_cli/_utilities/_options_parts/py.typed rename to src/flext_cli/_utilities/_options/py.typed diff --git a/src/flext_cli/_utilities/_toml_parts/__init__.py b/src/flext_cli/_utilities/_toml/__init__.py similarity index 100% rename from src/flext_cli/_utilities/_toml_parts/__init__.py rename to src/flext_cli/_utilities/_toml/__init__.py diff --git a/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_01.py b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_01.py similarity index 98% rename from src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_01.py rename to src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_01.py index 2a2666c66..335294e0a 100644 --- a/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_01.py +++ b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_01.py @@ -11,7 +11,7 @@ from tomlkit.toml_document import TOMLDocument from flext_cli import c, p, t -from flext_cli._utilities._toml_parts.flextcliutilitiestoml_part_02 import ( +from flext_cli._utilities._toml.flextcliutilitiestoml_part_02 import ( FlextCliUtilitiesToml as FlextCliUtilitiesTomlPart02, ) from flext_core import u diff --git a/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_02.py b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_02.py similarity index 100% rename from src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_02.py rename to src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_02.py diff --git a/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_03.py b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_03.py similarity index 96% rename from src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_03.py rename to src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_03.py index 6f23b35c6..deb2a680a 100644 --- a/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_03.py +++ b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_03.py @@ -8,10 +8,10 @@ from tomlkit.toml_document import TOMLDocument from flext_cli import t -from flext_cli._utilities._toml_parts.flextcliutilitiestoml_part_01 import ( +from flext_cli._utilities._toml.flextcliutilitiestoml_part_01 import ( FlextCliUtilitiesToml as FlextCliUtilitiesTomlPart01, ) -from flext_cli._utilities._toml_parts.flextcliutilitiestoml_part_02 import ( +from flext_cli._utilities._toml.flextcliutilitiestoml_part_02 import ( FlextCliUtilitiesToml as FlextCliUtilitiesTomlPart02, ) from flext_core import u diff --git a/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_04.py b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_04.py similarity index 96% rename from src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_04.py rename to src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_04.py index f0eb87893..416ed4ab7 100644 --- a/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_04.py +++ b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_04.py @@ -3,10 +3,10 @@ from __future__ import annotations -from flext_cli._utilities._toml_parts.flextcliutilitiestoml_part_01 import ( +from flext_cli._utilities._toml.flextcliutilitiestoml_part_01 import ( FlextCliUtilitiesToml as FlextCliUtilitiesTomlPart01, ) -from flext_cli._utilities._toml_parts.flextcliutilitiestoml_part_03 import ( +from flext_cli._utilities._toml.flextcliutilitiestoml_part_03 import ( FlextCliUtilitiesToml as FlextCliUtilitiesTomlPart03, ) from flext_core import u diff --git a/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_05.py b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_05.py similarity index 95% rename from src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_05.py rename to src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_05.py index d8be3f6a1..6badfe6fc 100644 --- a/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_05.py +++ b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_05.py @@ -7,13 +7,13 @@ from tomlkit.items import Item, Table from tomlkit.toml_document import TOMLDocument -from flext_cli._utilities._toml_parts.flextcliutilitiestoml_part_01 import ( +from flext_cli._utilities._toml.flextcliutilitiestoml_part_01 import ( FlextCliUtilitiesToml as FlextCliUtilitiesTomlPart01, ) -from flext_cli._utilities._toml_parts.flextcliutilitiestoml_part_02 import ( +from flext_cli._utilities._toml.flextcliutilitiestoml_part_02 import ( FlextCliUtilitiesToml as FlextCliUtilitiesTomlPart02, ) -from flext_cli._utilities._toml_parts.flextcliutilitiestoml_part_03 import ( +from flext_cli._utilities._toml.flextcliutilitiestoml_part_03 import ( FlextCliUtilitiesToml as FlextCliUtilitiesTomlPart03, ) from flext_core import u diff --git a/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_06.py b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_06.py similarity index 98% rename from src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_06.py rename to src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_06.py index cd6a18527..b526fe620 100644 --- a/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_06.py +++ b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_06.py @@ -7,7 +7,7 @@ from tomlkit.toml_document import TOMLDocument from flext_cli import c, e, p, r, t -from flext_cli._utilities._toml_parts.flextcliutilitiestoml_part_01 import ( +from flext_cli._utilities._toml.flextcliutilitiestoml_part_01 import ( FlextCliUtilitiesToml as FlextCliUtilitiesTomlPart01, ) from flext_cli._utilities.runtime import FlextCliUtilitiesRuntime as ur diff --git a/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_07.py b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_07.py similarity index 85% rename from src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_07.py rename to src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_07.py index 4c76a69ac..3ffb0bba6 100644 --- a/src/flext_cli/_utilities/_toml_parts/flextcliutilitiestoml_part_07.py +++ b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_07.py @@ -4,10 +4,10 @@ from flext_cli import c, e, p, r, t -from flext_cli._utilities._toml_parts.flextcliutilitiestoml_part_01 import ( +from flext_cli._utilities._toml.flextcliutilitiestoml_part_01 import ( FlextCliUtilitiesToml as FlextCliUtilitiesTomlPart01, ) -from flext_cli._utilities._toml_parts.flextcliutilitiestoml_part_06 import ( +from flext_cli._utilities._toml.flextcliutilitiestoml_part_06 import ( FlextCliUtilitiesToml as FlextCliUtilitiesTomlPart06, ) diff --git a/src/flext_cli/_utilities/_toml_parts/py.typed b/src/flext_cli/_utilities/_toml/py.typed similarity index 100% rename from src/flext_cli/_utilities/_toml_parts/py.typed rename to src/flext_cli/_utilities/_toml/py.typed diff --git a/src/flext_cli/_utilities/config.py b/src/flext_cli/_utilities/config.py index 214814f8a..743c0cc30 100644 --- a/src/flext_cli/_utilities/config.py +++ b/src/flext_cli/_utilities/config.py @@ -19,7 +19,7 @@ from jsonschema.exceptions import SchemaError, ValidationError from flext_cli import c, m, p, r, t -from flext_cli._utilities._toml_parts.flextcliutilitiestoml_part_06 import ( +from flext_cli._utilities._toml.flextcliutilitiestoml_part_06 import ( FlextCliUtilitiesToml as _TomlRead, ) from flext_cli._utilities.json import FlextCliUtilitiesJson diff --git a/src/flext_cli/_utilities/file_test_helpers.py b/src/flext_cli/_utilities/file_test_helpers.py index 8a5f7334c..69fd6041f 100644 --- a/src/flext_cli/_utilities/file_test_helpers.py +++ b/src/flext_cli/_utilities/file_test_helpers.py @@ -8,16 +8,16 @@ from __future__ import annotations -from flext_cli._utilities._file_test_helper_parts.flextcliutilitiesfiletesthelpersmixin_part_01 import ( +from flext_cli._utilities._file_test_helper.flextcliutilitiesfiletesthelpersmixin_part_01 import ( FlextCliUtilitiesFileTestHelpersMixin as FlextCliUtilitiesFileTestHelpersMixinPart01, ) -from flext_cli._utilities._file_test_helper_parts.flextcliutilitiesfiletesthelpersmixin_part_02 import ( +from flext_cli._utilities._file_test_helper.flextcliutilitiesfiletesthelpersmixin_part_02 import ( FlextCliUtilitiesFileTestHelpersMixin as FlextCliUtilitiesFileTestHelpersMixinPart02, ) -from flext_cli._utilities._file_test_helper_parts.flextcliutilitiesfiletesthelpersmixin_part_03 import ( +from flext_cli._utilities._file_test_helper.flextcliutilitiesfiletesthelpersmixin_part_03 import ( FlextCliUtilitiesFileTestHelpersMixin as FlextCliUtilitiesFileTestHelpersMixinPart03, ) -from flext_cli._utilities._file_test_helper_parts.flextcliutilitiesfiletesthelpersmixin_part_04 import ( +from flext_cli._utilities._file_test_helper.flextcliutilitiesfiletesthelpersmixin_part_04 import ( FlextCliUtilitiesFileTestHelpersMixin as FlextCliUtilitiesFileTestHelpersMixinPart04, ) diff --git a/src/flext_cli/_utilities/files.py b/src/flext_cli/_utilities/files.py index 8939a263e..e8b318518 100644 --- a/src/flext_cli/_utilities/files.py +++ b/src/flext_cli/_utilities/files.py @@ -2,16 +2,16 @@ from __future__ import annotations -from flext_cli._utilities._files_parts.flextcliutilitiesfiles_part_01 import ( +from flext_cli._utilities._files.flextcliutilitiesfiles_part_01 import ( FlextCliUtilitiesFiles as FlextCliUtilitiesFilesPart01, ) -from flext_cli._utilities._files_parts.flextcliutilitiesfiles_part_02 import ( +from flext_cli._utilities._files.flextcliutilitiesfiles_part_02 import ( FlextCliUtilitiesFiles as FlextCliUtilitiesFilesPart02, ) -from flext_cli._utilities._files_parts.flextcliutilitiesfiles_part_03 import ( +from flext_cli._utilities._files.flextcliutilitiesfiles_part_03 import ( FlextCliUtilitiesFiles as FlextCliUtilitiesFilesPart03, ) -from flext_cli._utilities._files_parts.flextcliutilitiesfiles_part_04 import ( +from flext_cli._utilities._files.flextcliutilitiesfiles_part_04 import ( FlextCliUtilitiesFiles as FlextCliUtilitiesFilesPart04, ) diff --git a/src/flext_cli/_utilities/toml.py b/src/flext_cli/_utilities/toml.py index 04122c638..e4aa32084 100644 --- a/src/flext_cli/_utilities/toml.py +++ b/src/flext_cli/_utilities/toml.py @@ -2,25 +2,25 @@ from __future__ import annotations -from flext_cli._utilities._toml_parts.flextcliutilitiestoml_part_01 import ( +from flext_cli._utilities._toml.flextcliutilitiestoml_part_01 import ( FlextCliUtilitiesToml as FlextCliUtilitiesTomlPart01, ) -from flext_cli._utilities._toml_parts.flextcliutilitiestoml_part_02 import ( +from flext_cli._utilities._toml.flextcliutilitiestoml_part_02 import ( FlextCliUtilitiesToml as FlextCliUtilitiesTomlPart02, ) -from flext_cli._utilities._toml_parts.flextcliutilitiestoml_part_03 import ( +from flext_cli._utilities._toml.flextcliutilitiestoml_part_03 import ( FlextCliUtilitiesToml as FlextCliUtilitiesTomlPart03, ) -from flext_cli._utilities._toml_parts.flextcliutilitiestoml_part_04 import ( +from flext_cli._utilities._toml.flextcliutilitiestoml_part_04 import ( FlextCliUtilitiesToml as FlextCliUtilitiesTomlPart04, ) -from flext_cli._utilities._toml_parts.flextcliutilitiestoml_part_05 import ( +from flext_cli._utilities._toml.flextcliutilitiestoml_part_05 import ( FlextCliUtilitiesToml as FlextCliUtilitiesTomlPart05, ) -from flext_cli._utilities._toml_parts.flextcliutilitiestoml_part_06 import ( +from flext_cli._utilities._toml.flextcliutilitiestoml_part_06 import ( FlextCliUtilitiesToml as FlextCliUtilitiesTomlPart06, ) -from flext_cli._utilities._toml_parts.flextcliutilitiestoml_part_07 import ( +from flext_cli._utilities._toml.flextcliutilitiestoml_part_07 import ( FlextCliUtilitiesToml as FlextCliUtilitiesTomlPart07, ) diff --git a/src/flext_cli/services/_cli_parts/__init__.py b/src/flext_cli/services/_cli/__init__.py similarity index 100% rename from src/flext_cli/services/_cli_parts/__init__.py rename to src/flext_cli/services/_cli/__init__.py diff --git a/src/flext_cli/services/_cli_parts/flextclicli_part_01.py b/src/flext_cli/services/_cli/flextclicli_part_01.py similarity index 100% rename from src/flext_cli/services/_cli_parts/flextclicli_part_01.py rename to src/flext_cli/services/_cli/flextclicli_part_01.py diff --git a/src/flext_cli/services/_cli_parts/flextclicli_part_02.py b/src/flext_cli/services/_cli/flextclicli_part_02.py similarity index 97% rename from src/flext_cli/services/_cli_parts/flextclicli_part_02.py rename to src/flext_cli/services/_cli/flextclicli_part_02.py index 304ab5c80..58e6be34b 100644 --- a/src/flext_cli/services/_cli_parts/flextclicli_part_02.py +++ b/src/flext_cli/services/_cli/flextclicli_part_02.py @@ -9,9 +9,7 @@ from inspect import Parameter from flext_cli import m, p, settings, t, u -from flext_cli.services._cli_parts.flextclicli_part_01 import ( - FlextCliCli as FlextCliCliPart01, -) +from flext_cli.services._cli.flextclicli_part_01 import FlextCliCli as FlextCliCliPart01 from flext_cli.services.cli_params import FlextCliCommonParams diff --git a/src/flext_cli/services/_cli_parts/flextclicli_part_03.py b/src/flext_cli/services/_cli/flextclicli_part_03.py similarity index 93% rename from src/flext_cli/services/_cli_parts/flextclicli_part_03.py rename to src/flext_cli/services/_cli/flextclicli_part_03.py index 960863c4a..c13f2b5c8 100644 --- a/src/flext_cli/services/_cli_parts/flextclicli_part_03.py +++ b/src/flext_cli/services/_cli/flextclicli_part_03.py @@ -9,15 +9,11 @@ from inspect import Parameter from flext_cli import c, m, p, r, t, u -from flext_cli.services._cli_parts.flextclicli_part_02 import ( - FlextCliCli as FlextCliCliPart02, -) +from flext_cli.services._cli.flextclicli_part_02 import FlextCliCli as FlextCliCliPart02 # mro-j47u (codex): the earlier MRO part is referenced only by annotation; # inspect.Parameter remains runtime because it constructs the CLI signature. -from flext_cli.services._cli_parts.flextclicli_part_01 import ( - FlextCliCli as FlextCliCliPart01, -) +from flext_cli.services._cli.flextclicli_part_01 import FlextCliCli as FlextCliCliPart01 class FlextCliCli(FlextCliCliPart02): diff --git a/src/flext_cli/services/_cli_parts/flextclicli_part_04.py b/src/flext_cli/services/_cli/flextclicli_part_04.py similarity index 94% rename from src/flext_cli/services/_cli_parts/flextclicli_part_04.py rename to src/flext_cli/services/_cli/flextclicli_part_04.py index 50a35f87a..aa9e12e7f 100644 --- a/src/flext_cli/services/_cli_parts/flextclicli_part_04.py +++ b/src/flext_cli/services/_cli/flextclicli_part_04.py @@ -7,9 +7,7 @@ from __future__ import annotations from flext_cli import p, t, u -from flext_cli.services._cli_parts.flextclicli_part_03 import ( - FlextCliCli as FlextCliCliPart03, -) +from flext_cli.services._cli.flextclicli_part_03 import FlextCliCli as FlextCliCliPart03 class FlextCliCli(FlextCliCliPart03): diff --git a/src/flext_cli/services/_cli_parts/flextclicli_part_05.py b/src/flext_cli/services/_cli/flextclicli_part_05.py similarity index 98% rename from src/flext_cli/services/_cli_parts/flextclicli_part_05.py rename to src/flext_cli/services/_cli/flextclicli_part_05.py index 6cecabc94..acfcfa40e 100644 --- a/src/flext_cli/services/_cli_parts/flextclicli_part_05.py +++ b/src/flext_cli/services/_cli/flextclicli_part_05.py @@ -8,9 +8,7 @@ from flext_cli import c, r, settings, t, u -from flext_cli.services._cli_parts.flextclicli_part_04 import ( - FlextCliCli as FlextCliCliPart04, -) +from flext_cli.services._cli.flextclicli_part_04 import FlextCliCli as FlextCliCliPart04 from flext_cli import p diff --git a/src/flext_cli/services/_cli_parts/py.typed b/src/flext_cli/services/_cli/py.typed similarity index 100% rename from src/flext_cli/services/_cli_parts/py.typed rename to src/flext_cli/services/_cli/py.typed diff --git a/src/flext_cli/services/cli.py b/src/flext_cli/services/cli.py index 15087971a..2d3e10875 100644 --- a/src/flext_cli/services/cli.py +++ b/src/flext_cli/services/cli.py @@ -7,9 +7,7 @@ from __future__ import annotations from flext_cli import s -from flext_cli.services._cli_parts.flextclicli_part_05 import ( - FlextCliCli as FlextCliCliPart05, -) +from flext_cli.services._cli.flextclicli_part_05 import FlextCliCli as FlextCliCliPart05 class FlextCliCli(s, FlextCliCliPart05): diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py index 10f5c9e48..bb89c536f 100644 --- a/tests/unit/conftest.py +++ b/tests/unit/conftest.py @@ -55,7 +55,7 @@ def raise_password(_prompt: str) -> str: def configure_state(self, *, interactive: bool = True, quiet: bool = False) -> Self: """Configure the observable prompt runtime state.""" - settingsure(m.Cli.PromptRuntimeState(interactive=interactive, quiet=quiet)) + configure(m.Cli.PromptRuntimeState(interactive=interactive, quiet=quiet)) return self From aa34f28ef97003fa1a24ddea1df6c42f2dff455a Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Wed, 15 Jul 2026 04:50:45 -0300 Subject: [PATCH 14/37] feat(toml): preserve lookup maps when discarding trivia TARGET: flext-cli public TOML utility facade and behavioral tests. IMPACT: non-breaking internal utility addition consumed by flext-infra structural codegen. RISK: low; fixed-cardinality mutation is prevalidated atomically and covered across nested lookups and invalid requests. --- .../_toml/flextcliutilitiestoml_part_02.py | 21 +++++++ tests/unit/test_toml_trivia.py | 58 +++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 tests/unit/test_toml_trivia.py diff --git a/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_02.py b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_02.py index d85b3ee68..af8ae6f03 100644 --- a/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_02.py +++ b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_02.py @@ -62,6 +62,27 @@ def toml_item_child(container: TOMLDocument | Table, key: str) -> Item | None: value = container[key] return value if FlextCliUtilitiesToml.toml_is_item(value) else None + @staticmethod + def toml_discard_unkeyed_items( + container: t.Cli.TomlContainer, indexes: t.SequenceOf[int] + ) -> None: + """Discard parsed trivia without invalidating keyed TOML lookup indexes.""" + normalized_indexes = tuple(indexes) + if len(frozenset(normalized_indexes)) != len(normalized_indexes): + msg = "TOML trivia indexes must be unique" + raise ValueError(msg) + body_length = len(container.body) + for index in normalized_indexes: + if index < 0 or index >= body_length: + msg = f"TOML trivia index {index} is outside the container body" + raise IndexError(msg) + key, _item = container.body[index] + if key is not None: + msg = f"TOML body index {index} is keyed and cannot be discarded" + raise ValueError(msg) + for index in normalized_indexes: + container.body[index] = (None, tomlkit.ws("")) + @staticmethod def toml_ensure_table(parent: TOMLDocument | Table, key: str) -> Table: """Return a table child without replacing TOMLKit super-tables.""" diff --git a/tests/unit/test_toml_trivia.py b/tests/unit/test_toml_trivia.py new file mode 100644 index 000000000..2908d0f31 --- /dev/null +++ b/tests/unit/test_toml_trivia.py @@ -0,0 +1,58 @@ +"""Behavioral tests for cardinality-preserving TOML trivia removal.""" + +from __future__ import annotations + +import pytest +from flext_tests import tm + +from tests import u + + +class TestsFlextCliTomlTrivia: + """Public contract for safe structural trivia removal.""" + + def test_discard_preserves_nested_public_lookups(self) -> None: + """Discard comment trivia without shifting keyed lookup indexes.""" + rendered = ( + "# managed marker\n" + "[project]\n" + 'name = "demo"\n' + "[project.optional-dependencies]\n" + 'dev = ["pytest"]\n' + ) + document = u.Cli.toml_parse_text(rendered) + expected = u.Cli.toml_mapping_from_text(rendered) + if document is None: + pytest.fail("valid TOML must produce a document") + + u.Cli.toml_discard_unkeyed_items(document, (0,)) + + project = u.Cli.toml_table_child(document, "project") + if project is None: + pytest.fail("project table must remain addressable") + optional = u.Cli.toml_table_child(project, "optional-dependencies") + if optional is None: + pytest.fail("optional-dependencies table must remain addressable") + tm.that(u.Cli.toml_item_child(optional, "dev"), none=False) + tm.that(u.Cli.toml_as_mapping(document), eq=expected) + tm.that(u.Cli.toml_dumps(document).startswith("# managed marker"), eq=False) + + def test_discard_rejects_keyed_or_duplicate_indexes(self) -> None: + """Fail loud rather than corrupting a keyed or ambiguous TOML slot.""" + document = u.Cli.toml_parse_text('# comment\nname = "demo"\n') + if document is None: + pytest.fail("valid TOML must produce a document") + original = u.Cli.toml_dumps(document) + + with pytest.raises(ValueError, match="unique"): + u.Cli.toml_discard_unkeyed_items(document, (0, 0)) + tm.that(u.Cli.toml_dumps(document), eq=original) + with pytest.raises(ValueError, match="keyed"): + u.Cli.toml_discard_unkeyed_items(document, (0, 1)) + tm.that(u.Cli.toml_dumps(document), eq=original) + with pytest.raises(IndexError, match="outside"): + u.Cli.toml_discard_unkeyed_items(document, (0, 2)) + tm.that(u.Cli.toml_dumps(document), eq=original) + + +__all__: list[str] = ["TestsFlextCliTomlTrivia"] From 320024f276c8516c7cc457163e095131b7ed7a98 Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Wed, 15 Jul 2026 22:12:34 -0300 Subject: [PATCH 15/37] fixes --- src/flext_cli/_typings/domain.py | 13 ++++++------- src/flext_cli/_utilities/_yaml/_convert.py | 10 +++++----- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/flext_cli/_typings/domain.py b/src/flext_cli/_typings/domain.py index 5165d4809..c0578746d 100644 --- a/src/flext_cli/_typings/domain.py +++ b/src/flext_cli/_typings/domain.py @@ -2,7 +2,7 @@ from __future__ import annotations -from collections.abc import Callable, Mapping, MutableMapping +from collections.abc import Callable, MutableMapping from pathlib import Path from ruamel.yaml.comments import CommentedMap, CommentedSeq @@ -14,14 +14,13 @@ from flext_cli._typings.base import FlextCliTypesBase as tb from flext_core import p, t -# NOTE (multi-agent): YAML round-trip aliases live at module level because a -# self-referencing PEP 695 alias in CLASS scope breaks pyrefly/pyright (proven -# in cosmos-charts). The class body only re-exports them as ``t.Cli.Yaml*``; -# never inline the recursion into the class body. +# Pydantic owns recursive JSON validation at the external YAML boundary. +# Round-trip ruamel nodes stay explicit so validation never copies away their +# comments, anchors, or identity. type _YamlScalar = str | int | float | bool | None -type _YamlValue = _YamlScalar | list[_YamlValue] | Mapping[str, _YamlValue] +type _YamlValue = t.JsonValue | t.JsonMapping | CommentedMap | CommentedSeq type _YamlNode = CommentedMap | CommentedSeq | _YamlScalar -type _YamlSequence = CommentedSeq | list[_YamlValue] +type _YamlSequence = CommentedSeq | list[t.JsonValue] class FlextCliTypesDomain: diff --git a/src/flext_cli/_utilities/_yaml/_convert.py b/src/flext_cli/_utilities/_yaml/_convert.py index 716a7e5aa..09a84b9aa 100644 --- a/src/flext_cli/_utilities/_yaml/_convert.py +++ b/src/flext_cli/_utilities/_yaml/_convert.py @@ -14,7 +14,7 @@ from __future__ import annotations from collections.abc import Mapping -from typing import SupportsFloat, SupportsIndex, SupportsInt, TypeGuard, cast, overload +from typing import SupportsFloat, SupportsIndex, SupportsInt, TypeGuard, overload from ruamel.yaml.comments import CommentedMap, CommentedSeq from ruamel.yaml.scalarstring import DoubleQuotedScalarString, LiteralScalarString @@ -65,11 +65,11 @@ def yaml_deep_to_commented(data: CommentedSeq) -> CommentedSeq: ... @overload @staticmethod - def yaml_deep_to_commented(data: Mapping[str, t.Cli.YamlValue]) -> CommentedMap: ... + def yaml_deep_to_commented(data: t.JsonMapping) -> CommentedMap: ... @overload @staticmethod - def yaml_deep_to_commented(data: list[t.Cli.YamlValue]) -> CommentedSeq: ... + def yaml_deep_to_commented(data: list[t.JsonValue]) -> CommentedSeq: ... @overload @staticmethod @@ -99,9 +99,9 @@ def yaml_deep_to_commented(data: t.Cli.YamlValue) -> t.Cli.YamlNode: ) if isinstance(data, str): if "\n" in data: - return cast("t.Cli.YamlScalar", LiteralScalarString(data)) + return LiteralScalarString(data) if data.lower() in _YAML_1_1_IMPLICIT_STRING_VALUES: - return cast("t.Cli.YamlScalar", DoubleQuotedScalarString(data)) + return DoubleQuotedScalarString(data) if data is not None and not isinstance(data, (str, int, float, bool)): msg = f"unsupported YAML value type: {type(data).__name__}" raise TypeError(msg) From ac79a24d053c39980227af35c042a5932e7aaed3 Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Wed, 15 Jul 2026 23:13:23 -0300 Subject: [PATCH 16/37] fixes --- examples/_models_parts/examples_advanced.py | 2 +- examples/_models_parts/examples_common.py | 2 +- examples/_models_parts/examples_database.py | 2 +- examples/ex_01_getting_started.py | 6 +-- examples/ex_04_file_operations.py | 24 +++++------ examples/ex_06_settings.py | 2 +- examples/ex_12_pydantic_driven_cli.py | 24 +++++------ examples/utilities.py | 2 +- .../_base/flextclimodelsbase_part_01.py | 14 +++---- .../_base/flextclimodelsbase_part_02.py | 8 ++-- .../_base/flextclimodelsbase_part_03.py | 6 +-- .../_base/flextclimodelsbase_part_05.py | 3 +- .../_base/flextclimodelsbase_part_06.py | 4 +- .../_base/flextclimodelsbase_part_07.py | 6 +-- src/flext_cli/_models/pipeline.py | 8 ++-- .../flextcliutilitiesoptionbuilder_part_01.py | 2 +- .../flextcliutilitiesoptions_part_01.py | 2 +- .../flextcliutilitiesoptions_part_02.py | 2 +- .../_utilities/_xlxx/xlsx_addresses.py | 14 +++---- .../_utilities/_xlxx/xlsx_archive.py | 14 +++---- .../_utilities/_xlxx/xlsx_archive_checks.py | 12 +++--- src/flext_cli/_utilities/_xlxx/xlsx_cells.py | 2 +- .../_utilities/_xlxx/xlsx_conditional.py | 10 ++--- src/flext_cli/_utilities/_xlxx/xlsx_recalc.py | 36 ++++++++--------- .../_utilities/_xlxx/xlsx_renderer.py | 12 +++--- .../_utilities/_xlxx/xlsx_snapshot.py | 10 ++--- .../_utilities/_xlxx/xlsx_snapshot_sheet.py | 12 +++--- .../_xlxx/xlsx_snapshot_structure.py | 40 +++++++++---------- .../_utilities/_xlxx/xlsx_snapshot_values.py | 28 ++++++------- .../_utilities/_xlxx/xlsx_style_catalog.py | 30 +++++++------- .../_utilities/_xlxx/xlsx_style_readers.py | 20 +++++----- src/flext_cli/_utilities/_xlxx/xlsx_tables.py | 8 ++-- .../_utilities/_xlxx/xlsx_validations.py | 2 +- src/flext_cli/_utilities/cmd.py | 8 ++-- src/flext_cli/_utilities/config.py | 10 ++--- src/flext_cli/_utilities/framework.py | 2 +- src/flext_cli/_utilities/params.py | 2 +- src/flext_cli/_utilities/pipeline.py | 14 +++---- src/flext_cli/_utilities/settings.py | 2 +- src/flext_cli/_utilities/tables.py | 8 ++-- src/flext_cli/_utilities/template.py | 8 ++-- src/flext_cli/api.py | 6 +-- .../services/_cli/flextclicli_part_02.py | 2 +- .../services/_cli/flextclicli_part_03.py | 8 ++-- src/flext_cli/services/cli_params.py | 4 +- src/flext_cli/services/cmd.py | 4 +- src/flext_cli/services/pipeline.py | 18 ++++----- src/flext_cli/services/prompts.py | 6 +-- tests/_models_parts/tests_runtime.py | 4 +- tests/_models_parts/tests_version.py | 2 +- tests/base.py | 2 +- tests/protocols.py | 2 +- tests/test_xlsx_recalc.py | 2 +- .../testsflextcliservice_part_01.py | 2 +- .../testsflextcliservice_part_02.py | 2 +- .../testsflextcliservice_part_05.py | 12 +++--- .../testsflextclipipeline_part_01.py | 12 +++--- .../testsflextclipipeline_part_02.py | 10 ++--- .../testsflextclipipeline_part_03.py | 2 +- ...flextclipubliccontractscoverage_part_02.py | 4 +- ...flextclipubliccontractscoverage_part_03.py | 4 +- tests/unit/test_options_cov.py | 2 +- tests/unit/test_tables_branch_cov.py | 2 +- 63 files changed, 268 insertions(+), 267 deletions(-) diff --git a/examples/_models_parts/examples_advanced.py b/examples/_models_parts/examples_advanced.py index d651c5a92..44290a735 100644 --- a/examples/_models_parts/examples_advanced.py +++ b/examples/_models_parts/examples_advanced.py @@ -19,7 +19,7 @@ class ExamplesFlextCliModelsExamplesAdvanced: class AppSettingsAdvanced(m.Value): """Advanced application settings — Pydantic v2 only.""" - model_config: ClassVar[m.ConfigDict] = m.ConfigDict( + model_config: ClassVar[p.ConfigDict] = m.ConfigDict( extra="forbid", validate_assignment=True, ) diff --git a/examples/_models_parts/examples_common.py b/examples/_models_parts/examples_common.py index 6c8e61798..1c030d24a 100644 --- a/examples/_models_parts/examples_common.py +++ b/examples/_models_parts/examples_common.py @@ -54,7 +54,7 @@ def merge_env_overrides( class MyAppSettings(m.Value): """Custom settings for YOUR CLI application — Pydantic v2 only.""" - model_config: ClassVar[m.ConfigDict] = m.ConfigDict( + model_config: ClassVar[p.ConfigDict] = m.ConfigDict( extra="forbid", validate_assignment=True, ) diff --git a/examples/_models_parts/examples_database.py b/examples/_models_parts/examples_database.py index 8c23db0a0..aa7320809 100644 --- a/examples/_models_parts/examples_database.py +++ b/examples/_models_parts/examples_database.py @@ -15,7 +15,7 @@ class ExamplesFlextCliModelsExamplesDatabase: class AdvancedDatabaseConfig(m.Value): """Database configuration with advanced validation.""" - model_config: ClassVar[m.ConfigDict] = m.ConfigDict( + model_config: ClassVar[p.ConfigDict] = m.ConfigDict( extra="forbid", validate_assignment=True, ) diff --git a/examples/ex_01_getting_started.py b/examples/ex_01_getting_started.py index ac54f14df..292079eae 100644 --- a/examples/ex_01_getting_started.py +++ b/examples/ex_01_getting_started.py @@ -19,7 +19,7 @@ class ExamplesFlextCliGettingStarted(s[t.JsonMapping]): # mro-wkii.17.26 (codex): specialize the canonical service result contract. - def build_example_settings(self) -> p.Result[m.Examples.MyAppSettings]: + def build_example_settings(self) -> p.Result[p.Examples.MyAppSettings]: """Build a validated application settings model through the examples facade.""" settings_payload: t.JsonMapping = { "app_name": c.EXAMPLE_DEFAULT_TOOL_NAME, @@ -27,14 +27,14 @@ def build_example_settings(self) -> p.Result[m.Examples.MyAppSettings]: "max_workers": c.EXAMPLE_DEFAULT_MAX_WORKERS, "timeout": c.EXAMPLE_DEFAULT_TIMEOUT_SECONDS, } - return r[m.Examples.MyAppSettings].ok( + return r[p.Examples.MyAppSettings].ok( m.Examples.MyAppSettings.model_validate(settings_payload) ) @staticmethod def persist_example_settings( settings: m.Examples.MyAppSettings, - ) -> p.Result[m.Cli.LoadedConfig]: + ) -> p.Result[p.Cli.LoadedConfig]: """Round-trip settings through the public JSON file facade.""" wrapped_config = m.Cli.LoadedConfig(content=settings.model_dump(mode="json")) with TemporaryDirectory(prefix=f"{c.EXAMPLE_DEFAULT_TEMP_SUBDIR}-") as temp_dir: diff --git a/examples/ex_04_file_operations.py b/examples/ex_04_file_operations.py index 2013b5258..b81619ce4 100644 --- a/examples/ex_04_file_operations.py +++ b/examples/ex_04_file_operations.py @@ -54,7 +54,7 @@ def save_user_preferences( return True -def load_user_preferences(config_dir: Path) -> p.Result[m.Cli.LoadedConfig]: +def load_user_preferences(config_dir: Path) -> p.Result[p.Cli.LoadedConfig]: """Load user preferences from JSON in YOUR app. Returns r[LoadedConfig]; no None.""" config_file = config_dir / "preferences.json" @@ -65,17 +65,17 @@ def load_user_preferences(config_dir: Path) -> p.Result[m.Cli.LoadedConfig]: f"⚠️ Could not load: {read_result.error}", style=c.Cli.MessageStyles.YELLOW, ) - return r[m.Cli.LoadedConfig].fail( + return r[p.Cli.LoadedConfig].fail( read_result.error or "Could not load preferences", ) if not isinstance(read_result.value, Mapping): - return r[m.Cli.LoadedConfig].fail("Preferences content must be a mapping") + return r[p.Cli.LoadedConfig].fail("Preferences content must be a mapping") cli.print( f"✅ Loaded preferences from {config_file.name}", style=c.Cli.MessageStyles.GREEN, ) - return r[m.Cli.LoadedConfig].ok( + return r[p.Cli.LoadedConfig].ok( m.Cli.LoadedConfig(content=dict(read_result.value)), ) @@ -111,7 +111,7 @@ def save_deployment_config( return True -def load_deployment_config(config_file: Path) -> p.Result[m.Cli.LoadedConfig]: +def load_deployment_config(config_file: Path) -> p.Result[p.Cli.LoadedConfig]: """Load deployment settings from YAML in YOUR tool. Returns r[LoadedConfig]; no None.""" load_result = cli.load_file_auto_dict(config_file) @@ -120,15 +120,15 @@ def load_deployment_config(config_file: Path) -> p.Result[m.Cli.LoadedConfig]: f"❌ Config load failed: {load_result.error}", style=c.Cli.MessageStyles.BOLD_RED, ) - return r[m.Cli.LoadedConfig].fail(load_result.error or "Config load failed") + return r[p.Cli.LoadedConfig].fail(load_result.error or "Config load failed") cli.print("✅ Loaded deployment settings", style=c.Cli.MessageStyles.GREEN) - return r[m.Cli.LoadedConfig].ok( + return r[p.Cli.LoadedConfig].ok( m.Cli.LoadedConfig(content=load_result.value), ) -def validate_and_import_data(input_file: Path) -> p.Result[m.Cli.LoadedConfig]: +def validate_and_import_data(input_file: Path) -> p.Result[p.Cli.LoadedConfig]: """Validate and import data in YOUR ETL pipeline. Returns r[LoadedConfig]; no None.""" read_result = cli.read_json_file(input_file) @@ -137,17 +137,17 @@ def validate_and_import_data(input_file: Path) -> p.Result[m.Cli.LoadedConfig]: f"❌ Read failed: {read_result.error}", style=c.Cli.MessageStyles.BOLD_RED, ) - return r[m.Cli.LoadedConfig].fail(read_result.error or "Read failed") + return r[p.Cli.LoadedConfig].fail(read_result.error or "Read failed") data = read_result.value if not isinstance(data, Mapping): - return r[m.Cli.LoadedConfig].fail("Input data must be a mapping") + return r[p.Cli.LoadedConfig].fail("Input data must be a mapping") for field in _EXAMPLE_REQUIRED_DATA_FIELDS: if field not in data: - return r[m.Cli.LoadedConfig].fail(f"Missing required field: {field}") + return r[p.Cli.LoadedConfig].fail(f"Missing required field: {field}") cli.print("✅ Data validated successfully", style=c.Cli.MessageStyles.GREEN) - return r[m.Cli.LoadedConfig].ok( + return r[p.Cli.LoadedConfig].ok( m.Cli.LoadedConfig(content=data), ) diff --git a/examples/ex_06_settings.py b/examples/ex_06_settings.py index 4bdf1fc0f..717baa83f 100644 --- a/examples/ex_06_settings.py +++ b/examples/ex_06_settings.py @@ -58,7 +58,7 @@ def show_cli_settings() -> p.Cli.Settings: return settings @staticmethod - def show_settings_locations() -> m.Cli.DisplayData: + def show_settings_locations() -> p.Cli.DisplayData: """Display settings file locations for YOUR application.""" home_dir = Path.home() token_file_path = u.Cli.auth_token_file_path(settings.cli_token_file) diff --git a/examples/ex_12_pydantic_driven_cli.py b/examples/ex_12_pydantic_driven_cli.py index b802362e0..747899333 100644 --- a/examples/ex_12_pydantic_driven_cli.py +++ b/examples/ex_12_pydantic_driven_cli.py @@ -45,13 +45,13 @@ def _report_step_success[T](value: T, message: str) -> T: def _finish_database_config( settings: m.Examples.AdvancedDatabaseConfig, -) -> m.Examples.AdvancedDatabaseConfig: +) -> p.Examples.AdvancedDatabaseConfig: """Emit the final success summary and preserve the validated settings.""" u.display_success_summary("Database configuration") return settings -def create_database_config_from_cli() -> p.Result[m.Examples.AdvancedDatabaseConfig]: +def create_database_config_from_cli() -> p.Result[p.Examples.AdvancedDatabaseConfig]: """Create validated DatabaseConfig using Railway Pattern with Pydantic.""" cli.print( "\n🗄️ Database Configuration with Railway Pattern:", @@ -67,7 +67,7 @@ def create_database_config_from_cli() -> p.Result[m.Examples.AdvancedDatabaseCon connection_pool=c.EXAMPLE_DATABASE_DEMO_CONNECTION_POOL, ) return ( - r[m.Examples.AdvancedDatabaseConfig] + r[p.Examples.AdvancedDatabaseConfig] .ok(cli_args) .map( lambda settings: _report_step_success( @@ -109,21 +109,21 @@ def validate_required_fields( def convert_and_validate_with_pydantic( data: t.JsonMapping, -) -> p.Result[m.Examples.AdvancedDatabaseConfig]: +) -> p.Result[p.Examples.AdvancedDatabaseConfig]: """Convert raw data to validated Pydantic model.""" try: - return r[m.Examples.AdvancedDatabaseConfig].ok( + return r[p.Examples.AdvancedDatabaseConfig].ok( m.Examples.AdvancedDatabaseConfig.model_validate(data) ) except c.ValidationError as error: - return r[m.Examples.AdvancedDatabaseConfig].fail( + return r[p.Examples.AdvancedDatabaseConfig].fail( f"Pydantic validation failed: {error}" ) def validate_business_rules( settings: m.Examples.AdvancedDatabaseConfig, -) -> p.Result[m.Examples.AdvancedDatabaseConfig]: +) -> p.Result[p.Examples.AdvancedDatabaseConfig]: """Apply custom business rules to validated database configuration.""" if settings.ssl_enabled and settings.port == c.EXAMPLE_DEFAULT_DB_PORT: settings = settings.model_copy(update={"port": c.EXAMPLE_SSL_DB_PORT}) @@ -131,16 +131,16 @@ def validate_business_rules( settings.connection_pool > c.EXAMPLE_LOCALHOST_CONNECTION_POOL_LIMIT and settings.host == c.EXAMPLE_DEFAULT_HOST ): - return r[m.Examples.AdvancedDatabaseConfig].fail( + return r[p.Examples.AdvancedDatabaseConfig].fail( "Localhost cannot handle large connection pools" ) - return r[m.Examples.AdvancedDatabaseConfig].ok(settings) + return r[p.Examples.AdvancedDatabaseConfig].ok(settings) def perform_connection_test( settings: m.Examples.AdvancedDatabaseConfig, -) -> p.Result[m.Examples.AdvancedDatabaseConfig]: +) -> p.Result[p.Examples.AdvancedDatabaseConfig]: """Simulate database connection test.""" if "fail" in settings.host: - return r[m.Examples.AdvancedDatabaseConfig].fail("Connection test failed") - return r[m.Examples.AdvancedDatabaseConfig].ok(settings) + return r[p.Examples.AdvancedDatabaseConfig].fail("Connection test failed") + return r[p.Examples.AdvancedDatabaseConfig].ok(settings) diff --git a/examples/utilities.py b/examples/utilities.py index e36d91f67..ca8935df0 100644 --- a/examples/utilities.py +++ b/examples/utilities.py @@ -29,7 +29,7 @@ class ExamplesFlextCliUtilities(u): def to_json_dict( cls, data: t.JsonMapping, - ) -> m.Cli.DisplayData: + ) -> p.Cli.DisplayData: """Normalize settings/mapping to DisplayData for create_table/display_config_table.""" json_value: t.JsonValue = t.Cli.JSON_VALUE_ADAPTER.validate_python( cls.normalize_to_json_value(data), diff --git a/src/flext_cli/_models/_base/flextclimodelsbase_part_01.py b/src/flext_cli/_models/_base/flextclimodelsbase_part_01.py index 8b16b0d90..0fa3e833a 100644 --- a/src/flext_cli/_models/_base/flextclimodelsbase_part_01.py +++ b/src/flext_cli/_models/_base/flextclimodelsbase_part_01.py @@ -7,7 +7,7 @@ from typing import Annotated, ClassVar from flext_cli import t -from flext_core import m, u +from flext_core import m, u, p class FlextCliModelsBase: @@ -41,7 +41,7 @@ class CommandBytesOutput(m.Value): class RuntimeComponents(m.BaseModel): """Availability state for canonical CLI runtime components.""" - model_config: ClassVar[m.ConfigDict] = m.ConfigDict(extra="forbid", frozen=True) + model_config: ClassVar[p.ConfigDict] = m.ConfigDict(extra="forbid", frozen=True) settings: Annotated[str, m.Field(description="Settings component state")] formatters: Annotated[str, m.Field(description="Formatters component state")] prompts: Annotated[str, m.Field(description="Prompts component state")] @@ -50,7 +50,7 @@ class RuntimeComponents(m.BaseModel): class RuntimeStatus(m.BaseModel): """Canonical public CLI runtime status payload.""" - model_config: ClassVar[m.ConfigDict] = m.ConfigDict(extra="forbid", frozen=True) + model_config: ClassVar[p.ConfigDict] = m.ConfigDict(extra="forbid", frozen=True) status: Annotated[str, m.Field(description="Overall service state")] service: Annotated[str, m.Field(description="Service identifier")] timestamp: Annotated[str, m.Field(description="Status generation timestamp")] @@ -63,7 +63,7 @@ class RuntimeStatus(m.BaseModel): class DisplayData(m.BaseModel): """Key-value data for table/display — Pydantic v2 contract. Use m.Cli.DisplayData.""" - model_config: ClassVar[m.ConfigDict] = m.ConfigDict( + model_config: ClassVar[p.ConfigDict] = m.ConfigDict( extra="forbid", validate_assignment=True ) data: Annotated[ @@ -82,7 +82,7 @@ def _serialize(self) -> t.JsonMapping: class LoadedConfig(m.BaseModel): """Loaded configuration content wrapper — Pydantic v2 contract. Use m.Cli.LoadedConfig.""" - model_config: ClassVar[m.ConfigDict] = m.ConfigDict( + model_config: ClassVar[p.ConfigDict] = m.ConfigDict( extra="forbid", validate_assignment=True ) content: Annotated[ @@ -101,7 +101,7 @@ class CliNormalizedJson(m.RootModel[t.JsonValue]): ``model_serializer`` required. """ - model_config: ClassVar[m.ConfigDict] = m.ConfigDict(frozen=True) + model_config: ClassVar[p.ConfigDict] = m.ConfigDict(frozen=True) root: Annotated[ t.JsonValue, m.Field(description="Normalized JSON-compatible value") ] @@ -109,7 +109,7 @@ class CliNormalizedJson(m.RootModel[t.JsonValue]): class NormalizedJsonList(m.BaseModel): """Resolve normalized JSON to a dict with defaults. Use m.Cli.NormalizedJsonList.""" - model_config: ClassVar[m.ConfigDict] = m.ConfigDict( + model_config: ClassVar[p.ConfigDict] = m.ConfigDict( extra="forbid", validate_assignment=True ) value: Annotated[ diff --git a/src/flext_cli/_models/_base/flextclimodelsbase_part_02.py b/src/flext_cli/_models/_base/flextclimodelsbase_part_02.py index cfdf96da5..533a0c421 100644 --- a/src/flext_cli/_models/_base/flextclimodelsbase_part_02.py +++ b/src/flext_cli/_models/_base/flextclimodelsbase_part_02.py @@ -5,7 +5,7 @@ from types import MappingProxyType from typing import Annotated, ClassVar -from flext_cli import c, t +from flext_cli import c, p, t from flext_core import m, u @@ -15,7 +15,7 @@ class FlextCliModelsBase: class PromptRuntimeState(m.FlexibleInternalModel): """Centralized runtime state for CLI prompt behavior.""" - model_config: ClassVar[m.ConfigDict] = m.ConfigDict( + model_config: ClassVar[p.ConfigDict] = m.ConfigDict( extra="forbid", validate_assignment=True ) @@ -32,7 +32,7 @@ class PromptRuntimeState(m.FlexibleInternalModel): class AuthCredentialsPayload(m.BaseModel): """Validated auth payload for token or username/password flows.""" - model_config: ClassVar[m.ConfigDict] = m.ConfigDict( + model_config: ClassVar[p.ConfigDict] = m.ConfigDict( extra="forbid", validate_assignment=True ) token: Annotated[ @@ -49,7 +49,7 @@ class AuthCredentialsPayload(m.BaseModel): class ProcessEnvironmentSpec(m.BaseModel): """Validated process environment contract for runtime command execution.""" - model_config: ClassVar[m.ConfigDict] = m.ConfigDict(extra="forbid", frozen=True) + model_config: ClassVar[p.ConfigDict] = m.ConfigDict(extra="forbid", frozen=True) base_env: Annotated[ t.StrMapping, m.Field( diff --git a/src/flext_cli/_models/_base/flextclimodelsbase_part_03.py b/src/flext_cli/_models/_base/flextclimodelsbase_part_03.py index bc0d444f7..071c40e35 100644 --- a/src/flext_cli/_models/_base/flextclimodelsbase_part_03.py +++ b/src/flext_cli/_models/_base/flextclimodelsbase_part_03.py @@ -4,7 +4,7 @@ from typing import Annotated, ClassVar -from flext_cli import c, t +from flext_cli import c, p, t from flext_core import m @@ -14,7 +14,7 @@ class FlextCliModelsBase: class CommandEntryModel(m.BaseModel): """Single command entry: name + handler. Use m.Cli.CommandEntryModel.""" - model_config: ClassVar[m.ConfigDict] = m.ConfigDict( + model_config: ClassVar[p.ConfigDict] = m.ConfigDict( arbitrary_types_allowed=True, extra="forbid" ) name: Annotated[t.NonEmptyStr, m.Field(..., description="Command name")] @@ -25,7 +25,7 @@ class CommandEntryModel(m.BaseModel): class ResultCommandRoute(m.BaseModel): """Type-erased route contract for heterogeneous batch registration.""" - model_config: ClassVar[m.ConfigDict] = m.ConfigDict( + model_config: ClassVar[p.ConfigDict] = m.ConfigDict( arbitrary_types_allowed=True, extra="forbid", frozen=True ) name: Annotated[t.NonEmptyStr, m.Field(..., description="Command name")] diff --git a/src/flext_cli/_models/_base/flextclimodelsbase_part_05.py b/src/flext_cli/_models/_base/flextclimodelsbase_part_05.py index c99b31964..32f2c323c 100644 --- a/src/flext_cli/_models/_base/flextclimodelsbase_part_05.py +++ b/src/flext_cli/_models/_base/flextclimodelsbase_part_05.py @@ -4,6 +4,7 @@ from typing import Annotated, ClassVar +from flext_cli import p from flext_core import m @@ -13,7 +14,7 @@ class FlextCliModelsBase: class SettingsSnapshot(m.Value): """Snapshot of current CLI settings information.""" - model_config: ClassVar[m.ConfigDict] = m.ConfigDict(frozen=True, extra="forbid") + model_config: ClassVar[p.ConfigDict] = m.ConfigDict(frozen=True, extra="forbid") settings_dir: Annotated[str, m.Field(description="Settings directory path")] = ( "" diff --git a/src/flext_cli/_models/_base/flextclimodelsbase_part_06.py b/src/flext_cli/_models/_base/flextclimodelsbase_part_06.py index 4182d5092..ef699cad6 100644 --- a/src/flext_cli/_models/_base/flextclimodelsbase_part_06.py +++ b/src/flext_cli/_models/_base/flextclimodelsbase_part_06.py @@ -4,7 +4,7 @@ from typing import Annotated, ClassVar -from flext_cli import t +from flext_cli import p, t from flext_core import m @@ -61,7 +61,7 @@ def params(self) -> t.JsonMapping: class OptionMetadata(m.BaseModel): """Validated option-registry metadata for Typer option generation.""" - model_config: ClassVar[m.ConfigDict] = m.ConfigDict(extra="ignore", frozen=True) + model_config: ClassVar[p.ConfigDict] = m.ConfigDict(extra="ignore", frozen=True) help: Annotated[ str, m.Field("", description="Option help text", strict=True) diff --git a/src/flext_cli/_models/_base/flextclimodelsbase_part_07.py b/src/flext_cli/_models/_base/flextclimodelsbase_part_07.py index 365468b66..476f749ed 100644 --- a/src/flext_cli/_models/_base/flextclimodelsbase_part_07.py +++ b/src/flext_cli/_models/_base/flextclimodelsbase_part_07.py @@ -6,7 +6,7 @@ from types import MappingProxyType from typing import Annotated, ClassVar -from flext_cli import c, t +from flext_cli import c, p, t from flext_core import m, u _EMPTY_JSON_MAPPING: t.JsonMapping = MappingProxyType({}) @@ -18,7 +18,7 @@ class FlextCliModelsBase: class LogLevelResolved(m.BaseModel): """Single contract for log level string.""" - model_config: ClassVar[m.ConfigDict] = m.ConfigDict(extra="forbid") + model_config: ClassVar[p.ConfigDict] = m.ConfigDict(extra="forbid") raw: Annotated[ str | None, m.Field(None, description="Raw log level input string") ] @@ -43,7 +43,7 @@ def resolve(self) -> str: class TypedExtract(m.BaseModel): """Single contract for typed value extraction (str | bool | dict).""" - model_config: ClassVar[m.ConfigDict] = m.ConfigDict(extra="forbid") + model_config: ClassVar[p.ConfigDict] = m.ConfigDict(extra="forbid") type_kind: Annotated[t.Cli.TypeKind, m.Field(description="Requested type")] value: Annotated[ t.JsonValue | None, m.Field(None, description="Value to extract and coerce") diff --git a/src/flext_cli/_models/pipeline.py b/src/flext_cli/_models/pipeline.py index 5f38f911e..4aa2323aa 100644 --- a/src/flext_cli/_models/pipeline.py +++ b/src/flext_cli/_models/pipeline.py @@ -17,7 +17,7 @@ class FlextCliModelsPipeline: class PipelineStageContext(m.ContractModel): """Accumulated state passed between pipeline stages.""" - model_config: ClassVar[m.ConfigDict] = m.ConfigDict( + model_config: ClassVar[p.ConfigDict] = m.ConfigDict( extra="forbid", validate_assignment=True, arbitrary_types_allowed=True ) @@ -40,7 +40,7 @@ class PipelineStageContext(m.ContractModel): class PipelineStageSpec(m.ContractModel): """Declarative stage definition with dependency tracking.""" - model_config: ClassVar[m.ConfigDict] = m.ConfigDict( + model_config: ClassVar[p.ConfigDict] = m.ConfigDict( extra="forbid", arbitrary_types_allowed=True ) @@ -78,7 +78,7 @@ class PipelineStageSpec(m.ContractModel): class PipelineStageResult(m.ContractModel): """What a stage produces after execution.""" - model_config: ClassVar[m.ConfigDict] = m.ConfigDict(extra="forbid") + model_config: ClassVar[p.ConfigDict] = m.ConfigDict(extra="forbid") stage_id: Annotated[str, m.Field(description="Stage that produced this result")] status: Annotated[ @@ -104,7 +104,7 @@ class PipelineStageResult(m.ContractModel): class PipelineResult(m.ContractModel): """Full pipeline execution result — aggregated from all stages.""" - model_config: ClassVar[m.ConfigDict] = m.ConfigDict(extra="forbid") + model_config: ClassVar[p.ConfigDict] = m.ConfigDict(extra="forbid") stages: Annotated[ t.SequenceOf[FlextCliModelsPipeline.PipelineStageResult], diff --git a/src/flext_cli/_utilities/_options/flextcliutilitiesoptionbuilder_part_01.py b/src/flext_cli/_utilities/_options/flextcliutilitiesoptionbuilder_part_01.py index d61635b65..75713f4c8 100644 --- a/src/flext_cli/_utilities/_options/flextcliutilitiesoptionbuilder_part_01.py +++ b/src/flext_cli/_utilities/_options/flextcliutilitiesoptionbuilder_part_01.py @@ -14,7 +14,7 @@ def __init__(self, field_name: str, registry: t.Cli.OptionRegistry) -> None: self.field_name = field_name self.registry = registry - def build(self) -> m.Cli.OptionSpec: + def build(self) -> p.Cli.OptionSpec: """Build one CLI option spec from field metadata.""" field_meta_raw = self.registry.get(self.field_name, {}) if not field_meta_raw: diff --git a/src/flext_cli/_utilities/_options/flextcliutilitiesoptions_part_01.py b/src/flext_cli/_utilities/_options/flextcliutilitiesoptions_part_01.py index e50194c54..5974a831b 100644 --- a/src/flext_cli/_utilities/_options/flextcliutilitiesoptions_part_01.py +++ b/src/flext_cli/_utilities/_options/flextcliutilitiesoptions_part_01.py @@ -93,7 +93,7 @@ def is_string_sequence(value: t.Cli.CliDefaultSource) -> bool: return False if isinstance(value, str | bytes): return False - return all(isinstance(item, str) for item in value) + return all(item for item in value) @classmethod def normalize_cli_atom( diff --git a/src/flext_cli/_utilities/_options/flextcliutilitiesoptions_part_02.py b/src/flext_cli/_utilities/_options/flextcliutilitiesoptions_part_02.py index de313ae3f..06ba370e7 100644 --- a/src/flext_cli/_utilities/_options/flextcliutilitiesoptions_part_02.py +++ b/src/flext_cli/_utilities/_options/flextcliutilitiesoptions_part_02.py @@ -60,7 +60,7 @@ def field_default( @staticmethod def build_option( field_name: str, registry: t.Cli.OptionRegistry - ) -> m.Cli.OptionSpec: + ) -> p.Cli.OptionSpec: """Build one CLI option spec from the canonical registry.""" return FlextCliUtilitiesOptionBuilder(field_name, registry).build() diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_addresses.py b/src/flext_cli/_utilities/_xlxx/xlsx_addresses.py index ded117c4b..b6ba90c53 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_addresses.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_addresses.py @@ -44,8 +44,8 @@ def _sheet_ref(name: str) -> str: return quote_sheetname(name) @staticmethod - def _range_failure(detail: str) -> p.Result[m.Cli.XlsxCellRange]: - return r[m.Cli.XlsxCellRange].fail(f"{c.Cli.XlsxError.RANGE_INVALID}: {detail}") + def _range_failure(detail: str) -> p.Result[p.Cli.XlsxCellRange]: + return r[p.Cli.XlsxCellRange].fail(f"{c.Cli.XlsxError.RANGE_INVALID}: {detail}") # mro-wkii.17.26 (xlsx-a): keep the caught vendor boundary to one operation. @classmethod @@ -65,7 +65,7 @@ def _format_reference_value(cls, request: m.Cli.XlsxFormatReferenceRequest) -> s @classmethod def xlsx_parse_range( cls, request: m.Cli.XlsxParseRangeRequest - ) -> p.Result[m.Cli.XlsxCellRange]: + ) -> p.Result[p.Cli.XlsxCellRange]: """Parse one concrete A1 cell/range through the XLSX adapter.""" try: first_column, first_row, last_column, last_row = range_boundaries( @@ -83,7 +83,7 @@ def xlsx_parse_range( return cls._range_failure(request.reference) if first_column > last_column or first_row > last_row: return cls._range_failure(request.reference) - return r[m.Cli.XlsxCellRange].ok( + return r[p.Cli.XlsxCellRange].ok( m.Cli.XlsxCellRange( first=m.Cli.XlsxCellAddress(row=first_row, column=first_column), last=m.Cli.XlsxCellAddress(row=last_row, column=last_column), @@ -94,16 +94,16 @@ def xlsx_parse_range( @classmethod def xlsx_format_reference( cls, request: m.Cli.XlsxFormatReferenceRequest - ) -> p.Result[m.Cli.XlsxReference]: + ) -> p.Result[p.Cli.XlsxReference]: """Format one validated range as a canonical Excel reference.""" try: reference = cls._format_reference_value(request) except (TypeError, ValueError) as exc: detail = str(exc).strip() or exc.__class__.__name__ - return r[m.Cli.XlsxReference].fail( + return r[p.Cli.XlsxReference].fail( f"{c.Cli.XlsxError.RANGE_INVALID}: {detail}" ) - return r[m.Cli.XlsxReference].ok(m.Cli.XlsxReference(reference=reference)) + return r[p.Cli.XlsxReference].ok(m.Cli.XlsxReference(reference=reference)) __all__: tuple[str, ...] = ("FlextCliUtilitiesXlsxAddresses",) diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_archive.py b/src/flext_cli/_utilities/_xlxx/xlsx_archive.py index 8d1265c01..9ffa4f00f 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_archive.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_archive.py @@ -18,12 +18,12 @@ class FlextCliUtilitiesXlsxArchive(FlextCliUtilitiesXlsxArchiveChecks): @classmethod def _inventory( cls, archive: p.Cli.XlsxArchiveReader, policy: m.Cli.XlsxArchivePolicy - ) -> m.Cli.XlsxArchiveInventory: + ) -> p.Cli.XlsxArchiveInventory: members: tuple[str, ...] = () blocked: frozenset[str] = frozenset() seen: frozenset[str] = frozenset() total_size = 0 - violations: tuple[m.Cli.XlsxArchiveViolation, ...] = () + violations: tuple[p.Cli.XlsxArchiveViolation, ...] = () for info in archive.infolist(): member = info.filename members = (*members, member) @@ -71,7 +71,7 @@ def _inventory( @classmethod def _inspect_archive( cls, archive: p.Cli.XlsxArchiveReader, policy: m.Cli.XlsxArchivePolicy - ) -> p.Result[m.Cli.XlsxArchiveInspection]: + ) -> p.Result[p.Cli.XlsxArchiveInspection]: inventory = cls._inventory(archive, policy) violations = inventory.violations workbook_member = c.Cli.XLSX_WORKBOOK_MEMBER @@ -109,7 +109,7 @@ def _inspect_archive( for member in xml_members: root_result = cls._xml_root(archive, member) if root_result.failure: - return r[m.Cli.XlsxArchiveInspection].fail( + return r[p.Cli.XlsxArchiveInspection].fail( root_result.error or f"Invalid OOXML member: {member}" ) root = root_result.value @@ -132,12 +132,12 @@ def _inspect_archive( violations=violations, clean=not violations, ) - return r[m.Cli.XlsxArchiveInspection].ok(inspection) + return r[p.Cli.XlsxArchiveInspection].ok(inspection) @classmethod def xlsx_inspect( cls, request: m.Cli.XlsxArchiveInspectionRequest - ) -> p.Result[m.Cli.XlsxArchiveInspection]: + ) -> p.Result[p.Cli.XlsxArchiveInspection]: """Inspect workbook bytes without extracting or trusting package XML.""" try: with ZipFile(BytesIO(request.source)) as archive: @@ -145,7 +145,7 @@ def xlsx_inspect( return cls._inspect_archive(archive, request.policy) except (BadZipFile, LargeZipFile, OSError, ValueError) as exc: detail = str(exc).strip() or exc.__class__.__name__ - return r[m.Cli.XlsxArchiveInspection].fail( + return r[p.Cli.XlsxArchiveInspection].fail( f"{c.Cli.XlsxError.ARCHIVE_INVALID}: {detail}" ) diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_archive_checks.py b/src/flext_cli/_utilities/_xlxx/xlsx_archive_checks.py index a65c82148..83efff89d 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_archive_checks.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_archive_checks.py @@ -16,7 +16,7 @@ class FlextCliUtilitiesXlsxArchiveChecks: @staticmethod def _violation( kind: t.Cli.XlsxArchiveViolationKind, location: str, detail: str - ) -> m.Cli.XlsxArchiveViolation: + ) -> p.Cli.XlsxArchiveViolation: return m.Cli.XlsxArchiveViolation(kind=kind, location=location, detail=detail) @staticmethod @@ -47,8 +47,8 @@ def _xml_root( @classmethod def _worksheet_violations( cls, root: p.Cli.XlsxXmlElement, member: str, policy: m.Cli.XlsxArchivePolicy - ) -> tuple[m.Cli.XlsxArchiveViolation, ...]: - violations: tuple[m.Cli.XlsxArchiveViolation, ...] = () + ) -> tuple[p.Cli.XlsxArchiveViolation, ...]: + violations: tuple[p.Cli.XlsxArchiveViolation, ...] = () for element in root.iter(): tag = cls._local_name(element.tag) if tag in policy.forbidden_worksheet_tags: @@ -58,7 +58,7 @@ def _worksheet_violations( @classmethod def _workbook_violations( cls, root: p.Cli.XlsxXmlElement, member: str, policy: m.Cli.XlsxArchivePolicy - ) -> tuple[m.Cli.XlsxArchiveViolation, ...]: + ) -> tuple[p.Cli.XlsxArchiveViolation, ...]: if not policy.reject_defined_names: return () return tuple( @@ -70,10 +70,10 @@ def _workbook_violations( @classmethod def _style_violations( cls, root: p.Cli.XlsxXmlElement, member: str, policy: m.Cli.XlsxArchivePolicy - ) -> tuple[m.Cli.XlsxArchiveViolation, ...]: + ) -> tuple[p.Cli.XlsxArchiveViolation, ...]: if not policy.reject_style_protection: return () - violations: tuple[m.Cli.XlsxArchiveViolation, ...] = () + violations: tuple[p.Cli.XlsxArchiveViolation, ...] = () for group in root.iter(): if ( cls._local_name(group.tag) diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_cells.py b/src/flext_cli/_utilities/_xlxx/xlsx_cells.py index f2ef2eac6..a8c9820d4 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_cells.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_cells.py @@ -30,7 +30,7 @@ def _cell_value(value: m.Cli.XlsxCellValue) -> t.Cli.XlsxCellPrimitive: def _apply_cells( cls, worksheet: Worksheet, - plans: tuple[m.Cli.XlsxCellPlan, ...], + plans: tuple[p.Cli.XlsxCellPlan, ...], named_styles: frozenset[str], ) -> p.Result[bool]: try: diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_conditional.py b/src/flext_cli/_utilities/_xlxx/xlsx_conditional.py index 9c2368ca8..055572114 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_conditional.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_conditional.py @@ -29,20 +29,20 @@ class FlextCliUtilitiesXlsxConditional( @classmethod def _registered_style( cls, worksheet: Worksheet, name: str - ) -> p.Result[m.Cli.XlsxNamedStyleSpec]: + ) -> p.Result[p.Cli.XlsxNamedStyleSpec]: try: probe = Cell(worksheet, row=1, column=1) probe.style = name except (KeyError, ValueError): - return r[m.Cli.XlsxNamedStyleSpec].fail( + return r[p.Cli.XlsxNamedStyleSpec].fail( f"{c.Cli.XlsxError.NAMED_STYLE_MISSING}: {name}" ) visual = cls._visual_from_styleable(probe) if visual.failure: - return r[m.Cli.XlsxNamedStyleSpec].fail( + return r[p.Cli.XlsxNamedStyleSpec].fail( visual.error or f"Failed to read registered style: {name}" ) - return r[m.Cli.XlsxNamedStyleSpec].ok( + return r[p.Cli.XlsxNamedStyleSpec].ok( m.Cli.XlsxNamedStyleSpec(name=name, visual=visual.value) ) @@ -102,7 +102,7 @@ def _rule( @classmethod def _apply_conditional_formats( - cls, worksheet: Worksheet, plans: tuple[m.Cli.XlsxConditionalFormatPlan, ...] + cls, worksheet: Worksheet, plans: tuple[p.Cli.XlsxConditionalFormatPlan, ...] ) -> p.Result[bool]: try: for plan in plans: diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_recalc.py b/src/flext_cli/_utilities/_xlxx/xlsx_recalc.py index 7ef738fd2..de2bea65b 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_recalc.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_recalc.py @@ -25,7 +25,7 @@ def _recalc_error(detail: str) -> str: @classmethod def _recalc_in_workspace( cls, request: m.Cli.XlsxRecalcRequest, workdir: Path - ) -> p.Result[m.Cli.XlsxRecalcResult]: + ) -> p.Result[p.Cli.XlsxRecalcResult]: input_dir = workdir / "input" output_dir = workdir / "output" source_path = input_dir / c.Cli.XLSX_RECALC_SOURCE_NAME @@ -35,7 +35,7 @@ def _recalc_in_workspace( source_path.write_bytes(request.source) except (OSError, ValueError) as exc: detail = str(exc).strip() or exc.__class__.__name__ - return r[m.Cli.XlsxRecalcResult].fail(cls._recalc_error(detail)) + return r[p.Cli.XlsxRecalcResult].fail(cls._recalc_error(detail)) try: started = FlextCliUtilitiesProcesses.process_start( (*c.Cli.XLSX_RECALC_COMMAND, str(output_dir), str(source_path)), @@ -43,36 +43,36 @@ def _recalc_in_workspace( ) except (OSError, ValueError) as exc: detail = str(exc).strip() or exc.__class__.__name__ - return r[m.Cli.XlsxRecalcResult].fail(cls._recalc_error(detail)) + return r[p.Cli.XlsxRecalcResult].fail(cls._recalc_error(detail)) if started.failure: - return r[m.Cli.XlsxRecalcResult].fail(cls._recalc_error(f"{started.error}")) + return r[p.Cli.XlsxRecalcResult].fail(cls._recalc_error(f"{started.error}")) process = started.value try: completed = process.wait(timeout=c.Cli.XLSX_RECALC_TIMEOUT_SECONDS) except (OSError, ValueError) as exc: detail = str(exc).strip() or exc.__class__.__name__ - return r[m.Cli.XlsxRecalcResult].fail(cls._recalc_error(detail)) + return r[p.Cli.XlsxRecalcResult].fail(cls._recalc_error(detail)) if completed.failure: try: killed = process.kill() except (OSError, ValueError) as exc: detail = str(exc).strip() or exc.__class__.__name__ - return r[m.Cli.XlsxRecalcResult].fail(cls._recalc_error(detail)) + return r[p.Cli.XlsxRecalcResult].fail(cls._recalc_error(detail)) detail = completed.error or "process wait failed" if killed.failure: detail = f"{detail}; kill failed: {killed.error}" - return r[m.Cli.XlsxRecalcResult].fail(cls._recalc_error(detail)) + return r[p.Cli.XlsxRecalcResult].fail(cls._recalc_error(detail)) if completed.value != 0: detail = process.stderr.strip() or process.stdout.strip() - return r[m.Cli.XlsxRecalcResult].fail( + return r[p.Cli.XlsxRecalcResult].fail( cls._recalc_error(f"exit={completed.value}: {detail}") ) try: content = (output_dir / c.Cli.XLSX_RECALC_SOURCE_NAME).read_bytes() except (OSError, ValueError) as exc: detail = str(exc).strip() or exc.__class__.__name__ - return r[m.Cli.XlsxRecalcResult].fail(cls._recalc_error(detail)) - return r[m.Cli.XlsxRecalcResult].ok(m.Cli.XlsxRecalcResult(content=content)) + return r[p.Cli.XlsxRecalcResult].fail(cls._recalc_error(detail)) + return r[p.Cli.XlsxRecalcResult].ok(m.Cli.XlsxRecalcResult(content=content)) # NOTE (multi-agent, mro-j2yt.1): the headless engine process terminates # at this private adapter; process spawning is consumed from the generic @@ -80,7 +80,7 @@ def _recalc_in_workspace( @classmethod def xlsx_recalc( cls, request: m.Cli.XlsxRecalcRequest - ) -> p.Result[m.Cli.XlsxRecalcResult]: + ) -> p.Result[p.Cli.XlsxRecalcResult]: """Recalculate every formula cache through the headless office engine.""" try: with tempfile.TemporaryDirectory( @@ -89,36 +89,36 @@ def xlsx_recalc( result = cls._recalc_in_workspace(request, Path(workspace)) except (OSError, ValueError) as exc: detail = str(exc).strip() or exc.__class__.__name__ - return r[m.Cli.XlsxRecalcResult].fail(cls._recalc_error(detail)) + return r[p.Cli.XlsxRecalcResult].fail(cls._recalc_error(detail)) return result @classmethod def xlsx_recalc_parity( cls, request: m.Cli.XlsxRecalcParityRequest - ) -> p.Result[m.Cli.XlsxRecalcParityReport]: + ) -> p.Result[p.Cli.XlsxRecalcParityReport]: """Recalculate and compare cached values against source formulas.""" formula_snapshot = cls.xlsx_snapshot( m.Cli.XlsxSnapshotRequest(source=request.source, data_only=False) ) if formula_snapshot.failure: - return r[m.Cli.XlsxRecalcParityReport].fail( + return r[p.Cli.XlsxRecalcParityReport].fail( f"{c.Cli.XlsxError.PARITY_FAILED}: {formula_snapshot.error}" ) recalculated = cls.xlsx_recalc(m.Cli.XlsxRecalcRequest(source=request.source)) if recalculated.failure: - return r[m.Cli.XlsxRecalcParityReport].fail( + return r[p.Cli.XlsxRecalcParityReport].fail( f"{c.Cli.XlsxError.PARITY_FAILED}: {recalculated.error}" ) value_snapshot = cls.xlsx_snapshot( m.Cli.XlsxSnapshotRequest(source=recalculated.value.content, data_only=True) ) if value_snapshot.failure: - return r[m.Cli.XlsxRecalcParityReport].fail( + return r[p.Cli.XlsxRecalcParityReport].fail( f"{c.Cli.XlsxError.PARITY_FAILED}: {value_snapshot.error}" ) cache_evidence = cls._formula_cache_evidence(recalculated.value.content) if cache_evidence.failure: - return r[m.Cli.XlsxRecalcParityReport].fail( + return r[p.Cli.XlsxRecalcParityReport].fail( f"{c.Cli.XlsxError.PARITY_FAILED}: {cache_evidence.error}" ) uncached_cells, empty_result_cells = cache_evidence.value @@ -146,7 +146,7 @@ def xlsx_recalc_parity( empty_result_cells=empty_result_cells, ok=not error_cells and not uncached_cells and count_matches, ) - return r[m.Cli.XlsxRecalcParityReport].ok(report) + return r[p.Cli.XlsxRecalcParityReport].ok(report) __all__: tuple[str, ...] = ("FlextCliUtilitiesXlsxRecalc",) diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_renderer.py b/src/flext_cli/_utilities/_xlxx/xlsx_renderer.py index 887b631d8..7fcff0fc1 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_renderer.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_renderer.py @@ -55,11 +55,11 @@ def _render_sheet( @classmethod def xlsx_render( cls, request: m.Cli.XlsxRenderRequest - ) -> p.Result[m.Cli.XlsxRenderResult]: + ) -> p.Result[p.Cli.XlsxRenderResult]: """Render typed sheets, names, styles, and rules into workbook bytes.""" workbook_result = cls._workbook_for_request(request) if workbook_result.failure: - return r[m.Cli.XlsxRenderResult].fail( + return r[p.Cli.XlsxRenderResult].fail( workbook_result.error or str(c.Cli.XlsxError.RENDER_FAILED) ) workbook = workbook_result.value @@ -67,21 +67,21 @@ def xlsx_render( for sheet in request.plan.sheets: rendered = cls._render_sheet(workbook, sheet, table_names) if rendered.failure: - return r[m.Cli.XlsxRenderResult].fail( + return r[p.Cli.XlsxRenderResult].fail( rendered.error or str(c.Cli.XlsxError.RENDER_FAILED) ) table_names = rendered.value names = cls._apply_defined_names(workbook, request.plan.defined_names) if names.failure: - return r[m.Cli.XlsxRenderResult].fail( + return r[p.Cli.XlsxRenderResult].fail( names.error or "Defined-name rendering failed" ) content = cls._serialize_workbook(workbook) if content.failure: - return r[m.Cli.XlsxRenderResult].fail( + return r[p.Cli.XlsxRenderResult].fail( content.error or str(c.Cli.XlsxError.SERIALIZE_FAILED) ) - return r[m.Cli.XlsxRenderResult].ok( + return r[p.Cli.XlsxRenderResult].ok( m.Cli.XlsxRenderResult(content=content.value, plan=request.plan) ) diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_snapshot.py b/src/flext_cli/_utilities/_xlxx/xlsx_snapshot.py index 2f9fd9d07..725fb5e40 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_snapshot.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_snapshot.py @@ -20,7 +20,7 @@ class FlextCliUtilitiesXlsxSnapshot( @classmethod def xlsx_snapshot( cls, request: m.Cli.XlsxSnapshotRequest - ) -> p.Result[m.Cli.XlsxWorkbookSnapshot]: + ) -> p.Result[p.Cli.XlsxWorkbookSnapshot]: """Inspect workbook bytes into one immutable semantic snapshot.""" try: formula_workbook = cls._require_success( @@ -32,12 +32,12 @@ def xlsx_snapshot( else formula_workbook ) except (TypeError, ValidationError, ValueError) as exc: - return r[m.Cli.XlsxWorkbookSnapshot].fail( + return r[p.Cli.XlsxWorkbookSnapshot].fail( f"Workbook snapshot failed ({exc.__class__.__name__}): {exc}", exception=exc, ) if len(formula_workbook.worksheets) != len(value_workbook.worksheets): - return r[m.Cli.XlsxWorkbookSnapshot].fail( + return r[p.Cli.XlsxWorkbookSnapshot].fail( "Workbook snapshot failed (ValueError): Formula and value workbook " "views have different sheet counts" ) @@ -65,11 +65,11 @@ def xlsx_snapshot( literal_count=sum(item.literal_count for item in sheets), ) except (TypeError, ValidationError, ValueError) as exc: - return r[m.Cli.XlsxWorkbookSnapshot].fail( + return r[p.Cli.XlsxWorkbookSnapshot].fail( f"Workbook snapshot failed ({exc.__class__.__name__}): {exc}", exception=exc, ) - return r[m.Cli.XlsxWorkbookSnapshot].ok(snapshot) + return r[p.Cli.XlsxWorkbookSnapshot].ok(snapshot) __all__: tuple[str, ...] = ("FlextCliUtilitiesXlsxSnapshot",) diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_sheet.py b/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_sheet.py index c2c658db3..f5128d8b6 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_sheet.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_sheet.py @@ -37,11 +37,11 @@ def _snapshot_state( @classmethod def _snapshot_sheet( cls, formula_sheet: Worksheet, value_sheet: Worksheet, *, position: int - ) -> p.Result[m.Cli.XlsxSheetSnapshot]: + ) -> p.Result[p.Cli.XlsxSheetSnapshot]: formula_title = formula_sheet.title value_title = value_sheet.title if formula_title != value_title: - return r[m.Cli.XlsxSheetSnapshot].fail( + return r[p.Cli.XlsxSheetSnapshot].fail( "Worksheet snapshot failed (ValueError): Worksheet view mismatch: " f"{formula_title} != {value_title}" ) @@ -64,14 +64,14 @@ def _snapshot_sheet( ) legacy_password_hash = formula_sheet.protection.password except (TypeError, ValidationError, ValueError) as exc: - return r[m.Cli.XlsxSheetSnapshot].fail( + return r[p.Cli.XlsxSheetSnapshot].fail( f"Worksheet snapshot failed ({exc.__class__.__name__}): {exc}", exception=exc, ) if legacy_password_hash is not None and not isinstance( legacy_password_hash, str ): - return r[m.Cli.XlsxSheetSnapshot].fail( + return r[p.Cli.XlsxSheetSnapshot].fail( "Worksheet snapshot failed (TypeError): Worksheet legacy protection " "hash is not textual" ) @@ -110,11 +110,11 @@ def _snapshot_sheet( merge_count=len(merged_ranges), ) except (TypeError, ValidationError, ValueError) as exc: - return r[m.Cli.XlsxSheetSnapshot].fail( + return r[p.Cli.XlsxSheetSnapshot].fail( f"Worksheet snapshot failed ({exc.__class__.__name__}): {exc}", exception=exc, ) - return r[m.Cli.XlsxSheetSnapshot].ok(snapshot) + return r[p.Cli.XlsxSheetSnapshot].ok(snapshot) __all__: tuple[str, ...] = ("FlextCliUtilitiesXlsxSnapshotSheet",) diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_structure.py b/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_structure.py index 0d2ea6514..de50ce67a 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_structure.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_structure.py @@ -20,16 +20,16 @@ class FlextCliUtilitiesXlsxSnapshotStructure: @staticmethod def _snapshot_tables( worksheet: Worksheet, - ) -> p.Result[tuple[m.Cli.XlsxTableSnapshot, ...]]: - tables: tuple[m.Cli.XlsxTableSnapshot, ...] = () + ) -> p.Result[tuple[p.Cli.XlsxTableSnapshot, ...]]: + tables: tuple[p.Cli.XlsxTableSnapshot, ...] = () try: for item in worksheet.tables.values(): if not isinstance(item, Table): - return r[tuple[m.Cli.XlsxTableSnapshot, ...]].fail( + return r[tuple[p.Cli.XlsxTableSnapshot, ...]].fail( f"Unsupported table value: {item.__class__.__name__}" ) if not isinstance(item.name, str) or not isinstance(item.ref, str): - return r[tuple[m.Cli.XlsxTableSnapshot, ...]].fail( + return r[tuple[p.Cli.XlsxTableSnapshot, ...]].fail( "Table requires a string name and reference" ) style_name = ( @@ -45,18 +45,18 @@ def _snapshot_tables( ) except (AttributeError, TypeError, ValidationError, ValueError) as exc: detail = str(exc).strip() or exc.__class__.__name__ - return r[tuple[m.Cli.XlsxTableSnapshot, ...]].fail( + return r[tuple[p.Cli.XlsxTableSnapshot, ...]].fail( f"Table snapshot failed: {detail}" ) - return r[tuple[m.Cli.XlsxTableSnapshot, ...]].ok( + return r[tuple[p.Cli.XlsxTableSnapshot, ...]].ok( tuple(sorted(tables, key=lambda item: item.name)) ) @staticmethod def _snapshot_rows( worksheet: Worksheet, - ) -> p.Result[tuple[m.Cli.XlsxRowDimensionSnapshot, ...]]: - rows: tuple[m.Cli.XlsxRowDimensionSnapshot, ...] = () + ) -> p.Result[tuple[p.Cli.XlsxRowDimensionSnapshot, ...]]: + rows: tuple[p.Cli.XlsxRowDimensionSnapshot, ...] = () try: for item in worksheet.row_dimensions.values(): rows = ( @@ -70,18 +70,18 @@ def _snapshot_rows( ) except (TypeError, ValidationError, ValueError) as exc: detail = str(exc).strip() or exc.__class__.__name__ - return r[tuple[m.Cli.XlsxRowDimensionSnapshot, ...]].fail( + return r[tuple[p.Cli.XlsxRowDimensionSnapshot, ...]].fail( f"Row-dimension snapshot failed: {detail}" ) - return r[tuple[m.Cli.XlsxRowDimensionSnapshot, ...]].ok( + return r[tuple[p.Cli.XlsxRowDimensionSnapshot, ...]].ok( tuple(sorted(rows, key=lambda item: item.position)) ) @staticmethod def _snapshot_columns( worksheet: Worksheet, - ) -> p.Result[tuple[m.Cli.XlsxColumnDimensionSnapshot, ...]]: - columns: tuple[m.Cli.XlsxColumnDimensionSnapshot, ...] = () + ) -> p.Result[tuple[p.Cli.XlsxColumnDimensionSnapshot, ...]]: + columns: tuple[p.Cli.XlsxColumnDimensionSnapshot, ...] = () try: for item in worksheet.column_dimensions.values(): anchor = column_index_from_string(item.index) @@ -98,26 +98,26 @@ def _snapshot_columns( ) except (TypeError, ValidationError, ValueError) as exc: detail = str(exc).strip() or exc.__class__.__name__ - return r[tuple[m.Cli.XlsxColumnDimensionSnapshot, ...]].fail( + return r[tuple[p.Cli.XlsxColumnDimensionSnapshot, ...]].fail( f"Column-dimension snapshot failed: {detail}" ) - return r[tuple[m.Cli.XlsxColumnDimensionSnapshot, ...]].ok( + return r[tuple[p.Cli.XlsxColumnDimensionSnapshot, ...]].ok( tuple(sorted(columns, key=lambda item: item.first)) ) @staticmethod def _snapshot_names( workbook: Workbook, - ) -> p.Result[tuple[m.Cli.XlsxDefinedNameSnapshot, ...]]: - names: tuple[m.Cli.XlsxDefinedNameSnapshot, ...] = () + ) -> p.Result[tuple[p.Cli.XlsxDefinedNameSnapshot, ...]]: + names: tuple[p.Cli.XlsxDefinedNameSnapshot, ...] = () try: for item in workbook.defined_names.values(): if not isinstance(item, DefinedName): - return r[tuple[m.Cli.XlsxDefinedNameSnapshot, ...]].fail( + return r[tuple[p.Cli.XlsxDefinedNameSnapshot, ...]].fail( f"Unsupported defined name: {item.__class__.__name__}" ) if not isinstance(item.attr_text, str): - return r[tuple[m.Cli.XlsxDefinedNameSnapshot, ...]].fail( + return r[tuple[p.Cli.XlsxDefinedNameSnapshot, ...]].fail( f"Defined name has no expression or kind: {item.name}" ) names = ( @@ -132,10 +132,10 @@ def _snapshot_names( ) except (TypeError, ValidationError, ValueError) as exc: detail = str(exc).strip() or exc.__class__.__name__ - return r[tuple[m.Cli.XlsxDefinedNameSnapshot, ...]].fail( + return r[tuple[p.Cli.XlsxDefinedNameSnapshot, ...]].fail( f"Defined-name snapshot failed: {detail}" ) - return r[tuple[m.Cli.XlsxDefinedNameSnapshot, ...]].ok( + return r[tuple[p.Cli.XlsxDefinedNameSnapshot, ...]].ok( tuple(sorted(names, key=lambda item: item.name)) ) diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_values.py b/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_values.py index e66cf0bab..c407c2b11 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_values.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_values.py @@ -36,14 +36,14 @@ def _require_success[T](result: p.Result[T]) -> T: @staticmethod def _snapshot_value( value: t.Cli.XlsxCellPrimitive, *, formula_view: bool - ) -> p.Result[m.Cli.XlsxCellValue]: + ) -> p.Result[p.Cli.XlsxCellValue]: formula = ( value if formula_view and isinstance(value, str) and value.startswith("=") else None ) if formula_view and formula is None: - return r[m.Cli.XlsxCellValue].fail( + return r[p.Cli.XlsxCellValue].fail( f"{c.Cli.XlsxError.CELL_VALUE_UNSUPPORTED}: " "formula cell has no formula expression" ) @@ -67,10 +67,10 @@ def _snapshot_value( ) except (InvalidOperation, ValidationError, ValueError) as exc: detail = str(exc).strip() or exc.__class__.__name__ - return r[m.Cli.XlsxCellValue].fail( + return r[p.Cli.XlsxCellValue].fail( f"{c.Cli.XlsxError.CELL_VALUE_UNSUPPORTED}: {detail}", exception=exc ) - return r[m.Cli.XlsxCellValue].ok(converted) + return r[p.Cli.XlsxCellValue].ok(converted) @staticmethod def _has_snapshot_content(cell: Cell) -> bool: @@ -97,7 +97,7 @@ def _formula(cell: Cell) -> str | None: @classmethod def _snapshot_cell( cls, formula_cell: Cell, value_sheet: Worksheet, *, data_only: bool - ) -> p.Result[m.Cli.XlsxCellSnapshot]: + ) -> p.Result[p.Cli.XlsxCellSnapshot]: try: formula = cls._formula(formula_cell) selected = ( @@ -107,16 +107,16 @@ def _snapshot_cell( ) except (IndexError, TypeError, ValidationError, ValueError) as exc: detail = str(exc).strip() or exc.__class__.__name__ - return r[m.Cli.XlsxCellSnapshot].fail(detail, exception=exc) + return r[p.Cli.XlsxCellSnapshot].fail(detail, exception=exc) if not isinstance(selected, Cell): - return r[m.Cli.XlsxCellSnapshot].fail( + return r[p.Cli.XlsxCellSnapshot].fail( f"Unsupported selected cell: {formula_cell.coordinate}" ) selected_value = selected.value if selected_value is not None and not isinstance( selected_value, (str, int, float, bool, Decimal, dt.date, dt.datetime) ): - return r[m.Cli.XlsxCellSnapshot].fail( + return r[p.Cli.XlsxCellSnapshot].fail( f"{c.Cli.XlsxError.CELL_VALUE_UNSUPPORTED}: " f"{selected_value.__class__.__name__} at {formula_cell.coordinate}" ) @@ -141,14 +141,14 @@ def _snapshot_cell( ) except (IndexError, TypeError, ValidationError, ValueError) as exc: detail = str(exc).strip() or exc.__class__.__name__ - return r[m.Cli.XlsxCellSnapshot].fail(detail, exception=exc) - return r[m.Cli.XlsxCellSnapshot].ok(snapshot) + return r[p.Cli.XlsxCellSnapshot].fail(detail, exception=exc) + return r[p.Cli.XlsxCellSnapshot].ok(snapshot) @classmethod def _snapshot_cells( cls, formula_sheet: Worksheet, value_sheet: Worksheet, *, data_only: bool - ) -> p.Result[tuple[m.Cli.XlsxCellSnapshot, ...]]: - cells: tuple[m.Cli.XlsxCellSnapshot, ...] = () + ) -> p.Result[tuple[p.Cli.XlsxCellSnapshot, ...]]: + cells: tuple[p.Cli.XlsxCellSnapshot, ...] = () try: for row in formula_sheet.iter_rows(): for formula_cell in row: @@ -165,8 +165,8 @@ def _snapshot_cells( ), ) except ValueError as exc: - return r[tuple[m.Cli.XlsxCellSnapshot, ...]].fail(str(exc), exception=exc) - return r[tuple[m.Cli.XlsxCellSnapshot, ...]].ok(cells) + return r[tuple[p.Cli.XlsxCellSnapshot, ...]].fail(str(exc), exception=exc) + return r[tuple[p.Cli.XlsxCellSnapshot, ...]].ok(cells) __all__: tuple[str, ...] = ("FlextCliUtilitiesXlsxSnapshotValues",) diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_style_catalog.py b/src/flext_cli/_utilities/_xlxx/xlsx_style_catalog.py index 7d4aaeda8..a912ef067 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_style_catalog.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_style_catalog.py @@ -25,14 +25,14 @@ def _style_name(prefix: str, visual: m.Cli.XlsxVisualStyleSpec) -> str: @classmethod def _source_visuals( cls, source: bytes - ) -> p.Result[tuple[m.Cli.XlsxSourceVisualStyle, ...]]: + ) -> p.Result[tuple[p.Cli.XlsxSourceVisualStyle, ...]]: workbook_result = cls._load_workbook(source) if workbook_result.failure: - return r[tuple[m.Cli.XlsxSourceVisualStyle, ...]].fail( + return r[tuple[p.Cli.XlsxSourceVisualStyle, ...]].fail( workbook_result.error or "Workbook load failed" ) seen: frozenset[int] = frozenset() - source_styles: tuple[m.Cli.XlsxSourceVisualStyle, ...] = () + source_styles: tuple[p.Cli.XlsxSourceVisualStyle, ...] = () for worksheet in workbook_result.value.worksheets: for row in worksheet.iter_rows(): for cell in row: @@ -48,7 +48,7 @@ def _source_visuals( continue visual_result = cls._visual_from_styleable(cell) if visual_result.failure: - return r[tuple[m.Cli.XlsxSourceVisualStyle, ...]].fail( + return r[tuple[p.Cli.XlsxSourceVisualStyle, ...]].fail( visual_result.error or f"Style extraction failed: {source_style_id}" ) @@ -60,20 +60,20 @@ def _source_visuals( ), ) ordered = tuple(sorted(source_styles, key=lambda item: item.source_style_id)) - return r[tuple[m.Cli.XlsxSourceVisualStyle, ...]].ok(ordered) + return r[tuple[p.Cli.XlsxSourceVisualStyle, ...]].ok(ordered) @classmethod def xlsx_style_catalog( cls, request: m.Cli.XlsxStyleCatalogRequest - ) -> p.Result[m.Cli.XlsxStyleCatalog]: + ) -> p.Result[p.Cli.XlsxStyleCatalog]: """Extract all cell-used visual styles and deduplicate them.""" source_result = cls._source_visuals(request.source) if source_result.failure: - return r[m.Cli.XlsxStyleCatalog].fail( + return r[p.Cli.XlsxStyleCatalog].fail( source_result.error or "Style catalog extraction failed" ) - styles: tuple[m.Cli.XlsxNamedStyleSpec, ...] = () - style_map: tuple[m.Cli.XlsxStyleMapEntry, ...] = () + styles: tuple[p.Cli.XlsxNamedStyleSpec, ...] = () + style_map: tuple[p.Cli.XlsxStyleMapEntry, ...] = () for source in source_result.value: existing = next( (style for style in styles if style.visual == source.visual), None @@ -84,7 +84,7 @@ def xlsx_style_catalog( visual=source.visual, ) if any(style.name == existing.name for style in styles): - return r[m.Cli.XlsxStyleCatalog].fail( + return r[p.Cli.XlsxStyleCatalog].fail( f"Deterministic style-name collision: {existing.name}" ) styles = (*styles, existing) @@ -94,14 +94,14 @@ def xlsx_style_catalog( source_style_id=source.source_style_id, style_name=existing.name ), ) - return r[m.Cli.XlsxStyleCatalog].ok( + return r[p.Cli.XlsxStyleCatalog].ok( m.Cli.XlsxStyleCatalog(style_map=style_map, styles=styles) ) @classmethod def xlsx_style_template( cls, request: m.Cli.XlsxStyleTemplateRequest - ) -> p.Result[m.Cli.XlsxStyleTemplateResult]: + ) -> p.Result[p.Cli.XlsxStyleTemplateResult]: """Emit a blank workbook containing only deduplicated visual styles.""" catalog_result = cls.xlsx_style_catalog( m.Cli.XlsxStyleCatalogRequest( @@ -109,7 +109,7 @@ def xlsx_style_template( ) ) if catalog_result.failure: - return r[m.Cli.XlsxStyleTemplateResult].fail( + return r[p.Cli.XlsxStyleTemplateResult].fail( catalog_result.error or "Style catalog extraction failed" ) catalog = catalog_result.value @@ -118,10 +118,10 @@ def xlsx_style_template( workbook.add_named_style(cls._named_style(spec)) content_result = cls._serialize_workbook(workbook) if content_result.failure: - return r[m.Cli.XlsxStyleTemplateResult].fail( + return r[p.Cli.XlsxStyleTemplateResult].fail( content_result.error or "Style template serialization failed" ) - return r[m.Cli.XlsxStyleTemplateResult].ok( + return r[p.Cli.XlsxStyleTemplateResult].ok( m.Cli.XlsxStyleTemplateResult( content=content_result.value, style_map=catalog.style_map ) diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_style_readers.py b/src/flext_cli/_utilities/_xlxx/xlsx_style_readers.py index af95e1e1b..0fd85c250 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_style_readers.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_style_readers.py @@ -19,7 +19,7 @@ class FlextCliUtilitiesXlsxStyleReaders: # NOTE (multi-agent, mro-wkii.17.26): copy() is the openpyxl proxy boundary; # proxy reads and Pydantic composition fail through distinct typed phases. @staticmethod - def _color_spec(color: Color | None) -> m.Cli.XlsxColor | None: + def _color_spec(color: Color | None) -> p.Cli.XlsxColor | None: if color is None: return None value = color.value @@ -35,7 +35,7 @@ def _color_spec(color: Color | None) -> m.Cli.XlsxColor | None: raise ValueError(msg) @classmethod - def _font_spec(cls, font: Font) -> m.Cli.XlsxFontSpec: + def _font_spec(cls, font: Font) -> p.Cli.XlsxFontSpec: return m.Cli.XlsxFontSpec( name=font.name, size=font.size, @@ -55,7 +55,7 @@ def _font_spec(cls, font: Font) -> m.Cli.XlsxFontSpec: ) @classmethod - def _fill_spec(cls, fill: Fill) -> m.Cli.XlsxFillSpec: + def _fill_spec(cls, fill: Fill) -> p.Cli.XlsxFillSpec: if isinstance(fill, PatternFill): return m.Cli.XlsxPatternFillSpec( pattern=fill.patternType, @@ -84,7 +84,7 @@ def _fill_spec(cls, fill: Fill) -> m.Cli.XlsxFillSpec: raise TypeError(msg) @classmethod - def _side_spec(cls, side: Side | None) -> m.Cli.XlsxBorderSideSpec | None: + def _side_spec(cls, side: Side | None) -> p.Cli.XlsxBorderSideSpec | None: if side is None: return None return m.Cli.XlsxBorderSideSpec( @@ -92,7 +92,7 @@ def _side_spec(cls, side: Side | None) -> m.Cli.XlsxBorderSideSpec | None: ) @classmethod - def _border_spec(cls, border: Border) -> m.Cli.XlsxBorderSpec: + def _border_spec(cls, border: Border) -> p.Cli.XlsxBorderSpec: return m.Cli.XlsxBorderSpec( left=cls._side_spec(border.left), right=cls._side_spec(border.right), @@ -109,7 +109,7 @@ def _border_spec(cls, border: Border) -> m.Cli.XlsxBorderSpec: ) @staticmethod - def _alignment_spec(alignment: Alignment) -> m.Cli.XlsxAlignmentSpec: + def _alignment_spec(alignment: Alignment) -> p.Cli.XlsxAlignmentSpec: return m.Cli.XlsxAlignmentSpec( horizontal=alignment.horizontal, vertical=alignment.vertical, @@ -125,18 +125,18 @@ def _alignment_spec(alignment: Alignment) -> m.Cli.XlsxAlignmentSpec: @classmethod def _visual_from_styleable( cls, value: StyleableObject - ) -> p.Result[m.Cli.XlsxVisualStyleSpec]: + ) -> p.Result[p.Cli.XlsxVisualStyleSpec]: try: visual = cls._visual_from_styleable_unchecked(value) except (TypeError, ValidationError, ValueError) as exc: detail = str(exc).strip() or exc.__class__.__name__ - return r[m.Cli.XlsxVisualStyleSpec].fail(detail) - return r[m.Cli.XlsxVisualStyleSpec].ok(visual) + return r[p.Cli.XlsxVisualStyleSpec].fail(detail) + return r[p.Cli.XlsxVisualStyleSpec].ok(visual) @classmethod def _visual_from_styleable_unchecked( cls, value: StyleableObject - ) -> m.Cli.XlsxVisualStyleSpec: + ) -> p.Cli.XlsxVisualStyleSpec: font = copy(value.font) fill = copy(value.fill) border = copy(value.border) diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_tables.py b/src/flext_cli/_utilities/_xlxx/xlsx_tables.py index 320c34fef..b860ec63e 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_tables.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_tables.py @@ -7,7 +7,7 @@ from openpyxl.worksheet.table import Table, TableStyleInfo from openpyxl.worksheet.worksheet import Worksheet -from flext_cli import c, m, p, r +from flext_cli import c, p, r from .xlsx_addresses import FlextCliUtilitiesXlsxAddresses from .xlsx_formula_codec import FlextCliUtilitiesXlsxFormulaCodec @@ -24,7 +24,7 @@ class FlextCliUtilitiesXlsxTables(FlextCliUtilitiesXlsxAddresses): def _apply_tables( cls, worksheet: Worksheet, - plans: tuple[m.Cli.XlsxTablePlan, ...], + plans: tuple[p.Cli.XlsxTablePlan, ...], used_names: frozenset[str], ) -> p.Result[frozenset[str]]: try: @@ -37,7 +37,7 @@ def _apply_tables( def _apply_tables_unchecked( cls, worksheet: Worksheet, - plans: tuple[m.Cli.XlsxTablePlan, ...], + plans: tuple[p.Cli.XlsxTablePlan, ...], used_names: frozenset[str], ) -> p.Result[frozenset[str]]: names = used_names @@ -66,7 +66,7 @@ def _apply_tables_unchecked( @classmethod def _apply_defined_names( - cls, workbook: Workbook, plans: tuple[m.Cli.XlsxDefinedNamePlan, ...] + cls, workbook: Workbook, plans: tuple[p.Cli.XlsxDefinedNamePlan, ...] ) -> p.Result[bool]: names: frozenset[str] = frozenset() for plan in plans: diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_validations.py b/src/flext_cli/_utilities/_xlxx/xlsx_validations.py index 93a24309e..9bb4846c9 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_validations.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_validations.py @@ -110,7 +110,7 @@ def _data_validation(cls, plan: m.Cli.XlsxDataValidationPlan) -> DataValidation: @classmethod def _apply_validations( - cls, worksheet: Worksheet, plans: tuple[m.Cli.XlsxDataValidationPlan, ...] + cls, worksheet: Worksheet, plans: tuple[p.Cli.XlsxDataValidationPlan, ...] ) -> p.Result[bool]: try: for plan in plans: diff --git a/src/flext_cli/_utilities/cmd.py b/src/flext_cli/_utilities/cmd.py index 2bea74a5b..6b343c884 100644 --- a/src/flext_cli/_utilities/cmd.py +++ b/src/flext_cli/_utilities/cmd.py @@ -11,7 +11,7 @@ class FlextCliUtilitiesCmd: """Utility helpers for FlextCliCmd service orchestration.""" @staticmethod - def cmd_status() -> m.Cli.RuntimeStatus: + def cmd_status() -> p.Cli.RuntimeStatus: """Return the canonical public CLI runtime status model.""" return m.Cli.RuntimeStatus( status=c.Cli.ServiceStatus.OPERATIONAL, @@ -27,12 +27,12 @@ def cmd_status() -> m.Cli.RuntimeStatus: ) @staticmethod - def cmd_settings_snapshot() -> p.Result[m.Cli.SettingsSnapshot]: + def cmd_settings_snapshot() -> p.Result[p.Cli.SettingsSnapshot]: """Return settings snapshot with canonical error mapping.""" try: - return r[m.Cli.SettingsSnapshot].ok(us.settings_snapshot()) + return r[p.Cli.SettingsSnapshot].ok(us.settings_snapshot()) except c.Cli.CLI_SAFE_EXCEPTIONS as exc: - return r[m.Cli.SettingsSnapshot].fail( + return r[p.Cli.SettingsSnapshot].fail( c.Cli.ERR_SETTINGS_INFO_FAILED.format(error=exc) ) diff --git a/src/flext_cli/_utilities/config.py b/src/flext_cli/_utilities/config.py index 743c0cc30..f58c239dd 100644 --- a/src/flext_cli/_utilities/config.py +++ b/src/flext_cli/_utilities/config.py @@ -45,7 +45,7 @@ def _read_by_suffix(path: Path) -> p.Result[t.JsonMapping]: @staticmethod def config_load( path: Path, *, schema_path: Path | None = None, expand_env: bool = True - ) -> p.Result[m.ConfigDocument]: + ) -> p.Result[p.ConfigDocument]: """Load a YAML/JSON/TOML config into a validated ``m.ConfigDocument``. Reuses core ``u.config_env_override`` for ``${VAR}`` expansion and @@ -53,21 +53,21 @@ def config_load( """ read = FlextCliUtilitiesConfig._read_by_suffix(path) if read.failure: - return r[m.ConfigDocument].fail( + return r[p.ConfigDocument].fail( read.error or f"{c.ERR_CONFIG_READ_FAILED}: {path}" ) data: t.JsonValue = dict(read.value) if expand_env: data = u.config_env_override(data, dict(os.environ)) if not isinstance(data, dict): - return r[m.ConfigDocument].fail(f"{c.ERR_CONFIG_NOT_MAPPING}: {path}") + return r[p.ConfigDocument].fail(f"{c.ERR_CONFIG_NOT_MAPPING}: {path}") if schema_path is not None: validated = FlextCliUtilitiesConfig.schema_validate(data, schema_path) if validated.failure: - return r[m.ConfigDocument].fail( + return r[p.ConfigDocument].fail( validated.error or c.Cli.ERR_SCHEMA_INVALID ) - return r[m.ConfigDocument].ok( + return r[p.ConfigDocument].ok( m.ConfigDocument( data=data, source_path=str(path), diff --git a/src/flext_cli/_utilities/framework.py b/src/flext_cli/_utilities/framework.py index c46081d40..4b8b8445b 100644 --- a/src/flext_cli/_utilities/framework.py +++ b/src/flext_cli/_utilities/framework.py @@ -290,7 +290,7 @@ def framework_invoke( args: t.StrSequence | None = None, charset: str = c.Cli.ENCODING_DEFAULT, env: t.StrMapping | None = None, - ) -> m.Cli.InvocationResult: + ) -> p.Cli.InvocationResult: """Invoke one application through the real framework test runner.""" from flext_cli import m diff --git a/src/flext_cli/_utilities/params.py b/src/flext_cli/_utilities/params.py index 200dfc409..af35061f7 100644 --- a/src/flext_cli/_utilities/params.py +++ b/src/flext_cli/_utilities/params.py @@ -13,7 +13,7 @@ class FlextCliUtilitiesParams: @staticmethod def params_resolve( params: p.Cli.CliParamsConfig | None, kwargs: t.Cli.CliParamKwargs - ) -> m.Cli.CliParamsConfig: + ) -> p.Cli.CliParamsConfig: """Resolve explicit params and kwargs into one validated model.""" kwargs_model = m.Cli.CliParamsConfig.model_validate(kwargs) if params is None: diff --git a/src/flext_cli/_utilities/pipeline.py b/src/flext_cli/_utilities/pipeline.py index c7c7cfa63..1eb939c03 100644 --- a/src/flext_cli/_utilities/pipeline.py +++ b/src/flext_cli/_utilities/pipeline.py @@ -17,12 +17,12 @@ class FlextCliUtilitiesPipeline: @staticmethod def execute_pipeline( - stages: t.SequenceOf[m.Cli.PipelineStageSpec], + stages: t.SequenceOf[p.Cli.PipelineStageSpec], context: m.Cli.PipelineStageContext, *, fail_fast: bool = c.Cli.PIPELINE_DEFAULT_FAIL_FAST, logger: p.Logger | None = None, - ) -> p.Result[m.Cli.PipelineResult]: + ) -> p.Result[p.Cli.PipelineResult]: """Execute pipeline stages in topological order. Uses graphlib.TopologicalSorter for dependency resolution. @@ -30,10 +30,10 @@ def execute_pipeline( """ log = logger or FlextCliUtilitiesPipeline._pipeline_logger pipeline_start = time.monotonic() - results: t.MutableSequenceOf[m.Cli.PipelineStageResult] = [] + results: t.MutableSequenceOf[p.Cli.PipelineStageResult] = [] if not stages: - return r[m.Cli.PipelineResult].ok( + return r[p.Cli.PipelineResult].ok( m.Cli.PipelineResult(stages=[], total_duration_ms=0.0) ) @@ -50,7 +50,7 @@ def execute_pipeline( try: order = tuple(sorter.static_order()) except CycleError as exc: - return r[m.Cli.PipelineResult].fail(f"pipeline cycle detected: {exc}") + return r[p.Cli.PipelineResult].fail(f"pipeline cycle detected: {exc}") failed = False for stage_id in order: @@ -87,14 +87,14 @@ def execute_pipeline( duration_ms=round(total_ms, 2), ) - return r[m.Cli.PipelineResult].ok(pipeline_result) + return r[p.Cli.PipelineResult].ok(pipeline_result) @staticmethod def _run_stage( spec: m.Cli.PipelineStageSpec, context: m.Cli.PipelineStageContext, log: p.Logger, - ) -> m.Cli.PipelineStageResult: + ) -> p.Cli.PipelineStageResult: """Execute a single stage with skip check and retry logic.""" if spec.skip_if is not None and spec.skip_if(context): log.debug("stage_skipped", stage_id=spec.stage_id, reason="skip_if") diff --git a/src/flext_cli/_utilities/settings.py b/src/flext_cli/_utilities/settings.py index 7799d5b65..47e1fd71c 100644 --- a/src/flext_cli/_utilities/settings.py +++ b/src/flext_cli/_utilities/settings.py @@ -69,7 +69,7 @@ def project_numbers_from_values( return [int(name) for name in names] @staticmethod - def settings_snapshot() -> m.Cli.SettingsSnapshot: + def settings_snapshot() -> p.Cli.SettingsSnapshot: """Return the canonical CLI settings snapshot.""" path = Path.home() / c.Cli.PATH_FLEXT_DIR_NAME exists = path.exists() diff --git a/src/flext_cli/_utilities/tables.py b/src/flext_cli/_utilities/tables.py index 7fc9f20b6..b1d6c9dc9 100644 --- a/src/flext_cli/_utilities/tables.py +++ b/src/flext_cli/_utilities/tables.py @@ -36,11 +36,11 @@ def tables_normalize_sequence_row( def tables_resolve_config( settings: m.Cli.TableConfig | None = None, **settings_kwargs: t.Cli.TableConfigValue, - ) -> p.Result[m.Cli.TableConfig]: + ) -> p.Result[p.Cli.TableConfig]: """Resolve table config via canonical Pydantic model contract.""" try: if settings is not None and not settings_kwargs: - return r[m.Cli.TableConfig].ok(settings) + return r[p.Cli.TableConfig].ok(settings) base_data = ( settings.model_dump(exclude_computed_fields=True) if settings is not None @@ -48,9 +48,9 @@ def tables_resolve_config( ) settings_data = {**base_data, **settings_kwargs} resolved = m.Cli.TableConfig.model_validate(settings_data) - return r[m.Cli.TableConfig].ok(resolved) + return r[p.Cli.TableConfig].ok(resolved) except c.Cli.CLI_SAFE_EXCEPTIONS as exc: - return r[m.Cli.TableConfig].fail( + return r[p.Cli.TableConfig].fail( c.Cli.OUTPUT_TABLE_CONFIG_INVALID_FMT.format(error=exc) ) diff --git a/src/flext_cli/_utilities/template.py b/src/flext_cli/_utilities/template.py index 52fecc0de..216252639 100644 --- a/src/flext_cli/_utilities/template.py +++ b/src/flext_cli/_utilities/template.py @@ -77,11 +77,11 @@ def template_render_dir( templates_root: Path, output_root: Path, context: p.Model, - entries: t.SequenceOf[m.Cli.TemplateRenderEntry], + entries: t.SequenceOf[p.Cli.TemplateRenderEntry], *, strip_suffix: str = c.Cli.TEMPLATE_SUFFIX, overwrite: bool = False, - ) -> p.Result[m.Cli.TemplateRenderReport]: + ) -> p.Result[p.Cli.TemplateRenderReport]: """Render every entry from ``templates_root`` into ``output_root``. Generic, folder-parameterized engine (ADR-005): the caller supplies the @@ -95,7 +95,7 @@ def template_render_dir( the caller decides the fail policy (the report is always returned). """ if not templates_root.is_dir(): - return r[m.Cli.TemplateRenderReport].fail( + return r[p.Cli.TemplateRenderReport].fail( f"{c.Cli.ERR_TEMPLATE_NOT_FOUND}: {templates_root}" ) root = output_root.resolve() @@ -129,7 +129,7 @@ def template_render_dir( report = m.Cli.TemplateRenderReport( created=tuple(created), skipped=tuple(skipped), failed=tuple(failed) ) - return r[m.Cli.TemplateRenderReport].ok(report) + return r[p.Cli.TemplateRenderReport].ok(report) @staticmethod def _write(dest: Path, content: str) -> bool: diff --git a/src/flext_cli/api.py b/src/flext_cli/api.py index 943aaa873..a4c735bc9 100644 --- a/src/flext_cli/api.py +++ b/src/flext_cli/api.py @@ -8,7 +8,7 @@ from typing import override -from flext_cli import m, p, r, t, u +from flext_cli import p, r, t, u from flext_cli.services.auth import FlextCliAuth from flext_cli.services.cli import FlextCliCli from flext_cli.services.cli_params import FlextCliCommonParams @@ -50,9 +50,9 @@ class FlextCli( """ @override - def execute(self) -> p.Result[m.Cli.RuntimeStatus]: + def execute(self) -> p.Result[p.Cli.RuntimeStatus]: """Report the public CLI runtime surface state.""" - return r[m.Cli.RuntimeStatus].ok(u.Cli.cmd_status()) + return r[p.Cli.RuntimeStatus].ok(u.Cli.cmd_status()) cli: FlextCli = FlextCli.fetch_global() diff --git a/src/flext_cli/services/_cli/flextclicli_part_02.py b/src/flext_cli/services/_cli/flextclicli_part_02.py index 58e6be34b..7c7f18222 100644 --- a/src/flext_cli/services/_cli/flextclicli_part_02.py +++ b/src/flext_cli/services/_cli/flextclicli_part_02.py @@ -77,7 +77,7 @@ def apply_common_params(params: m.Cli.CliParamsConfig) -> bool: ) parameters.append(parameter) annotations[field_name] = annotation - global_callback: FlextCliCli._ModelCommand[m.Cli.CliParamsConfig] = ( + global_callback: FlextCliCli._ModelCommand[p.Cli.CliParamsConfig] = ( self._ModelCommand( handler=apply_common_params, model_cls=m.Cli.CliParamsConfig, diff --git a/src/flext_cli/services/_cli/flextclicli_part_03.py b/src/flext_cli/services/_cli/flextclicli_part_03.py index c13f2b5c8..e4004dee9 100644 --- a/src/flext_cli/services/_cli/flextclicli_part_03.py +++ b/src/flext_cli/services/_cli/flextclicli_part_03.py @@ -8,7 +8,7 @@ from inspect import Parameter -from flext_cli import c, m, p, r, t, u +from flext_cli import c, p, r, t, u from flext_cli.services._cli.flextclicli_part_02 import FlextCliCli as FlextCliCliPart02 # mro-j47u (codex): the earlier MRO part is referenced only by annotation; @@ -67,15 +67,15 @@ def invoke_app( args: t.StrSequence | None = None, charset: str = c.Cli.ENCODING_DEFAULT, env: t.StrMapping | None = None, - ) -> p.Result[m.Cli.InvocationResult]: + ) -> p.Result[p.Cli.InvocationResult]: """Invoke an application through the private real-framework boundary.""" try: invocation = u.Cli.framework_invoke( app, args=args, charset=charset, env=env ) except (TypeError, ValueError) as exc: - return r[m.Cli.InvocationResult].fail(str(exc)) - return r[m.Cli.InvocationResult].ok(invocation) + return r[p.Cli.InvocationResult].fail(str(exc)) + return r[p.Cli.InvocationResult].ok(invocation) __all__: list[str] = ["FlextCliCli"] diff --git a/src/flext_cli/services/cli_params.py b/src/flext_cli/services/cli_params.py index 80133ec1b..9098e7c8f 100644 --- a/src/flext_cli/services/cli_params.py +++ b/src/flext_cli/services/cli_params.py @@ -2,7 +2,7 @@ from __future__ import annotations -from flext_cli import c, m, p, r, s, t, u +from flext_cli import c, p, r, s, t, u class FlextCliCommonParams(s): @@ -38,7 +38,7 @@ def apply_to_config( ) @classmethod - def create_option(cls, field_name: str) -> m.Cli.OptionSpec: + def create_option(cls, field_name: str) -> p.Cli.OptionSpec: """Create one validated framework-neutral option model.""" if field_name not in c.Cli.CLI_PARAM_REGISTRY: msg = c.Cli.CLI_PARAM_ERR_FIELD_NOT_FOUND_FMT.format(field_name=field_name) diff --git a/src/flext_cli/services/cmd.py b/src/flext_cli/services/cmd.py index 79baea444..b689c3dae 100644 --- a/src/flext_cli/services/cmd.py +++ b/src/flext_cli/services/cmd.py @@ -10,7 +10,7 @@ from __future__ import annotations -from flext_cli import m, p, s, t, u +from flext_cli import p, s, t, u class FlextCliCmd(s): @@ -22,7 +22,7 @@ class FlextCliCmd(s): """ @staticmethod - def settings_snapshot() -> p.Result[m.Cli.SettingsSnapshot]: + def settings_snapshot() -> p.Result[p.Cli.SettingsSnapshot]: """Return the current settings snapshot using ``u.Cli``.""" return u.Cli.cmd_settings_snapshot() diff --git a/src/flext_cli/services/pipeline.py b/src/flext_cli/services/pipeline.py index 0bb803ab6..ae5182d58 100644 --- a/src/flext_cli/services/pipeline.py +++ b/src/flext_cli/services/pipeline.py @@ -17,7 +17,7 @@ def stage_context( *, shared: t.MutableJsonMapping | None = None, settings: t.JsonMapping | None = None, - ) -> m.Cli.PipelineStageContext: + ) -> p.Cli.PipelineStageContext: """Build one validated stage context from the public DSL.""" return m.Cli.PipelineStageContext.model_validate({ "workspace_root": workspace_root, @@ -33,7 +33,7 @@ def stage( depends_on: t.SequenceOf[str] | frozenset[str] = (), skip_if: t.Cli.PipelineSkipPredicate | None = None, retry: int = c.Cli.PIPELINE_DEFAULT_RETRY, - ) -> m.Cli.PipelineStageSpec: + ) -> p.Cli.PipelineStageSpec: """Build one declarative stage spec from the public DSL.""" return m.Cli.PipelineStageSpec.model_validate({ "stage_id": stage_id, @@ -51,7 +51,7 @@ def stage_result( output: t.JsonMapping | None = None, duration_ms: float = 0.0, error: str | None = None, - ) -> m.Cli.PipelineStageResult: + ) -> p.Cli.PipelineStageResult: """Build one typed stage result payload.""" return m.Cli.PipelineStageResult.model_validate({ "stage_id": stage_id, @@ -68,9 +68,9 @@ def ok_stage( *, output: t.JsonMapping | None = None, duration_ms: float = 0.0, - ) -> p.Result[m.Cli.PipelineStageResult]: + ) -> p.Result[p.Cli.PipelineStageResult]: """Return one successful stage result via the canonical ``r`` API.""" - return r[m.Cli.PipelineStageResult].ok( + return r[p.Cli.PipelineStageResult].ok( cls.stage_result( stage_id, status=c.Cli.PipelineStageStatus.OK, @@ -87,13 +87,13 @@ def linear_pipeline( *, retry_by_stage: t.Cli.PipelineRetryMap | None = None, skip_by_stage: t.Cli.PipelineSkipMap | None = None, - ) -> t.SequenceOf[m.Cli.PipelineStageSpec]: + ) -> t.SequenceOf[p.Cli.PipelineStageSpec]: """Build a linear dependency chain from ordered stage handlers.""" retries: t.Cli.PipelineRetryMap = ( retry_by_stage if retry_by_stage is not None else {} ) skips = skip_by_stage or {} - stage_list: t.MutableSequenceOf[m.Cli.PipelineStageSpec] = [] + stage_list: t.MutableSequenceOf[p.Cli.PipelineStageSpec] = [] previous_stage_id: str | None = None for stage_id in stage_order: # NOTE (multi-agent): Typed retry map keeps ``get`` strictly integer. @@ -114,12 +114,12 @@ def linear_pipeline( def pipeline( self, - stages: t.SequenceOf[m.Cli.PipelineStageSpec], + stages: t.SequenceOf[p.Cli.PipelineStageSpec], *, context: m.Cli.PipelineStageContext, fail_fast: bool = c.Cli.PIPELINE_DEFAULT_FAIL_FAST, logger: p.Logger | None = None, - ) -> p.Result[m.Cli.PipelineResult]: + ) -> p.Result[p.Cli.PipelineResult]: """Execute a pipeline through the public CLI DSL surface.""" return self.execute_pipeline( stages, context, fail_fast=fail_fast, logger=logger or self.logger diff --git a/src/flext_cli/services/prompts.py b/src/flext_cli/services/prompts.py index 5e6c71944..5d163781d 100644 --- a/src/flext_cli/services/prompts.py +++ b/src/flext_cli/services/prompts.py @@ -4,7 +4,7 @@ from typing import override -from flext_cli import c, m, p, r, t, u +from flext_cli import c, p, r, t, u from flext_cli.services._prompts_support import FlextCliPromptsSupport # NOTE (multi-agent): mro-i6nq.13 — consolidated _prompts_parts/part_01+part_02 @@ -18,8 +18,8 @@ class FlextCliPrompts(FlextCliPromptsSupport): """Interactive CLI prompt surface exposed through the CLI service runtime.""" @override - def execute(self) -> p.Result[m.Cli.RuntimeStatus]: - return r[m.Cli.RuntimeStatus].ok(u.Cli.cmd_status()) + def execute(self) -> p.Result[p.Cli.RuntimeStatus]: + return r[p.Cli.RuntimeStatus].ok(u.Cli.cmd_status()) def confirm(self, message: str, *, default: bool = False) -> p.Result[bool]: try: diff --git a/tests/_models_parts/tests_runtime.py b/tests/_models_parts/tests_runtime.py index b1e6ffea5..869a762bd 100644 --- a/tests/_models_parts/tests_runtime.py +++ b/tests/_models_parts/tests_runtime.py @@ -14,7 +14,7 @@ class TestsFlextCliModelsRuntime: class ApiResponse(m.BaseModel): """API response for type scenario tests -- Pydantic v2.""" - model_config: ClassVar[m.ConfigDict] = m.ConfigDict(extra="forbid") + model_config: ClassVar[p.ConfigDict] = m.ConfigDict(extra="forbid") status: Annotated[str, m.Field(description="Status")] data: Annotated[t.JsonMapping | None, m.Field(description="Payload")] = None message: Annotated[str, m.Field(description="Message")] @@ -47,7 +47,7 @@ class ModelCommandRequired(m.BaseModel): class RuntimeCommandCase(m.BaseModel): """Runtime command parametrization case.""" - model_config: ClassVar[m.ConfigDict] = m.ConfigDict(frozen=True) + model_config: ClassVar[p.ConfigDict] = m.ConfigDict(frozen=True) case_id: Annotated[str, m.Field(description="Pytest case id")] command: Annotated[t.StrSequence, m.Field(description="Command argv")] diff --git a/tests/_models_parts/tests_version.py b/tests/_models_parts/tests_version.py index 7ce192509..8e759ee85 100644 --- a/tests/_models_parts/tests_version.py +++ b/tests/_models_parts/tests_version.py @@ -17,7 +17,7 @@ class TestsFlextCliModelsVersion: class VersionTestScenario(m.BaseModel): """Version test scenario data.""" - model_config: ClassVar[m.ConfigDict] = m.ConfigDict(frozen=True) + model_config: ClassVar[p.ConfigDict] = m.ConfigDict(frozen=True) name: Annotated[str, m.Field(description="Scenario name")] version_string: Annotated[ diff --git a/tests/base.py b/tests/base.py index 6ede92f6d..040312951 100644 --- a/tests/base.py +++ b/tests/base.py @@ -17,7 +17,7 @@ class TestsFlextCliServiceBase(tests_s): # this project declares only its more-specific bootstrap settings type. @classmethod @override - def _runtime_bootstrap_options(cls) -> m.RuntimeBootstrapOptions: + def _runtime_bootstrap_options(cls) -> p.RuntimeBootstrapOptions: return m.RuntimeBootstrapOptions(settings_type=TestsFlextCliSettings) diff --git a/tests/protocols.py b/tests/protocols.py index 15170f7f1..ce688e528 100644 --- a/tests/protocols.py +++ b/tests/protocols.py @@ -52,7 +52,7 @@ def configure_state( """Set the observable interactive and quiet prompt state.""" ... - def execute(self) -> p.Result[m.Cli.RuntimeStatus]: + def execute(self) -> p.Result[p.Cli.RuntimeStatus]: """Return the canonical typed CLI runtime status.""" ... diff --git a/tests/test_xlsx_recalc.py b/tests/test_xlsx_recalc.py index a795caaa1..f77171e9d 100644 --- a/tests/test_xlsx_recalc.py +++ b/tests/test_xlsx_recalc.py @@ -56,7 +56,7 @@ def _render_workbook() -> bytes: def _numeric_cell_value( source: bytes, sheet_name: str, coordinate: str -) -> m.Cli.XlsxIntegerValue | m.Cli.XlsxDecimalValue: +) -> p.Cli.XlsxIntegerValue | m.Cli.XlsxDecimalValue: snapshot = cli.xlsx_snapshot( m.Cli.XlsxSnapshotRequest(source=source, data_only=True) ) diff --git a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_01.py b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_01.py index 7d7092163..c7f02aedc 100644 --- a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_01.py +++ b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_01.py @@ -68,7 +68,7 @@ def test_create_app_with_common_params_accepts_log_level_flag(self) -> None: def test_model_command_generates_real_typer_options(self) -> None: """Generate and execute real Typer options from the request model.""" - captured: MutableSequence[m.Tests.SampleInput] = [] + captured: MutableSequence[p.Tests.SampleInput] = [] app = cli.create_app_with_common_params( name="root", help_text="Root application" ) diff --git a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_02.py b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_02.py index 71b21785b..a93936a97 100644 --- a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_02.py +++ b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_02.py @@ -24,7 +24,7 @@ class TestsFlextCliService: def test_model_command_accepts_repeatable_list_options(self) -> None: """Parse repeatable CLI options into one validated model.""" - captured: MutableSequence[m.Tests.RepeatableInput] = [] + captured: MutableSequence[p.Tests.RepeatableInput] = [] app = cli.create_app_with_common_params( name="root", help_text="Root application" ) diff --git a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_05.py b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_05.py index 31d489c22..dbefa36a0 100644 --- a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_05.py +++ b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_05.py @@ -27,19 +27,19 @@ def test_register_result_command_renders_success_and_failure(self) -> None: ) group = cli.create_group(help_text="Grouped commands", name="group") - def ok_handler(params: m.Tests.SampleInput) -> p.Result[m.Tests.SampleOutput]: + def ok_handler(params: m.Tests.SampleInput) -> p.Result[p.Tests.SampleOutput]: return cli.execute().map( lambda _payload: m.Tests.SampleOutput( message=f"processed {params.name}" ) ) - def fail_handler(params: m.Tests.SampleInput) -> p.Result[m.Tests.SampleOutput]: + def fail_handler(params: m.Tests.SampleInput) -> p.Result[p.Tests.SampleOutput]: return cli.validate_credentials("", "password").map( lambda _value: m.Tests.SampleOutput(message=params.name) ) - def build_ok_route() -> m.Cli.ResultCommandRoute: + def build_ok_route() -> p.Cli.ResultCommandRoute: return m.Cli.ResultCommandRoute( name="ok", help_text="Successful command", @@ -47,7 +47,7 @@ def build_ok_route() -> m.Cli.ResultCommandRoute: handler=ok_handler, ) - def build_fail_route() -> m.Cli.ResultCommandRoute: + def build_fail_route() -> p.Cli.ResultCommandRoute: return m.Cli.ResultCommandRoute( name="fail", help_text="Failing command", @@ -82,8 +82,8 @@ def test_register_result_routes_propagates_real_failure(self) -> None: name="result-app", help_text="Result application" ) - def fail_handler(params: m.Tests.SampleInput) -> p.Result[m.Tests.SampleOutput]: - return r[m.Tests.SampleOutput].fail( + def fail_handler(params: m.Tests.SampleInput) -> p.Result[p.Tests.SampleOutput]: + return r[p.Tests.SampleOutput].fail( "Password cannot be resolved", error_code="secret_unavailable", error_data={"field": "password", "name": params.name}, diff --git a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_01.py b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_01.py index a923adca1..2e099d986 100644 --- a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_01.py +++ b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_01.py @@ -26,7 +26,7 @@ def _ok_handler(stage_id: str, output_key: str = "done") -> t.Cli.PipelineHandle def handler( ctx: p.Cli.PipelineStageContext, - ) -> p.Result[m.Cli.PipelineStageResult]: + ) -> p.Result[p.Cli.PipelineStageResult]: ctx.shared[output_key] = stage_id return cli.ok_stage( stage_id, output={output_key: stage_id}, duration_ms=1.0 @@ -40,8 +40,8 @@ def _fail_handler(stage_id: str) -> t.Cli.PipelineHandler: def handler( _ctx: p.Cli.PipelineStageContext, - ) -> p.Result[m.Cli.PipelineStageResult]: - return r[m.Cli.PipelineStageResult].fail(f"{stage_id} failed") + ) -> p.Result[p.Cli.PipelineStageResult]: + return r[p.Cli.PipelineStageResult].fail(f"{stage_id} failed") return handler @@ -67,7 +67,7 @@ def test_dependency_order(self, tmp_path: Path) -> None: def tracking_handler(stage_id: str) -> t.Cli.PipelineHandler: def handler( ctx: p.Cli.PipelineStageContext, - ) -> p.Result[m.Cli.PipelineStageResult]: + ) -> p.Result[p.Cli.PipelineStageResult]: _ = ctx execution_order.append(stage_id) return cli.ok_stage(stage_id) @@ -87,13 +87,13 @@ def test_shared_state_propagation(self, tmp_path: Path) -> None: def reader( ctx: p.Cli.PipelineStageContext, - ) -> p.Result[m.Cli.PipelineStageResult]: + ) -> p.Result[p.Cli.PipelineStageResult]: received["from_a"] = ctx.shared.get("a_output") return cli.ok_stage("b") def writer( ctx: p.Cli.PipelineStageContext, - ) -> p.Result[m.Cli.PipelineStageResult]: + ) -> p.Result[p.Cli.PipelineStageResult]: ctx.shared["a_output"] = "hello" return cli.ok_stage("a") diff --git a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_02.py b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_02.py index 2048f6788..e6711521c 100644 --- a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_02.py +++ b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_02.py @@ -26,7 +26,7 @@ def _ok_handler(stage_id: str, output_key: str = "done") -> t.Cli.PipelineHandle def handler( ctx: p.Cli.PipelineStageContext, - ) -> p.Result[m.Cli.PipelineStageResult]: + ) -> p.Result[p.Cli.PipelineStageResult]: ctx.shared[output_key] = stage_id return cli.ok_stage( stage_id, output={output_key: stage_id}, duration_ms=1.0 @@ -50,12 +50,12 @@ def test_retry_on_failure(self, tmp_path: Path) -> None: def flaky( _ctx: p.Cli.PipelineStageContext, - ) -> p.Result[m.Cli.PipelineStageResult]: + ) -> p.Result[p.Cli.PipelineStageResult]: nonlocal call_count call_count += 1 if call_count < expected_attempts: - return r[m.Cli.PipelineStageResult].fail("transient") - return r[m.Cli.PipelineStageResult].ok( + return r[p.Cli.PipelineStageResult].fail("transient") + return r[p.Cli.PipelineStageResult].ok( cli.stage_result("flaky", status=c.Cli.PipelineStageStatus.OK) ) @@ -72,7 +72,7 @@ def test_retry_on_safe_exception_marks_stage_failed(self, tmp_path: Path) -> Non def exploding( ctx: p.Cli.PipelineStageContext, - ) -> p.Result[m.Cli.PipelineStageResult]: + ) -> p.Result[p.Cli.PipelineStageResult]: nonlocal call_count _ = ctx call_count += 1 diff --git a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_03.py b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_03.py index edec52791..dbcb78fa2 100644 --- a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_03.py +++ b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_03.py @@ -27,7 +27,7 @@ def test_diamond_dependency(self, tmp_path: Path) -> None: def track(sid: str) -> t.Cli.PipelineHandler: def h( ctx: p.Cli.PipelineStageContext, - ) -> p.Result[m.Cli.PipelineStageResult]: + ) -> p.Result[p.Cli.PipelineStageResult]: _ = ctx order.append(sid) return cli.ok_stage(sid) diff --git a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_02.py b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_02.py index 5fed033d8..3935c4927 100644 --- a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_02.py +++ b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_02.py @@ -38,8 +38,8 @@ def test_public_model_contracts_cover_cli_shapes(self, tmp_path: Path) -> None: def route_handler( _params: m.Tests.SampleInput, - ) -> p.Result[m.Tests.SampleOutput]: - return r[m.Tests.SampleOutput].ok(m.Tests.SampleOutput(message="ok")) + ) -> p.Result[p.Tests.SampleOutput]: + return r[p.Tests.SampleOutput].ok(m.Tests.SampleOutput(message="ok")) route = m.Cli.ResultCommandRoute( name="inspect", diff --git a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_03.py b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_03.py index c962d460b..111e35ab7 100644 --- a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_03.py +++ b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_03.py @@ -23,8 +23,8 @@ def test_public_pipeline_model_contracts(self, tmp_path: Path) -> None: def stage_handler( current: m.Cli.PipelineStageContext, - ) -> p.Result[m.Cli.PipelineStageResult]: - return r[m.Cli.PipelineStageResult].ok( + ) -> p.Result[p.Cli.PipelineStageResult]: + return r[p.Cli.PipelineStageResult].ok( m.Cli.PipelineStageResult.model_validate({ "stage_id": "build", "status": c.Cli.PipelineStageStatus.OK, diff --git a/tests/unit/test_options_cov.py b/tests/unit/test_options_cov.py index dbfa02539..b41f299a4 100644 --- a/tests/unit/test_options_cov.py +++ b/tests/unit/test_options_cov.py @@ -94,7 +94,7 @@ class _OptionsDefaultsModel(m.BaseModel): ) _ANNOTATION_CASES: ClassVar[ - tuple[tuple[t.ModelClass[m.BaseModel], t.Cli.RuntimeAnnotation], ...] + tuple[tuple[t.ModelClass[p.BaseModel], t.Cli.RuntimeAnnotation], ...] ] = ( (_StringAnnotationModel, str), (_OptionalStringAnnotationModel, str), diff --git a/tests/unit/test_tables_branch_cov.py b/tests/unit/test_tables_branch_cov.py index 9f6ebde75..e64d0739c 100644 --- a/tests/unit/test_tables_branch_cov.py +++ b/tests/unit/test_tables_branch_cov.py @@ -15,7 +15,7 @@ class TestsFlextCliTablesBranchCov: """Assert the observable contract of the ``u.Cli`` table helpers.""" @pytest.fixture - def two_column_config(self) -> m.Cli.TableConfig: + def two_column_config(self) -> p.Cli.TableConfig: """Return a minimal two-column table configuration.""" return m.Cli.TableConfig(headers=("Key", "Value")) From abe94a5128d64e2b19b1804949224c689d9a1f98 Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Wed, 15 Jul 2026 23:33:49 -0300 Subject: [PATCH 17/37] fixes --- examples/_models_parts/examples_advanced.py | 2 +- examples/_models_parts/examples_common.py | 2 +- examples/_models_parts/examples_database.py | 2 +- examples/constants.py | 4 ++-- examples/ex_01_getting_started.py | 2 +- examples/ex_06_settings.py | 2 +- examples/ex_12_pydantic_driven_cli.py | 8 +++---- examples/utilities.py | 4 ++-- .../_base/flextclimodelsbase_part_01.py | 2 +- .../_base/flextclimodelsbase_part_02.py | 2 +- .../_base/flextclimodelsbase_part_07.py | 2 +- src/flext_cli/_models/pipeline.py | 2 +- src/flext_cli/_utilities/_json/_core.py | 4 ++-- .../flextcliutilitiesoptions_part_02.py | 4 ++-- .../_utilities/_xlxx/xlsx_addresses.py | 12 +++++----- .../_utilities/_xlxx/xlsx_archive.py | 6 ++--- .../_utilities/_xlxx/xlsx_archive_checks.py | 6 ++--- src/flext_cli/_utilities/_xlxx/xlsx_cells.py | 4 ++-- .../_utilities/_xlxx/xlsx_conditional.py | 4 ++-- src/flext_cli/_utilities/_xlxx/xlsx_layout.py | 12 +++++----- .../_utilities/_xlxx/xlsx_protection.py | 10 ++++----- src/flext_cli/_utilities/_xlxx/xlsx_recalc.py | 6 ++--- .../_utilities/_xlxx/xlsx_renderer.py | 4 ++-- src/flext_cli/_utilities/_xlxx/xlsx_rules.py | 4 ++-- .../_utilities/_xlxx/xlsx_snapshot.py | 2 +- .../_utilities/_xlxx/xlsx_snapshot_values.py | 2 +- .../_utilities/_xlxx/xlsx_style_builders.py | 16 ++++++-------- .../_utilities/_xlxx/xlsx_style_catalog.py | 6 ++--- .../_utilities/_xlxx/xlsx_validations.py | 2 +- .../_utilities/_xlxx/xlsx_workbook_plan.py | 8 +++---- src/flext_cli/_utilities/formatters.py | 5 ++--- src/flext_cli/_utilities/framework.py | 4 +--- src/flext_cli/_utilities/model_commands.py | 4 ++-- src/flext_cli/_utilities/pipeline.py | 6 ++--- src/flext_cli/_utilities/tables.py | 4 ++-- src/flext_cli/constants.py | 22 +++++++++---------- .../services/_cli/flextclicli_part_01.py | 2 +- .../services/_cli/flextclicli_part_02.py | 4 ++-- src/flext_cli/services/_prompts_support.py | 2 +- src/flext_cli/services/auth.py | 2 +- src/flext_cli/services/file_tools.py | 4 ++-- src/flext_cli/services/pipeline.py | 2 +- src/flext_cli/services/tables.py | 6 ++--- tests/_constants_parts/tests_core.py | 4 ++-- tests/_constants_parts/tests_rules_options.py | 2 +- tests/_constants_parts/tests_yaml_output.py | 2 +- tests/_models_parts/tests_runtime.py | 2 +- tests/_models_parts/tests_version.py | 2 +- tests/conftest.py | 2 +- tests/protocols.py | 2 +- tests/typings.py | 2 +- .../testsflextcliservice_part_01.py | 6 ++--- .../testsflextcliservice_part_02.py | 6 ++--- .../testsflextcliservice_part_04.py | 4 ++-- .../testsflextcliservice_part_05.py | 10 ++++----- .../testsflextclifilescov_part_01.py | 2 +- .../testsflextclijsoncov_part_01.py | 2 +- .../testsflextclipipeline_part_01.py | 2 +- .../testsflextclipipeline_part_02.py | 2 +- .../testsflextclipipeline_part_03.py | 2 +- ...flextclipubliccontractscoverage_part_02.py | 2 +- ...flextclipubliccontractscoverage_part_03.py | 2 +- .../testsflextclirulescov_part_01.py | 2 +- .../testsflextclirulescov_part_03.py | 2 +- .../testsflextclirulescov_part_04.py | 2 +- .../testsflextclitomlutilities_part_01.py | 2 +- .../testsflextclitomlutilities_part_02.py | 2 +- .../testsflextclitomlutilities_part_03.py | 2 +- tests/unit/conftest.py | 2 +- tests/unit/test_auth_utils_cov.py | 2 +- .../test_cmd_runtime_validation_branch_cov.py | 2 +- tests/unit/test_commands_utils_cov.py | 2 +- tests/unit/test_conversion_cov.py | 2 +- tests/unit/test_files_cov.py | 2 +- tests/unit/test_formatters_cov.py | 2 +- tests/unit/test_json_cov.py | 2 +- tests/unit/test_matching_cov.py | 2 +- tests/unit/test_model_commands_cov.py | 12 +++++----- tests/unit/test_options_cov.py | 2 +- tests/unit/test_options_public_cov.py | 2 +- tests/unit/test_protocols.py | 2 +- tests/unit/test_rules_cov.py | 2 +- tests/unit/test_runtime_utilities_core.py | 12 +++++----- tests/unit/test_services_tables_branch_cov.py | 2 +- tests/unit/test_tables.py | 2 +- tests/unit/test_tables_branch_cov.py | 14 ++++++------ tests/unit/test_tables_cov.py | 2 +- tests/unit/test_toml_sync_cov.py | 2 +- tests/unit/test_toml_utilities.py | 2 +- tests/unit/test_typings.py | 8 +++---- tests/unit/test_utilities_cov.py | 2 +- tests/unit/test_yaml_cov.py | 2 +- tests/unit/test_yaml_roundtrip.py | 2 +- 93 files changed, 183 insertions(+), 188 deletions(-) diff --git a/examples/_models_parts/examples_advanced.py b/examples/_models_parts/examples_advanced.py index 44290a735..99f970bbe 100644 --- a/examples/_models_parts/examples_advanced.py +++ b/examples/_models_parts/examples_advanced.py @@ -7,7 +7,7 @@ from examples import c, p, r, t from examples._models_parts.examples_common import ExamplesFlextCliModelsExamplesCommon -from flext_cli import m, u +from flext_cli import m, p, u from collections.abc import MutableSequence diff --git a/examples/_models_parts/examples_common.py b/examples/_models_parts/examples_common.py index 1c030d24a..5352e7191 100644 --- a/examples/_models_parts/examples_common.py +++ b/examples/_models_parts/examples_common.py @@ -7,7 +7,7 @@ from pathlib import Path from typing import Annotated, ClassVar -from examples import c, t +from examples import c, p, t from flext_cli import m, settings, u diff --git a/examples/_models_parts/examples_database.py b/examples/_models_parts/examples_database.py index aa7320809..19a8f3965 100644 --- a/examples/_models_parts/examples_database.py +++ b/examples/_models_parts/examples_database.py @@ -6,7 +6,7 @@ from typing import ClassVar from examples import c -from flext_cli import m, u +from flext_cli import m, p, u class ExamplesFlextCliModelsExamplesDatabase: diff --git a/examples/constants.py b/examples/constants.py index 1fd1cc072..4754d3b4c 100644 --- a/examples/constants.py +++ b/examples/constants.py @@ -3,13 +3,13 @@ from __future__ import annotations import re -from enum import StrEnum, unique +from enum import StrEnum, p, unique from types import MappingProxyType from typing import TYPE_CHECKING, Final from flext_cli import c -from examples import t +from examples import p, t diff --git a/examples/ex_01_getting_started.py b/examples/ex_01_getting_started.py index 292079eae..076ccff2a 100644 --- a/examples/ex_01_getting_started.py +++ b/examples/ex_01_getting_started.py @@ -33,7 +33,7 @@ def build_example_settings(self) -> p.Result[p.Examples.MyAppSettings]: @staticmethod def persist_example_settings( - settings: m.Examples.MyAppSettings, + settings: p.Examples.MyAppSettings, ) -> p.Result[p.Cli.LoadedConfig]: """Round-trip settings through the public JSON file facade.""" wrapped_config = m.Cli.LoadedConfig(content=settings.model_dump(mode="json")) diff --git a/examples/ex_06_settings.py b/examples/ex_06_settings.py index 717baa83f..b193b34a6 100644 --- a/examples/ex_06_settings.py +++ b/examples/ex_06_settings.py @@ -27,7 +27,7 @@ from pathlib import Path -from examples import c, m, t, u +from examples import c, m, p, t, u from flext_cli import cli, p, settings from flext_core import r diff --git a/examples/ex_12_pydantic_driven_cli.py b/examples/ex_12_pydantic_driven_cli.py index 747899333..b622e14c7 100644 --- a/examples/ex_12_pydantic_driven_cli.py +++ b/examples/ex_12_pydantic_driven_cli.py @@ -28,7 +28,7 @@ import secrets -from examples import c, m, t, u +from examples import c, m, p, t, u from flext_cli import cli from flext_core import p, r @@ -44,7 +44,7 @@ def _report_step_success[T](value: T, message: str) -> T: def _finish_database_config( - settings: m.Examples.AdvancedDatabaseConfig, + settings: p.Examples.AdvancedDatabaseConfig, ) -> p.Examples.AdvancedDatabaseConfig: """Emit the final success summary and preserve the validated settings.""" u.display_success_summary("Database configuration") @@ -122,7 +122,7 @@ def convert_and_validate_with_pydantic( def validate_business_rules( - settings: m.Examples.AdvancedDatabaseConfig, + settings: p.Examples.AdvancedDatabaseConfig, ) -> p.Result[p.Examples.AdvancedDatabaseConfig]: """Apply custom business rules to validated database configuration.""" if settings.ssl_enabled and settings.port == c.EXAMPLE_DEFAULT_DB_PORT: @@ -138,7 +138,7 @@ def validate_business_rules( def perform_connection_test( - settings: m.Examples.AdvancedDatabaseConfig, + settings: p.Examples.AdvancedDatabaseConfig, ) -> p.Result[p.Examples.AdvancedDatabaseConfig]: """Simulate database connection test.""" if "fail" in settings.host: diff --git a/examples/utilities.py b/examples/utilities.py index ca8935df0..a9b26dd5f 100644 --- a/examples/utilities.py +++ b/examples/utilities.py @@ -60,7 +60,7 @@ def print_demo_completion( @staticmethod def display_config_table( - config_data: m.Cli.DisplayData | m.Value, + config_data: p.Cli.DisplayData | m.Value, headers: t.StrSequence | None = None, ) -> None: """Display configuration as a table using canonical example models.""" @@ -79,7 +79,7 @@ def display_config_table( @staticmethod def display_success_summary( operation: str, - details: m.Cli.SuccessSummaryDetails | None = None, + details: p.Cli.SuccessSummaryDetails | None = None, ) -> None: """Display a standardized success summary using cli.""" cli.print( diff --git a/src/flext_cli/_models/_base/flextclimodelsbase_part_01.py b/src/flext_cli/_models/_base/flextclimodelsbase_part_01.py index 0fa3e833a..145c3ddea 100644 --- a/src/flext_cli/_models/_base/flextclimodelsbase_part_01.py +++ b/src/flext_cli/_models/_base/flextclimodelsbase_part_01.py @@ -6,7 +6,7 @@ from types import MappingProxyType from typing import Annotated, ClassVar -from flext_cli import t +from flext_cli import p, t from flext_core import m, u, p diff --git a/src/flext_cli/_models/_base/flextclimodelsbase_part_02.py b/src/flext_cli/_models/_base/flextclimodelsbase_part_02.py index 533a0c421..8beab1020 100644 --- a/src/flext_cli/_models/_base/flextclimodelsbase_part_02.py +++ b/src/flext_cli/_models/_base/flextclimodelsbase_part_02.py @@ -6,7 +6,7 @@ from typing import Annotated, ClassVar from flext_cli import c, p, t -from flext_core import m, u +from flext_core import m, p, u class FlextCliModelsBase: diff --git a/src/flext_cli/_models/_base/flextclimodelsbase_part_07.py b/src/flext_cli/_models/_base/flextclimodelsbase_part_07.py index 476f749ed..f7897d9d9 100644 --- a/src/flext_cli/_models/_base/flextclimodelsbase_part_07.py +++ b/src/flext_cli/_models/_base/flextclimodelsbase_part_07.py @@ -7,7 +7,7 @@ from typing import Annotated, ClassVar from flext_cli import c, p, t -from flext_core import m, u +from flext_core import m, p, u _EMPTY_JSON_MAPPING: t.JsonMapping = MappingProxyType({}) diff --git a/src/flext_cli/_models/pipeline.py b/src/flext_cli/_models/pipeline.py index 4aa2323aa..08e327a64 100644 --- a/src/flext_cli/_models/pipeline.py +++ b/src/flext_cli/_models/pipeline.py @@ -8,7 +8,7 @@ from typing import Annotated, ClassVar from flext_cli import c, p, t -from flext_core import m, u +from flext_core import m, p, u class FlextCliModelsPipeline: diff --git a/src/flext_cli/_utilities/_json/_core.py b/src/flext_cli/_utilities/_json/_core.py index 30c9e689a..7fa59ce0f 100644 --- a/src/flext_cli/_utilities/_json/_core.py +++ b/src/flext_cli/_utilities/_json/_core.py @@ -81,7 +81,7 @@ def normalize_json_value(item: t.JsonPayload) -> t.JsonValue: @staticmethod def _json_write_content( - payload: t.JsonPayload, options: m.Cli.JsonWriteOptions + payload: t.JsonPayload, options: p.Cli.JsonWriteOptions ) -> str: """Serialize a JSON payload using canonical write options.""" validated = FlextCliUtilitiesJsonCoreMixin.normalize_json_value(payload) @@ -122,7 +122,7 @@ def json_read(path: Path) -> p.Result[t.JsonMapping]: def json_write( path: Path, payload: t.JsonPayload, - options: m.Cli.JsonWriteOptions | None = None, + options: p.Cli.JsonWriteOptions | None = None, ) -> p.Result[bool]: """Write any Pydantic-serializable payload to a JSON file.""" opts = options or m.Cli.JsonWriteOptions() diff --git a/src/flext_cli/_utilities/_options/flextcliutilitiesoptions_part_02.py b/src/flext_cli/_utilities/_options/flextcliutilitiesoptions_part_02.py index 06ba370e7..b971cce33 100644 --- a/src/flext_cli/_utilities/_options/flextcliutilitiesoptions_part_02.py +++ b/src/flext_cli/_utilities/_options/flextcliutilitiesoptions_part_02.py @@ -4,7 +4,7 @@ from collections.abc import Mapping -from flext_cli import c, m, t +from flext_cli import c, p, t from flext_cli._utilities._options.flextcliutilitiesoptionbuilder_part_01 import ( FlextCliUtilitiesOptionBuilder, ) @@ -18,7 +18,7 @@ class FlextCliUtilitiesOptions(FlextCliUtilitiesOptionsPart01): @classmethod def field_default( - cls, field_name: str, field_info: m.FieldInfo, settings: t.Cli.ModelLike | None + cls, field_name: str, field_info: p.FieldInfo, settings: t.Cli.ModelLike | None ) -> t.Cli.CliValue | None: """Resolve CLI default from settings first, then from model field metadata.""" default_factory = getattr(field_info, "default_factory", None) diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_addresses.py b/src/flext_cli/_utilities/_xlxx/xlsx_addresses.py index b6ba90c53..194de477d 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_addresses.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_addresses.py @@ -18,11 +18,11 @@ class FlextCliUtilitiesXlsxAddresses: # NOTE (multi-agent, mro-j2yt.1): address rendering is implementation # policy, shared by cells, layout, tables, names, and worksheet rules. @staticmethod - def _cell_ref(address: m.Cli.XlsxCellAddress) -> str: + def _cell_ref(address: p.Cli.XlsxCellAddress) -> str: return f"{get_column_letter(address.column)}{address.row}" @classmethod - def _range_ref(cls, area: m.Cli.XlsxCellRange) -> str: + def _range_ref(cls, area: p.Cli.XlsxCellRange) -> str: if area.first.row > area.last.row or area.first.column > area.last.column: msg = ( "XLSX range starts after it ends: " @@ -32,7 +32,7 @@ def _range_ref(cls, area: m.Cli.XlsxCellRange) -> str: return f"{cls._cell_ref(area.first)}:{cls._cell_ref(area.last)}" @classmethod - def _absolute_range_ref(cls, area: m.Cli.XlsxCellRange) -> str: + def _absolute_range_ref(cls, area: p.Cli.XlsxCellRange) -> str: return absolute_coordinate(cls._range_ref(area)) @staticmethod @@ -49,7 +49,7 @@ def _range_failure(detail: str) -> p.Result[p.Cli.XlsxCellRange]: # mro-wkii.17.26 (xlsx-a): keep the caught vendor boundary to one operation. @classmethod - def _format_reference_value(cls, request: m.Cli.XlsxFormatReferenceRequest) -> str: + def _format_reference_value(cls, request: p.Cli.XlsxFormatReferenceRequest) -> str: if request.collapse_single_cell and request.area.first == request.area.last: reference = cls._cell_ref(request.area.first) if request.absolute: @@ -64,7 +64,7 @@ def _format_reference_value(cls, request: m.Cli.XlsxFormatReferenceRequest) -> s @classmethod def xlsx_parse_range( - cls, request: m.Cli.XlsxParseRangeRequest + cls, request: p.Cli.XlsxParseRangeRequest ) -> p.Result[p.Cli.XlsxCellRange]: """Parse one concrete A1 cell/range through the XLSX adapter.""" try: @@ -93,7 +93,7 @@ def xlsx_parse_range( # mro-j2yt.1 (xlsx_reference_api): keep vendor formatting behind cli. @classmethod def xlsx_format_reference( - cls, request: m.Cli.XlsxFormatReferenceRequest + cls, request: p.Cli.XlsxFormatReferenceRequest ) -> p.Result[p.Cli.XlsxReference]: """Format one validated range as a canonical Excel reference.""" try: diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_archive.py b/src/flext_cli/_utilities/_xlxx/xlsx_archive.py index 9ffa4f00f..97c4d8110 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_archive.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_archive.py @@ -17,7 +17,7 @@ class FlextCliUtilitiesXlsxArchive(FlextCliUtilitiesXlsxArchiveChecks): # this private adapter; consumers receive immutable inspection models. @classmethod def _inventory( - cls, archive: p.Cli.XlsxArchiveReader, policy: m.Cli.XlsxArchivePolicy + cls, archive: p.Cli.XlsxArchiveReader, policy: p.Cli.XlsxArchivePolicy ) -> p.Cli.XlsxArchiveInventory: members: tuple[str, ...] = () blocked: frozenset[str] = frozenset() @@ -70,7 +70,7 @@ def _inventory( @classmethod def _inspect_archive( - cls, archive: p.Cli.XlsxArchiveReader, policy: m.Cli.XlsxArchivePolicy + cls, archive: p.Cli.XlsxArchiveReader, policy: p.Cli.XlsxArchivePolicy ) -> p.Result[p.Cli.XlsxArchiveInspection]: inventory = cls._inventory(archive, policy) violations = inventory.violations @@ -136,7 +136,7 @@ def _inspect_archive( @classmethod def xlsx_inspect( - cls, request: m.Cli.XlsxArchiveInspectionRequest + cls, request: p.Cli.XlsxArchiveInspectionRequest ) -> p.Result[p.Cli.XlsxArchiveInspection]: """Inspect workbook bytes without extracting or trusting package XML.""" try: diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_archive_checks.py b/src/flext_cli/_utilities/_xlxx/xlsx_archive_checks.py index 83efff89d..f2fd23187 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_archive_checks.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_archive_checks.py @@ -46,7 +46,7 @@ def _xml_root( @classmethod def _worksheet_violations( - cls, root: p.Cli.XlsxXmlElement, member: str, policy: m.Cli.XlsxArchivePolicy + cls, root: p.Cli.XlsxXmlElement, member: str, policy: p.Cli.XlsxArchivePolicy ) -> tuple[p.Cli.XlsxArchiveViolation, ...]: violations: tuple[p.Cli.XlsxArchiveViolation, ...] = () for element in root.iter(): @@ -57,7 +57,7 @@ def _worksheet_violations( @classmethod def _workbook_violations( - cls, root: p.Cli.XlsxXmlElement, member: str, policy: m.Cli.XlsxArchivePolicy + cls, root: p.Cli.XlsxXmlElement, member: str, policy: p.Cli.XlsxArchivePolicy ) -> tuple[p.Cli.XlsxArchiveViolation, ...]: if not policy.reject_defined_names: return () @@ -69,7 +69,7 @@ def _workbook_violations( @classmethod def _style_violations( - cls, root: p.Cli.XlsxXmlElement, member: str, policy: m.Cli.XlsxArchivePolicy + cls, root: p.Cli.XlsxXmlElement, member: str, policy: p.Cli.XlsxArchivePolicy ) -> tuple[p.Cli.XlsxArchiveViolation, ...]: if not policy.reject_style_protection: return () diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_cells.py b/src/flext_cli/_utilities/_xlxx/xlsx_cells.py index a8c9820d4..ac3e203b9 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_cells.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_cells.py @@ -7,7 +7,7 @@ from openpyxl.worksheet.worksheet import Worksheet # mro-j47u (kimi): utilities consume local facades only, never private modules. -from flext_cli import c, m, p, r, t +from flext_cli import c, p, r, t from .xlsx_formula_codec import FlextCliUtilitiesXlsxFormulaCodec @@ -19,7 +19,7 @@ class FlextCliUtilitiesXlsxCells: # models until the one external cell-value assignment below; formula text # crosses the boundary in OOXML storage form (_xlfn. future functions). @staticmethod - def _cell_value(value: m.Cli.XlsxCellValue) -> t.Cli.XlsxCellPrimitive: + def _cell_value(value: p.Cli.XlsxCellValue) -> t.Cli.XlsxCellPrimitive: if value.kind == "blank": return None if value.kind == "formula": diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_conditional.py b/src/flext_cli/_utilities/_xlxx/xlsx_conditional.py index 055572114..3ff2ac041 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_conditional.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_conditional.py @@ -47,7 +47,7 @@ def _registered_style( ) @classmethod - def _differential_style(cls, spec: m.Cli.XlsxNamedStyleSpec) -> DifferentialStyle: + def _differential_style(cls, spec: p.Cli.XlsxNamedStyleSpec) -> DifferentialStyle: visual = spec.visual number_format_id = builtin_format_id(visual.number_format) or 0 return DifferentialStyle( @@ -62,7 +62,7 @@ def _differential_style(cls, spec: m.Cli.XlsxNamedStyleSpec) -> DifferentialStyl @classmethod def _rule( - cls, plan: m.Cli.XlsxConditionalFormatPlan, style: m.Cli.XlsxNamedStyleSpec + cls, plan: p.Cli.XlsxConditionalFormatPlan, style: p.Cli.XlsxNamedStyleSpec ) -> Rule: differential = cls._differential_style(style) if plan.kind == "contains_text": diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_layout.py b/src/flext_cli/_utilities/_xlxx/xlsx_layout.py index 0f5eb8b89..79c814d44 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_layout.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_layout.py @@ -6,7 +6,7 @@ from openpyxl.comments import Comment from openpyxl.worksheet.worksheet import Worksheet -from flext_cli import c, m, p, r, t +from flext_cli import c, p, r, t from .xlsx_addresses import FlextCliUtilitiesXlsxAddresses @@ -17,7 +17,7 @@ class FlextCliUtilitiesXlsxLayout(FlextCliUtilitiesXlsxAddresses): # mro-wkii.17.26 (xlsx-a): preserve typed results across cohesive phases. @classmethod def _apply_layout_annotations( - cls, worksheet: Worksheet, plan: m.Cli.XlsxSheetLayoutPlan + cls, worksheet: Worksheet, plan: p.Cli.XlsxSheetLayoutPlan ) -> p.Result[bool]: for item in plan.comments: comment = Comment(item.text, item.author) @@ -49,7 +49,7 @@ def _apply_layout_annotations( @classmethod def _apply_layout_structure( - cls, worksheet: Worksheet, plan: m.Cli.XlsxSheetLayoutPlan + cls, worksheet: Worksheet, plan: p.Cli.XlsxSheetLayoutPlan ) -> p.Result[bool]: for item in plan.dimensions: for index in range(item.first, item.last + 1): @@ -80,7 +80,7 @@ def _apply_layout_structure( @classmethod def _apply_layout_view( - cls, worksheet: Worksheet, plan: m.Cli.XlsxSheetLayoutPlan + cls, worksheet: Worksheet, plan: p.Cli.XlsxSheetLayoutPlan ) -> p.Result[bool]: if plan.freeze_pane is not None: worksheet.freeze_panes = cls._cell_ref(plan.freeze_pane.at) @@ -93,7 +93,7 @@ def _apply_layout_view( @classmethod def _apply_layout_merges( - cls, worksheet: Worksheet, plan: m.Cli.XlsxSheetLayoutPlan + cls, worksheet: Worksheet, plan: p.Cli.XlsxSheetLayoutPlan ) -> p.Result[bool]: for item in plan.merges: worksheet.merge_cells(cls._range_ref(item.area)) @@ -103,7 +103,7 @@ def _apply_layout_merges( # and hyperlinks can still target every concrete cell in the plan. @classmethod def _apply_layout( - cls, worksheet: Worksheet, plan: m.Cli.XlsxSheetLayoutPlan + cls, worksheet: Worksheet, plan: p.Cli.XlsxSheetLayoutPlan ) -> p.Result[bool]: phases: tuple[t.Cli.NullaryOperation[p.Result[bool]], ...] = ( lambda: cls._apply_layout_annotations(worksheet, plan), diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_protection.py b/src/flext_cli/_utilities/_xlxx/xlsx_protection.py index 199396c33..ea6cdd43b 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_protection.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_protection.py @@ -5,7 +5,7 @@ from openpyxl.styles import Protection from openpyxl.worksheet.worksheet import Worksheet -from flext_cli import c, m, p, r +from flext_cli import c, p, r class FlextCliUtilitiesXlsxProtection: @@ -14,7 +14,7 @@ class FlextCliUtilitiesXlsxProtection: # mro-wkii.17.26 (xlsx-a): keep one responsibility per vendor phase. @staticmethod def _apply_cell_protection( - worksheet: Worksheet, plan: m.Cli.XlsxSheetProtectionPlan + worksheet: Worksheet, plan: p.Cli.XlsxSheetProtectionPlan ) -> None: for item in plan.cells: for row in range(item.area.first.row, item.area.last.row + 1): @@ -25,7 +25,7 @@ def _apply_cell_protection( @staticmethod def _apply_sheet_permissions( - worksheet: Worksheet, plan: m.Cli.XlsxSheetProtectionPlan + worksheet: Worksheet, plan: p.Cli.XlsxSheetProtectionPlan ) -> None: permissions = plan.permissions protection = worksheet.protection @@ -48,7 +48,7 @@ def _apply_sheet_permissions( @staticmethod def _apply_protection_credential( - worksheet: Worksheet, plan: m.Cli.XlsxSheetProtectionPlan + worksheet: Worksheet, plan: p.Cli.XlsxSheetProtectionPlan ) -> None: credential = plan.credential if credential is None: @@ -62,7 +62,7 @@ def _apply_protection_credential( # actions, so positive allow_* model flags are inverted exactly once here. @classmethod def _apply_protection( - cls, worksheet: Worksheet, plan: m.Cli.XlsxSheetProtectionPlan | None + cls, worksheet: Worksheet, plan: p.Cli.XlsxSheetProtectionPlan | None ) -> p.Result[bool]: if plan is None: return r[bool].ok(True) diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_recalc.py b/src/flext_cli/_utilities/_xlxx/xlsx_recalc.py index de2bea65b..2105cf92c 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_recalc.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_recalc.py @@ -24,7 +24,7 @@ def _recalc_error(detail: str) -> str: @classmethod def _recalc_in_workspace( - cls, request: m.Cli.XlsxRecalcRequest, workdir: Path + cls, request: p.Cli.XlsxRecalcRequest, workdir: Path ) -> p.Result[p.Cli.XlsxRecalcResult]: input_dir = workdir / "input" output_dir = workdir / "output" @@ -79,7 +79,7 @@ def _recalc_in_workspace( # processes facade without polluting the XLSX composition order. @classmethod def xlsx_recalc( - cls, request: m.Cli.XlsxRecalcRequest + cls, request: p.Cli.XlsxRecalcRequest ) -> p.Result[p.Cli.XlsxRecalcResult]: """Recalculate every formula cache through the headless office engine.""" try: @@ -94,7 +94,7 @@ def xlsx_recalc( @classmethod def xlsx_recalc_parity( - cls, request: m.Cli.XlsxRecalcParityRequest + cls, request: p.Cli.XlsxRecalcParityRequest ) -> p.Result[p.Cli.XlsxRecalcParityReport]: """Recalculate and compare cached values against source formulas.""" formula_snapshot = cls.xlsx_snapshot( diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_renderer.py b/src/flext_cli/_utilities/_xlxx/xlsx_renderer.py index 7fcff0fc1..b01d71934 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_renderer.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_renderer.py @@ -28,7 +28,7 @@ class FlextCliUtilitiesXlsxRenderer( # later stages never run after an earlier mutation reports failure. @classmethod def _render_sheet( - cls, workbook: Workbook, plan: m.Cli.XlsxSheetPlan, table_names: frozenset[str] + cls, workbook: Workbook, plan: p.Cli.XlsxSheetPlan, table_names: frozenset[str] ) -> p.Result[frozenset[str]]: if plan.name not in workbook.sheetnames: return r[frozenset[str]].fail( @@ -54,7 +54,7 @@ def _render_sheet( @classmethod def xlsx_render( - cls, request: m.Cli.XlsxRenderRequest + cls, request: p.Cli.XlsxRenderRequest ) -> p.Result[p.Cli.XlsxRenderResult]: """Render typed sheets, names, styles, and rules into workbook bytes.""" workbook_result = cls._workbook_for_request(request) diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_rules.py b/src/flext_cli/_utilities/_xlxx/xlsx_rules.py index 6cc9c75e7..fa88bcb2f 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_rules.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_rules.py @@ -4,7 +4,7 @@ from openpyxl.worksheet.worksheet import Worksheet -from flext_cli import m, p, r +from flext_cli import p, r from .xlsx_conditional import FlextCliUtilitiesXlsxConditional from .xlsx_protection import FlextCliUtilitiesXlsxProtection @@ -22,7 +22,7 @@ class FlextCliUtilitiesXlsxRules( # no dump, revalidation, or rule-specific transport is introduced. @classmethod def _apply_rules( - cls, worksheet: Worksheet, plan: m.Cli.XlsxSheetRulesPlan + cls, worksheet: Worksheet, plan: p.Cli.XlsxSheetRulesPlan ) -> p.Result[bool]: validations = cls._apply_validations(worksheet, plan.validations) if validations.failure: diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_snapshot.py b/src/flext_cli/_utilities/_xlxx/xlsx_snapshot.py index 725fb5e40..ac22b7b2f 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_snapshot.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_snapshot.py @@ -19,7 +19,7 @@ class FlextCliUtilitiesXlsxSnapshot( # narrow phases; a data-only view supplies cached values only when requested. @classmethod def xlsx_snapshot( - cls, request: m.Cli.XlsxSnapshotRequest + cls, request: p.Cli.XlsxSnapshotRequest ) -> p.Result[p.Cli.XlsxWorkbookSnapshot]: """Inspect workbook bytes into one immutable semantic snapshot.""" try: diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_values.py b/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_values.py index c407c2b11..cefb4963c 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_values.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_values.py @@ -48,7 +48,7 @@ def _snapshot_value( "formula cell has no formula expression" ) try: - converted: m.Cli.XlsxCellValue = ( + converted: p.Cli.XlsxCellValue = ( m.Cli.XlsxFormulaValue(value=formula) if formula is not None else m.Cli.XlsxBlankValue() diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_style_builders.py b/src/flext_cli/_utilities/_xlxx/xlsx_style_builders.py index 9a6be5201..6c99c684d 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_style_builders.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_style_builders.py @@ -6,8 +6,6 @@ from openpyxl.styles.borders import Side from openpyxl.styles.fills import PatternFill, Stop -from flext_cli import m - class FlextCliUtilitiesXlsxStyleBuilders: """Build external visual styles only from validated model fields.""" @@ -15,7 +13,7 @@ class FlextCliUtilitiesXlsxStyleBuilders: # NOTE (multi-agent, mro-j2yt.1): protection is deliberately absent from # every builder and is applied only by the worksheet protection adapter. @staticmethod - def _color(spec: m.Cli.XlsxColor | None) -> Color | None: + def _color(spec: p.Cli.XlsxColor | None) -> Color | None: if spec is None: return None if spec.kind == "rgb": @@ -27,7 +25,7 @@ def _color(spec: m.Cli.XlsxColor | None) -> Color | None: return Color(auto=True, tint=spec.tint) @classmethod - def _font(cls, spec: m.Cli.XlsxFontSpec) -> Font: + def _font(cls, spec: p.Cli.XlsxFontSpec) -> Font: return Font( name=spec.name, size=spec.size, @@ -47,7 +45,7 @@ def _font(cls, spec: m.Cli.XlsxFontSpec) -> Font: ) @classmethod - def _fill(cls, spec: m.Cli.XlsxFillSpec) -> PatternFill | GradientFill: + def _fill(cls, spec: p.Cli.XlsxFillSpec) -> PatternFill | GradientFill: if spec.kind == "pattern": foreground = cls._color(spec.foreground) background = cls._color(spec.background) @@ -71,13 +69,13 @@ def _fill(cls, spec: m.Cli.XlsxFillSpec) -> PatternFill | GradientFill: ) @classmethod - def _side(cls, spec: m.Cli.XlsxBorderSideSpec | None) -> Side | None: + def _side(cls, spec: p.Cli.XlsxBorderSideSpec | None) -> Side | None: if spec is None: return None return Side(style=spec.style, color=cls._color(spec.color)) @classmethod - def _border(cls, spec: m.Cli.XlsxBorderSpec) -> Border: + def _border(cls, spec: p.Cli.XlsxBorderSpec) -> Border: return Border( left=cls._side(spec.left), right=cls._side(spec.right), @@ -94,7 +92,7 @@ def _border(cls, spec: m.Cli.XlsxBorderSpec) -> Border: ) @staticmethod - def _alignment(spec: m.Cli.XlsxAlignmentSpec) -> Alignment: + def _alignment(spec: p.Cli.XlsxAlignmentSpec) -> Alignment: return Alignment( horizontal=spec.horizontal, vertical=spec.vertical, @@ -108,7 +106,7 @@ def _alignment(spec: m.Cli.XlsxAlignmentSpec) -> Alignment: ) @classmethod - def _named_style(cls, spec: m.Cli.XlsxNamedStyleSpec) -> NamedStyle: + def _named_style(cls, spec: p.Cli.XlsxNamedStyleSpec) -> NamedStyle: visual = spec.visual return NamedStyle( name=spec.name, diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_style_catalog.py b/src/flext_cli/_utilities/_xlxx/xlsx_style_catalog.py index a912ef067..53150375e 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_style_catalog.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_style_catalog.py @@ -18,7 +18,7 @@ class FlextCliUtilitiesXlsxStyleCatalog( # NOTE (multi-agent, mro-j2yt.1): cells identify source style IDs through # public openpyxl properties; protection never enters the visual signature. @staticmethod - def _style_name(prefix: str, visual: m.Cli.XlsxVisualStyleSpec) -> str: + def _style_name(prefix: str, visual: p.Cli.XlsxVisualStyleSpec) -> str: digest = sha256(repr(visual).encode("utf-8")).hexdigest()[:16] return f"{prefix}_{digest}" @@ -64,7 +64,7 @@ def _source_visuals( @classmethod def xlsx_style_catalog( - cls, request: m.Cli.XlsxStyleCatalogRequest + cls, request: p.Cli.XlsxStyleCatalogRequest ) -> p.Result[p.Cli.XlsxStyleCatalog]: """Extract all cell-used visual styles and deduplicate them.""" source_result = cls._source_visuals(request.source) @@ -100,7 +100,7 @@ def xlsx_style_catalog( @classmethod def xlsx_style_template( - cls, request: m.Cli.XlsxStyleTemplateRequest + cls, request: p.Cli.XlsxStyleTemplateRequest ) -> p.Result[p.Cli.XlsxStyleTemplateResult]: """Emit a blank workbook containing only deduplicated visual styles.""" catalog_result = cls.xlsx_style_catalog( diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_validations.py b/src/flext_cli/_utilities/_xlxx/xlsx_validations.py index 9bb4846c9..bd78fe315 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_validations.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_validations.py @@ -61,7 +61,7 @@ def _inline_formula(values: tuple[str, ...]) -> str: return formula @classmethod - def _data_validation(cls, plan: m.Cli.XlsxDataValidationPlan) -> DataValidation: + def _data_validation(cls, plan: p.Cli.XlsxDataValidationPlan) -> DataValidation: messages = plan.messages formula1: str | None = None formula2: str | None = None diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_workbook_plan.py b/src/flext_cli/_utilities/_xlxx/xlsx_workbook_plan.py index a69da8694..bcc13c441 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_workbook_plan.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_workbook_plan.py @@ -7,7 +7,7 @@ from openpyxl.worksheet.worksheet import Worksheet # mro-j47u (kimi): utilities consume local facades only, never private modules. -from flext_cli import c, m, p, r +from flext_cli import c, p, r from .xlsx_style_codec import FlextCliUtilitiesXlsxStyleCodec from .xlsx_workbook_io import FlextCliUtilitiesXlsxWorkbookIo @@ -21,7 +21,7 @@ class FlextCliUtilitiesXlsxWorkbookPlan( # NOTE (multi-agent, mro-j2yt.1): template sheets and names are discarded; # only visual resources survive, so stale document content cannot leak. @staticmethod - def _validate_plan(plan: m.Cli.XlsxWorkbookPlan) -> p.Result[bool]: + def _validate_plan(plan: p.Cli.XlsxWorkbookPlan) -> p.Result[bool]: sheet_names: frozenset[str] = frozenset() style_names: frozenset[str] = frozenset() defined_names: frozenset[str] = frozenset() @@ -50,7 +50,7 @@ def _validate_plan(plan: m.Cli.XlsxWorkbookPlan) -> p.Result[bool]: @classmethod def _workbook_for_request( - cls, request: m.Cli.XlsxRenderRequest + cls, request: p.Cli.XlsxRenderRequest ) -> p.Result[Workbook]: validation = cls._validate_plan(request.plan) if validation.failure: @@ -75,7 +75,7 @@ def _workbook_for_request( @classmethod def _prepare_workbook( - cls, workbook: Workbook, plan: m.Cli.XlsxWorkbookPlan + cls, workbook: Workbook, plan: p.Cli.XlsxWorkbookPlan ) -> p.Result[Workbook]: for worksheet in tuple(workbook.worksheets): workbook.remove(worksheet) diff --git a/src/flext_cli/_utilities/formatters.py b/src/flext_cli/_utilities/formatters.py index c991aed6e..e33c6f6ec 100644 --- a/src/flext_cli/_utilities/formatters.py +++ b/src/flext_cli/_utilities/formatters.py @@ -7,8 +7,7 @@ from rich.console import Console from rich.panel import Panel from rich.table import Table as RichTable - -from flext_cli import m +from flext_cli import p class FlextCliUtilitiesFormatters: @@ -32,7 +31,7 @@ def formatters_render_panel(cls, content: str, *, title: str = "") -> None: cls._console.print(Panel(content, title=title or None)) @classmethod - def formatters_render_table(cls, request: m.Cli.TableRenderRequest) -> None: + def formatters_render_table(cls, request: p.Cli.TableRenderRequest) -> None: """Render one table via Rich.""" table = RichTable(title=request.title or None) for col in request.columns: diff --git a/src/flext_cli/_utilities/framework.py b/src/flext_cli/_utilities/framework.py index 4b8b8445b..f4dfd0461 100644 --- a/src/flext_cli/_utilities/framework.py +++ b/src/flext_cli/_utilities/framework.py @@ -168,7 +168,7 @@ def framework_register_command( @staticmethod def framework_build_parameter( - field_name: str, annotation: type | GenericAlias, spec: m.Cli.OptionSpec + field_name: str, annotation: type | GenericAlias, spec: p.Cli.OptionSpec ) -> Parameter: """Build one inspect parameter with a private Typer option default.""" option_default: t.Cli.CliValue | EllipsisType | None = ( @@ -292,8 +292,6 @@ def framework_invoke( env: t.StrMapping | None = None, ) -> p.Cli.InvocationResult: """Invoke one application through the real framework test runner.""" - from flext_cli import m - runner = CliRunner(charset=charset, env=env) private_application = cls._unwrap(application) result = runner.invoke( diff --git a/src/flext_cli/_utilities/model_commands.py b/src/flext_cli/_utilities/model_commands.py index dfea5b013..07a148599 100644 --- a/src/flext_cli/_utilities/model_commands.py +++ b/src/flext_cli/_utilities/model_commands.py @@ -15,7 +15,7 @@ from typing import cast from flext_cli import settings, t -from flext_core import m +from flext_cli import p class FlextCliUtilitiesModelCommands: @@ -32,7 +32,7 @@ def __init__( self.model_class = model_class self.handler = handler - def _resolve_default(self, field_info: m.FieldInfo) -> t.Cli.CliValue | type: + def _resolve_default(self, field_info: p.FieldInfo) -> t.Cli.CliValue | type: if field_info.is_required(): return inspect.Parameter.empty # NOTE (multi-agent): ``FieldInfo.get_default`` is typed ``Any`` diff --git a/src/flext_cli/_utilities/pipeline.py b/src/flext_cli/_utilities/pipeline.py index 1eb939c03..b1e218c1e 100644 --- a/src/flext_cli/_utilities/pipeline.py +++ b/src/flext_cli/_utilities/pipeline.py @@ -18,7 +18,7 @@ class FlextCliUtilitiesPipeline: @staticmethod def execute_pipeline( stages: t.SequenceOf[p.Cli.PipelineStageSpec], - context: m.Cli.PipelineStageContext, + context: p.Cli.PipelineStageContext, *, fail_fast: bool = c.Cli.PIPELINE_DEFAULT_FAIL_FAST, logger: p.Logger | None = None, @@ -91,8 +91,8 @@ def execute_pipeline( @staticmethod def _run_stage( - spec: m.Cli.PipelineStageSpec, - context: m.Cli.PipelineStageContext, + spec: p.Cli.PipelineStageSpec, + context: p.Cli.PipelineStageContext, log: p.Logger, ) -> p.Cli.PipelineStageResult: """Execute a single stage with skip check and retry logic.""" diff --git a/src/flext_cli/_utilities/tables.py b/src/flext_cli/_utilities/tables.py index b1d6c9dc9..f4479020e 100644 --- a/src/flext_cli/_utilities/tables.py +++ b/src/flext_cli/_utilities/tables.py @@ -34,7 +34,7 @@ def tables_normalize_sequence_row( @staticmethod def tables_resolve_config( - settings: m.Cli.TableConfig | None = None, + settings: p.Cli.TableConfig | None = None, **settings_kwargs: t.Cli.TableConfigValue, ) -> p.Result[p.Cli.TableConfig]: """Resolve table config via canonical Pydantic model contract.""" @@ -112,7 +112,7 @@ def tables_tabulate_payload( @staticmethod def tables_render( - rows: t.SequenceOf[t.Cli.TableRow], settings: m.Cli.TableConfig + rows: t.SequenceOf[t.Cli.TableRow], settings: p.Cli.TableConfig ) -> p.Result[str]: """Render normalized rows to a tabulated string.""" headers: str | t.StrSequence diff --git a/src/flext_cli/constants.py b/src/flext_cli/constants.py index a45ba62d8..b8da7c8fa 100644 --- a/src/flext_cli/constants.py +++ b/src/flext_cli/constants.py @@ -2,17 +2,17 @@ from __future__ import annotations -from flext_cli._constants.base import FlextCliConstantsBase -from flext_cli._constants.config import FlextCliConstantsConfig -from flext_cli._constants.enums import FlextCliConstantsEnums -from flext_cli._constants.errors import FlextCliConstantsErrors -from flext_cli._constants.exceptions import FlextCliConstantsExceptions -from flext_cli._constants.files import FlextCliConstantsFiles -from flext_cli._constants.output import FlextCliConstantsOutput -from flext_cli._constants.pipeline import FlextCliConstantsPipeline -from flext_cli._constants.settings import FlextCliConstantsSettings -from flext_cli._constants.xlsx import FlextCliConstantsXlsx -from flext_cli._constants.xlsx_future_functions import ( +from ._constants import ( + FlextCliConstantsBase, + FlextCliConstantsConfig, + FlextCliConstantsEnums, + FlextCliConstantsErrors, + FlextCliConstantsExceptions, + FlextCliConstantsFiles, + FlextCliConstantsOutput, + FlextCliConstantsPipeline, + FlextCliConstantsSettings, + FlextCliConstantsXlsx, FlextCliConstantsXlsxFutureFunctions, ) from flext_core import c, t diff --git a/src/flext_cli/services/_cli/flextclicli_part_01.py b/src/flext_cli/services/_cli/flextclicli_part_01.py index ff4a2007e..c31538c30 100644 --- a/src/flext_cli/services/_cli/flextclicli_part_01.py +++ b/src/flext_cli/services/_cli/flextclicli_part_01.py @@ -49,7 +49,7 @@ def __call__(self, **kwargs: t.Cli.CliValue) -> t.JsonValue: @classmethod def _build_model_parameter( - cls, field_name: str, field_info: m.FieldInfo, settings: t.Cli.ModelLike | None + cls, field_name: str, field_info: p.FieldInfo, settings: t.Cli.ModelLike | None ) -> tuple[Parameter, type | GenericAlias]: """Build a keyword-only Typer option from a Pydantic field.""" alias = getattr(field_info, "alias", None) diff --git a/src/flext_cli/services/_cli/flextclicli_part_02.py b/src/flext_cli/services/_cli/flextclicli_part_02.py index 7c7f18222..f311ba00c 100644 --- a/src/flext_cli/services/_cli/flextclicli_part_02.py +++ b/src/flext_cli/services/_cli/flextclicli_part_02.py @@ -16,7 +16,7 @@ class FlextCliCli(FlextCliCliPart01): """Implementation part for FlextCliCli.""" - def _apply_common_params_to_config(self, *, params: m.Cli.CliParamsConfig) -> None: + def _apply_common_params_to_config(self, *, params: p.Cli.CliParamsConfig) -> None: """Apply global CLI flags to the shared settings singleton.""" resolved_log_level: str = ( params.log_level if params.log_level is not None else settings.cli_log_level @@ -64,7 +64,7 @@ def create_app_with_common_params( name=name, help_text=help_text, add_completion=add_completion ) - def apply_common_params(params: m.Cli.CliParamsConfig) -> bool: + def apply_common_params(params: p.Cli.CliParamsConfig) -> bool: self._apply_common_params_to_config(params=params) return True diff --git a/src/flext_cli/services/_prompts_support.py b/src/flext_cli/services/_prompts_support.py index d4f949bd0..883a752fd 100644 --- a/src/flext_cli/services/_prompts_support.py +++ b/src/flext_cli/services/_prompts_support.py @@ -33,7 +33,7 @@ class FlextCliPromptsSupport(s): _test_env_override: bool | None = m.PrivateAttr(default_factory=lambda: None) - def configure(self, state: m.Cli.PromptRuntimeState) -> Self: + def configure(self, state: p.Cli.PromptRuntimeState) -> Self: """Replace prompt runtime state using the canonical CLI model.""" self.state = state return self diff --git a/src/flext_cli/services/auth.py b/src/flext_cli/services/auth.py index b239eae26..bdec841ca 100644 --- a/src/flext_cli/services/auth.py +++ b/src/flext_cli/services/auth.py @@ -54,7 +54,7 @@ def authenticate(self, credentials: t.StrMapping) -> p.Result[str]: return r[str].fail(c.Cli.ERR_INVALID_CREDENTIALS) return self._resolve_token(payload).flat_map(self._persist_token) - def _resolve_token(self, payload: m.Cli.AuthCredentialsPayload) -> p.Result[str]: + def _resolve_token(self, payload: p.Cli.AuthCredentialsPayload) -> p.Result[str]: if payload.token: return r[str].ok(payload.token) return ( diff --git a/src/flext_cli/services/file_tools.py b/src/flext_cli/services/file_tools.py index 92fdf4f61..81c82353b 100644 --- a/src/flext_cli/services/file_tools.py +++ b/src/flext_cli/services/file_tools.py @@ -5,7 +5,7 @@ from collections.abc import Sequence from pathlib import Path -from flext_cli import c, m, p, r, s, t, u +from flext_cli import c, p, r, s, t, u class FlextCliFileTools(s): @@ -64,7 +64,7 @@ def read_yaml_model_chain[M: t.Cli.ModelLike]( def write_json_file( file_path: t.Cli.TextPath, data: t.Cli.JsonWriteData, - options: m.Cli.JsonWriteOptions | None = None, + options: p.Cli.JsonWriteOptions | None = None, ) -> p.Result[bool]: return u.Cli.json_write(Path(file_path), data, options=options) diff --git a/src/flext_cli/services/pipeline.py b/src/flext_cli/services/pipeline.py index ae5182d58..31c959812 100644 --- a/src/flext_cli/services/pipeline.py +++ b/src/flext_cli/services/pipeline.py @@ -116,7 +116,7 @@ def pipeline( self, stages: t.SequenceOf[p.Cli.PipelineStageSpec], *, - context: m.Cli.PipelineStageContext, + context: p.Cli.PipelineStageContext, fail_fast: bool = c.Cli.PIPELINE_DEFAULT_FAIL_FAST, logger: p.Logger | None = None, ) -> p.Result[p.Cli.PipelineResult]: diff --git a/src/flext_cli/services/tables.py b/src/flext_cli/services/tables.py index eec8b8383..26cb69f97 100644 --- a/src/flext_cli/services/tables.py +++ b/src/flext_cli/services/tables.py @@ -10,7 +10,7 @@ from __future__ import annotations -from flext_cli import c, m, p, s, t, u +from flext_cli import c, p, s, t, u from flext_cli.services.formatters import FlextCliFormatters @@ -20,7 +20,7 @@ class FlextCliTables(s): @staticmethod def format_table( data: t.Cli.TableDataSource, - settings: m.Cli.TableConfig | None = None, + settings: p.Cli.TableConfig | None = None, **config_kwargs: t.Cli.TableConfigValue, ) -> p.Result[str]: """Format table data to a string using the public CLI API.""" @@ -33,7 +33,7 @@ def format_table( @staticmethod def show_table( data: t.Cli.TableDataSource, - settings: m.Cli.TableConfig | None = None, + settings: p.Cli.TableConfig | None = None, **config_kwargs: t.Cli.TableConfigValue, ) -> None: """Render and display a formatted table on the console.""" diff --git a/tests/_constants_parts/tests_core.py b/tests/_constants_parts/tests_core.py index f02498f59..f2ffcbbfc 100644 --- a/tests/_constants_parts/tests_core.py +++ b/tests/_constants_parts/tests_core.py @@ -3,13 +3,13 @@ from __future__ import annotations import re -from enum import StrEnum, unique +from enum import StrEnum, p, unique from types import MappingProxyType from typing import TYPE_CHECKING, Final from flext_cli import c -from tests import t +from tests import p, t diff --git a/tests/_constants_parts/tests_rules_options.py b/tests/_constants_parts/tests_rules_options.py index cbadcfb8c..781cef6b7 100644 --- a/tests/_constants_parts/tests_rules_options.py +++ b/tests/_constants_parts/tests_rules_options.py @@ -5,7 +5,7 @@ from types import MappingProxyType from typing import TYPE_CHECKING, Final -from tests import t +from tests import p, t diff --git a/tests/_constants_parts/tests_yaml_output.py b/tests/_constants_parts/tests_yaml_output.py index 6c3ab56b7..e47045ebd 100644 --- a/tests/_constants_parts/tests_yaml_output.py +++ b/tests/_constants_parts/tests_yaml_output.py @@ -6,7 +6,7 @@ from flext_cli import c -from tests import t +from tests import p, t diff --git a/tests/_models_parts/tests_runtime.py b/tests/_models_parts/tests_runtime.py index 869a762bd..62d17ecdd 100644 --- a/tests/_models_parts/tests_runtime.py +++ b/tests/_models_parts/tests_runtime.py @@ -5,7 +5,7 @@ from typing import Annotated, ClassVar, Self from flext_cli import m -from tests import t +from tests import p, t class TestsFlextCliModelsRuntime: diff --git a/tests/_models_parts/tests_version.py b/tests/_models_parts/tests_version.py index 8e759ee85..87b15398e 100644 --- a/tests/_models_parts/tests_version.py +++ b/tests/_models_parts/tests_version.py @@ -7,7 +7,7 @@ from flext_cli import m from tests import c -from tests import t +from tests import p, t diff --git a/tests/conftest.py b/tests/conftest.py index 7d40a07e4..a9c48d8b4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -6,7 +6,7 @@ import pytest -from tests import t +from tests import p, t diff --git a/tests/protocols.py b/tests/protocols.py index ce688e528..5bfafb3e8 100644 --- a/tests/protocols.py +++ b/tests/protocols.py @@ -13,7 +13,7 @@ from flext_cli import p from flext_cli import m -from tests import t +from tests import p, t diff --git a/tests/typings.py b/tests/typings.py index 9376b2e6f..789574f4e 100644 --- a/tests/typings.py +++ b/tests/typings.py @@ -12,7 +12,7 @@ from flext_tests import FlextTestsTypes -from flext_cli import t +from flext_cli import p, t class TestsFlextCliTypes(FlextTestsTypes, t): diff --git a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_01.py b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_01.py index c7f02aedc..857f7ed99 100644 --- a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_01.py +++ b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_01.py @@ -15,7 +15,7 @@ from collections.abc import MutableSequence -from tests import t +from tests import p, t @@ -26,7 +26,7 @@ def test_model_command_validates_runtime_settings_fields(self) -> None: """Validate runtime CLI parameters through the model command.""" command_settings = m.Cli.CliParamsConfig() - def handle(params: m.Cli.CliParamsConfig) -> t.JsonValue: + def handle(params: p.Cli.CliParamsConfig) -> t.JsonValue: return params.debug is True command = cli.model_command( @@ -74,7 +74,7 @@ def test_model_command_generates_real_typer_options(self) -> None: ) group = cli.create_group(help_text="Sample group", name="sample") - def handle(params: m.Tests.SampleInput) -> t.JsonValue: + def handle(params: p.Tests.SampleInput) -> t.JsonValue: captured.append(params) return True diff --git a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_02.py b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_02.py index a93936a97..deaf77a70 100644 --- a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_02.py +++ b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_02.py @@ -15,7 +15,7 @@ from collections.abc import MutableSequence -from tests import t +from tests import p, t @@ -30,7 +30,7 @@ def test_model_command_accepts_repeatable_list_options(self) -> None: ) group = cli.create_group(help_text="Sample group", name="sample") - def handle(params: m.Tests.RepeatableInput) -> t.JsonValue: + def handle(params: p.Tests.RepeatableInput) -> t.JsonValue: captured.append(params) return True @@ -63,7 +63,7 @@ def handle(params: m.Tests.RepeatableInput) -> t.JsonValue: def test_model_command_returns_handler_value(self) -> None: """Return the handler value from the model-generated command.""" - def handle(params: m.Tests.SampleInput) -> t.JsonValue: + def handle(params: p.Tests.SampleInput) -> t.JsonValue: return { "name": params.name, "count": params.count, diff --git a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_04.py b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_04.py index 7c3de222a..ef9755f61 100644 --- a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_04.py +++ b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_04.py @@ -11,7 +11,7 @@ # NOTE (multi-agent, mro-wkii.19.4): app creation owns the settings singleton. -from tests import t +from tests import p, t @@ -65,7 +65,7 @@ def test_execute_app_prefers_real_failure_message(self) -> None: ) group = cli.create_group(help_text="Grouped failure commands", name="group") - def fail_handler(_params: m.Tests.SampleInput) -> t.JsonValue: + def fail_handler(_params: p.Tests.SampleInput) -> t.JsonValue: cli.exit(code=1) return True diff --git a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_05.py b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_05.py index dbefa36a0..820c70f95 100644 --- a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_05.py +++ b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_05.py @@ -27,16 +27,16 @@ def test_register_result_command_renders_success_and_failure(self) -> None: ) group = cli.create_group(help_text="Grouped commands", name="group") - def ok_handler(params: m.Tests.SampleInput) -> p.Result[p.Tests.SampleOutput]: + def ok_handler(params: p.Tests.SampleInput) -> p.Result[p.Tests.SampleOutput]: return cli.execute().map( - lambda _payload: m.Tests.SampleOutput( + lambda _payload: p.Tests.SampleOutput( message=f"processed {params.name}" ) ) - def fail_handler(params: m.Tests.SampleInput) -> p.Result[p.Tests.SampleOutput]: + def fail_handler(params: p.Tests.SampleInput) -> p.Result[p.Tests.SampleOutput]: return cli.validate_credentials("", "password").map( - lambda _value: m.Tests.SampleOutput(message=params.name) + lambda _value: p.Tests.SampleOutput(message=params.name) ) def build_ok_route() -> p.Cli.ResultCommandRoute: @@ -82,7 +82,7 @@ def test_register_result_routes_propagates_real_failure(self) -> None: name="result-app", help_text="Result application" ) - def fail_handler(params: m.Tests.SampleInput) -> p.Result[p.Tests.SampleOutput]: + def fail_handler(params: p.Tests.SampleInput) -> p.Result[p.Tests.SampleOutput]: return r[p.Tests.SampleOutput].fail( "Password cannot be resolved", error_code="secret_unavailable", diff --git a/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_01.py b/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_01.py index 468213436..0c8de6d73 100644 --- a/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_01.py +++ b/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_01.py @@ -14,7 +14,7 @@ from pathlib import Path -from tests import t +from tests import p, t diff --git a/tests/unit/_cases/test_json_cov/testsflextclijsoncov_part_01.py b/tests/unit/_cases/test_json_cov/testsflextclijsoncov_part_01.py index 372964258..3d01eaca0 100644 --- a/tests/unit/_cases/test_json_cov/testsflextclijsoncov_part_01.py +++ b/tests/unit/_cases/test_json_cov/testsflextclijsoncov_part_01.py @@ -5,7 +5,7 @@ from typing import TYPE_CHECKING from tests import m -from tests import t +from tests import p, t from tests import u from flext_tests import tm diff --git a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_01.py b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_01.py index 2e099d986..bacc4c9b5 100644 --- a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_01.py +++ b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_01.py @@ -13,7 +13,7 @@ from pathlib import Path from tests import p -from tests import t +from tests import p, t diff --git a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_02.py b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_02.py index e6711521c..92ce6f01b 100644 --- a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_02.py +++ b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_02.py @@ -13,7 +13,7 @@ from pathlib import Path from tests import p -from tests import t +from tests import p, t diff --git a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_03.py b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_03.py index dbcb78fa2..f20f8e118 100644 --- a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_03.py +++ b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_03.py @@ -11,7 +11,7 @@ from tests import m from tests import p -from tests import t +from tests import p, t # ── Fixtures ──────────────────────────────────────────────────────── diff --git a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_02.py b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_02.py index 3935c4927..ca6026a88 100644 --- a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_02.py +++ b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_02.py @@ -37,7 +37,7 @@ def test_public_model_contracts_cover_cli_shapes(self, tmp_path: Path) -> None: entry = m.Cli.CommandEntryModel(name="inspect", handler=lambda: True) def route_handler( - _params: m.Tests.SampleInput, + _params: p.Tests.SampleInput, ) -> p.Result[p.Tests.SampleOutput]: return r[p.Tests.SampleOutput].ok(m.Tests.SampleOutput(message="ok")) diff --git a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_03.py b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_03.py index 111e35ab7..63ef2d4ac 100644 --- a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_03.py +++ b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_03.py @@ -22,7 +22,7 @@ def test_public_pipeline_model_contracts(self, tmp_path: Path) -> None: context = cli.stage_context(tmp_path, settings={"mode": "test"}) def stage_handler( - current: m.Cli.PipelineStageContext, + current: p.Cli.PipelineStageContext, ) -> p.Result[p.Cli.PipelineStageResult]: return r[p.Cli.PipelineStageResult].ok( m.Cli.PipelineStageResult.model_validate({ diff --git a/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_01.py b/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_01.py index 7df8fb843..5bf86fbdd 100644 --- a/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_01.py +++ b/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_01.py @@ -11,7 +11,7 @@ from tests import u from flext_tests import tm -from tests import t +from tests import p, t diff --git a/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_03.py b/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_03.py index 7a1eb6057..bcfe87a47 100644 --- a/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_03.py +++ b/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_03.py @@ -11,7 +11,7 @@ from tests import u from flext_tests import tm -from tests import t +from tests import p, t diff --git a/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_04.py b/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_04.py index 6a989ba14..ce290f48a 100644 --- a/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_04.py +++ b/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_04.py @@ -8,7 +8,7 @@ from tests import u from flext_tests import tm -from tests import t +from tests import p, t diff --git a/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_01.py b/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_01.py index d11b217b3..2eff0a041 100644 --- a/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_01.py +++ b/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_01.py @@ -13,7 +13,7 @@ from collections.abc import Generator -from tests import t +from tests import p, t diff --git a/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_02.py b/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_02.py index 821d024fe..22efe2869 100644 --- a/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_02.py +++ b/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_02.py @@ -7,7 +7,7 @@ from flext_tests import tm from tests import u -from tests import t +from tests import p, t diff --git a/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_03.py b/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_03.py index f5b1ae9f1..d3bf610d9 100644 --- a/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_03.py +++ b/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_03.py @@ -10,7 +10,7 @@ from pathlib import Path -from tests import t +from tests import p, t diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py index bb89c536f..a31db3ffc 100644 --- a/tests/unit/conftest.py +++ b/tests/unit/conftest.py @@ -12,7 +12,7 @@ from collections.abc import Callable -from tests import t +from tests import p, t diff --git a/tests/unit/test_auth_utils_cov.py b/tests/unit/test_auth_utils_cov.py index aabc207f0..101c9643e 100644 --- a/tests/unit/test_auth_utils_cov.py +++ b/tests/unit/test_auth_utils_cov.py @@ -23,7 +23,7 @@ from tests import u from flext_tests import tm -from tests import t +from tests import p, t diff --git a/tests/unit/test_cmd_runtime_validation_branch_cov.py b/tests/unit/test_cmd_runtime_validation_branch_cov.py index 94f0157cb..fa608cf36 100644 --- a/tests/unit/test_cmd_runtime_validation_branch_cov.py +++ b/tests/unit/test_cmd_runtime_validation_branch_cov.py @@ -14,7 +14,7 @@ from tests import c from tests import m -from tests import t +from tests import p, t from tests import u from flext_tests import tm diff --git a/tests/unit/test_commands_utils_cov.py b/tests/unit/test_commands_utils_cov.py index 2676a92e6..2209738ba 100644 --- a/tests/unit/test_commands_utils_cov.py +++ b/tests/unit/test_commands_utils_cov.py @@ -20,7 +20,7 @@ from flext_cli import r from flext_tests import tm from tests import c -from tests import t +from tests import p, t from tests import u diff --git a/tests/unit/test_conversion_cov.py b/tests/unit/test_conversion_cov.py index 0991d5f83..3ae5e987d 100644 --- a/tests/unit/test_conversion_cov.py +++ b/tests/unit/test_conversion_cov.py @@ -12,7 +12,7 @@ from tests import m from tests import u -from tests import t +from tests import p, t diff --git a/tests/unit/test_files_cov.py b/tests/unit/test_files_cov.py index caba423e3..8dcdcf1ed 100644 --- a/tests/unit/test_files_cov.py +++ b/tests/unit/test_files_cov.py @@ -21,7 +21,7 @@ from pathlib import Path -from tests import t +from tests import p, t diff --git a/tests/unit/test_formatters_cov.py b/tests/unit/test_formatters_cov.py index d37316025..d28bf0831 100644 --- a/tests/unit/test_formatters_cov.py +++ b/tests/unit/test_formatters_cov.py @@ -21,7 +21,7 @@ from tests import c from flext_tests import tm -from tests import t +from tests import p, t diff --git a/tests/unit/test_json_cov.py b/tests/unit/test_json_cov.py index b193761f1..18b73ea10 100644 --- a/tests/unit/test_json_cov.py +++ b/tests/unit/test_json_cov.py @@ -7,7 +7,7 @@ import pytest from tests import m -from tests import t +from tests import p, t from tests import u from flext_tests import tm diff --git a/tests/unit/test_matching_cov.py b/tests/unit/test_matching_cov.py index 47556c72c..cf4daefcf 100644 --- a/tests/unit/test_matching_cov.py +++ b/tests/unit/test_matching_cov.py @@ -20,7 +20,7 @@ from tests import u from flext_tests import tm -from tests import t +from tests import p, t diff --git a/tests/unit/test_model_commands_cov.py b/tests/unit/test_model_commands_cov.py index 0041b1d75..4893c26ca 100644 --- a/tests/unit/test_model_commands_cov.py +++ b/tests/unit/test_model_commands_cov.py @@ -34,7 +34,7 @@ class TestsFlextCliModelCommandsCov: ) def test_derive_model_from_source_model_applies_defaults( self, - payload: m.Tests.ModelCommandSource, + payload: p.Tests.ModelCommandSource, expected_name: str, expected_value: int, ) -> None: @@ -94,7 +94,7 @@ def test_model_command_returns_callable(self) -> None: tm.that(callable(cmd), eq=True) def test_model_command_dispatches_to_handler_with_bound_model(self) -> None: - def handler(model: m.Tests.ModelCommandSample) -> str: + def handler(model: p.Tests.ModelCommandSample) -> str: return f"{model.name}-{model.value}" cmd = cli.model_command(m.Tests.ModelCommandSample, handler) @@ -102,7 +102,7 @@ def handler(model: m.Tests.ModelCommandSample) -> str: tm.that(cmd(name="x", value=3), eq="x-3") def test_model_command_applies_field_default_for_omitted_optional(self) -> None: - def handler(model: m.Tests.ModelCommandSample) -> int: + def handler(model: p.Tests.ModelCommandSample) -> int: return model.value cmd = cli.model_command(m.Tests.ModelCommandSample, handler) @@ -115,7 +115,7 @@ def test_model_command_resolves_values_without_mutating_settings(self) -> None: # resolved values reach the handler through the validated model. settings = m.Tests.ModelCommandSample(name="from_settings", value=0) - def handler(model: m.Tests.ModelCommandSample) -> str: + def handler(model: p.Tests.ModelCommandSample) -> str: return model.name cmd = cli.model_command(m.Tests.ModelCommandSample, handler, settings=settings) @@ -126,7 +126,7 @@ def handler(model: m.Tests.ModelCommandSample) -> str: tm.that(settings.value, eq=0) def test_model_command_raises_validation_error_for_missing_required(self) -> None: - def handler(model: m.Tests.ModelCommandRequired) -> str: + def handler(model: p.Tests.ModelCommandRequired) -> str: return model.key cmd = cli.model_command(m.Tests.ModelCommandRequired, handler) @@ -135,7 +135,7 @@ def handler(model: m.Tests.ModelCommandRequired) -> str: cmd() def test_model_command_binds_all_required_fields_to_model(self) -> None: - def handler(model: m.Tests.ModelCommandRequired) -> str: + def handler(model: p.Tests.ModelCommandRequired) -> str: return f"{model.key}={model.count}" cmd = cli.model_command(m.Tests.ModelCommandRequired, handler) diff --git a/tests/unit/test_options_cov.py b/tests/unit/test_options_cov.py index b41f299a4..73badcac6 100644 --- a/tests/unit/test_options_cov.py +++ b/tests/unit/test_options_cov.py @@ -23,7 +23,7 @@ from flext_cli import cli, m from tests import c -from tests import t +from tests import p, t from tests import u from flext_tests import tm diff --git a/tests/unit/test_options_public_cov.py b/tests/unit/test_options_public_cov.py index e58cea55e..7faefa35f 100644 --- a/tests/unit/test_options_public_cov.py +++ b/tests/unit/test_options_public_cov.py @@ -13,7 +13,7 @@ import pytest from flext_cli import c, m -from tests import t +from tests import p, t from tests import u from flext_tests import tm diff --git a/tests/unit/test_protocols.py b/tests/unit/test_protocols.py index 6827b0ab9..19f95f4b6 100644 --- a/tests/unit/test_protocols.py +++ b/tests/unit/test_protocols.py @@ -20,7 +20,7 @@ import pytest -from flext_cli import t +from flext_cli import p, t from tests import p, u from flext_tests import tm diff --git a/tests/unit/test_rules_cov.py b/tests/unit/test_rules_cov.py index d3af02b40..66abf4a57 100644 --- a/tests/unit/test_rules_cov.py +++ b/tests/unit/test_rules_cov.py @@ -19,7 +19,7 @@ from pathlib import Path -from tests import t +from tests import p, t diff --git a/tests/unit/test_runtime_utilities_core.py b/tests/unit/test_runtime_utilities_core.py index 5c6919a4b..1ea9c185b 100644 --- a/tests/unit/test_runtime_utilities_core.py +++ b/tests/unit/test_runtime_utilities_core.py @@ -13,7 +13,7 @@ from pathlib import Path -from tests import t +from tests import p, t @@ -45,7 +45,7 @@ def test_run_raw_remove_env_keys_strips_inherited_values( ids=m.Tests.RuntimeCommandCase.id_for, ) def test_run_raw_cases( - self, runner: u.Cli, tmp_path: Path, case: m.Tests.RuntimeCommandCase + self, runner: u.Cli, tmp_path: Path, case: p.Tests.RuntimeCommandCase ) -> None: cwd = tmp_path if case.use_tmp_path else None result = runner.run_raw( @@ -58,7 +58,7 @@ def test_run_raw_cases( if case.expect_success: output_raw: t.JsonPayload | None = tm.ok(result) tm.that(output_raw, is_=m.Cli.CommandOutput) - output: m.Cli.CommandOutput = output_raw + output: p.Cli.CommandOutput = output_raw if case.stdout_has: tm.that(output.stdout, has=case.stdout_has) if case.stderr_has: @@ -76,14 +76,14 @@ def test_run_raw_cases( ids=m.Tests.RuntimeCommandCase.id_for, ) def test_run_cases( - self, runner: u.Cli, tmp_path: Path, case: m.Tests.RuntimeCommandCase + self, runner: u.Cli, tmp_path: Path, case: p.Tests.RuntimeCommandCase ) -> None: cwd = tmp_path if case.use_tmp_path else None result = runner.run(case.command, cwd=cwd, timeout=case.timeout, env=case.env) if case.expect_success: output_raw: t.JsonPayload | None = tm.ok(result) tm.that(output_raw, is_=m.Cli.CommandOutput) - output: m.Cli.CommandOutput = output_raw + output: p.Cli.CommandOutput = output_raw if case.stdout_has: tm.that(output.stdout, has=case.stdout_has) if case.use_tmp_path: @@ -97,7 +97,7 @@ def test_run_cases( ids=m.Tests.RuntimeCommandCase.id_for, ) def test_capture_cases( - self, runner: u.Cli, tmp_path: Path, case: m.Tests.RuntimeCommandCase + self, runner: u.Cli, tmp_path: Path, case: p.Tests.RuntimeCommandCase ) -> None: cwd = tmp_path if case.use_tmp_path else None result = runner.capture( diff --git a/tests/unit/test_services_tables_branch_cov.py b/tests/unit/test_services_tables_branch_cov.py index 738013e42..a5bdbe050 100644 --- a/tests/unit/test_services_tables_branch_cov.py +++ b/tests/unit/test_services_tables_branch_cov.py @@ -15,7 +15,7 @@ from tests import c from flext_tests import tm -from flext_cli import t +from flext_cli import p, t diff --git a/tests/unit/test_tables.py b/tests/unit/test_tables.py index 20198dbd7..b2ca0299f 100644 --- a/tests/unit/test_tables.py +++ b/tests/unit/test_tables.py @@ -16,7 +16,7 @@ from flext_cli import cli from tests import c -from flext_cli import t +from flext_cli import p, t diff --git a/tests/unit/test_tables_branch_cov.py b/tests/unit/test_tables_branch_cov.py index e64d0739c..024dcbcab 100644 --- a/tests/unit/test_tables_branch_cov.py +++ b/tests/unit/test_tables_branch_cov.py @@ -6,7 +6,7 @@ from tests import c from tests import m -from tests import t +from tests import p, t from tests import u from flext_tests import tm @@ -56,7 +56,7 @@ def test_normalize_rejects_string_rows_as_data_invalid( tm.that((result.error or ""), has=c.Cli.OUTPUT_TABLE_DATA_INVALID) def test_render_returns_string_containing_cell_values( - self, two_column_config: m.Cli.TableConfig + self, two_column_config: p.Cli.TableConfig ) -> None: result = u.Cli.tables_render([{"Key": "a", "Value": 1}], two_column_config) @@ -87,7 +87,7 @@ def test_render_without_header_omits_header_labels(self) -> None: tm.that(rendered, has="a") def test_render_empty_rows_still_succeeds( - self, two_column_config: m.Cli.TableConfig + self, two_column_config: p.Cli.TableConfig ) -> None: result = u.Cli.tables_render([], two_column_config) @@ -95,7 +95,7 @@ def test_render_empty_rows_still_succeeds( tm.that(result.unwrap(), is_=str) def test_render_is_idempotent_for_same_input( - self, two_column_config: m.Cli.TableConfig + self, two_column_config: p.Cli.TableConfig ) -> None: rows: t.SequenceOf[t.Cli.TableRow] = [{"Key": "a", "Value": 1}] @@ -107,7 +107,7 @@ def test_render_is_idempotent_for_same_input( tm.that(first.unwrap(), eq=second.unwrap()) def test_resolve_config_returns_provided_settings_unchanged( - self, two_column_config: m.Cli.TableConfig + self, two_column_config: p.Cli.TableConfig ) -> None: result = u.Cli.tables_resolve_config(two_column_config) @@ -115,7 +115,7 @@ def test_resolve_config_returns_provided_settings_unchanged( tm.that(result.unwrap().headers, eq=("Key", "Value")) def test_resolve_config_reports_invalid_override_as_failure( - self, two_column_config: m.Cli.TableConfig + self, two_column_config: p.Cli.TableConfig ) -> None: result = u.Cli.tables_resolve_config(two_column_config, show_header="nope") @@ -123,7 +123,7 @@ def test_resolve_config_reports_invalid_override_as_failure( tm.that((result.error or ""), has=c.Cli.OUTPUT_TABLE_CONFIG_INVALID) def test_normalize_then_render_round_trips_mapping_source( - self, two_column_config: m.Cli.TableConfig + self, two_column_config: p.Cli.TableConfig ) -> None: normalized = u.Cli.tables_normalize_data({"alpha": 1}) tm.ok(normalized) diff --git a/tests/unit/test_tables_cov.py b/tests/unit/test_tables_cov.py index ad9d4eac9..5b62b567c 100644 --- a/tests/unit/test_tables_cov.py +++ b/tests/unit/test_tables_cov.py @@ -19,7 +19,7 @@ from tests import u from flext_tests import tm -from tests import t +from tests import p, t diff --git a/tests/unit/test_toml_sync_cov.py b/tests/unit/test_toml_sync_cov.py index bcd2f3d1e..8204be7c0 100644 --- a/tests/unit/test_toml_sync_cov.py +++ b/tests/unit/test_toml_sync_cov.py @@ -24,7 +24,7 @@ from tomlkit.items import Table -from tests import t +from tests import p, t diff --git a/tests/unit/test_toml_utilities.py b/tests/unit/test_toml_utilities.py index 14a1cb788..e30c2aaf4 100644 --- a/tests/unit/test_toml_utilities.py +++ b/tests/unit/test_toml_utilities.py @@ -19,7 +19,7 @@ from tests import u -from tests import t +from tests import p, t diff --git a/tests/unit/test_typings.py b/tests/unit/test_typings.py index 475949f58..6cb951086 100644 --- a/tests/unit/test_typings.py +++ b/tests/unit/test_typings.py @@ -17,7 +17,7 @@ from flext_tests import tm from tests import m -from tests import t +from tests import p, t from pathlib import Path @@ -111,14 +111,14 @@ def test_scalar_types_superset_primitive_types(self) -> None: def test_scalar_alias_validates_each_primitive(self) -> None: """The Scalar alias round-trips every primitive value.""" - adapter: m.TypeAdapter[t.Scalar] = m.TypeAdapter(t.Scalar) + adapter: p.TypeAdapter[t.Scalar] = m.TypeAdapter(t.Scalar) tm.that(adapter.validate_python("value"), eq="value") tm.that(adapter.validate_python(True), eq=True) tm.that(adapter.validate_python(3), eq=3) def test_optional_str_sequence_alias_accepts_value_and_none(self) -> None: """A ``StrSequence | None`` alias accepts both a sequence and None.""" - adapter: m.TypeAdapter[t.StrSequence | None] = m.TypeAdapter( + adapter: p.TypeAdapter[t.StrSequence | None] = m.TypeAdapter( t.StrSequence | None ) tm.that(adapter.validate_python(["alpha", "beta"]), eq=["alpha", "beta"]) @@ -126,7 +126,7 @@ def test_optional_str_sequence_alias_accepts_value_and_none(self) -> None: def test_mapping_alias_validates_sequence_of_typed_mappings(self) -> None: """MappingKV composes into a validatable sequence-of-mappings alias.""" - adapter: m.TypeAdapter[Sequence[t.MappingKV[str, str | int]]] = m.TypeAdapter( + adapter: p.TypeAdapter[Sequence[t.MappingKV[str, str | int]]] = m.TypeAdapter( Sequence[t.MappingKV[str, str | int]] ) validated = adapter.validate_python([{"name": "entry", "count": 1}]) diff --git a/tests/unit/test_utilities_cov.py b/tests/unit/test_utilities_cov.py index a545653d6..769b2bc09 100644 --- a/tests/unit/test_utilities_cov.py +++ b/tests/unit/test_utilities_cov.py @@ -13,7 +13,7 @@ import pytest from flext_tests import tm -from tests import t +from tests import p, t from tests import u diff --git a/tests/unit/test_yaml_cov.py b/tests/unit/test_yaml_cov.py index 14e3d5d78..dcb1c6600 100644 --- a/tests/unit/test_yaml_cov.py +++ b/tests/unit/test_yaml_cov.py @@ -25,7 +25,7 @@ from pathlib import Path -from tests import t +from tests import p, t diff --git a/tests/unit/test_yaml_roundtrip.py b/tests/unit/test_yaml_roundtrip.py index c1ef0f148..a5e9c0c17 100644 --- a/tests/unit/test_yaml_roundtrip.py +++ b/tests/unit/test_yaml_roundtrip.py @@ -14,7 +14,7 @@ import pytest from ruamel.yaml.comments import CommentedMap, CommentedSeq -from tests import t +from tests import p, t from tests import u from flext_tests import tm From d21a418f1056e10aa64b792485e5aaf19c9ca13c Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Thu, 16 Jul 2026 09:58:57 -0300 Subject: [PATCH 18/37] fix(models,constants): ConfigDict type from typings + direct _constants imports model_config annotations use t.ConfigDict (the typings alias) instead of the non-existent p.ConfigDict, which crashed flext_cli.m at import (FlextProtocols has no ConfigDict). 19 sites across _models/pipeline.py + _models/_base/*. Remove the now-unused p imports (their only use was p.ConfigDict). constants.py imports the 11 FlextCliConstants* classes directly from their _constants submodules (mirrors models.py), because the generated _constants barrel is empty; this unblocks the whole import chain. Impact: fixes an import-time crash cascading to every flext_cli consumer. Risk: low (ruff+pyrefly 0 on all 8 files; flext_cli.m loads again). --- .../_base/flextclimodelsbase_part_01.py | 16 +++++------ .../_base/flextclimodelsbase_part_02.py | 10 +++---- .../_base/flextclimodelsbase_part_03.py | 6 ++--- .../_base/flextclimodelsbase_part_05.py | 4 +-- .../_base/flextclimodelsbase_part_06.py | 4 +-- .../_base/flextclimodelsbase_part_07.py | 8 +++--- src/flext_cli/_models/pipeline.py | 10 +++---- src/flext_cli/constants.py | 27 ++++++++++--------- 8 files changed, 43 insertions(+), 42 deletions(-) diff --git a/src/flext_cli/_models/_base/flextclimodelsbase_part_01.py b/src/flext_cli/_models/_base/flextclimodelsbase_part_01.py index 145c3ddea..504c3f400 100644 --- a/src/flext_cli/_models/_base/flextclimodelsbase_part_01.py +++ b/src/flext_cli/_models/_base/flextclimodelsbase_part_01.py @@ -6,8 +6,8 @@ from types import MappingProxyType from typing import Annotated, ClassVar -from flext_cli import p, t -from flext_core import m, u, p +from flext_cli import t +from flext_core import m, u class FlextCliModelsBase: @@ -41,7 +41,7 @@ class CommandBytesOutput(m.Value): class RuntimeComponents(m.BaseModel): """Availability state for canonical CLI runtime components.""" - model_config: ClassVar[p.ConfigDict] = m.ConfigDict(extra="forbid", frozen=True) + model_config: ClassVar[t.ConfigDict] = m.ConfigDict(extra="forbid", frozen=True) settings: Annotated[str, m.Field(description="Settings component state")] formatters: Annotated[str, m.Field(description="Formatters component state")] prompts: Annotated[str, m.Field(description="Prompts component state")] @@ -50,7 +50,7 @@ class RuntimeComponents(m.BaseModel): class RuntimeStatus(m.BaseModel): """Canonical public CLI runtime status payload.""" - model_config: ClassVar[p.ConfigDict] = m.ConfigDict(extra="forbid", frozen=True) + model_config: ClassVar[t.ConfigDict] = m.ConfigDict(extra="forbid", frozen=True) status: Annotated[str, m.Field(description="Overall service state")] service: Annotated[str, m.Field(description="Service identifier")] timestamp: Annotated[str, m.Field(description="Status generation timestamp")] @@ -63,7 +63,7 @@ class RuntimeStatus(m.BaseModel): class DisplayData(m.BaseModel): """Key-value data for table/display — Pydantic v2 contract. Use m.Cli.DisplayData.""" - model_config: ClassVar[p.ConfigDict] = m.ConfigDict( + model_config: ClassVar[t.ConfigDict] = m.ConfigDict( extra="forbid", validate_assignment=True ) data: Annotated[ @@ -82,7 +82,7 @@ def _serialize(self) -> t.JsonMapping: class LoadedConfig(m.BaseModel): """Loaded configuration content wrapper — Pydantic v2 contract. Use m.Cli.LoadedConfig.""" - model_config: ClassVar[p.ConfigDict] = m.ConfigDict( + model_config: ClassVar[t.ConfigDict] = m.ConfigDict( extra="forbid", validate_assignment=True ) content: Annotated[ @@ -101,7 +101,7 @@ class CliNormalizedJson(m.RootModel[t.JsonValue]): ``model_serializer`` required. """ - model_config: ClassVar[p.ConfigDict] = m.ConfigDict(frozen=True) + model_config: ClassVar[t.ConfigDict] = m.ConfigDict(frozen=True) root: Annotated[ t.JsonValue, m.Field(description="Normalized JSON-compatible value") ] @@ -109,7 +109,7 @@ class CliNormalizedJson(m.RootModel[t.JsonValue]): class NormalizedJsonList(m.BaseModel): """Resolve normalized JSON to a dict with defaults. Use m.Cli.NormalizedJsonList.""" - model_config: ClassVar[p.ConfigDict] = m.ConfigDict( + model_config: ClassVar[t.ConfigDict] = m.ConfigDict( extra="forbid", validate_assignment=True ) value: Annotated[ diff --git a/src/flext_cli/_models/_base/flextclimodelsbase_part_02.py b/src/flext_cli/_models/_base/flextclimodelsbase_part_02.py index 8beab1020..d8e45d9c7 100644 --- a/src/flext_cli/_models/_base/flextclimodelsbase_part_02.py +++ b/src/flext_cli/_models/_base/flextclimodelsbase_part_02.py @@ -5,8 +5,8 @@ from types import MappingProxyType from typing import Annotated, ClassVar -from flext_cli import c, p, t -from flext_core import m, p, u +from flext_cli import c, t +from flext_core import m, u class FlextCliModelsBase: @@ -15,7 +15,7 @@ class FlextCliModelsBase: class PromptRuntimeState(m.FlexibleInternalModel): """Centralized runtime state for CLI prompt behavior.""" - model_config: ClassVar[p.ConfigDict] = m.ConfigDict( + model_config: ClassVar[t.ConfigDict] = m.ConfigDict( extra="forbid", validate_assignment=True ) @@ -32,7 +32,7 @@ class PromptRuntimeState(m.FlexibleInternalModel): class AuthCredentialsPayload(m.BaseModel): """Validated auth payload for token or username/password flows.""" - model_config: ClassVar[p.ConfigDict] = m.ConfigDict( + model_config: ClassVar[t.ConfigDict] = m.ConfigDict( extra="forbid", validate_assignment=True ) token: Annotated[ @@ -49,7 +49,7 @@ class AuthCredentialsPayload(m.BaseModel): class ProcessEnvironmentSpec(m.BaseModel): """Validated process environment contract for runtime command execution.""" - model_config: ClassVar[p.ConfigDict] = m.ConfigDict(extra="forbid", frozen=True) + model_config: ClassVar[t.ConfigDict] = m.ConfigDict(extra="forbid", frozen=True) base_env: Annotated[ t.StrMapping, m.Field( diff --git a/src/flext_cli/_models/_base/flextclimodelsbase_part_03.py b/src/flext_cli/_models/_base/flextclimodelsbase_part_03.py index 071c40e35..34b79add6 100644 --- a/src/flext_cli/_models/_base/flextclimodelsbase_part_03.py +++ b/src/flext_cli/_models/_base/flextclimodelsbase_part_03.py @@ -4,7 +4,7 @@ from typing import Annotated, ClassVar -from flext_cli import c, p, t +from flext_cli import c, t from flext_core import m @@ -14,7 +14,7 @@ class FlextCliModelsBase: class CommandEntryModel(m.BaseModel): """Single command entry: name + handler. Use m.Cli.CommandEntryModel.""" - model_config: ClassVar[p.ConfigDict] = m.ConfigDict( + model_config: ClassVar[t.ConfigDict] = m.ConfigDict( arbitrary_types_allowed=True, extra="forbid" ) name: Annotated[t.NonEmptyStr, m.Field(..., description="Command name")] @@ -25,7 +25,7 @@ class CommandEntryModel(m.BaseModel): class ResultCommandRoute(m.BaseModel): """Type-erased route contract for heterogeneous batch registration.""" - model_config: ClassVar[p.ConfigDict] = m.ConfigDict( + model_config: ClassVar[t.ConfigDict] = m.ConfigDict( arbitrary_types_allowed=True, extra="forbid", frozen=True ) name: Annotated[t.NonEmptyStr, m.Field(..., description="Command name")] diff --git a/src/flext_cli/_models/_base/flextclimodelsbase_part_05.py b/src/flext_cli/_models/_base/flextclimodelsbase_part_05.py index 32f2c323c..8af8f40c3 100644 --- a/src/flext_cli/_models/_base/flextclimodelsbase_part_05.py +++ b/src/flext_cli/_models/_base/flextclimodelsbase_part_05.py @@ -4,7 +4,7 @@ from typing import Annotated, ClassVar -from flext_cli import p +from flext_cli import t from flext_core import m @@ -14,7 +14,7 @@ class FlextCliModelsBase: class SettingsSnapshot(m.Value): """Snapshot of current CLI settings information.""" - model_config: ClassVar[p.ConfigDict] = m.ConfigDict(frozen=True, extra="forbid") + model_config: ClassVar[t.ConfigDict] = m.ConfigDict(frozen=True, extra="forbid") settings_dir: Annotated[str, m.Field(description="Settings directory path")] = ( "" diff --git a/src/flext_cli/_models/_base/flextclimodelsbase_part_06.py b/src/flext_cli/_models/_base/flextclimodelsbase_part_06.py index ef699cad6..718fbacc0 100644 --- a/src/flext_cli/_models/_base/flextclimodelsbase_part_06.py +++ b/src/flext_cli/_models/_base/flextclimodelsbase_part_06.py @@ -4,7 +4,7 @@ from typing import Annotated, ClassVar -from flext_cli import p, t +from flext_cli import t from flext_core import m @@ -61,7 +61,7 @@ def params(self) -> t.JsonMapping: class OptionMetadata(m.BaseModel): """Validated option-registry metadata for Typer option generation.""" - model_config: ClassVar[p.ConfigDict] = m.ConfigDict(extra="ignore", frozen=True) + model_config: ClassVar[t.ConfigDict] = m.ConfigDict(extra="ignore", frozen=True) help: Annotated[ str, m.Field("", description="Option help text", strict=True) diff --git a/src/flext_cli/_models/_base/flextclimodelsbase_part_07.py b/src/flext_cli/_models/_base/flextclimodelsbase_part_07.py index f7897d9d9..ef3fa8c54 100644 --- a/src/flext_cli/_models/_base/flextclimodelsbase_part_07.py +++ b/src/flext_cli/_models/_base/flextclimodelsbase_part_07.py @@ -6,8 +6,8 @@ from types import MappingProxyType from typing import Annotated, ClassVar -from flext_cli import c, p, t -from flext_core import m, p, u +from flext_cli import c, t +from flext_core import m, u _EMPTY_JSON_MAPPING: t.JsonMapping = MappingProxyType({}) @@ -18,7 +18,7 @@ class FlextCliModelsBase: class LogLevelResolved(m.BaseModel): """Single contract for log level string.""" - model_config: ClassVar[p.ConfigDict] = m.ConfigDict(extra="forbid") + model_config: ClassVar[t.ConfigDict] = m.ConfigDict(extra="forbid") raw: Annotated[ str | None, m.Field(None, description="Raw log level input string") ] @@ -43,7 +43,7 @@ def resolve(self) -> str: class TypedExtract(m.BaseModel): """Single contract for typed value extraction (str | bool | dict).""" - model_config: ClassVar[p.ConfigDict] = m.ConfigDict(extra="forbid") + model_config: ClassVar[t.ConfigDict] = m.ConfigDict(extra="forbid") type_kind: Annotated[t.Cli.TypeKind, m.Field(description="Requested type")] value: Annotated[ t.JsonValue | None, m.Field(None, description="Value to extract and coerce") diff --git a/src/flext_cli/_models/pipeline.py b/src/flext_cli/_models/pipeline.py index 08e327a64..f56e41c2e 100644 --- a/src/flext_cli/_models/pipeline.py +++ b/src/flext_cli/_models/pipeline.py @@ -8,7 +8,7 @@ from typing import Annotated, ClassVar from flext_cli import c, p, t -from flext_core import m, p, u +from flext_core import m, u class FlextCliModelsPipeline: @@ -17,7 +17,7 @@ class FlextCliModelsPipeline: class PipelineStageContext(m.ContractModel): """Accumulated state passed between pipeline stages.""" - model_config: ClassVar[p.ConfigDict] = m.ConfigDict( + model_config: ClassVar[t.ConfigDict] = m.ConfigDict( extra="forbid", validate_assignment=True, arbitrary_types_allowed=True ) @@ -40,7 +40,7 @@ class PipelineStageContext(m.ContractModel): class PipelineStageSpec(m.ContractModel): """Declarative stage definition with dependency tracking.""" - model_config: ClassVar[p.ConfigDict] = m.ConfigDict( + model_config: ClassVar[t.ConfigDict] = m.ConfigDict( extra="forbid", arbitrary_types_allowed=True ) @@ -78,7 +78,7 @@ class PipelineStageSpec(m.ContractModel): class PipelineStageResult(m.ContractModel): """What a stage produces after execution.""" - model_config: ClassVar[p.ConfigDict] = m.ConfigDict(extra="forbid") + model_config: ClassVar[t.ConfigDict] = m.ConfigDict(extra="forbid") stage_id: Annotated[str, m.Field(description="Stage that produced this result")] status: Annotated[ @@ -104,7 +104,7 @@ class PipelineStageResult(m.ContractModel): class PipelineResult(m.ContractModel): """Full pipeline execution result — aggregated from all stages.""" - model_config: ClassVar[p.ConfigDict] = m.ConfigDict(extra="forbid") + model_config: ClassVar[t.ConfigDict] = m.ConfigDict(extra="forbid") stages: Annotated[ t.SequenceOf[FlextCliModelsPipeline.PipelineStageResult], diff --git a/src/flext_cli/constants.py b/src/flext_cli/constants.py index b8da7c8fa..f7ab5351d 100644 --- a/src/flext_cli/constants.py +++ b/src/flext_cli/constants.py @@ -2,19 +2,20 @@ from __future__ import annotations -from ._constants import ( - FlextCliConstantsBase, - FlextCliConstantsConfig, - FlextCliConstantsEnums, - FlextCliConstantsErrors, - FlextCliConstantsExceptions, - FlextCliConstantsFiles, - FlextCliConstantsOutput, - FlextCliConstantsPipeline, - FlextCliConstantsSettings, - FlextCliConstantsXlsx, - FlextCliConstantsXlsxFutureFunctions, -) +# NOTE (mro-0ftd.3.7.2, operator-authorized cross-lane fix): import direct from +# submodules (mirrors models.py) because the generated ._constants barrel is empty +# (__all__ = ()); the codegen that would repopulate it is itself blocked by this break. +from ._constants.base import FlextCliConstantsBase +from ._constants.config import FlextCliConstantsConfig +from ._constants.enums import FlextCliConstantsEnums +from ._constants.errors import FlextCliConstantsErrors +from ._constants.exceptions import FlextCliConstantsExceptions +from ._constants.files import FlextCliConstantsFiles +from ._constants.output import FlextCliConstantsOutput +from ._constants.pipeline import FlextCliConstantsPipeline +from ._constants.settings import FlextCliConstantsSettings +from ._constants.xlsx import FlextCliConstantsXlsx +from ._constants.xlsx_future_functions import FlextCliConstantsXlsxFutureFunctions from flext_core import c, t From 70cef39851f40273595143f72337c7c4da9b6320 Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Thu, 16 Jul 2026 10:18:21 -0300 Subject: [PATCH 19/37] fixes --- examples/_models_parts/examples_advanced.py | 2 +- examples/_models_parts/examples_common.py | 2 +- examples/_models_parts/examples_database.py | 2 +- examples/constants.py | 2 +- examples/utilities.py | 2 +- .../_options/flextcliutilitiesoptionbuilder_part_01.py | 2 +- src/flext_cli/_utilities/_xlxx/xlsx_style_builders.py | 2 +- src/flext_cli/base.py | 2 +- tests/_constants_parts/tests_core.py | 2 +- tests/_models_parts/tests_runtime.py | 4 ++-- tests/_models_parts/tests_version.py | 2 +- 11 files changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/_models_parts/examples_advanced.py b/examples/_models_parts/examples_advanced.py index 99f970bbe..b649450af 100644 --- a/examples/_models_parts/examples_advanced.py +++ b/examples/_models_parts/examples_advanced.py @@ -19,7 +19,7 @@ class ExamplesFlextCliModelsExamplesAdvanced: class AppSettingsAdvanced(m.Value): """Advanced application settings — Pydantic v2 only.""" - model_config: ClassVar[p.ConfigDict] = m.ConfigDict( + model_config: ClassVar[t.ConfigDict] = m.ConfigDict( extra="forbid", validate_assignment=True, ) diff --git a/examples/_models_parts/examples_common.py b/examples/_models_parts/examples_common.py index 5352e7191..d5a663e36 100644 --- a/examples/_models_parts/examples_common.py +++ b/examples/_models_parts/examples_common.py @@ -54,7 +54,7 @@ def merge_env_overrides( class MyAppSettings(m.Value): """Custom settings for YOUR CLI application — Pydantic v2 only.""" - model_config: ClassVar[p.ConfigDict] = m.ConfigDict( + model_config: ClassVar[t.ConfigDict] = m.ConfigDict( extra="forbid", validate_assignment=True, ) diff --git a/examples/_models_parts/examples_database.py b/examples/_models_parts/examples_database.py index 19a8f3965..ce880db66 100644 --- a/examples/_models_parts/examples_database.py +++ b/examples/_models_parts/examples_database.py @@ -15,7 +15,7 @@ class ExamplesFlextCliModelsExamplesDatabase: class AdvancedDatabaseConfig(m.Value): """Database configuration with advanced validation.""" - model_config: ClassVar[p.ConfigDict] = m.ConfigDict( + model_config: ClassVar[t.ConfigDict] = m.ConfigDict( extra="forbid", validate_assignment=True, ) diff --git a/examples/constants.py b/examples/constants.py index 4754d3b4c..21699704d 100644 --- a/examples/constants.py +++ b/examples/constants.py @@ -3,7 +3,7 @@ from __future__ import annotations import re -from enum import StrEnum, p, unique +from enum import StrEnum, unique from types import MappingProxyType from typing import TYPE_CHECKING, Final diff --git a/examples/utilities.py b/examples/utilities.py index a9b26dd5f..dc718a938 100644 --- a/examples/utilities.py +++ b/examples/utilities.py @@ -13,7 +13,7 @@ from typing import TYPE_CHECKING -from examples import c, m, t +from examples import c, m, p, t from flext_cli import cli, u from collections.abc import ( diff --git a/src/flext_cli/_utilities/_options/flextcliutilitiesoptionbuilder_part_01.py b/src/flext_cli/_utilities/_options/flextcliutilitiesoptionbuilder_part_01.py index 75713f4c8..24340dff1 100644 --- a/src/flext_cli/_utilities/_options/flextcliutilitiesoptionbuilder_part_01.py +++ b/src/flext_cli/_utilities/_options/flextcliutilitiesoptionbuilder_part_01.py @@ -2,7 +2,7 @@ from __future__ import annotations -from flext_cli import c, m, t +from flext_cli import c, m, p, t class FlextCliUtilitiesOptionBuilder: diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_style_builders.py b/src/flext_cli/_utilities/_xlxx/xlsx_style_builders.py index 6c99c684d..0b85f26f0 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_style_builders.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_style_builders.py @@ -1,7 +1,7 @@ """Translate typed visual style models into openpyxl objects.""" from __future__ import annotations - +from flext_cli import p from openpyxl.styles import Alignment, Border, Color, Font, GradientFill, NamedStyle from openpyxl.styles.borders import Side from openpyxl.styles.fills import PatternFill, Stop diff --git a/src/flext_cli/base.py b/src/flext_cli/base.py index 75368000f..1b9286db7 100644 --- a/src/flext_cli/base.py +++ b/src/flext_cli/base.py @@ -9,7 +9,7 @@ from __future__ import annotations -from flext_cli import m, t +from flext_cli import m, p, t from flext_core import p, s diff --git a/tests/_constants_parts/tests_core.py b/tests/_constants_parts/tests_core.py index f2ffcbbfc..a83abcd06 100644 --- a/tests/_constants_parts/tests_core.py +++ b/tests/_constants_parts/tests_core.py @@ -3,7 +3,7 @@ from __future__ import annotations import re -from enum import StrEnum, p, unique +from enum import StrEnum, unique from types import MappingProxyType from typing import TYPE_CHECKING, Final diff --git a/tests/_models_parts/tests_runtime.py b/tests/_models_parts/tests_runtime.py index 62d17ecdd..f703e78a2 100644 --- a/tests/_models_parts/tests_runtime.py +++ b/tests/_models_parts/tests_runtime.py @@ -14,7 +14,7 @@ class TestsFlextCliModelsRuntime: class ApiResponse(m.BaseModel): """API response for type scenario tests -- Pydantic v2.""" - model_config: ClassVar[p.ConfigDict] = m.ConfigDict(extra="forbid") + model_config: ClassVar[t.ConfigDict] = m.ConfigDict(extra="forbid") status: Annotated[str, m.Field(description="Status")] data: Annotated[t.JsonMapping | None, m.Field(description="Payload")] = None message: Annotated[str, m.Field(description="Message")] @@ -47,7 +47,7 @@ class ModelCommandRequired(m.BaseModel): class RuntimeCommandCase(m.BaseModel): """Runtime command parametrization case.""" - model_config: ClassVar[p.ConfigDict] = m.ConfigDict(frozen=True) + model_config: ClassVar[t.ConfigDict] = m.ConfigDict(frozen=True) case_id: Annotated[str, m.Field(description="Pytest case id")] command: Annotated[t.StrSequence, m.Field(description="Command argv")] diff --git a/tests/_models_parts/tests_version.py b/tests/_models_parts/tests_version.py index 87b15398e..11780a763 100644 --- a/tests/_models_parts/tests_version.py +++ b/tests/_models_parts/tests_version.py @@ -17,7 +17,7 @@ class TestsFlextCliModelsVersion: class VersionTestScenario(m.BaseModel): """Version test scenario data.""" - model_config: ClassVar[p.ConfigDict] = m.ConfigDict(frozen=True) + model_config: ClassVar[t.ConfigDict] = m.ConfigDict(frozen=True) name: Annotated[str, m.Field(description="Scenario name")] version_string: Annotated[ From df9aefde20987a9f373bf66435084eb94059ad4b Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Thu, 16 Jul 2026 16:10:54 -0300 Subject: [PATCH 20/37] feat(cli): add TOML operation domain models to flext-cli (m.Cli.Toml*) flext-cli owns the TOML domain. Add the declarative TOML operation models (TomlSetOp/TomlListOp/TomlRemoveOp/TomlOperation/TomlPhaseConfig + Builder DSL) and their enums (c.Cli.TomlOperationKind/TomlMergeMode), composed into m.Cli / c.Cli via MRO. These supersede the duplicated flext-infra models; downstream projects will consume m.Cli.Toml* directly (net-negative LOC). Tracked mro-gzj0. --- src/flext_cli/_constants/enums.py | 16 ++ src/flext_cli/_models/toml.py | 237 ++++++++++++++++++++++++++++++ src/flext_cli/models.py | 2 + 3 files changed, 255 insertions(+) create mode 100644 src/flext_cli/_models/toml.py diff --git a/src/flext_cli/_constants/enums.py b/src/flext_cli/_constants/enums.py index b0c68ad33..cc460f856 100644 --- a/src/flext_cli/_constants/enums.py +++ b/src/flext_cli/_constants/enums.py @@ -121,5 +121,21 @@ class MessageStyles(StrEnum): BOLD_WHITE = "bold white" BOLD_WHITE_ON_BLUE = "bold white on blue" + @unique + class TomlOperationKind(StrEnum): + """SSOT TOML phase operation kinds.""" + + SET = "set" + LIST = "list" + REMOVE = "remove" + + @unique + class TomlMergeMode(StrEnum): + """SSOT merge strategies for TOML list synchronization.""" + + REPLACE = "replace" + ADDITIVE = "additive" + MERGE = "merge" + __all__: list[str] = ["FlextCliConstantsEnums"] diff --git a/src/flext_cli/_models/toml.py b/src/flext_cli/_models/toml.py new file mode 100644 index 000000000..dfa4c545b --- /dev/null +++ b/src/flext_cli/_models/toml.py @@ -0,0 +1,237 @@ +"""Generic TOML operation models with Builder DSL, flat in ``m.Cli.Toml*``. + +flext-cli owns the TOML domain: these declarative operation models +(``TomlSetOp`` / ``TomlListOp`` / ``TomlRemoveOp`` / ``TomlOperation`` / +``TomlPhaseConfig``) are consumed by any project that syncs a TOML document, +paired with the ``u.Cli.toml_*`` utilities and ``t.Cli.Toml*`` types. + +Copyright (c) 2025 FLEXT Team. All rights reserved. +SPDX-License-Identifier: MIT +""" + +from __future__ import annotations + +from collections.abc import Callable +from itertools import chain +from typing import Annotated, Literal, Self + +from flext_core import m, t + +from flext_cli._constants.enums import FlextCliConstantsEnums as _enum + +# Pyproject "tool" table name — the default TOML root for tool configuration. +_TOOL_TABLE: str = "tool" + + +class FlextCliModelsToml: + """TOML operation models exposed FLAT through ``m.Cli.Toml*``.""" + + class TomlSetOp(m.ContractModel): + """Set one TOML key to one JSON-compatible value.""" + + kind: Literal[_enum.TomlOperationKind.SET] = m.Field( + _enum.TomlOperationKind.SET, + description="Operation kind", + validate_default=True, + ) + key: str = m.Field(description="TOML key name") + value: t.JsonValue = m.Field(description="JSON-compatible value") + + class TomlListOp(m.ContractModel): + """Set or merge one TOML string list.""" + + kind: Literal[_enum.TomlOperationKind.LIST] = m.Field( + _enum.TomlOperationKind.LIST, + description="Operation kind", + validate_default=True, + ) + key: str = m.Field(description="TOML key name") + values: t.StrSequence = m.Field(description="Expected values") + strategy: Annotated[ + _enum.TomlMergeMode, + m.Field(description="Merge strategy", validate_default=True), + ] = _enum.TomlMergeMode.REPLACE + sort: Annotated[ + bool, + m.Field(description="Sort values before sync", validate_default=True), + ] = True + + class TomlRemoveOp(m.ContractModel): + """Remove one TOML key, optionally from a nested relative table.""" + + kind: Literal[_enum.TomlOperationKind.REMOVE] = m.Field( + _enum.TomlOperationKind.REMOVE, + description="Operation kind", + validate_default=True, + ) + key: str = m.Field(description="Key to remove") + table_path: Annotated[ + t.StrSequence, + m.Field(description="Relative sub-table path", validate_default=True), + ] = () + + type TomlOperation = Annotated[ + TomlSetOp | TomlListOp | TomlRemoveOp, m.Field(discriminator="kind") + ] + + class TomlPhaseConfig(m.ContractModel): + """Declarative TOML phase with inline Builder DSL.""" + + name: str = m.Field(description="Phase name") + root_path: Annotated[ + t.StrSequence, m.Field(description="Root path before table_path") + ] = (_TOOL_TABLE,) + table_path: Annotated[ + t.StrSequence, m.Field(description="Primary table path") + ] = () + operations: Annotated[ + t.SequenceOf[FlextCliModelsToml.TomlOperation], + m.Field(description="Declarative TOML operations"), + ] = () + nested_tables: Annotated[ + t.SequenceOf[FlextCliModelsToml.TomlPhaseConfig], + m.Field(description="Nested TOML phase configs"), + ] = () + custom_handler: Annotated[ + Callable[..., t.StrSequence] | None, + m.Field(exclude=True, description="Custom handler"), + ] = None + + class Builder(m.Builder.Identity["FlextCliModelsToml.TomlPhaseConfig"]): + """Fluent builder for ``m.Cli.TomlPhaseConfig``.""" + + def __init__(self, name: str) -> None: + super().__init__(state=FlextCliModelsToml.TomlPhaseConfig(name=name)) + + @classmethod + def _nested_operations( + cls, + *, + values: t.SequenceOf[tuple[str, t.JsonValue]] = (), + lists: t.SequenceOf[t.StrSequencePair] = (), + deprecated_keys: t.StrSequence = (), + ) -> tuple[FlextCliModelsToml.TomlOperation, ...]: + """Nested operations.""" + return tuple( + chain( + ( + FlextCliModelsToml.TomlSetOp(key=key, value=value) + for key, value in values + ), + ( + FlextCliModelsToml.TomlListOp( + key=key, values=tuple(entries) + ) + for key, entries in lists + ), + ( + FlextCliModelsToml.TomlRemoveOp(key=key) + for key in deprecated_keys + ), + ) + ) + + def operation( + self, + operation_type: type[m.ContractModel], + /, + **data: t.JsonValue | t.JsonPayload | t.SequenceOf[t.JsonPayload], + ) -> Self: + """Operation.""" + operation_item = operation_type.model_validate(data) + replaced: Self = self._replace( + self.state.model_copy( + update={ + "operations": ( + *self.state.operations, + operation_item, + ) + } + ) + ) + return replaced + + def root(self, *path: str) -> Self: + """Root.""" + result: Self = self._path("root_path", *path) + return result + + def table(self, *path: str) -> Self: + """Table.""" + result: Self = self._path("table_path", *path) + return result + + def value(self, key: str, value: t.JsonValue) -> Self: + """Value.""" + return self.operation( + FlextCliModelsToml.TomlSetOp, + key=key, + value=value, + ) + + def list( + self, + key: str, + values: t.StrSequence, + *, + strategy: _enum.TomlMergeMode = _enum.TomlMergeMode.REPLACE, + sort: bool = True, + ) -> Self: + """List.""" + return self.operation( + FlextCliModelsToml.TomlListOp, + key=key, + values=tuple(values), + strategy=strategy, + sort=sort, + ) + + def deprecated(self, key: str, *sub_path: str) -> Self: + """Mark a key as deprecated by scheduling its removal.""" + return self.operation( + FlextCliModelsToml.TomlRemoveOp, + key=key, + table_path=tuple(sub_path), + ) + + def nested( + self, + *path: str, + values: t.SequenceOf[tuple[str, t.JsonValue]] = (), + lists: t.SequenceOf[t.StrSequencePair] = (), + deprecated_keys: t.StrSequence = (), + ) -> Self: + """Nested.""" + nested_table = FlextCliModelsToml.TomlPhaseConfig( + name=self.state.name, + root_path=(), + table_path=tuple(path), + operations=tuple( + self._nested_operations( + values=values, + lists=lists, + deprecated_keys=deprecated_keys, + ) + ), + ) + replaced: Self = self._replace( + self.state.model_copy( + update={ + "nested_tables": ( + *self.state.nested_tables, + nested_table, + ) + } + ) + ) + return replaced + + def handler(self, fn: Callable[..., t.StrSequence]) -> Self: + """Set a custom handler function.""" + replaced: Self = self._replace( + self.state.model_copy(update={"custom_handler": fn}) + ) + return replaced + + +__all__: list[str] = ["FlextCliModelsToml"] diff --git a/src/flext_cli/models.py b/src/flext_cli/models.py index d5104ec26..821fdcc0e 100644 --- a/src/flext_cli/models.py +++ b/src/flext_cli/models.py @@ -7,6 +7,7 @@ from flext_cli._models.pipeline import FlextCliModelsPipeline from flext_cli._models.rules import FlextCliModelsRules from flext_cli._models.template import FlextCliModelsTemplate +from flext_cli._models.toml import FlextCliModelsToml from flext_cli._models.xlsx import FlextCliModelsXlsx from flext_core import m @@ -19,6 +20,7 @@ class Cli( FlextCliModelsRules, FlextCliModelsBase, FlextCliModelsTemplate, + FlextCliModelsToml, FlextCliModelsXlsx, ): """CLI project namespace.""" From 7b78ae751a47044d03a3c02be6428ccc7a8c5430 Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Thu, 16 Jul 2026 16:17:35 -0300 Subject: [PATCH 21/37] feat(cli): add TOML operation protocols to flext-cli (p.Cli.Toml*) Structural contracts mirroring the m.Cli.Toml* operation models (TomlSetOp/TomlListOp/TomlRemoveOp/TomlOperation/TomlPhaseConfig), composed into p.Cli via the pure-MRO protocols facade. Consumers type against p.Cli.Toml* (DIP) instead of the concrete m classes; this supersedes the absent p.Infra.Deps.Toml.* protocols in flext-infra. Tracked mro-gzj0. --- src/flext_cli/_protocols/toml.py | 129 +++++++++++++++++++++++++++++++ src/flext_cli/protocols.py | 2 + 2 files changed, 131 insertions(+) create mode 100644 src/flext_cli/_protocols/toml.py diff --git a/src/flext_cli/_protocols/toml.py b/src/flext_cli/_protocols/toml.py new file mode 100644 index 000000000..a61f3224f --- /dev/null +++ b/src/flext_cli/_protocols/toml.py @@ -0,0 +1,129 @@ +"""Structural protocols for the generic TOML operation domain (``p.Cli.Toml*``). + +Field-level contracts mirroring the ``m.Cli.Toml*`` operation models. Consumers +type against these protocols (``p.Cli.TomlPhaseConfig`` etc.) and never against +the concrete ``m`` classes (DIP). No project imports — foundation purity. + +Copyright (c) 2025 FLEXT Team. All rights reserved. +SPDX-License-Identifier: MIT +""" + +from __future__ import annotations + +from collections.abc import Callable +from typing import Protocol, runtime_checkable + +from flext_cli._constants.enums import FlextCliConstantsEnums as ce +from flext_core import t + + +class FlextCliProtocolsToml: + """TOML operation protocol namespace (structural; flat in ``p.Cli.Toml*``).""" + + @runtime_checkable + class TomlSetOp(Protocol): + """Set one TOML key to one JSON-compatible value.""" + + @property + def kind(self) -> ce.TomlOperationKind: + """Operation kind.""" + ... + + @property + def key(self) -> str: + """TOML key name.""" + ... + + @property + def value(self) -> t.JsonValue: + """JSON-compatible value.""" + ... + + @runtime_checkable + class TomlListOp(Protocol): + """Set or merge one TOML string list.""" + + @property + def kind(self) -> ce.TomlOperationKind: + """Operation kind.""" + ... + + @property + def key(self) -> str: + """TOML key name.""" + ... + + @property + def values(self) -> t.StrSequence: + """Expected values.""" + ... + + @property + def strategy(self) -> ce.TomlMergeMode: + """Merge strategy.""" + ... + + @property + def sort(self) -> bool: + """Sort values before sync.""" + ... + + @runtime_checkable + class TomlRemoveOp(Protocol): + """Remove one TOML key, optionally from a nested relative table.""" + + @property + def kind(self) -> ce.TomlOperationKind: + """Operation kind.""" + ... + + @property + def key(self) -> str: + """Key to remove.""" + ... + + @property + def table_path(self) -> t.StrSequence: + """Relative sub-table path.""" + ... + + type TomlOperation = TomlSetOp | TomlListOp | TomlRemoveOp + + @runtime_checkable + class TomlPhaseConfig(Protocol): + """Declarative TOML phase surface.""" + + @property + def name(self) -> str: + """Phase name.""" + ... + + @property + def root_path(self) -> t.StrSequence: + """Root path before table_path.""" + ... + + @property + def table_path(self) -> t.StrSequence: + """Primary table path.""" + ... + + @property + def operations(self) -> t.SequenceOf[FlextCliProtocolsToml.TomlOperation]: + """Declarative TOML operations.""" + ... + + @property + def nested_tables( + self, + ) -> t.SequenceOf[FlextCliProtocolsToml.TomlPhaseConfig]: + """Nested TOML phase configs.""" + ... + + @property + def custom_handler(self) -> Callable[..., t.StrSequence] | None: + """Custom handler.""" + ... + + +__all__: list[str] = ["FlextCliProtocolsToml"] diff --git a/src/flext_cli/protocols.py b/src/flext_cli/protocols.py index 38cc6e6f7..77a75ef62 100644 --- a/src/flext_cli/protocols.py +++ b/src/flext_cli/protocols.py @@ -8,6 +8,7 @@ from flext_cli._protocols.framework import FlextCliProtocolsFramework from flext_cli._protocols.pipeline import FlextCliProtocolsPipeline from flext_cli._protocols.xlsx import FlextCliProtocolsXlsx +from flext_cli._protocols.toml import FlextCliProtocolsToml from flext_core import p @@ -25,6 +26,7 @@ class Cli( FlextCliProtocolsBase, FlextCliProtocolsConfig, FlextCliProtocolsXlsx, + FlextCliProtocolsToml, ): """Unified CLI protocol namespace.""" From 329e4e4bc36a880fdd9ce53df4923a92e7b5f2cf Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Thu, 16 Jul 2026 20:36:18 -0300 Subject: [PATCH 22/37] fixes --- examples/ex_01_getting_started.py | 4 +-- examples/ex_04_file_operations.py | 8 ++--- examples/ex_11_complete_integration.py | 4 +-- examples/utilities.py | 4 +-- src/flext_cli/_constants/config.py | 6 ++-- src/flext_cli/_constants/errors.py | 6 ++-- src/flext_cli/_constants/files.py | 12 +++---- .../_base/flextclimodelsbase_part_01.py | 10 +++--- src/flext_cli/_models/toml.py | 27 ++++------------ .../_base/flextcliprotocolsbase_part_01.py | 2 +- src/flext_cli/_protocols/toml.py | 4 +-- src/flext_cli/_protocols/xlsx.py | 2 +- ...liutilitiesfiletesthelpersmixin_part_01.py | 8 ++--- ...liutilitiesfiletesthelpersmixin_part_04.py | 6 ++-- .../_files/flextcliutilitiesfiles_part_01.py | 26 +++++++-------- .../_files/flextcliutilitiesfiles_part_02.py | 4 +-- .../_files/flextcliutilitiesfiles_part_04.py | 6 ++-- src/flext_cli/_utilities/_json/_core.py | 4 +-- .../flextcliutilitiesoptions_part_01.py | 2 +- .../flextcliutilitiesoptions_part_02.py | 4 +-- src/flext_cli/_utilities/template.py | 20 ++++++------ src/flext_cli/_utilities/yaml.py | 4 +-- src/flext_cli/_utilities/yaml_model.py | 2 +- src/flext_cli/services/auth.py | 4 +-- src/flext_cli/services/file_tools.py | 32 +++++++++---------- tests/test_yaml_model_write.py | 4 +-- .../testsflextcliexamplessmoke_part_01.py | 2 +- .../testsflextclifilescov_part_01.py | 26 +++++++-------- .../testsflextclijsoncov_part_01.py | 4 +-- ...flextclipubliccontractscoverage_part_02.py | 6 ++-- tests/unit/test_config_engine.py | 4 +-- tests/unit/test_file_tools_yaml.py | 10 +++--- tests/unit/test_files_cov.py | 22 ++++++------- tests/unit/test_json_cov.py | 4 +-- tests/unit/test_options_public_cov.py | 2 +- 35 files changed, 139 insertions(+), 156 deletions(-) diff --git a/examples/ex_01_getting_started.py b/examples/ex_01_getting_started.py index 076ccff2a..b45447c06 100644 --- a/examples/ex_01_getting_started.py +++ b/examples/ex_01_getting_started.py @@ -39,10 +39,10 @@ def persist_example_settings( wrapped_config = m.Cli.LoadedConfig(content=settings.model_dump(mode="json")) with TemporaryDirectory(prefix=f"{c.EXAMPLE_DEFAULT_TEMP_SUBDIR}-") as temp_dir: config_path = Path(temp_dir) / "settings.json" - return cli.write_json_file( + return cli.json_write_file( str(config_path), wrapped_config.model_dump(mode="json") ).flat_map( - lambda _: cli.read_json_model(str(config_path), m.Cli.LoadedConfig) + lambda _: cli.json_read_model(str(config_path), m.Cli.LoadedConfig) ) @override diff --git a/examples/ex_04_file_operations.py b/examples/ex_04_file_operations.py index b81619ce4..f87f61b3e 100644 --- a/examples/ex_04_file_operations.py +++ b/examples/ex_04_file_operations.py @@ -35,7 +35,7 @@ def save_user_preferences( # with open(config_file, 'w') as f: # json.dump(preferences, f) - write_result = cli.write_json_file( + write_result = cli.json_write_file( config_file, u.normalize_to_json_value(preferences), ) @@ -58,7 +58,7 @@ def load_user_preferences(config_dir: Path) -> p.Result[p.Cli.LoadedConfig]: """Load user preferences from JSON in YOUR app. Returns r[LoadedConfig]; no None.""" config_file = config_dir / "preferences.json" - read_result = cli.read_json_file(config_file) + read_result = cli.json_read_file(config_file) if read_result.failure: cli.print( @@ -95,7 +95,7 @@ def save_deployment_config( # yaml.dump(settings, f) # Normalize the mapping into the CLI JSON contract before writing YAML. - write_result = cli.write_yaml_file( + write_result = cli.yaml_write_file( config_file, u.normalize_to_json_value(settings), ) @@ -130,7 +130,7 @@ def load_deployment_config(config_file: Path) -> p.Result[p.Cli.LoadedConfig]: def validate_and_import_data(input_file: Path) -> p.Result[p.Cli.LoadedConfig]: """Validate and import data in YOUR ETL pipeline. Returns r[LoadedConfig]; no None.""" - read_result = cli.read_json_file(input_file) + read_result = cli.json_read_file(input_file) if read_result.failure: cli.print( diff --git a/examples/ex_11_complete_integration.py b/examples/ex_11_complete_integration.py index 0d6d21372..5581ddb0d 100644 --- a/examples/ex_11_complete_integration.py +++ b/examples/ex_11_complete_integration.py @@ -65,7 +65,7 @@ def load_data(self) -> p.Result[t.JsonMapping]: """Load previously saved data through the public file surface.""" if not self.data_file.exists(): return r[t.JsonMapping].fail(_EXAMPLE_ERR_NO_DATA_FILE_FOUND) - read_result = cli.read_json_file(str(self.data_file)) + read_result = cli.json_read_file(str(self.data_file)) if read_result.failure: error_msg = read_result.error or "Unknown error" cli.print( @@ -82,7 +82,7 @@ def load_data(self) -> p.Result[t.JsonMapping]: def save_data(self, data: t.JsonMapping) -> p.Result[bool]: """Persist the current dataset through the public file surface.""" - write_result = cli.write_json_file(self.data_file, data) + write_result = cli.json_write_file(self.data_file, data) if write_result.failure: error_msg = write_result.error or "Unknown error" cli.print( diff --git a/examples/utilities.py b/examples/utilities.py index dc718a938..1a9ae4b50 100644 --- a/examples/utilities.py +++ b/examples/utilities.py @@ -34,8 +34,8 @@ def to_json_dict( json_value: t.JsonValue = t.Cli.JSON_VALUE_ADAPTER.validate_python( cls.normalize_to_json_value(data), ) - normalized = m.Cli.CliNormalizedJson(json_value).root - resolved = m.Cli.NormalizedJsonList(value=normalized, default={}).resolved + normalized = m.Cli.JsonNormalized(json_value).root + resolved = m.Cli.JsonNormalizedList(value=normalized, default={}).resolved result_dict = dict(resolved.items()) return m.Cli.DisplayData(data=result_dict) diff --git a/src/flext_cli/_constants/config.py b/src/flext_cli/_constants/config.py index c8a08f693..f97869cca 100644 --- a/src/flext_cli/_constants/config.py +++ b/src/flext_cli/_constants/config.py @@ -20,9 +20,9 @@ class FlextCliConstantsConfig: TEMPLATE_TRIM_BLOCKS: Final[bool] = False TEMPLATE_LSTRIP_BLOCKS: Final[bool] = False TEMPLATE_KEEP_TRAILING_NEWLINE: Final[bool] = True - ERR_TEMPLATE_RENDER_FAILED: Final[str] = "template: render failed" - ERR_TEMPLATE_NOT_FOUND: Final[str] = "template: source not found" - ERR_TEMPLATE_OUTPUT_ESCAPE: Final[str] = "template: output path escapes output_root" + TEMPLATE_ERR_RENDER_FAILED: Final[str] = "template: render failed" + TEMPLATE_ERR_NOT_FOUND: Final[str] = "template: source not found" + TEMPLATE_ERR_OUTPUT_ESCAPE: Final[str] = "template: output path escapes output_root" ERR_SCHEMA_INVALID: Final[str] = "schema: document failed validation" ERR_SCHEMA_READ_FAILED: Final[str] = "schema: cannot read schema file" ERR_CONFIG_UNSUPPORTED_FORMAT: Final[str] = "config: unsupported source format" diff --git a/src/flext_cli/_constants/errors.py b/src/flext_cli/_constants/errors.py index 7665fc897..0a8528d79 100644 --- a/src/flext_cli/_constants/errors.py +++ b/src/flext_cli/_constants/errors.py @@ -14,8 +14,8 @@ class FlextCliConstantsErrors: ERR_ATOMIC_WRITE_TEXT_FILE_FAILED: Final[str] = "atomic_write_text_file: {error}" ERR_TEXT_READ_FAILED: Final[str] = "Text read failed: {error}" ERR_TEXT_WRITE_FAILED: Final[str] = "Text write failed: {error}" - ERR_CSV_WRITE_FAILED: Final[str] = "CSV write failed: {error}" - ERR_CSV_READ_FAILED: Final[str] = "CSV read failed: {error}" + CSV_ERR_WRITE_FAILED: Final[str] = "CSV write failed: {error}" + CSV_ERR_READ_FAILED: Final[str] = "CSV read failed: {error}" ERR_BINARY_READ_FAILED: Final[str] = "Binary read failed: {error}" ERR_BINARY_WRITE_FAILED: Final[str] = "Binary write failed: {error}" ERR_FILE_COPY_FAILED: Final[str] = "File copy failed: {error}" @@ -28,7 +28,7 @@ class FlextCliConstantsErrors: ERR_FILE_PATH_EMPTY: Final[str] = "File path must be non-empty" ERR_AUTO_LOAD_FAILED: Final[str] = "Auto load failed" ERR_FILE_DELETION_FAILED: Final[str] = "File deletion failed: {error}" - ERR_JSON_LOAD_FAILED: Final[str] = "JSON load failed: {error}" + JSON_ERR_LOAD_FAILED: Final[str] = "JSON load failed: {error}" ERR_INVALID_CREDENTIALS: Final[str] = ( "Invalid credentials: missing token or username/password" diff --git a/src/flext_cli/_constants/files.py b/src/flext_cli/_constants/files.py index a6196ebba..a152a6308 100644 --- a/src/flext_cli/_constants/files.py +++ b/src/flext_cli/_constants/files.py @@ -32,10 +32,10 @@ class FileFormat(StrEnum): FILE_FORMAT_AUTO: Final[FileFormat] = FileFormat.AUTO FILE_FORMAT_TEXT: Final[FileFormat] = FileFormat.TEXT FILE_FORMAT_BIN: Final[FileFormat] = FileFormat.BIN - FILE_FORMAT_JSON: Final[FileFormat] = FileFormat.JSON - FILE_FORMAT_YAML: Final[FileFormat] = FileFormat.YAML - FILE_FORMAT_TOML: Final[FileFormat] = FileFormat.TOML - FILE_FORMAT_CSV: Final[FileFormat] = FileFormat.CSV + JSON_FILE_FORMAT: Final[FileFormat] = FileFormat.JSON + YAML_FILE_FORMAT: Final[FileFormat] = FileFormat.YAML + TOML_FILE_FORMAT: Final[FileFormat] = FileFormat.TOML + CSV_FILE_FORMAT: Final[FileFormat] = FileFormat.CSV FILE_FORMAT_UNKNOWN: Final[FileFormat] = FileFormat.UNKNOWN KNOWN_FORMATS: Final[frozenset[str]] = frozenset({ @@ -63,8 +63,8 @@ class FileFormat(StrEnum): DEFAULT_FILENAME: Final[str] = "file" DEFAULT_EXTENSION: Final[str] = ".txt" - DEFAULT_JSON_INDENT: Final[int] = 2 - DEFAULT_CSV_DELIMITER: Final[str] = "," + JSON_DEFAULT_INDENT: Final[int] = 2 + CSV_DEFAULT_DELIMITER: Final[str] = "," SIZE_UNITS: Final[t.StrSequence] = ("B", "KB", "MB", "GB", "TB", "PB") SIZE_THRESHOLD: Final[int] = 1024 diff --git a/src/flext_cli/_models/_base/flextclimodelsbase_part_01.py b/src/flext_cli/_models/_base/flextclimodelsbase_part_01.py index 504c3f400..3defc4e75 100644 --- a/src/flext_cli/_models/_base/flextclimodelsbase_part_01.py +++ b/src/flext_cli/_models/_base/flextclimodelsbase_part_01.py @@ -93,10 +93,10 @@ class LoadedConfig(m.BaseModel): ), ] - class CliNormalizedJson(m.RootModel[t.JsonValue]): + class JsonNormalized(m.RootModel[t.JsonValue]): """Normalize raw JSON value with flat JSON serialization semantics. - - ``RootModel`` provides positional construction (``CliNormalizedJson(value)``) + + ``RootModel`` provides positional construction (``JsonNormalized(value)``) and root-level serialization natively — no custom ``__init__`` or ``model_serializer`` required. """ @@ -106,8 +106,8 @@ class CliNormalizedJson(m.RootModel[t.JsonValue]): t.JsonValue, m.Field(description="Normalized JSON-compatible value") ] - class NormalizedJsonList(m.BaseModel): - """Resolve normalized JSON to a dict with defaults. Use m.Cli.NormalizedJsonList.""" + class JsonNormalizedList(m.BaseModel): + """Resolve normalized JSON to a dict with defaults. Use m.Cli.JsonNormalizedList.""" model_config: ClassVar[t.ConfigDict] = m.ConfigDict( extra="forbid", validate_assignment=True diff --git a/src/flext_cli/_models/toml.py b/src/flext_cli/_models/toml.py index dfa4c545b..0e4574c06 100644 --- a/src/flext_cli/_models/toml.py +++ b/src/flext_cli/_models/toml.py @@ -52,8 +52,7 @@ class TomlListOp(m.ContractModel): m.Field(description="Merge strategy", validate_default=True), ] = _enum.TomlMergeMode.REPLACE sort: Annotated[ - bool, - m.Field(description="Sort values before sync", validate_default=True), + bool, m.Field(description="Sort values before sync", validate_default=True) ] = True class TomlRemoveOp(m.ContractModel): @@ -141,12 +140,7 @@ def operation( operation_item = operation_type.model_validate(data) replaced: Self = self._replace( self.state.model_copy( - update={ - "operations": ( - *self.state.operations, - operation_item, - ) - } + update={"operations": (*self.state.operations, operation_item)} ) ) return replaced @@ -164,9 +158,7 @@ def table(self, *path: str) -> Self: def value(self, key: str, value: t.JsonValue) -> Self: """Value.""" return self.operation( - FlextCliModelsToml.TomlSetOp, - key=key, - value=value, + FlextCliModelsToml.TomlSetOp, key=key, value=value ) def list( @@ -189,9 +181,7 @@ def list( def deprecated(self, key: str, *sub_path: str) -> Self: """Mark a key as deprecated by scheduling its removal.""" return self.operation( - FlextCliModelsToml.TomlRemoveOp, - key=key, - table_path=tuple(sub_path), + FlextCliModelsToml.TomlRemoveOp, key=key, table_path=tuple(sub_path) ) def nested( @@ -208,19 +198,14 @@ def nested( table_path=tuple(path), operations=tuple( self._nested_operations( - values=values, - lists=lists, - deprecated_keys=deprecated_keys, + values=values, lists=lists, deprecated_keys=deprecated_keys ) ), ) replaced: Self = self._replace( self.state.model_copy( update={ - "nested_tables": ( - *self.state.nested_tables, - nested_table, - ) + "nested_tables": (*self.state.nested_tables, nested_table) } ) ) diff --git a/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_01.py b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_01.py index 738b80a16..6deeebb41 100644 --- a/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_01.py +++ b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_01.py @@ -20,7 +20,7 @@ class CliSettings(Protocol): are flat ``cli_*`` scalars loadable from env/.env. Test-runtime detection moved to ``u.Cli.cli_test_env`` (behavior lives in the utilities layer, never on settings). Plain ``Protocol`` (not - ``p.Model``): pyrefly cannot reconcile pydantic ``model_fields`` + ``p.BaseModel``): pyrefly cannot reconcile pydantic ``model_fields`` metaclass descriptors on this hot path — structural field access is the whole contract. """ diff --git a/src/flext_cli/_protocols/toml.py b/src/flext_cli/_protocols/toml.py index a61f3224f..dd56191c2 100644 --- a/src/flext_cli/_protocols/toml.py +++ b/src/flext_cli/_protocols/toml.py @@ -114,9 +114,7 @@ def operations(self) -> t.SequenceOf[FlextCliProtocolsToml.TomlOperation]: ... @property - def nested_tables( - self, - ) -> t.SequenceOf[FlextCliProtocolsToml.TomlPhaseConfig]: + def nested_tables(self) -> t.SequenceOf[FlextCliProtocolsToml.TomlPhaseConfig]: """Nested TOML phase configs.""" ... diff --git a/src/flext_cli/_protocols/xlsx.py b/src/flext_cli/_protocols/xlsx.py index b4c8774e9..d002fd383 100644 --- a/src/flext_cli/_protocols/xlsx.py +++ b/src/flext_cli/_protocols/xlsx.py @@ -185,7 +185,7 @@ class XlsxNamedStyleSpec(Protocol): def name(self) -> str: ... @property - def visual(self) -> p.Model: ... + def visual(self) -> p.BaseModel: ... @runtime_checkable class XlsxStyleCatalog(Protocol): diff --git a/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_01.py b/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_01.py index c42ea3596..781509381 100644 --- a/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_01.py +++ b/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_01.py @@ -59,13 +59,13 @@ def files_context( file_path.write_text(raw, encoding=c.Cli.ENCODING_DEFAULT) elif isinstance(raw, Mapping): fmt = ( - c.Cli.FILE_FORMAT_YAML + c.Cli.YAML_FILE_FORMAT if file_path.suffix in {".yaml", ".yml"} - else c.Cli.FILE_FORMAT_JSON + else c.Cli.JSON_FILE_FORMAT ) cls._files_write_structured(file_path, raw, fmt) elif isinstance(raw, list): - FlextCliUtilitiesFiles.files_write_csv( + FlextCliUtilitiesFiles.csv_write_files( file_path, cast("t.SequenceOf[t.StrSequence]", raw) ) else: @@ -89,7 +89,7 @@ def _files_write_structured( ) -> p.Result[bool]: """Write a structured payload as JSON or YAML.""" validated = t.Cli.JSON_VALUE_ADAPTER.validate_python(data) - if fmt == c.Cli.FILE_FORMAT_YAML: + if fmt == c.Cli.YAML_FILE_FORMAT: dumped = uy.yaml_dump_str(validated) return FlextCliUtilitiesFiles.files_write_text(path, dumped) dumped_result = uj.json_dumps(validated) diff --git a/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_04.py b/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_04.py index 277ae706b..3f010176c 100644 --- a/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_04.py +++ b/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_04.py @@ -23,17 +23,17 @@ class FlextCliUtilitiesFileTestHelpersMixin: @staticmethod def files_parse_content(path: Path, fmt: str) -> p.Result[object]: """Parse JSON/YAML/TOML file content generically by format token.""" - if fmt == c.Cli.FILE_FORMAT_JSON: + if fmt == c.Cli.JSON_FILE_FORMAT: result = uj.json_read(path) if result.failure: return r[object].fail(result.error or "json_read failed") return r[object].ok(result.value) - if fmt == c.Cli.FILE_FORMAT_YAML: + if fmt == c.Cli.YAML_FILE_FORMAT: result = uy.yaml_safe_load(path) if result.failure: return r[object].fail(result.error or "yaml_safe_load failed") return r[object].ok(result.value) - if fmt == c.Cli.FILE_FORMAT_TOML: + if fmt == c.Cli.TOML_FILE_FORMAT: toml_result = ut.toml_read_json(path) if toml_result.failure: return r[object].fail(toml_result.error or "toml_read_json failed") diff --git a/src/flext_cli/_utilities/_files/flextcliutilitiesfiles_part_01.py b/src/flext_cli/_utilities/_files/flextcliutilitiesfiles_part_01.py index 070fdf3ae..68b8c6a95 100644 --- a/src/flext_cli/_utilities/_files/flextcliutilitiesfiles_part_01.py +++ b/src/flext_cli/_utilities/_files/flextcliutilitiesfiles_part_01.py @@ -67,7 +67,7 @@ def _write() -> bool: ) @staticmethod - def files_read_json(file_path: t.Cli.TextPath) -> p.Result[t.JsonValue]: + def json_read_files(file_path: t.Cli.TextPath) -> p.Result[t.JsonValue]: """Read one JSON file and validate to canonical JSON value.""" def _load() -> t.JsonValue: @@ -75,11 +75,11 @@ def _load() -> t.JsonValue: return t.Cli.JSON_VALUE_ADAPTER.validate_json(raw) return FlextCliUtilitiesFilesPart02.files_execute( - _load, c.Cli.ERR_JSON_LOAD_FAILED + _load, c.Cli.JSON_ERR_LOAD_FAILED ) @staticmethod - def files_read_json_model[M: t.Cli.ModelLike]( + def json_read_files_model[M: t.Cli.ModelLike]( file_path: t.Cli.TextPath, model_type: t.ModelClass[M] ) -> p.Result[M]: """Read one JSON file directly into one Pydantic model.""" @@ -91,11 +91,11 @@ def _load() -> M: return loaded return FlextCliUtilitiesFilesPart02.files_execute( - _load, c.Cli.ERR_JSON_LOAD_FAILED + _load, c.Cli.JSON_ERR_LOAD_FAILED ) @staticmethod - def files_read_first_json_model[M: t.Cli.ModelLike]( + def json_read_first_files_model[M: t.Cli.ModelLike]( file_path: t.Cli.TextPath, model_type: t.ModelClass[M] ) -> p.Result[M]: """Stream and validate the first non-empty JSON line into one model.""" @@ -111,11 +111,11 @@ def _load() -> M: raise ValueError(msg) return FlextCliUtilitiesFilesPart02.files_execute( - _load, c.Cli.ERR_JSON_LOAD_FAILED + _load, c.Cli.JSON_ERR_LOAD_FAILED ) @staticmethod - def files_read_json_lines_model[M: t.Cli.ModelLike]( + def json_read_files_lines_model[M: t.Cli.ModelLike]( file_path: t.Cli.TextPath, model_type: t.ModelClass[M] ) -> p.Result[tuple[M, ...]]: """Stream every non-empty JSON line and validate each into one model.""" @@ -131,25 +131,25 @@ def _load() -> tuple[M, ...]: ) return FlextCliUtilitiesFilesPart02.files_execute( - _load, c.Cli.ERR_JSON_LOAD_FAILED + _load, c.Cli.JSON_ERR_LOAD_FAILED ) @staticmethod - def files_read_yaml(file_path: t.Cli.TextPath) -> p.Result[t.JsonValue]: + def yaml_read_files(file_path: t.Cli.TextPath) -> p.Result[t.JsonValue]: """Read one YAML file and validate to canonical JSON value.""" return uy.yaml_safe_load(Path(file_path)).map( t.Cli.JSON_VALUE_ADAPTER.validate_python ) @staticmethod - def files_read_yaml_model[M: t.Cli.ModelLike]( + def yaml_read_files_model[M: t.Cli.ModelLike]( file_path: t.Cli.TextPath, model_type: t.ModelClass[M] ) -> p.Result[M]: """Read YAML directly into one caller-supplied validated model.""" return uy.yaml_safe_load(Path(file_path)).map(model_type.model_validate) @staticmethod - def files_read_yaml_model_chain[M: t.Cli.ModelLike]( + def yaml_read_files_model_chain[M: t.Cli.ModelLike]( file_paths: t.SequenceOf[t.Cli.TextPath], model_type: t.ModelClass[M] ) -> p.Result[M]: """Merge ordered YAML sources and validate the final payload once.""" @@ -168,7 +168,7 @@ def files_read_yaml_model_chain[M: t.Cli.ModelLike]( return r[t.JsonMapping].ok(merged).map(model_type.model_validate) @staticmethod - def files_write_csv( + def csv_write_files( file_path: t.Cli.TextPath, rows: t.SequenceOf[t.StrSequence] ) -> p.Result[bool]: """Write one CSV file from row sequence.""" @@ -183,7 +183,7 @@ def _write() -> bool: return True return FlextCliUtilitiesFilesPart02.files_execute( - _write, c.Cli.ERR_CSV_WRITE_FAILED + _write, c.Cli.CSV_ERR_WRITE_FAILED ) diff --git a/src/flext_cli/_utilities/_files/flextcliutilitiesfiles_part_02.py b/src/flext_cli/_utilities/_files/flextcliutilitiesfiles_part_02.py index 6ef07a56c..020b769e0 100644 --- a/src/flext_cli/_utilities/_files/flextcliutilitiesfiles_part_02.py +++ b/src/flext_cli/_utilities/_files/flextcliutilitiesfiles_part_02.py @@ -15,7 +15,7 @@ class FlextCliUtilitiesFiles: """Implementation part for FlextCliUtilitiesFiles.""" @staticmethod - def files_read_csv_with_headers( + def csv_read_files_with_headers( file_path: t.Cli.TextPath, ) -> p.Result[t.SequenceOf[t.StrMapping]]: """Read one CSV file into mapping rows using header row.""" @@ -26,7 +26,7 @@ def _load() -> t.SequenceOf[t.StrMapping]: ) as handle: return [dict(row) for row in csv.DictReader(handle)] - return FlextCliUtilitiesFiles.files_execute(_load, c.Cli.ERR_CSV_READ_FAILED) + return FlextCliUtilitiesFiles.files_execute(_load, c.Cli.CSV_ERR_READ_FAILED) @staticmethod def files_read_binary(file_path: t.Cli.TextPath) -> p.Result[bytes]: diff --git a/src/flext_cli/_utilities/_files/flextcliutilitiesfiles_part_04.py b/src/flext_cli/_utilities/_files/flextcliutilitiesfiles_part_04.py index ebecd6f3b..aaf34a27a 100644 --- a/src/flext_cli/_utilities/_files/flextcliutilitiesfiles_part_04.py +++ b/src/flext_cli/_utilities/_files/flextcliutilitiesfiles_part_04.py @@ -57,12 +57,12 @@ def files_detect_format_from_content( if isinstance(content, (m.ConfigMap, m.Dict, Mapping)): ext = Path(name).suffix.lower() return ( - str(c.Cli.FILE_FORMAT_YAML) + str(c.Cli.YAML_FILE_FORMAT) if ext in {".yaml", ".yml"} - else str(c.Cli.FILE_FORMAT_JSON) + else str(c.Cli.JSON_FILE_FORMAT) ) if isinstance(content, list): - return str(c.Cli.FILE_FORMAT_CSV) + return str(c.Cli.CSV_FILE_FORMAT) return c.Cli.format_for_extension(Path(name).suffix) @staticmethod diff --git a/src/flext_cli/_utilities/_json/_core.py b/src/flext_cli/_utilities/_json/_core.py index 7fa59ce0f..483615092 100644 --- a/src/flext_cli/_utilities/_json/_core.py +++ b/src/flext_cli/_utilities/_json/_core.py @@ -75,7 +75,7 @@ def json_sort_keys(data: t.JsonValue) -> t.JsonValue: return data @staticmethod - def normalize_json_value(item: t.JsonPayload) -> t.JsonValue: + def json_normalize_value(item: t.JsonPayload) -> t.JsonValue: """Normalize any runtime value to JSON-compatible output (Pydantic-native).""" return u.normalize_to_json_value(item) @@ -84,7 +84,7 @@ def _json_write_content( payload: t.JsonPayload, options: p.Cli.JsonWriteOptions ) -> str: """Serialize a JSON payload using canonical write options.""" - validated = FlextCliUtilitiesJsonCoreMixin.normalize_json_value(payload) + validated = FlextCliUtilitiesJsonCoreMixin.json_normalize_value(payload) normalized = ( FlextCliUtilitiesJsonCoreMixin.json_sort_keys(validated) if options.sort_keys diff --git a/src/flext_cli/_utilities/_options/flextcliutilitiesoptions_part_01.py b/src/flext_cli/_utilities/_options/flextcliutilitiesoptions_part_01.py index 5974a831b..3bccde9c6 100644 --- a/src/flext_cli/_utilities/_options/flextcliutilitiesoptions_part_01.py +++ b/src/flext_cli/_utilities/_options/flextcliutilitiesoptions_part_01.py @@ -96,7 +96,7 @@ def is_string_sequence(value: t.Cli.CliDefaultSource) -> bool: return all(item for item in value) @classmethod - def normalize_cli_atom( + def cli_normalize_atom( cls, value: t.Cli.CliDefaultSource ) -> t.Cli.DefaultAtom | None: """Normalize one runtime value into an allowed Typer scalar or string sequence.""" diff --git a/src/flext_cli/_utilities/_options/flextcliutilitiesoptions_part_02.py b/src/flext_cli/_utilities/_options/flextcliutilitiesoptions_part_02.py index b971cce33..1eed1e299 100644 --- a/src/flext_cli/_utilities/_options/flextcliutilitiesoptions_part_02.py +++ b/src/flext_cli/_utilities/_options/flextcliutilitiesoptions_part_02.py @@ -39,13 +39,13 @@ def field_default( return None match normalized_source: case _ if ( - normalized_atom := cls.normalize_cli_atom(normalized_source) + normalized_atom := cls.cli_normalize_atom(normalized_source) ) is not None: normalized_default: t.Cli.CliValue | None = normalized_atom case Mapping() as normalized_source_mapping: normalized_mapping: t.Cli.MutableDefaultMapping = {} for key, item_value in normalized_source_mapping.items(): - normalized_item = cls.normalize_cli_atom(item_value) + normalized_item = cls.cli_normalize_atom(item_value) if normalized_item is not None: normalized_mapping[key] = normalized_item normalized_default = normalized_mapping or None diff --git a/src/flext_cli/_utilities/template.py b/src/flext_cli/_utilities/template.py index 216252639..08695e85e 100644 --- a/src/flext_cli/_utilities/template.py +++ b/src/flext_cli/_utilities/template.py @@ -40,14 +40,14 @@ def _environment(search_path: Path) -> SandboxedEnvironment: ) @staticmethod - def template_render(path: Path, context: p.Model) -> p.Result[str]: + def template_render(path: Path, context: p.BaseModel) -> p.Result[str]: """Render a ``templates/*.j2`` file with ``context`` → ``r[str]``. Fail-closed: a missing template or any Jinja error (including undefined variables via ``StrictUndefined``) is a failed ``r[T]``. """ if not path.is_file(): - return r[str].fail(f"{c.Cli.ERR_TEMPLATE_NOT_FOUND}: {path}") + return r[str].fail(f"{c.Cli.TEMPLATE_ERR_NOT_FOUND}: {path}") env = FlextCliUtilitiesTemplate._environment(path.parent) rendered = u.try_( lambda: env.get_template(path.name).render(context.model_dump(mode="json")), @@ -56,16 +56,16 @@ def template_render(path: Path, context: p.Model) -> p.Result[str]: ) if rendered.failure: return r[str].fail( - rendered.error or f"{c.Cli.ERR_TEMPLATE_RENDER_FAILED}: {path}" + rendered.error or f"{c.Cli.TEMPLATE_ERR_RENDER_FAILED}: {path}" ) return r[str].ok(rendered.value) @staticmethod - def template_render_to(path: Path, dest: Path, context: p.Model) -> p.Result[bool]: + def template_render_to(path: Path, dest: Path, context: p.BaseModel) -> p.Result[bool]: """Render ``path`` with ``context`` and write it to ``dest`` → ``r[bool]``.""" rendered = FlextCliUtilitiesTemplate.template_render(path, context) if rendered.failure: - return r[bool].fail(rendered.error or c.Cli.ERR_TEMPLATE_RENDER_FAILED) + return r[bool].fail(rendered.error or c.Cli.TEMPLATE_ERR_RENDER_FAILED) return u.try_( lambda: FlextCliUtilitiesTemplate._write(dest, rendered.value), catch=OSError, @@ -76,7 +76,7 @@ def template_render_to(path: Path, dest: Path, context: p.Model) -> p.Result[boo def template_render_dir( templates_root: Path, output_root: Path, - context: p.Model, + context: p.BaseModel, entries: t.SequenceOf[p.Cli.TemplateRenderEntry], *, strip_suffix: str = c.Cli.TEMPLATE_SUFFIX, @@ -96,7 +96,7 @@ def template_render_dir( """ if not templates_root.is_dir(): return r[p.Cli.TemplateRenderReport].fail( - f"{c.Cli.ERR_TEMPLATE_NOT_FOUND}: {templates_root}" + f"{c.Cli.TEMPLATE_ERR_NOT_FOUND}: {templates_root}" ) root = output_root.resolve() created: list[Path] = [] @@ -109,10 +109,10 @@ def template_render_dir( dest = output_root / out_rel try: if not dest.resolve().is_relative_to(root): - failed.append((dest, c.Cli.ERR_TEMPLATE_OUTPUT_ESCAPE)) + failed.append((dest, c.Cli.TEMPLATE_ERR_OUTPUT_ESCAPE)) continue except (OSError, ValueError): - failed.append((dest, c.Cli.ERR_TEMPLATE_OUTPUT_ESCAPE)) + failed.append((dest, c.Cli.TEMPLATE_ERR_OUTPUT_ESCAPE)) continue if not entry.when: skipped.append(dest) @@ -123,7 +123,7 @@ def template_render_dir( src = templates_root / entry.relpath_template result = FlextCliUtilitiesTemplate.template_render_to(src, dest, context) if result.failure: - failed.append((dest, result.error or c.Cli.ERR_TEMPLATE_RENDER_FAILED)) + failed.append((dest, result.error or c.Cli.TEMPLATE_ERR_RENDER_FAILED)) continue created.append(dest) report = m.Cli.TemplateRenderReport( diff --git a/src/flext_cli/_utilities/yaml.py b/src/flext_cli/_utilities/yaml.py index 7a28ca524..413690644 100644 --- a/src/flext_cli/_utilities/yaml.py +++ b/src/flext_cli/_utilities/yaml.py @@ -141,7 +141,7 @@ def yaml_dump( """ try: path.parent.mkdir(parents=True, exist_ok=True) - validated = FlextCliUtilitiesJson.normalize_json_value(data) + validated = FlextCliUtilitiesJson.json_normalize_value(data) with path.open("w", encoding=c.Cli.ENCODING_DEFAULT) as fh: safe_dump( validated, @@ -168,7 +168,7 @@ def yaml_dump_str( text = u.Cli.yaml_dump_str(payload) """ try: - validated = FlextCliUtilitiesJson.normalize_json_value(data) + validated = FlextCliUtilitiesJson.json_normalize_value(data) return safe_dump( validated, default_flow_style=False, diff --git a/src/flext_cli/_utilities/yaml_model.py b/src/flext_cli/_utilities/yaml_model.py index 60a5823a6..cab521f5b 100644 --- a/src/flext_cli/_utilities/yaml_model.py +++ b/src/flext_cli/_utilities/yaml_model.py @@ -14,7 +14,7 @@ class FlextCliUtilitiesYamlModel: # NOTE (multi-agent, mro-j2yt.1): the validated model remains intact until # this external egress; no internal dump/revalidation round trip is allowed. @staticmethod - def write_yaml_model(file_path: t.Cli.TextPath, model: p.Model) -> p.Result[bool]: + def yaml_write_model(file_path: t.Cli.TextPath, model: p.BaseModel) -> p.Result[bool]: """Write one protocol-backed model as YAML and propagate failures.""" try: return FlextCliUtilitiesYaml.yaml_dump( diff --git a/src/flext_cli/services/auth.py b/src/flext_cli/services/auth.py index bdec841ca..712a59b9d 100644 --- a/src/flext_cli/services/auth.py +++ b/src/flext_cli/services/auth.py @@ -35,14 +35,14 @@ def save_auth_token(self, token: str) -> p.Result[bool]: c.Cli.VALIDATION_MSG_FIELD_CANNOT_BE_EMPTY.format(field_name="token") ) token_file_path = u.Cli.auth_token_file_path(settings.cli_token_file) - return FlextCliFileTools.write_json_file( + return FlextCliFileTools.json_write_file( token_file_path, {c.Cli.DICT_KEY_AUTH_TOKEN: token} ) def fetch_auth_token(self) -> p.Result[str]: """Load the persisted authentication token from the configured token file.""" token_file_path = u.Cli.auth_token_file_path(settings.cli_token_file) - return FlextCliFileTools.read_json_file(token_file_path).flat_map( + return FlextCliFileTools.json_read_file(token_file_path).flat_map( u.Cli.auth_extract_token ) diff --git a/src/flext_cli/services/file_tools.py b/src/flext_cli/services/file_tools.py index 81c82353b..1bcef0e1e 100644 --- a/src/flext_cli/services/file_tools.py +++ b/src/flext_cli/services/file_tools.py @@ -24,8 +24,8 @@ def atomic_write_text_file( return u.Cli.atomic_write_text_file(file_path, content) @staticmethod - def read_json_file(file_path: t.Cli.TextPath) -> p.Result[t.JsonValue]: - return u.Cli.files_read_json(Path(file_path)) + def json_read_file(file_path: t.Cli.TextPath) -> p.Result[t.JsonValue]: + return u.Cli.json_read_files(Path(file_path)) @staticmethod def read_text_file(file_path: t.Cli.TextPath) -> p.Result[str]: @@ -33,35 +33,35 @@ def read_text_file(file_path: t.Cli.TextPath) -> p.Result[str]: return u.Cli.files_read_text(Path(file_path)) @staticmethod - def read_json_model[M: t.Cli.ModelLike]( + def json_read_model[M: t.Cli.ModelLike]( file_path: t.Cli.TextPath, model_type: t.ModelClass[M] ) -> p.Result[M]: """Read JSON into the canonical structural model-class contract.""" - return u.Cli.files_read_json_model(Path(file_path), model_type) + return u.Cli.json_read_files_model(Path(file_path), model_type) @staticmethod - def read_yaml_file(file_path: t.Cli.TextPath) -> p.Result[t.JsonValue]: + def yaml_read_file(file_path: t.Cli.TextPath) -> p.Result[t.JsonValue]: normalized_path = u.Cli.normalize_optional_text(file_path) if normalized_path is None: return r[t.JsonValue].fail(c.Cli.ERR_FILE_PATH_EMPTY) - return u.Cli.files_read_yaml(Path(normalized_path)) + return u.Cli.yaml_read_files(Path(normalized_path)) @staticmethod - def read_yaml_model[M: t.Cli.ModelLike]( + def yaml_read_model[M: t.Cli.ModelLike]( file_path: t.Cli.TextPath, model_type: t.ModelClass[M] ) -> p.Result[M]: """Read YAML and validate it once into the requested model type.""" - return u.Cli.files_read_yaml_model(Path(file_path), model_type) + return u.Cli.yaml_read_files_model(Path(file_path), model_type) @staticmethod - def read_yaml_model_chain[M: t.Cli.ModelLike]( + def yaml_read_model_chain[M: t.Cli.ModelLike]( file_paths: Sequence[t.Cli.TextPath], model_type: t.ModelClass[M] ) -> p.Result[M]: """Merge ordered YAML sources and validate the final payload once.""" - return u.Cli.files_read_yaml_model_chain(file_paths, model_type) + return u.Cli.yaml_read_files_model_chain(file_paths, model_type) @staticmethod - def write_json_file( + def json_write_file( file_path: t.Cli.TextPath, data: t.Cli.JsonWriteData, options: p.Cli.JsonWriteOptions | None = None, @@ -69,22 +69,22 @@ def write_json_file( return u.Cli.json_write(Path(file_path), data, options=options) @staticmethod - def write_yaml_file( + def yaml_write_file( file_path: t.Cli.TextPath, data: t.Cli.JsonWriteData ) -> p.Result[bool]: return u.Cli.yaml_dump(Path(file_path), data) @staticmethod - def write_csv_file( + def csv_write_file( file_path: t.Cli.TextPath, rows: t.SequenceOf[t.StrSequence] ) -> p.Result[bool]: - return u.Cli.files_write_csv(Path(file_path), rows) + return u.Cli.csv_write_files(Path(file_path), rows) @staticmethod - def read_csv_file_with_headers( + def csv_read_file_with_headers( file_path: t.Cli.TextPath, ) -> p.Result[t.SequenceOf[t.StrMapping]]: - return u.Cli.files_read_csv_with_headers(Path(file_path)) + return u.Cli.csv_read_files_with_headers(Path(file_path)) @staticmethod def read_binary_file(file_path: t.Cli.TextPath) -> p.Result[bytes]: diff --git a/tests/test_yaml_model_write.py b/tests/test_yaml_model_write.py index fe0f31307..c1d921a6f 100644 --- a/tests/test_yaml_model_write.py +++ b/tests/test_yaml_model_write.py @@ -17,8 +17,8 @@ def test_write_yaml_model_round_trips_the_same_model_contract(tmp_path: Path) -> source = m.Cli.XlsxCellAddress(row=7, column=9) target = tmp_path / "address.yaml" - written = cli.write_yaml_model(target, source) - loaded = cli.read_yaml_model(target, m.Cli.XlsxCellAddress) + written = cli.yaml_write_model(target, source) + loaded = cli.yaml_read_model(target, m.Cli.XlsxCellAddress) tm.that(written.success, eq=True) tm.that(loaded.success, eq=True) diff --git a/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_01.py b/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_01.py index 1680000e6..17cf82a4f 100644 --- a/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_01.py +++ b/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_01.py @@ -92,7 +92,7 @@ def test_file_operation_examples(self, tmp_path: Path) -> None: import_file = tmp_path / "record.json" record = m.Tests.ImportRecord(id=1, name="Alice", value="ok") - write_result = cli.write_json_file(import_file, record.model_dump(mode="json")) + write_result = cli.json_write_file(import_file, record.model_dump(mode="json")) tm.ok(write_result) validation_result = validate_and_import_data(import_file) tm.ok(validation_result) diff --git a/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_01.py b/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_01.py index 0c8de6d73..d155bbb1a 100644 --- a/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_01.py +++ b/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_01.py @@ -60,21 +60,21 @@ def test_files_write_text_invalid_path(self) -> None: def test_files_read_write_json(self, tmp_path: Path) -> None: """Round-trip a JSON document through the public CLI facade.""" path = tmp_path / "data.json" - write_result = cli.write_json_file(path, {"key": "value"}) + write_result = cli.json_write_file(path, {"key": "value"}) tm.ok(write_result) - read_result = cli.read_json_file(path) + read_result = cli.json_read_file(path) tm.ok(read_result) def test_files_read_json_missing(self, tmp_path: Path) -> None: """Return failure when a JSON source is absent.""" - result = cli.read_json_file(tmp_path / "missing.json") + result = cli.json_read_file(tmp_path / "missing.json") tm.fail(result) def test_files_read_json_model(self, tmp_path: Path) -> None: """Validate one complete JSON document into the requested model.""" path = tmp_path / "opts.json" path.write_text('{"indent": 4, "sort_keys": true}', encoding="utf-8") - result = cli.read_json_model(path, m.Cli.JsonWriteOptions) + result = cli.json_read_model(path, m.Cli.JsonWriteOptions) tm.ok(result) tm.that(result.value.indent, eq=4) @@ -85,8 +85,8 @@ def test_files_read_json_lines_models(self, tmp_path: Path) -> None: '\n{"indent": 2, "sort_keys": false}\n{"indent": 4, "sort_keys": true}\n', encoding="utf-8", ) - first = u.Cli.files_read_first_json_model(path, m.Cli.JsonWriteOptions) - all_records = u.Cli.files_read_json_lines_model(path, m.Cli.JsonWriteOptions) + first = u.Cli.json_read_first_files_model(path, m.Cli.JsonWriteOptions) + all_records = u.Cli.json_read_files_lines_model(path, m.Cli.JsonWriteOptions) tm.ok(first) tm.ok(all_records) tm.that(first.value.indent, eq=2) @@ -95,34 +95,34 @@ def test_files_read_json_lines_models(self, tmp_path: Path) -> None: def test_files_read_write_yaml(self, tmp_path: Path) -> None: """Round-trip a YAML document through the public CLI facade.""" path = tmp_path / "data.yaml" - write_result = cli.write_yaml_file(path, {"key": "val"}) + write_result = cli.yaml_write_file(path, {"key": "val"}) tm.ok(write_result) - read_result = cli.read_yaml_file(path) + read_result = cli.yaml_read_file(path) tm.ok(read_result) def test_files_read_yaml_missing(self, tmp_path: Path) -> None: """Return failure when a YAML source is absent.""" - result = cli.read_yaml_file(tmp_path / "missing.yaml") + result = cli.yaml_read_file(tmp_path / "missing.yaml") tm.fail(result) def test_files_read_yaml_empty_path(self) -> None: """Reject an empty YAML path.""" - result = cli.read_yaml_file(" ") + result = cli.yaml_read_file(" ") tm.fail(result) def test_files_write_read_csv(self, tmp_path: Path) -> None: """Round-trip CSV rows with validated headers.""" path = tmp_path / "data.csv" rows: list[t.StrSequence] = [["name", "age"], ["alice", "30"], ["bob", "25"]] - write_result = cli.write_csv_file(path, rows) + write_result = cli.csv_write_file(path, rows) tm.ok(write_result) - read_result = cli.read_csv_file_with_headers(path) + read_result = cli.csv_read_file_with_headers(path) tm.ok(read_result) tm.that(len(read_result.value), eq=2) def test_files_read_csv_missing(self, tmp_path: Path) -> None: """Return failure when a CSV source is absent.""" - result = cli.read_csv_file_with_headers(tmp_path / "missing.csv") + result = cli.csv_read_file_with_headers(tmp_path / "missing.csv") tm.fail(result) def test_files_write_read_binary(self, tmp_path: Path) -> None: diff --git a/tests/unit/_cases/test_json_cov/testsflextclijsoncov_part_01.py b/tests/unit/_cases/test_json_cov/testsflextclijsoncov_part_01.py index 3d01eaca0..fa0d66f1f 100644 --- a/tests/unit/_cases/test_json_cov/testsflextclijsoncov_part_01.py +++ b/tests/unit/_cases/test_json_cov/testsflextclijsoncov_part_01.py @@ -16,8 +16,8 @@ class TestsFlextCliJsonCov: """Implementation part for TestsFlextCliJsonCov.""" - def test_normalize_json_value(self) -> None: - result = u.Cli.normalize_json_value({"key": "value"}) + def test_json_normalize_value(self) -> None: + result = u.Cli.json_normalize_value({"key": "value"}) tm.that(result, eq={"key": "value"}) def test_json_read_missing_file(self, tmp_path: Path) -> None: diff --git a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_02.py b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_02.py index ca6026a88..36bbbbd36 100644 --- a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_02.py +++ b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_02.py @@ -25,7 +25,7 @@ def test_public_model_contracts_cover_cli_shapes(self, tmp_path: Path) -> None: ) display = m.Cli.DisplayData(data={"name": "flext", "count": 1}) loaded = m.Cli.LoadedConfig(content={"debug": True}) - normalized = m.Cli.CliNormalizedJson({"name": "flext"}) + normalized = m.Cli.JsonNormalized({"name": "flext"}) summary = m.Cli.SuccessSummaryDetails({"status": "ok"}) prompt_state = m.Cli.PromptRuntimeState(quiet=True) auth = m.Cli.AuthCredentialsPayload(token="token-123") @@ -61,9 +61,9 @@ def route_handler( tm.that(display.model_dump(), eq={"name": "flext", "count": 1}) tm.that(loaded.content, eq={"debug": True}) tm.that(normalized.model_dump(), eq={"name": "flext"}) - tm.that(m.Cli.NormalizedJsonList(value={"ok": True}).resolved, eq={"ok": True}) + tm.that(m.Cli.JsonNormalizedList(value={"ok": True}).resolved, eq={"ok": True}) tm.that( - m.Cli.NormalizedJsonList( + m.Cli.JsonNormalizedList( value="plain-text", default={"fallback": "yes"} ).resolved, eq={"fallback": "yes"}, diff --git a/tests/unit/test_config_engine.py b/tests/unit/test_config_engine.py index c151e0195..2c32a86ee 100644 --- a/tests/unit/test_config_engine.py +++ b/tests/unit/test_config_engine.py @@ -35,7 +35,7 @@ def test_template_render_strict_undefined_fails(self, tmp_path: Path) -> None: def test_template_render_missing_source_fails(self, tmp_path: Path) -> None: result = u.Cli.template_render(tmp_path / "absent.j2", m.Tests.TemplateEmpty()) tm.fail(result) - tm.that((result.error or ""), has=c.Cli.ERR_TEMPLATE_NOT_FOUND) + tm.that((result.error or ""), has=c.Cli.TEMPLATE_ERR_NOT_FOUND) def test_template_render_to_writes(self, tmp_path: Path) -> None: tpl = tmp_path / "t.j2" @@ -198,7 +198,7 @@ def test_render_dir_blocks_escape(self, tmp_path: Path) -> None: root, out, m.Tests.TemplateEmpty(), entries ).unwrap() assert report.failed - tm.that(report.failed[0][1], has=c.Cli.ERR_TEMPLATE_OUTPUT_ESCAPE) + tm.that(report.failed[0][1], has=c.Cli.TEMPLATE_ERR_OUTPUT_ESCAPE) assert not (tmp_path / "escape").exists() def test_render_dir_missing_root_fails(self, tmp_path: Path) -> None: diff --git a/tests/unit/test_file_tools_yaml.py b/tests/unit/test_file_tools_yaml.py index 89dd18d19..8a7591457 100644 --- a/tests/unit/test_file_tools_yaml.py +++ b/tests/unit/test_file_tools_yaml.py @@ -23,7 +23,7 @@ def test_single_source_returns_requested_model(self, tmp_path: Path) -> None: ) tm.that(written.success, eq=True) - result = cli.read_yaml_model(source, m.Tests.YamlConsumerConfig) + result = cli.yaml_read_model(source, m.Tests.YamlConsumerConfig) tm.that(result.success, eq=True) tm.that(result.value, is_=m.Tests.YamlConsumerConfig) @@ -52,7 +52,7 @@ def test_chain_deep_merges_before_one_final_validation( tm.that(type_written.success, eq=True) tm.that(consumer_written.success, eq=True) - result = cli.read_yaml_model_chain( + result = cli.yaml_read_model_chain( (base_source, type_source, consumer_source), m.Tests.YamlConsumerConfig ) @@ -64,7 +64,7 @@ def test_chain_deep_merges_before_one_final_validation( def test_missing_file_fails_loud(self, tmp_path: Path) -> None: """A missing external source returns a failed public result.""" - result = cli.read_yaml_model( + result = cli.yaml_read_model( tmp_path / "missing.yaml", m.Tests.YamlConsumerConfig ) @@ -85,7 +85,7 @@ def test_malformed_chain_source_fails_loud(self, tmp_path: Path) -> None: tm.that(base_written.success, eq=True) tm.that(malformed_written.success, eq=True) - result = cli.read_yaml_model_chain( + result = cli.yaml_read_model_chain( (base_source, malformed_source), m.Tests.YamlConsumerConfig ) @@ -101,7 +101,7 @@ def test_strict_model_rejects_quoted_integer(self, tmp_path: Path) -> None: ) tm.that(written.success, eq=True) - result = cli.read_yaml_model(source, m.Tests.YamlConsumerConfig) + result = cli.yaml_read_model(source, m.Tests.YamlConsumerConfig) tm.that(result.failure, eq=True) diff --git a/tests/unit/test_files_cov.py b/tests/unit/test_files_cov.py index 8dcdcf1ed..53ab0f7c5 100644 --- a/tests/unit/test_files_cov.py +++ b/tests/unit/test_files_cov.py @@ -60,45 +60,45 @@ def test_write_text_fails_for_unwritable_path(self) -> None: def test_write_then_read_json_round_trips(self, tmp_path: Path) -> None: path = tmp_path / "data.json" - tm.ok(cli.write_json_file(path, {"key": "value"})) - read_result = cli.read_json_file(path) + tm.ok(cli.json_write_file(path, {"key": "value"})) + read_result = cli.json_read_file(path) tm.ok(read_result) tm.that(read_result.value, eq={"key": "value"}) def test_read_json_fails_for_missing_file(self, tmp_path: Path) -> None: - tm.fail(cli.read_json_file(tmp_path / "missing.json")) + tm.fail(cli.json_read_file(tmp_path / "missing.json")) def test_read_json_model_parses_into_typed_model(self, tmp_path: Path) -> None: path = tmp_path / "opts.json" path.write_text('{"indent": 4, "sort_keys": true}', encoding="utf-8") - result = cli.read_json_model(path, m.Cli.JsonWriteOptions) + result = cli.json_read_model(path, m.Cli.JsonWriteOptions) tm.ok(result) tm.that(result.value.indent, eq=4) tm.that(result.value.sort_keys, eq=True) def test_write_then_read_yaml_round_trips(self, tmp_path: Path) -> None: path = tmp_path / "data.yaml" - tm.ok(cli.write_yaml_file(path, {"key": "val"})) - read_result = cli.read_yaml_file(path) + tm.ok(cli.yaml_write_file(path, {"key": "val"})) + read_result = cli.yaml_read_file(path) tm.ok(read_result) tm.that(read_result.value, eq={"key": "val"}) def test_read_yaml_fails_for_missing_file(self, tmp_path: Path) -> None: - tm.fail(cli.read_yaml_file(tmp_path / "missing.yaml")) + tm.fail(cli.yaml_read_file(tmp_path / "missing.yaml")) def test_read_yaml_fails_for_blank_path(self) -> None: - tm.fail(cli.read_yaml_file(" ")) + tm.fail(cli.yaml_read_file(" ")) def test_write_then_read_csv_preserves_data_rows(self, tmp_path: Path) -> None: path = tmp_path / "data.csv" rows: list[t.StrSequence] = [["name", "age"], ["alice", "30"], ["bob", "25"]] - tm.ok(cli.write_csv_file(path, rows)) - read_result = cli.read_csv_file_with_headers(path) + tm.ok(cli.csv_write_file(path, rows)) + read_result = cli.csv_read_file_with_headers(path) tm.ok(read_result) tm.that(len(read_result.value), eq=2) def test_read_csv_fails_for_missing_file(self, tmp_path: Path) -> None: - tm.fail(cli.read_csv_file_with_headers(tmp_path / "missing.csv")) + tm.fail(cli.csv_read_file_with_headers(tmp_path / "missing.csv")) def test_write_then_read_binary_round_trips_bytes(self, tmp_path: Path) -> None: path = tmp_path / "data.bin" diff --git a/tests/unit/test_json_cov.py b/tests/unit/test_json_cov.py index 18b73ea10..6ff19a642 100644 --- a/tests/unit/test_json_cov.py +++ b/tests/unit/test_json_cov.py @@ -20,9 +20,9 @@ class TestsFlextCliJsonCov: # ----- normalize ------------------------------------------------------- - def test_normalize_json_value_preserves_mapping(self) -> None: + def test_json_normalize_value_preserves_mapping(self) -> None: """Preserve a JSON-compatible mapping during normalization.""" - tm.that(u.Cli.normalize_json_value({"key": "value"}), eq={"key": "value"}) + tm.that(u.Cli.json_normalize_value({"key": "value"}), eq={"key": "value"}) # ----- json_read (fallible, r[JsonMapping]) ---------------------------- diff --git a/tests/unit/test_options_public_cov.py b/tests/unit/test_options_public_cov.py index 7faefa35f..0c642e6e5 100644 --- a/tests/unit/test_options_public_cov.py +++ b/tests/unit/test_options_public_cov.py @@ -66,7 +66,7 @@ def test_normalize_cli_atom_returns_typer_ready_value_or_none( self, value: t.Cli.CliDefaultSource, expected: t.Cli.DefaultAtom | None ) -> None: """Normalize supported CLI atoms and reject unsupported values.""" - tm.that(u.Cli.normalize_cli_atom(value), eq=expected) + tm.that(u.Cli.cli_normalize_atom(value), eq=expected) @pytest.mark.parametrize( ("value", "expected"), From 75fade37bcd747f5ee02c7668a79182826e43738 Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Thu, 16 Jul 2026 21:20:30 -0300 Subject: [PATCH 23/37] fixes --- examples/README.md | 2 +- .../_base/flextcliprotocolsbase_part_01.py | 79 -------------- .../_base/flextcliprotocolsbase_part_02.py | 32 +----- .../_base/flextcliprotocolsbase_part_05.py | 2 - src/flext_cli/_protocols/settings.py | 103 ++++++++++++++++++ src/flext_cli/_utilities/settings.py | 2 +- src/flext_cli/protocols.py | 2 + 7 files changed, 108 insertions(+), 114 deletions(-) delete mode 100644 src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_01.py create mode 100644 src/flext_cli/_protocols/settings.py diff --git a/examples/README.md b/examples/README.md index c40bba0be..a54ee2897 100644 --- a/examples/README.md +++ b/examples/README.md @@ -62,7 +62,7 @@ from examples import c from flext_cli import cli cli.print("hello", style=c.Cli.MessageStyles.GREEN) -result = cli.read_json_file("settings.json") +result = cli.json_read_file("settings.json") ``` Keep interaction with flext-cli on the public facade unless the example is explicitly documenting an internal type. diff --git a/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_01.py b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_01.py deleted file mode 100644 index 6deeebb41..000000000 --- a/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_01.py +++ /dev/null @@ -1,79 +0,0 @@ -"""FlextCli protocol definitions - Structural typing contracts. - -Copyright (c) 2025 FLEXT Team. All rights reserved. -SPDX-License-Identifier: MIT -""" - -from __future__ import annotations - -from typing import Protocol, runtime_checkable - - -class FlextCliProtocolsBase: - """Implementation part for FlextCliProtocolsBase.""" - - @runtime_checkable - class CliSettings(Protocol): - """Flat CLI runtime settings (§2.6 — simple scalars only). - - NOTE (multi-agent): the nested ``Cli`` branch was removed; settings - are flat ``cli_*`` scalars loadable from env/.env. Test-runtime - detection moved to ``u.Cli.cli_test_env`` (behavior lives in the - utilities layer, never on settings). Plain ``Protocol`` (not - ``p.BaseModel``): pyrefly cannot reconcile pydantic ``model_fields`` - metaclass descriptors on this hot path — structural field access is - the whole contract. - """ - - @property - def cli_app_name(self) -> str: - """CLI application name.""" - ... - - @property - def cli_log_level(self) -> str: - """CLI log level.""" - ... - - @property - def cli_log_verbosity(self) -> str: - """Log verbosity mode.""" - ... - - @property - def cli_no_color(self) -> bool: - """Whether color output is disabled.""" - ... - - @property - def cli_output_format(self) -> str: - """Configured output format.""" - ... - - @property - def cli_quiet(self) -> bool: - """Whether quiet mode is enabled.""" - ... - - @property - def cli_verbose(self) -> bool: - """Whether verbose mode is enabled.""" - ... - - cli_config_file: str | None - """Path to the configured settings file.""" - - cli_token_file: str | None - """Path to the configured authentication token file.""" - - cli_ci: bool - """Whether the current runtime is a CI environment.""" - - cli_pytest_current_test: str | None - """Current pytest test identifier, when present.""" - - cli_shell_command: str | None - """Current shell command propagated by the runtime environment.""" - - -__all__: list[str] = ["FlextCliProtocolsBase"] diff --git a/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_02.py b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_02.py index 6d19f4e10..9fefea31b 100644 --- a/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_02.py +++ b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_02.py @@ -8,40 +8,10 @@ from typing import Protocol, runtime_checkable -from flext_cli._protocols._base.flextcliprotocolsbase_part_01 import ( - FlextCliProtocolsBase as FlextCliProtocolsBasePart01, -) -from flext_core import p - -class FlextCliProtocolsBase(FlextCliProtocolsBasePart01): +class FlextCliProtocolsBase: """Implementation part for FlextCliProtocolsBase.""" - @runtime_checkable - class Settings(p.Settings, FlextCliProtocolsBasePart01.CliSettings, Protocol): - """Protocol for CLI runtime settings consumed by the public services. - - NOTE (multi-agent): settings are flat ``cli_*`` scalars (§2.6); the - nested ``Cli`` branch and its pyrefly ``Final`` workaround were - removed with it. The flat field contract comes from - ``CliSettings`` (part_01) via protocol composition. - """ - - @property - def debug(self) -> bool: - """Check if debug mode is enabled.""" - ... - - @property - def trace(self) -> bool: - """Check if trace mode is enabled.""" - ... - - @classmethod - def reset_for_testing(cls) -> None: - """Reset the process-wide singleton (test isolation only).""" - ... - @runtime_checkable class CommandOutput(Protocol): """Minimal external command execution output contract.""" diff --git a/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_05.py b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_05.py index 0aac684b1..f9e20b95d 100644 --- a/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_05.py +++ b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_05.py @@ -12,8 +12,6 @@ FlextCliProtocolsBase as FlextCliProtocolsBasePart04, ) -# mro-wkii.17.26 (codex): YAML protocol data is defined by the upstream JSON -# alias; importing the local t facade would re-enter its own p composition. from flext_core import t diff --git a/src/flext_cli/_protocols/settings.py b/src/flext_cli/_protocols/settings.py new file mode 100644 index 000000000..8e06f9c2c --- /dev/null +++ b/src/flext_cli/_protocols/settings.py @@ -0,0 +1,103 @@ +"""Settings-domain protocols part (composed into ``p.Cli`` via MRO). + +Structural, field-level protocols for the validated config domains — never +model classes, never ``Any``/``object``. No runtime project imports; importable +by ``c``/``t``/``p``/``m``/``u`` without creating a cycle (foundation purity). + +Copyright (c) 2025 FLEXT Team. All rights reserved. +SPDX-License-Identifier: MIT +""" + +from __future__ import annotations + +from typing import Protocol, runtime_checkable +from flext_core import p + + +class FlextCliProtocolsSettings: + """Settings-domain protocol namespace (structural types; no project imports).""" + + @runtime_checkable + class Settings(p.Settings, Protocol): + """Protocol for CLI runtime settings consumed by the public services. + + Flat ``cli_*`` scalars (§2.6) loadable from env/.env; the nested + ``Cli`` branch was removed. ``clone`` and the base contract come from + the upstream ``p.Settings``; the ``cli_*`` fields below are the + flext-cli surface consumers type against as ``p.Cli.Settings``. + """ + + @property + def cli_app_name(self) -> str: + """CLI application name.""" + ... + + @property + def cli_ci(self) -> bool: + """Whether running in a CI environment.""" + ... + + @property + def cli_config_file(self) -> str | None: + """Optional CLI config file path.""" + ... + + @property + def cli_log_level(self) -> str: + """CLI log level.""" + ... + + @property + def cli_log_verbosity(self) -> str: + """CLI log verbosity.""" + ... + + @property + def cli_no_color(self) -> bool: + """Whether color output is disabled.""" + ... + + @property + def cli_output_format(self) -> str: + """CLI output format.""" + ... + + @property + def cli_pytest_current_test(self) -> str | None: + """Current pytest test id when under test, else None.""" + ... + + @property + def cli_quiet(self) -> bool: + """Whether quiet mode is enabled.""" + ... + + @property + def cli_shell_command(self) -> str | None: + """Originating shell command, if known.""" + ... + + @property + def cli_token_file(self) -> str | None: + """Optional auth token file path.""" + ... + + @property + def cli_verbose(self) -> bool: + """Whether verbose mode is enabled.""" + ... + + @property + def debug(self) -> bool: + """Check if debug mode is enabled.""" + ... + + @property + def trace(self) -> bool: + """Check if trace mode is enabled.""" + ... + + @classmethod + def reset_for_testing(cls) -> None: + """Reset the process-wide singleton (test isolation only).""" + ... diff --git a/src/flext_cli/_utilities/settings.py b/src/flext_cli/_utilities/settings.py index 47e1fd71c..95c60ca98 100644 --- a/src/flext_cli/_utilities/settings.py +++ b/src/flext_cli/_utilities/settings.py @@ -14,7 +14,7 @@ class FlextCliUtilitiesSettings: """Settings and selector methods exposed directly on ``u.Cli``.""" @staticmethod - def cli_test_env(cli_settings: p.Cli.CliSettings) -> bool: + def cli_test_env(cli_settings: p.Cli.Settings) -> bool: """Detect test/CI runtime from the flat CLI settings scalars. NOTE (multi-agent): replaces the removed ``settings.Cli.test_env`` diff --git a/src/flext_cli/protocols.py b/src/flext_cli/protocols.py index 77a75ef62..99f5e4d4a 100644 --- a/src/flext_cli/protocols.py +++ b/src/flext_cli/protocols.py @@ -7,6 +7,7 @@ from flext_cli._protocols.domain import FlextCliProtocolsDomain from flext_cli._protocols.framework import FlextCliProtocolsFramework from flext_cli._protocols.pipeline import FlextCliProtocolsPipeline +from flext_cli._protocols.settings import FlextCliProtocolsSettings from flext_cli._protocols.xlsx import FlextCliProtocolsXlsx from flext_cli._protocols.toml import FlextCliProtocolsToml from flext_core import p @@ -25,6 +26,7 @@ class Cli( FlextCliProtocolsFramework, FlextCliProtocolsBase, FlextCliProtocolsConfig, + FlextCliProtocolsSettings, FlextCliProtocolsXlsx, FlextCliProtocolsToml, ): From e1393ed6d2657dc686ad285c35c5d46200af1a0e Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Thu, 16 Jul 2026 21:58:38 -0300 Subject: [PATCH 24/37] fixes --- src/flext_cli/_constants/exceptions.py | 60 ++++++++----------- .../_base/flextclimodelsbase_part_01.py | 2 +- .../_base/flextclimodelsbase_part_06.py | 8 +-- .../_base/flextcliprotocolsbase_part_03.py | 2 +- .../_base/flextcliprotocolsbase_part_04.py | 4 +- src/flext_cli/_protocols/domain.py | 2 +- src/flext_cli/_typings/base.py | 10 ++-- src/flext_cli/_typings/domain.py | 8 +-- .../flextcliutilitiesoptions_part_01.py | 6 +- .../flextcliutilitiesoptions_part_02.py | 4 +- src/flext_cli/_utilities/_rules/_loaders.py | 2 +- src/flext_cli/_utilities/framework.py | 6 +- src/flext_cli/_utilities/model_commands.py | 11 ++-- src/flext_cli/_utilities/params.py | 16 ++--- src/flext_cli/_utilities/template.py | 4 +- src/flext_cli/_utilities/validation.py | 4 +- src/flext_cli/_utilities/yaml_model.py | 4 +- .../services/_cli/flextclicli_part_01.py | 4 +- .../services/_cli/flextclicli_part_02.py | 12 ++-- .../services/_cli/flextclicli_part_03.py | 4 +- .../services/_cli/flextclicli_part_04.py | 4 +- src/flext_cli/services/cli_params.py | 4 +- tests/_constants_parts/tests_core.py | 5 +- tests/_constants_parts/tests_rules_options.py | 5 +- tests/_constants_parts/tests_yaml_output.py | 5 +- tests/_models_parts/tests_runtime.py | 2 +- tests/_models_parts/tests_version.py | 5 +- tests/conftest.py | 4 +- tests/protocols.py | 4 +- tests/test_yaml_model_write.py | 2 - tests/typings.py | 2 +- .../testsflextcliservice_part_01.py | 8 +-- .../testsflextcliservice_part_02.py | 2 - .../testsflextcliservice_part_04.py | 2 - .../testsflextcliservice_part_05.py | 2 - .../testsflextcliexamplessmoke_part_01.py | 1 - .../testsflextcliexamplessmoke_part_02.py | 2 - .../testsflextcliexamplessmoke_part_03.py | 2 - .../testsflextcliexamplessmoke_part_04.py | 2 - .../testsflextclifilescov_part_01.py | 4 +- .../testsflextclifilescov_part_02.py | 2 - .../testsflextclijsoncov_part_01.py | 4 +- .../testsflextclioutputcov_part_02.py | 2 - .../testsflextclipipeline_part_01.py | 5 +- .../testsflextclipipeline_part_02.py | 5 +- .../testsflextclipipeline_part_03.py | 4 +- .../testsflextcliprompts_part_01.py | 3 - .../testsflextcliprompts_part_02.py | 2 - ...flextclipubliccontractscoverage_part_01.py | 1 - ...flextclipubliccontractscoverage_part_02.py | 2 - ...flextclipubliccontractscoverage_part_03.py | 2 - .../testsflextclirulescov_part_01.py | 4 +- .../testsflextclirulescov_part_03.py | 4 +- .../testsflextclirulescov_part_04.py | 4 +- .../testsflextclitomlutilities_part_01.py | 4 +- .../testsflextclitomlutilities_part_02.py | 4 +- .../testsflextclitomlutilities_part_03.py | 4 +- tests/unit/conftest.py | 5 +- tests/unit/test_auth_utils_cov.py | 4 +- tests/unit/test_cli_params.py | 4 +- tests/unit/test_cmd.py | 2 - tests/unit/test_cmd_cov.py | 2 - .../test_cmd_runtime_validation_branch_cov.py | 6 +- tests/unit/test_commands_utils_cov.py | 5 +- tests/unit/test_conversion_cov.py | 4 +- tests/unit/test_files_cov.py | 4 +- tests/unit/test_formatters_cov.py | 4 +- tests/unit/test_json_cov.py | 4 +- tests/unit/test_matching_cov.py | 4 +- tests/unit/test_options_cov.py | 2 +- tests/unit/test_options_public_cov.py | 6 +- tests/unit/test_params_branch_cov.py | 38 ++++++------ tests/unit/test_prompts_cov.py | 2 - tests/unit/test_rules_cov.py | 4 +- tests/unit/test_runtime_utilities_core.py | 2 - tests/unit/test_runtime_utilities_extra.py | 2 - tests/unit/test_services_auth_branch_cov.py | 2 - tests/unit/test_services_auth_cov.py | 2 - tests/unit/test_services_tables_branch_cov.py | 4 +- tests/unit/test_tables.py | 4 +- tests/unit/test_tables_cov.py | 4 +- tests/unit/test_toml_cov.py | 2 - tests/unit/test_toml_sync_cov.py | 4 +- tests/unit/test_toml_utilities.py | 4 +- tests/unit/test_typings.py | 2 - tests/unit/test_utilities_cov.py | 4 +- tests/unit/test_yaml_cov.py | 4 +- tests/unit/test_yaml_roundtrip.py | 4 +- 88 files changed, 162 insertions(+), 278 deletions(-) diff --git a/src/flext_cli/_constants/exceptions.py b/src/flext_cli/_constants/exceptions.py index 90b5324e6..6c20e5bc5 100644 --- a/src/flext_cli/_constants/exceptions.py +++ b/src/flext_cli/_constants/exceptions.py @@ -14,33 +14,6 @@ from flext_core import e -# NOTE (multi-agent): base classes come from the PUBLIC ``flext_core.e`` facade. -# ``e.ValidationError`` IS ``FlextExceptionsTypes.ValidationError`` (same class -# object via MRO) — verified, behavior-preserving. Do not re-import the private -# ``flext_core._exceptions.types`` module (ruff PLC2701). -class CliDefinitionError(e.ValidationError): - """Located CLI definition-time failure (route/model/field). - - Raised while building/registering the automatic CLI so that consumers - surface ``[CLI_DEFINITION_ERROR] command '' field '': ...`` - instead of a raw stacktrace. Inherits ``[code] message`` rendering and - correlation metadata from ``flext_core`` ``e.ValidationError``. - """ - - _default_error_code: ClassVar[str] = "CLI_DEFINITION_ERROR" - - -class CliValidationError(e.ValidationError): - """Located CLI runtime input failure (command/field). - - Raised when ``model_validate`` rejects user input so that consumers - surface ``[VALIDATION_ERROR] command '' field '': ...`` - instead of pydantic's multi-line dump. - """ - - _default_error_code: ClassVar[str] = "VALIDATION_ERROR" - - class FlextCliConstantsExceptions: """Canonical owned exception types for cross-project consumption.""" @@ -51,12 +24,31 @@ class FlextCliConstantsExceptions: # (validation.py). YamlParseError: ClassVar[type[Exception]] = YAMLError YamlRoundtripError: ClassVar[type[Exception]] = RuamelYAMLError - CliDefinitionError: ClassVar[type[CliDefinitionError]] = CliDefinitionError - CliValidationError: ClassVar[type[CliValidationError]] = CliValidationError + + # NOTE (multi-agent): base classes come from the PUBLIC ``flext_core.e`` facade. + # ``e.ValidationError`` IS ``FlextExceptionsTypes.ValidationError`` (same class + # object via MRO) — verified, behavior-preserving. Do not re-import the private + # ``flext_core._exceptions.types`` module (ruff PLC2701). + class DefinitionError(e.ValidationError): + """Located CLI definition-time failure (route/model/field). + + Raised while building/registering the automatic CLI so that consumers + surface ``[CLI_DEFINITION_ERROR] command '' field '': ...`` + instead of a raw stacktrace. Inherits ``[code] message`` rendering and + correlation metadata from ``flext_core`` ``e.ValidationError``. + """ + + _default_error_code: ClassVar[str] = "CLI_DEFINITION_ERROR" + + class ValidationError(e.ValidationError): + """Located CLI runtime input failure (command/field). + + Raised when ``model_validate`` rejects user input so that consumers + surface ``[VALIDATION_ERROR] command '' field '': ...`` + instead of pydantic's multi-line dump. + """ + + _default_error_code: ClassVar[str] = "VALIDATION_ERROR" -__all__: list[str] = [ - "CliDefinitionError", - "CliValidationError", - "FlextCliConstantsExceptions", -] +__all__: list[str] = ["FlextCliConstantsExceptions"] diff --git a/src/flext_cli/_models/_base/flextclimodelsbase_part_01.py b/src/flext_cli/_models/_base/flextclimodelsbase_part_01.py index 3defc4e75..27a0f8341 100644 --- a/src/flext_cli/_models/_base/flextclimodelsbase_part_01.py +++ b/src/flext_cli/_models/_base/flextclimodelsbase_part_01.py @@ -95,7 +95,7 @@ class LoadedConfig(m.BaseModel): class JsonNormalized(m.RootModel[t.JsonValue]): """Normalize raw JSON value with flat JSON serialization semantics. - + ``RootModel`` provides positional construction (``JsonNormalized(value)``) and root-level serialization natively — no custom ``__init__`` or ``model_serializer`` required. diff --git a/src/flext_cli/_models/_base/flextclimodelsbase_part_06.py b/src/flext_cli/_models/_base/flextclimodelsbase_part_06.py index 718fbacc0..e1f086198 100644 --- a/src/flext_cli/_models/_base/flextclimodelsbase_part_06.py +++ b/src/flext_cli/_models/_base/flextclimodelsbase_part_06.py @@ -11,7 +11,7 @@ class FlextCliModelsBase: """Implementation part for FlextCliModelsBase.""" - class CliParamsConfig(m.Value): + class ParamsConfig(m.Value): """CLI parameters configuration for command-line parsing. Maps directly to CLI flags: --verbose, --quiet, --debug, --trace, etc. @@ -46,7 +46,7 @@ class CliParamsConfig(m.Value): @property def params(self) -> t.JsonMapping: - """Parameters mapping - required by CliParamsConfig.""" + """Parameters mapping - required by ParamsConfig.""" return { "verbose": self.verbose or False, "quiet": self.quiet or False, @@ -75,7 +75,7 @@ class OptionMetadata(m.BaseModel): ), ] = "" default: Annotated[ - t.Cli.CliValue | None, + t.Cli.Value | None, m.Field(None, description="Option default value when explicitly provided"), ] = None field_name_override: Annotated[ @@ -94,7 +94,7 @@ class OptionSpec(m.Value): ] help_text: Annotated[str, m.Field(description="Human-readable option help")] default: Annotated[ - t.Cli.CliValue | None, + t.Cli.Value | None, m.Field(None, description="Validated optional default value"), ] = None required: Annotated[ diff --git a/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_03.py b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_03.py index 53668c6cc..3203d2614 100644 --- a/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_03.py +++ b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_03.py @@ -96,7 +96,7 @@ def run_to_file( ... @runtime_checkable - class CliParamsConfig(Protocol): + class ParamsConfig(Protocol): """Protocol for CLI parameters configuration.""" @property diff --git a/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_04.py b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_04.py index 260e17144..1eb0e1ecd 100644 --- a/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_04.py +++ b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_04.py @@ -56,7 +56,7 @@ def version(self) -> str: ... def components(self) -> FlextCliProtocolsBase.RuntimeComponents: ... @runtime_checkable - class CliOptionSpec(Protocol): + class OptionSpec(Protocol): """Framework-neutral option model contract returned by the CLI DSL.""" @property @@ -124,7 +124,7 @@ def clear_auth_tokens(self) -> p.Result[bool]: ... @runtime_checkable - class CliCommandWrapper(Protocol): + class CommandWrapper(Protocol): """Protocol for dynamically-created CLI command wrapper functions.""" def __call__( diff --git a/src/flext_cli/_protocols/domain.py b/src/flext_cli/_protocols/domain.py index a8bd3fccd..cde856f63 100644 --- a/src/flext_cli/_protocols/domain.py +++ b/src/flext_cli/_protocols/domain.py @@ -46,7 +46,7 @@ class CommandEntry(Protocol): name: str # mro-j47u (codex): callable behavior remains in the p facade. - handler: FlextCliProtocolsBase.CliCommandWrapper + handler: FlextCliProtocolsBase.CommandWrapper @runtime_checkable class ResultCommandRoute(Protocol): diff --git a/src/flext_cli/_typings/base.py b/src/flext_cli/_typings/base.py index 4ab3d1a30..7bdf1c9bd 100644 --- a/src/flext_cli/_typings/base.py +++ b/src/flext_cli/_typings/base.py @@ -31,9 +31,9 @@ class FlextCliTypesBase: type TableShowIndex = bool | TableIndexSelection type TableDisableNumparse = bool | t.SequenceOf[int] type TableColAlign = t.StrSequence | None - type CliValue = t.Scalar | t.StrSequence | DefaultMapping - type CliDefaultSource = CliValue | Path - type CliAnnotations = MutableMapping[str, type | GenericAlias] + type Value = t.Scalar | t.StrSequence | DefaultMapping + type DefaultSource = Value | Path + type Annotations = MutableMapping[str, type | GenericAlias] type TomlDocument = TOMLDocument type TomlTable = Table type TomlItem = Item @@ -61,8 +61,8 @@ class FlextCliTypesBase: t.json_mapping_adapter() ) YAML_SEQ_ADAPTER: ClassVar[t.ValueAdapter[t.JsonList]] = t.json_list_adapter() - CLI_DEFAULT_SOURCE_ADAPTER: ClassVar[t.ValueAdapter[CliDefaultSource]] = ( - t.TypeAdapter(CliDefaultSource) + CLI_DEFAULT_SOURCE_ADAPTER: ClassVar[t.ValueAdapter[DefaultSource]] = t.TypeAdapter( + DefaultSource ) diff --git a/src/flext_cli/_typings/domain.py b/src/flext_cli/_typings/domain.py index c0578746d..cac8e5b2c 100644 --- a/src/flext_cli/_typings/domain.py +++ b/src/flext_cli/_typings/domain.py @@ -50,15 +50,15 @@ class FlextCliTypesDomain: t.SequenceOf[tuple[TFileRuleKind, t.JsonMapping]], ] type RuleLoadOption[TRuleKind, TFileRuleKind] = ( - tb.CliValue + tb.Value | Path | FlextCliTypesDomain.RuleCatalog[TRuleKind] | FlextCliTypesDomain.RuleCatalog[TFileRuleKind] | None ) type MutableDefaultMapping = MutableMapping[str, t.Scalar | t.StrSequence] - type CliParamValue = bool | str - type CliParamKwargs = t.MappingKV[str, CliParamValue] + type ParamValue = bool | str + type ParamKwargs = t.MappingKV[str, ParamValue] type DefaultAtom = t.Scalar | t.StrSequence type ProjectNamesValue = str | t.StrSequence type TableHeaders = str | t.StrSequence @@ -70,7 +70,7 @@ class FlextCliTypesDomain: type OptionRegistry = t.MappingKV[str, t.MappingKV[str, t.Scalar | t.StrSequence]] type NullaryOperation[T] = Callable[[], T] type PromptTextReader = Callable[[str], str] - type CliCommand = Callable[..., t.JsonPayload] + type Command = Callable[..., t.JsonPayload] # mro-j47u (codex): one generic alias owns formatter data and call contracts. type JsonCommandFn = Callable[..., p.Result[t.JsonPayload]] # NOTE (multi-agent): route outputs are observation-only so payloads covary. diff --git a/src/flext_cli/_utilities/_options/flextcliutilitiesoptions_part_01.py b/src/flext_cli/_utilities/_options/flextcliutilitiesoptions_part_01.py index 3bccde9c6..51c7cf198 100644 --- a/src/flext_cli/_utilities/_options/flextcliutilitiesoptions_part_01.py +++ b/src/flext_cli/_utilities/_options/flextcliutilitiesoptions_part_01.py @@ -87,7 +87,7 @@ def resolve_typer_annotation( ) @staticmethod - def is_string_sequence(value: t.Cli.CliDefaultSource) -> bool: + def is_string_sequence(value: t.Cli.DefaultSource) -> bool: """Return True for concrete string sequences accepted by repeated CLI options.""" if isinstance(value, Path) or not isinstance(value, Sequence): return False @@ -96,9 +96,7 @@ def is_string_sequence(value: t.Cli.CliDefaultSource) -> bool: return all(item for item in value) @classmethod - def cli_normalize_atom( - cls, value: t.Cli.CliDefaultSource - ) -> t.Cli.DefaultAtom | None: + def cli_normalize_atom(cls, value: t.Cli.DefaultSource) -> t.Cli.DefaultAtom | None: """Normalize one runtime value into an allowed Typer scalar or string sequence.""" if isinstance(value, c.Cli.CLI_SCALAR_TYPES_TUPLE): return value diff --git a/src/flext_cli/_utilities/_options/flextcliutilitiesoptions_part_02.py b/src/flext_cli/_utilities/_options/flextcliutilitiesoptions_part_02.py index 1eed1e299..3e5e2e60b 100644 --- a/src/flext_cli/_utilities/_options/flextcliutilitiesoptions_part_02.py +++ b/src/flext_cli/_utilities/_options/flextcliutilitiesoptions_part_02.py @@ -19,7 +19,7 @@ class FlextCliUtilitiesOptions(FlextCliUtilitiesOptionsPart01): @classmethod def field_default( cls, field_name: str, field_info: p.FieldInfo, settings: t.Cli.ModelLike | None - ) -> t.Cli.CliValue | None: + ) -> t.Cli.Value | None: """Resolve CLI default from settings first, then from model field metadata.""" default_factory = getattr(field_info, "default_factory", None) source_value = ( @@ -41,7 +41,7 @@ def field_default( case _ if ( normalized_atom := cls.cli_normalize_atom(normalized_source) ) is not None: - normalized_default: t.Cli.CliValue | None = normalized_atom + normalized_default: t.Cli.Value | None = normalized_atom case Mapping() as normalized_source_mapping: normalized_mapping: t.Cli.MutableDefaultMapping = {} for key, item_value in normalized_source_mapping.items(): diff --git a/src/flext_cli/_utilities/_rules/_loaders.py b/src/flext_cli/_utilities/_rules/_loaders.py index fab7606ad..083a6d413 100644 --- a/src/flext_cli/_utilities/_rules/_loaders.py +++ b/src/flext_cli/_utilities/_rules/_loaders.py @@ -86,7 +86,7 @@ def rules_load_registry( def rules_load_local_definitions[TRuleKind, TFileRuleKind]( cls, config_path: Path, - **kwargs: t.Cli.CliValue + **kwargs: t.Cli.Value | Path | t.Cli.RuleCatalog[TRuleKind] | t.Cli.RuleCatalog[TFileRuleKind] diff --git a/src/flext_cli/_utilities/framework.py b/src/flext_cli/_utilities/framework.py index f4dfd0461..87df49708 100644 --- a/src/flext_cli/_utilities/framework.py +++ b/src/flext_cli/_utilities/framework.py @@ -149,7 +149,7 @@ def framework_add_group( @classmethod def framework_register_callback( - cls, application: p.Cli.Application, callback: t.Cli.CliCommand + cls, application: p.Cli.Application, callback: t.Cli.Command ) -> None: """Register one application callback.""" _ = cls._unwrap(application).callback()(callback) @@ -161,7 +161,7 @@ def framework_register_command( *, name: str, help_text: str, - command: t.Cli.CliCommand, + command: t.Cli.Command, ) -> None: """Register one named command.""" _ = cls._unwrap(application).command(name, help=help_text)(command) @@ -171,7 +171,7 @@ def framework_build_parameter( field_name: str, annotation: type | GenericAlias, spec: p.Cli.OptionSpec ) -> Parameter: """Build one inspect parameter with a private Typer option default.""" - option_default: t.Cli.CliValue | EllipsisType | None = ( + option_default: t.Cli.Value | EllipsisType | None = ( ... if spec.required else spec.default ) option = OptionInfo( diff --git a/src/flext_cli/_utilities/model_commands.py b/src/flext_cli/_utilities/model_commands.py index 07a148599..dad5f8eca 100644 --- a/src/flext_cli/_utilities/model_commands.py +++ b/src/flext_cli/_utilities/model_commands.py @@ -32,17 +32,16 @@ def __init__( self.model_class = model_class self.handler = handler - def _resolve_default(self, field_info: p.FieldInfo) -> t.Cli.CliValue | type: + def _resolve_default(self, field_info: p.FieldInfo) -> t.Cli.Value | type: if field_info.is_required(): return inspect.Parameter.empty # NOTE (multi-agent): ``FieldInfo.get_default`` is typed ``Any`` # in pydantic; the declared union is the real runtime contract. return cast( - "t.Cli.CliValue | type", - field_info.get_default(call_default_factory=True), + "t.Cli.Value | type", field_info.get_default(call_default_factory=True) ) - def build(self) -> t.Cli.CliCommand: + def build(self) -> t.Cli.Command: """Build a direct callable with a real runtime signature.""" model_fields = getattr(self.model_class, "model_fields", {}) parameters = [ @@ -63,7 +62,7 @@ def build(self) -> t.Cli.CliCommand: # Settings protocol (has update_global) — a plain model skips them. effective_settings = settings - def command(**kwargs: t.Cli.CliValue) -> t.JsonValue: + def command(**kwargs: t.Cli.Value) -> t.JsonValue: settings_fields = effective_settings.model_dump() applicable_overrides = { field_name: field_value @@ -121,7 +120,7 @@ def build_model_command[M: t.Cli.ModelLike]( model_class: t.ModelClass[M], handler: Callable[[M], t.JsonValue], settings: t.Cli.ModelLike | None = None, - ) -> t.Cli.CliCommand: + ) -> t.Cli.Command: """Build a model command through the canonical CLI service.""" # NOTE (multi-agent): All model-class ingress uses t.ModelClass. return FlextCliUtilitiesModelCommands.Builder( diff --git a/src/flext_cli/_utilities/params.py b/src/flext_cli/_utilities/params.py index af35061f7..f6a9efb3c 100644 --- a/src/flext_cli/_utilities/params.py +++ b/src/flext_cli/_utilities/params.py @@ -12,19 +12,19 @@ class FlextCliUtilitiesParams: @staticmethod def params_resolve( - params: p.Cli.CliParamsConfig | None, kwargs: t.Cli.CliParamKwargs - ) -> p.Cli.CliParamsConfig: + params: p.Cli.ParamsConfig | None, kwargs: t.Cli.ParamKwargs + ) -> p.Cli.ParamsConfig: """Resolve explicit params and kwargs into one validated model.""" - kwargs_model = m.Cli.CliParamsConfig.model_validate(kwargs) + kwargs_model = m.Cli.ParamsConfig.model_validate(kwargs) if params is None: return kwargs_model - if not isinstance(params, m.Cli.CliParamsConfig): + if not isinstance(params, m.Cli.ParamsConfig): return kwargs_model return params.model_copy(update=kwargs_model.model_dump(exclude_none=True)) @staticmethod def params_set_bool( - settings: p.Cli.Settings, params: p.Cli.CliParamsConfig + settings: p.Cli.Settings, params: p.Cli.ParamsConfig ) -> p.Result[p.Cli.Settings]: """Set boolean parameters through validated model_copy updates.""" if params.trace is not None and params.trace: @@ -49,7 +49,7 @@ def params_set_bool( @staticmethod def params_set_log_level( - settings: p.Cli.Settings, params: p.Cli.CliParamsConfig + settings: p.Cli.Settings, params: p.Cli.ParamsConfig ) -> p.Result[p.Cli.Settings]: """Set CLI log level with enum conversion/validation.""" if params.log_level is None: @@ -72,7 +72,7 @@ def params_set_log_level( @staticmethod def params_set_format( - settings: p.Cli.Settings, params: p.Cli.CliParamsConfig + settings: p.Cli.Settings, params: p.Cli.ParamsConfig ) -> p.Result[p.Cli.Settings]: """Set output/log format values with canonical validation helpers.""" next_config = settings @@ -105,7 +105,7 @@ def params_set_format( @staticmethod def params_apply( - settings: p.Cli.Settings, params: p.Cli.CliParamsConfig + settings: p.Cli.Settings, params: p.Cli.ParamsConfig ) -> p.Result[p.Cli.Settings]: """Apply all parameter-setting stages to one settings model.""" return ( diff --git a/src/flext_cli/_utilities/template.py b/src/flext_cli/_utilities/template.py index 08695e85e..581b8fd8c 100644 --- a/src/flext_cli/_utilities/template.py +++ b/src/flext_cli/_utilities/template.py @@ -61,7 +61,9 @@ def template_render(path: Path, context: p.BaseModel) -> p.Result[str]: return r[str].ok(rendered.value) @staticmethod - def template_render_to(path: Path, dest: Path, context: p.BaseModel) -> p.Result[bool]: + def template_render_to( + path: Path, dest: Path, context: p.BaseModel + ) -> p.Result[bool]: """Render ``path`` with ``context`` and write it to ``dest`` → ``r[bool]``.""" rendered = FlextCliUtilitiesTemplate.template_render(path, context) if rendered.failure: diff --git a/src/flext_cli/_utilities/validation.py b/src/flext_cli/_utilities/validation.py index df6ad97ad..904536310 100644 --- a/src/flext_cli/_utilities/validation.py +++ b/src/flext_cli/_utilities/validation.py @@ -45,7 +45,7 @@ def process_mapping[T, U]( @staticmethod def validate_not_empty( - val: t.Cli.CliValue | None, *, name: str = "field" + val: t.Cli.Value | None, *, name: str = "field" ) -> p.Result[bool]: """Validate that a value is not empty.""" if val is None: @@ -107,7 +107,7 @@ def assert_model_definition(model_cls: object, *, command: str) -> None: model_name = getattr(model_cls, "__name__", repr(model_cls)) model_fields = getattr(model_cls, "model_fields", None) if not isinstance(model_fields, dict) or not model_fields: - raise c.Cli.CliDefinitionError( + raise c.Cli.DefinitionError( c.Cli.ERR_CLI_DEFINITION_INVALID_MODEL.format( command=command, model=model_name, diff --git a/src/flext_cli/_utilities/yaml_model.py b/src/flext_cli/_utilities/yaml_model.py index cab521f5b..19050fbd6 100644 --- a/src/flext_cli/_utilities/yaml_model.py +++ b/src/flext_cli/_utilities/yaml_model.py @@ -14,7 +14,9 @@ class FlextCliUtilitiesYamlModel: # NOTE (multi-agent, mro-j2yt.1): the validated model remains intact until # this external egress; no internal dump/revalidation round trip is allowed. @staticmethod - def yaml_write_model(file_path: t.Cli.TextPath, model: p.BaseModel) -> p.Result[bool]: + def yaml_write_model( + file_path: t.Cli.TextPath, model: p.BaseModel + ) -> p.Result[bool]: """Write one protocol-backed model as YAML and propagate failures.""" try: return FlextCliUtilitiesYaml.yaml_dump( diff --git a/src/flext_cli/services/_cli/flextclicli_part_01.py b/src/flext_cli/services/_cli/flextclicli_part_01.py index c31538c30..6a8a3fcbb 100644 --- a/src/flext_cli/services/_cli/flextclicli_part_01.py +++ b/src/flext_cli/services/_cli/flextclicli_part_01.py @@ -41,7 +41,7 @@ def __init__( self._handler = handler self._model_cls = model_cls - def __call__(self, **kwargs: t.Cli.CliValue) -> t.JsonValue: + def __call__(self, **kwargs: t.Cli.Value) -> t.JsonValue: # mro-wkii.17.26 (codex): the adapter supplies field names while # external callers may use declared aliases at this single boundary. model = self._model_cls.model_validate(kwargs, by_alias=True, by_name=True) @@ -59,7 +59,7 @@ def _build_model_parameter( getattr(field_info, "annotation", None) or str ) is_required = field_info.is_required() - default_value: t.Cli.CliValue | None = ( + default_value: t.Cli.Value | None = ( None if is_required else u.Cli.field_default(field_name, field_info, settings) diff --git a/src/flext_cli/services/_cli/flextclicli_part_02.py b/src/flext_cli/services/_cli/flextclicli_part_02.py index f311ba00c..d661b2cce 100644 --- a/src/flext_cli/services/_cli/flextclicli_part_02.py +++ b/src/flext_cli/services/_cli/flextclicli_part_02.py @@ -16,7 +16,7 @@ class FlextCliCli(FlextCliCliPart01): """Implementation part for FlextCliCli.""" - def _apply_common_params_to_config(self, *, params: p.Cli.CliParamsConfig) -> None: + def _apply_common_params_to_config(self, *, params: p.Cli.ParamsConfig) -> None: """Apply global CLI flags to the shared settings singleton.""" resolved_log_level: str = ( params.log_level if params.log_level is not None else settings.cli_log_level @@ -64,23 +64,23 @@ def create_app_with_common_params( name=name, help_text=help_text, add_completion=add_completion ) - def apply_common_params(params: p.Cli.CliParamsConfig) -> bool: + def apply_common_params(params: p.Cli.ParamsConfig) -> bool: self._apply_common_params_to_config(params=params) return True field_names = ("debug", "trace", "verbose", "quiet", "log_level") parameters: t.MutableSequenceOf[Parameter] = [] - annotations: t.Cli.CliAnnotations = {"return": bool} + annotations: t.Cli.Annotations = {"return": bool} for field_name in field_names: parameter, annotation = self._build_model_parameter( - field_name, m.Cli.CliParamsConfig.model_fields[field_name], None + field_name, m.Cli.ParamsConfig.model_fields[field_name], None ) parameters.append(parameter) annotations[field_name] = annotation - global_callback: FlextCliCli._ModelCommand[p.Cli.CliParamsConfig] = ( + global_callback: FlextCliCli._ModelCommand[p.Cli.ParamsConfig] = ( self._ModelCommand( handler=apply_common_params, - model_cls=m.Cli.CliParamsConfig, + model_cls=m.Cli.ParamsConfig, parameters=parameters, ) ) diff --git a/src/flext_cli/services/_cli/flextclicli_part_03.py b/src/flext_cli/services/_cli/flextclicli_part_03.py index e4004dee9..58b8c82fc 100644 --- a/src/flext_cli/services/_cli/flextclicli_part_03.py +++ b/src/flext_cli/services/_cli/flextclicli_part_03.py @@ -25,10 +25,10 @@ def model_command[M: t.Cli.ModelLike]( model_cls: t.ModelClass[M], handler: p.Cli.ModelCommandHandler[M], settings: t.Cli.ModelLike | None = None, - ) -> t.Cli.CliCommand: + ) -> t.Cli.Command: """Build a Typer command directly from a Pydantic request model.""" parameters: t.MutableSequenceOf[Parameter] = [] - annotations: t.Cli.CliAnnotations = {"return": type(None)} + annotations: t.Cli.Annotations = {"return": type(None)} fields = getattr(model_cls, "model_fields", {}) for field_name, field_info in fields.items(): if getattr(field_info, "exclude", None) is True: diff --git a/src/flext_cli/services/_cli/flextclicli_part_04.py b/src/flext_cli/services/_cli/flextclicli_part_04.py index aa9e12e7f..aa3a7a0f3 100644 --- a/src/flext_cli/services/_cli/flextclicli_part_04.py +++ b/src/flext_cli/services/_cli/flextclicli_part_04.py @@ -36,7 +36,7 @@ def external_command(app: p.Cli.Application) -> p.Cli.ExternalCommand: return u.Cli.framework_external_command(app) @staticmethod - def register_callback(app: p.Cli.Application, *, command: t.Cli.CliCommand) -> None: + def register_callback(app: p.Cli.Application, *, command: t.Cli.Command) -> None: """Register one model-backed root callback.""" u.Cli.framework_register_callback(app, command) @@ -47,7 +47,7 @@ def exit(code: int = 0) -> None: @staticmethod def register_command( - app: p.Cli.Application, *, name: str, help_text: str, command: t.Cli.CliCommand + app: p.Cli.Application, *, name: str, help_text: str, command: t.Cli.Command ) -> None: """Register a command through the private framework boundary.""" u.Cli.framework_register_command( diff --git a/src/flext_cli/services/cli_params.py b/src/flext_cli/services/cli_params.py index 9098e7c8f..b4c65eaa5 100644 --- a/src/flext_cli/services/cli_params.py +++ b/src/flext_cli/services/cli_params.py @@ -21,8 +21,8 @@ class FlextCliCommonParams(s): def apply_to_config( cls, settings: p.Cli.Settings, - params: p.Cli.CliParamsConfig | None = None, - **kwargs: t.Cli.CliParamValue, + params: p.Cli.ParamsConfig | None = None, + **kwargs: t.Cli.ParamValue, ) -> p.Result[p.Cli.Settings]: """Apply CLI parameter values to FlextSettings using Pydantic validation. diff --git a/tests/_constants_parts/tests_core.py b/tests/_constants_parts/tests_core.py index a83abcd06..684debaa5 100644 --- a/tests/_constants_parts/tests_core.py +++ b/tests/_constants_parts/tests_core.py @@ -5,12 +5,11 @@ import re from enum import StrEnum, unique from types import MappingProxyType -from typing import TYPE_CHECKING, Final +from typing import Final from flext_cli import c -from tests import p, t - +from tests import t class TestsFlextCliConstantsCore: diff --git a/tests/_constants_parts/tests_rules_options.py b/tests/_constants_parts/tests_rules_options.py index 781cef6b7..1c041dc60 100644 --- a/tests/_constants_parts/tests_rules_options.py +++ b/tests/_constants_parts/tests_rules_options.py @@ -3,10 +3,9 @@ from __future__ import annotations from types import MappingProxyType -from typing import TYPE_CHECKING, Final - -from tests import p, t +from typing import Final +from tests import t class TestsFlextCliConstantsRulesOptions: diff --git a/tests/_constants_parts/tests_yaml_output.py b/tests/_constants_parts/tests_yaml_output.py index e47045ebd..1f70a090c 100644 --- a/tests/_constants_parts/tests_yaml_output.py +++ b/tests/_constants_parts/tests_yaml_output.py @@ -2,12 +2,11 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Final +from typing import Final from flext_cli import c -from tests import p, t - +from tests import t class TestsFlextCliConstantsYamlOutput: diff --git a/tests/_models_parts/tests_runtime.py b/tests/_models_parts/tests_runtime.py index f703e78a2..ddbf40bbd 100644 --- a/tests/_models_parts/tests_runtime.py +++ b/tests/_models_parts/tests_runtime.py @@ -5,7 +5,7 @@ from typing import Annotated, ClassVar, Self from flext_cli import m -from tests import p, t +from tests import t class TestsFlextCliModelsRuntime: diff --git a/tests/_models_parts/tests_version.py b/tests/_models_parts/tests_version.py index 11780a763..b682147c9 100644 --- a/tests/_models_parts/tests_version.py +++ b/tests/_models_parts/tests_version.py @@ -2,13 +2,12 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Annotated, ClassVar, Self +from typing import Annotated, ClassVar, Self from flext_cli import m from tests import c -from tests import p, t - +from tests import t class TestsFlextCliModelsVersion: diff --git a/tests/conftest.py b/tests/conftest.py index a9c48d8b4..44420a134 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,12 +2,10 @@ from __future__ import annotations -from typing import TYPE_CHECKING import pytest -from tests import p, t - +from tests import t def pytest_collection_modifyitems( diff --git a/tests/protocols.py b/tests/protocols.py index 5bfafb3e8..41b73dd78 100644 --- a/tests/protocols.py +++ b/tests/protocols.py @@ -6,17 +6,15 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Protocol, Self +from typing import Protocol, Self from flext_tests import FlextTestsProtocols from flext_cli import p -from flext_cli import m from tests import p, t - class TestsFlextCliProtocols(FlextTestsProtocols, p): """Test protocols for flext-cli.""" diff --git a/tests/test_yaml_model_write.py b/tests/test_yaml_model_write.py index c1d921a6f..528533e7d 100644 --- a/tests/test_yaml_model_write.py +++ b/tests/test_yaml_model_write.py @@ -2,7 +2,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING from flext_tests import tm @@ -11,7 +10,6 @@ from pathlib import Path - def test_write_yaml_model_round_trips_the_same_model_contract(tmp_path: Path) -> None: """The only owned payload is a validated model on both sides of YAML.""" source = m.Cli.XlsxCellAddress(row=7, column=9) diff --git a/tests/typings.py b/tests/typings.py index 789574f4e..9376b2e6f 100644 --- a/tests/typings.py +++ b/tests/typings.py @@ -12,7 +12,7 @@ from flext_tests import FlextTestsTypes -from flext_cli import p, t +from flext_cli import t class TestsFlextCliTypes(FlextTestsTypes, t): diff --git a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_01.py b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_01.py index 857f7ed99..943be14ea 100644 --- a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_01.py +++ b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_01.py @@ -2,7 +2,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING from flext_tests import tm from tests import c @@ -18,19 +17,18 @@ from tests import p, t - class TestsFlextCliService: """Implementation part for TestsFlextCliService.""" def test_model_command_validates_runtime_settings_fields(self) -> None: """Validate runtime CLI parameters through the model command.""" - command_settings = m.Cli.CliParamsConfig() + command_settings = m.Cli.ParamsConfig() - def handle(params: p.Cli.CliParamsConfig) -> t.JsonValue: + def handle(params: p.Cli.ParamsConfig) -> t.JsonValue: return params.debug is True command = cli.model_command( - m.Cli.CliParamsConfig, handle, settings=command_settings + m.Cli.ParamsConfig, handle, settings=command_settings ) result = command(debug=True) diff --git a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_02.py b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_02.py index deaf77a70..88dc30d8c 100644 --- a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_02.py +++ b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_02.py @@ -2,7 +2,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING from flext_tests import tm from tests import c @@ -18,7 +17,6 @@ from tests import p, t - class TestsFlextCliService: """Implementation part for TestsFlextCliService.""" diff --git a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_04.py b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_04.py index ef9755f61..db0134868 100644 --- a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_04.py +++ b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_04.py @@ -2,7 +2,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING from flext_tests import tm from tests import m @@ -14,7 +13,6 @@ from tests import p, t - class TestsFlextCliService: """Implementation part for TestsFlextCliService.""" diff --git a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_05.py b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_05.py index 820c70f95..f26fe5f02 100644 --- a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_05.py +++ b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_05.py @@ -2,7 +2,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING from flext_tests import tm from tests import c @@ -16,7 +15,6 @@ from tests import p - class TestsFlextCliService: """Implementation part for TestsFlextCliService.""" diff --git a/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_01.py b/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_01.py index 17cf82a4f..b23ac6650 100644 --- a/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_01.py +++ b/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_01.py @@ -2,7 +2,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING from examples import ExamplesFlextCliGettingStarted from examples.ex_02_output_formatting import export_report diff --git a/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_02.py b/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_02.py index 6de4b1e4b..27ffbf2fe 100644 --- a/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_02.py +++ b/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_02.py @@ -3,7 +3,6 @@ from __future__ import annotations from collections.abc import Mapping -from typing import TYPE_CHECKING import pytest from examples import Ex05Authentication, Ex06Settings, c as ec, p as ep @@ -23,7 +22,6 @@ from pathlib import Path - class TestsFlextCliExamplesSmoke: """Implementation part for TestsFlextCliExamplesSmoke.""" diff --git a/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_03.py b/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_03.py index 4449cbd78..d275e64bf 100644 --- a/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_03.py +++ b/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_03.py @@ -3,7 +3,6 @@ from __future__ import annotations from pathlib import Path -from typing import TYPE_CHECKING import pytest from examples import Ex05Authentication, Ex06Settings, c as ec @@ -14,7 +13,6 @@ from collections.abc import Iterator - class TestsFlextCliExamplesSmoke: """Implementation part for TestsFlextCliExamplesSmoke.""" diff --git a/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_04.py b/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_04.py index 01e4ebc93..977ee39c0 100644 --- a/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_04.py +++ b/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_04.py @@ -2,7 +2,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING from unittest.mock import patch from examples import DataManagerCLI @@ -15,7 +14,6 @@ from tests import p - class TestsFlextCliExamplesSmoke: """Implementation part for TestsFlextCliExamplesSmoke.""" diff --git a/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_01.py b/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_01.py index d155bbb1a..1fdc034bb 100644 --- a/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_01.py +++ b/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_01.py @@ -2,7 +2,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING import pytest from flext_tests import tm @@ -14,8 +13,7 @@ from pathlib import Path -from tests import p, t - +from tests import t class TestsFlextCliFilesCov: diff --git a/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_02.py b/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_02.py index 309f35467..ae8c5d330 100644 --- a/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_02.py +++ b/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_02.py @@ -2,7 +2,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING from flext_tests import tm from tests import u @@ -12,7 +11,6 @@ from pathlib import Path - class TestsFlextCliFilesCov: """Implementation part for TestsFlextCliFilesCov.""" diff --git a/tests/unit/_cases/test_json_cov/testsflextclijsoncov_part_01.py b/tests/unit/_cases/test_json_cov/testsflextclijsoncov_part_01.py index fa0d66f1f..0dbe30794 100644 --- a/tests/unit/_cases/test_json_cov/testsflextclijsoncov_part_01.py +++ b/tests/unit/_cases/test_json_cov/testsflextclijsoncov_part_01.py @@ -2,17 +2,15 @@ from __future__ import annotations -from typing import TYPE_CHECKING from tests import m -from tests import p, t +from tests import t from tests import u from flext_tests import tm from pathlib import Path - class TestsFlextCliJsonCov: """Implementation part for TestsFlextCliJsonCov.""" diff --git a/tests/unit/_cases/test_output_cov/testsflextclioutputcov_part_02.py b/tests/unit/_cases/test_output_cov/testsflextclioutputcov_part_02.py index 56498f2aa..dac01bccd 100644 --- a/tests/unit/_cases/test_output_cov/testsflextclioutputcov_part_02.py +++ b/tests/unit/_cases/test_output_cov/testsflextclioutputcov_part_02.py @@ -3,7 +3,6 @@ from __future__ import annotations from pathlib import Path -from typing import TYPE_CHECKING from tests import c from tests import u @@ -12,7 +11,6 @@ import pytest - class TestsFlextCliOutputCov: """Implementation part for TestsFlextCliOutputCov.""" diff --git a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_01.py b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_01.py index bacc4c9b5..4c4eb0a30 100644 --- a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_01.py +++ b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_01.py @@ -2,10 +2,8 @@ from __future__ import annotations -from typing import TYPE_CHECKING from tests import c -from tests import m from flext_cli import cli, r from flext_tests import tm @@ -13,8 +11,7 @@ from pathlib import Path from tests import p -from tests import p, t - +from tests import t class TestsFlextCliPipeline: diff --git a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_02.py b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_02.py index 92ce6f01b..ac85d9fda 100644 --- a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_02.py +++ b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_02.py @@ -2,10 +2,8 @@ from __future__ import annotations -from typing import TYPE_CHECKING from tests import c -from tests import m from flext_cli import cli, r from flext_tests import tm @@ -13,8 +11,7 @@ from pathlib import Path from tests import p -from tests import p, t - +from tests import t class TestsFlextCliPipeline: diff --git a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_03.py b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_03.py index f20f8e118..59cc9784f 100644 --- a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_03.py +++ b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_03.py @@ -2,16 +2,14 @@ from __future__ import annotations -from typing import TYPE_CHECKING from flext_cli import cli from flext_tests import tm from pathlib import Path -from tests import m from tests import p -from tests import p, t +from tests import t # ── Fixtures ──────────────────────────────────────────────────────── diff --git a/tests/unit/_cases/test_prompts/testsflextcliprompts_part_01.py b/tests/unit/_cases/test_prompts/testsflextcliprompts_part_01.py index 0a65a3772..5851656d5 100644 --- a/tests/unit/_cases/test_prompts/testsflextcliprompts_part_01.py +++ b/tests/unit/_cases/test_prompts/testsflextcliprompts_part_01.py @@ -2,10 +2,8 @@ from __future__ import annotations -from typing import TYPE_CHECKING import pytest -from flext_cli import m from flext_tests import tm from tests import c @@ -14,7 +12,6 @@ from tests import p - class TestsFlextCliPrompts: """Implementation part for TestsFlextCliPrompts.""" diff --git a/tests/unit/_cases/test_prompts/testsflextcliprompts_part_02.py b/tests/unit/_cases/test_prompts/testsflextcliprompts_part_02.py index 8805f8e0c..e91198808 100644 --- a/tests/unit/_cases/test_prompts/testsflextcliprompts_part_02.py +++ b/tests/unit/_cases/test_prompts/testsflextcliprompts_part_02.py @@ -3,7 +3,6 @@ from __future__ import annotations import time -from typing import TYPE_CHECKING import pytest from flext_tests import tm @@ -14,7 +13,6 @@ from tests import p - class TestsFlextCliPrompts: """Implementation part for TestsFlextCliPrompts.""" diff --git a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_01.py b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_01.py index cd378f4a8..9b540dced 100644 --- a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_01.py +++ b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_01.py @@ -55,7 +55,6 @@ def test_public_facade_and_settings_contract(self) -> None: result = cli.execute() tm.ok(result, is_=m.Cli.RuntimeStatus) - status = result.value tm.ok(facade_result) tm.that( diff --git a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_02.py b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_02.py index 36bbbbd36..2327b98ca 100644 --- a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_02.py +++ b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_02.py @@ -2,7 +2,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING from tests import c from tests import m @@ -15,7 +14,6 @@ from tests import p - class TestsFlextCliPublicContractsCoverage: """Implementation part for TestsFlextCliPublicContractsCoverage.""" diff --git a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_03.py b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_03.py index 63ef2d4ac..41228e223 100644 --- a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_03.py +++ b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_03.py @@ -2,7 +2,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING from tests import c from tests import p @@ -13,7 +12,6 @@ from pathlib import Path - class TestsFlextCliPublicContractsCoverage: """Implementation part for TestsFlextCliPublicContractsCoverage.""" diff --git a/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_01.py b/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_01.py index 5bf86fbdd..8117e6652 100644 --- a/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_01.py +++ b/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_01.py @@ -4,15 +4,13 @@ import tempfile from pathlib import Path -from typing import TYPE_CHECKING import pytest from tests import c from tests import u from flext_tests import tm -from tests import p, t - +from tests import t class TestsFlextCliRulesCov: diff --git a/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_03.py b/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_03.py index bcfe87a47..7f9d63273 100644 --- a/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_03.py +++ b/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_03.py @@ -4,15 +4,13 @@ import tempfile from pathlib import Path -from typing import TYPE_CHECKING import pytest from tests import c from tests import u from flext_tests import tm -from tests import p, t - +from tests import t class TestsFlextCliRulesCov: diff --git a/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_04.py b/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_04.py index ce290f48a..a09f1a646 100644 --- a/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_04.py +++ b/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_04.py @@ -2,14 +2,12 @@ from __future__ import annotations -from typing import TYPE_CHECKING from tests import c from tests import u from flext_tests import tm -from tests import p, t - +from tests import t class TestsFlextCliRulesCov: diff --git a/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_01.py b/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_01.py index 2eff0a041..5100ea186 100644 --- a/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_01.py +++ b/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_01.py @@ -6,15 +6,13 @@ import stat from contextlib import contextmanager from pathlib import Path -from typing import TYPE_CHECKING from flext_tests import tm from tests import u from collections.abc import Generator -from tests import p, t - +from tests import t class TestsFlextCliTomlUtilities: diff --git a/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_02.py b/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_02.py index 22efe2869..2afb051af 100644 --- a/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_02.py +++ b/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_02.py @@ -2,13 +2,11 @@ from __future__ import annotations -from typing import TYPE_CHECKING from flext_tests import tm from tests import u -from tests import p, t - +from tests import t class TestsFlextCliTomlUtilities: diff --git a/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_03.py b/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_03.py index d3bf610d9..b62a3d81e 100644 --- a/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_03.py +++ b/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_03.py @@ -3,15 +3,13 @@ from __future__ import annotations import tomllib -from typing import TYPE_CHECKING from flext_tests import tm from tests import u from pathlib import Path -from tests import p, t - +from tests import t class TestsFlextCliTomlUtilities: diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py index a31db3ffc..31ca34df9 100644 --- a/tests/unit/conftest.py +++ b/tests/unit/conftest.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Self, override +from typing import Self, override import pytest @@ -12,8 +12,7 @@ from collections.abc import Callable -from tests import p, t - +from tests import t class TestsFlextCliScriptedPrompts(FlextCliPrompts): diff --git a/tests/unit/test_auth_utils_cov.py b/tests/unit/test_auth_utils_cov.py index 101c9643e..96a9490b3 100644 --- a/tests/unit/test_auth_utils_cov.py +++ b/tests/unit/test_auth_utils_cov.py @@ -15,7 +15,6 @@ from __future__ import annotations from pathlib import Path -from typing import TYPE_CHECKING import pytest @@ -23,8 +22,7 @@ from tests import u from flext_tests import tm -from tests import p, t - +from tests import t class TestsFlextCliAuthUtilsCov: diff --git a/tests/unit/test_cli_params.py b/tests/unit/test_cli_params.py index e0881d2a1..23d70cdac 100644 --- a/tests/unit/test_cli_params.py +++ b/tests/unit/test_cli_params.py @@ -35,9 +35,9 @@ def settings(self) -> p.Cli.Settings: def test_create_option_returns_option_spec_for_registered_field( self, field_name: str ) -> None: - """create_option yields a public CliOptionSpec for each registered field.""" + """create_option yields a public OptionSpec for each registered field.""" option = cli.create_option(field_name) - tm.that(option, is_=p.Cli.CliOptionSpec) + tm.that(option, is_=p.Cli.OptionSpec) def test_create_option_raises_valueerror_for_unknown_field(self) -> None: """create_option rejects an unregistered field with a descriptive ValueError.""" diff --git a/tests/unit/test_cmd.py b/tests/unit/test_cmd.py index 83cd62dbf..5a54f6346 100644 --- a/tests/unit/test_cmd.py +++ b/tests/unit/test_cmd.py @@ -18,7 +18,6 @@ from __future__ import annotations from datetime import datetime -from typing import TYPE_CHECKING import pytest from flext_tests import tm @@ -30,7 +29,6 @@ from pathlib import Path - class TestsFlextCliCmd: """Public behavioral contract of the CLI command service facade.""" diff --git a/tests/unit/test_cmd_cov.py b/tests/unit/test_cmd_cov.py index 96f33b2da..15660fb57 100644 --- a/tests/unit/test_cmd_cov.py +++ b/tests/unit/test_cmd_cov.py @@ -11,7 +11,6 @@ import os from contextlib import contextmanager -from typing import TYPE_CHECKING import pytest from flext_tests import tm @@ -23,7 +22,6 @@ from pathlib import Path - class TestsFlextCliCmdCov: """Contract tests for the settings commands exposed on ``FlextCli``.""" diff --git a/tests/unit/test_cmd_runtime_validation_branch_cov.py b/tests/unit/test_cmd_runtime_validation_branch_cov.py index fa608cf36..78b797637 100644 --- a/tests/unit/test_cmd_runtime_validation_branch_cov.py +++ b/tests/unit/test_cmd_runtime_validation_branch_cov.py @@ -14,7 +14,7 @@ from tests import c from tests import m -from tests import p, t +from tests import t from tests import u from flext_tests import tm @@ -135,7 +135,7 @@ def test_validate_format_rejects_unknown_and_echoes_original_input(self) -> None @pytest.mark.parametrize("value", ["ok", " padded ", 0, 1]) def test_validate_not_empty_accepts_meaningful_values( - self, value: t.Cli.CliValue + self, value: t.Cli.Value ) -> None: result = u.Cli.validate_not_empty(value, name="field") @@ -144,7 +144,7 @@ def test_validate_not_empty_accepts_meaningful_values( @pytest.mark.parametrize("value", [None, "", " "]) def test_validate_not_empty_rejects_empty_and_names_the_field( - self, value: t.Cli.CliValue | None + self, value: t.Cli.Value | None ) -> None: result = u.Cli.validate_not_empty(value, name="myfield") diff --git a/tests/unit/test_commands_utils_cov.py b/tests/unit/test_commands_utils_cov.py index 2209738ba..fc1fb1a47 100644 --- a/tests/unit/test_commands_utils_cov.py +++ b/tests/unit/test_commands_utils_cov.py @@ -20,7 +20,7 @@ from flext_cli import r from flext_tests import tm from tests import c -from tests import p, t +from tests import t from tests import u @@ -149,7 +149,8 @@ def test_error_message_adds_traceback_in_verbose_mode( ) -> None: # Arrange try: - raise FileNotFoundError("nope") + msg = "nope" + raise FileNotFoundError(msg) except FileNotFoundError as exc: captured_exception: BaseException = exc diff --git a/tests/unit/test_conversion_cov.py b/tests/unit/test_conversion_cov.py index 3ae5e987d..de20b93a3 100644 --- a/tests/unit/test_conversion_cov.py +++ b/tests/unit/test_conversion_cov.py @@ -3,7 +3,6 @@ from __future__ import annotations from pathlib import Path -from typing import TYPE_CHECKING import pytest from flext_tests import tm @@ -12,8 +11,7 @@ from tests import m from tests import u -from tests import p, t - +from tests import t class TestsFlextCliConversion: diff --git a/tests/unit/test_files_cov.py b/tests/unit/test_files_cov.py index 53ab0f7c5..62e348f28 100644 --- a/tests/unit/test_files_cov.py +++ b/tests/unit/test_files_cov.py @@ -9,7 +9,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING import pytest from flext_tests import tm @@ -21,8 +20,7 @@ from pathlib import Path -from tests import p, t - +from tests import t class TestsFlextCliFilesCov: diff --git a/tests/unit/test_formatters_cov.py b/tests/unit/test_formatters_cov.py index d28bf0831..aca91a2ce 100644 --- a/tests/unit/test_formatters_cov.py +++ b/tests/unit/test_formatters_cov.py @@ -13,7 +13,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING import pytest @@ -21,8 +20,7 @@ from tests import c from flext_tests import tm -from tests import p, t - +from tests import t class TestsFlextCliFormattersCov: diff --git a/tests/unit/test_json_cov.py b/tests/unit/test_json_cov.py index 6ff19a642..a70551cb7 100644 --- a/tests/unit/test_json_cov.py +++ b/tests/unit/test_json_cov.py @@ -2,19 +2,17 @@ from __future__ import annotations -from typing import TYPE_CHECKING import pytest from tests import m -from tests import p, t +from tests import t from tests import u from flext_tests import tm from pathlib import Path - class TestsFlextCliJsonCov: """Assert the observable contract of the ``u.Cli`` JSON helpers.""" diff --git a/tests/unit/test_matching_cov.py b/tests/unit/test_matching_cov.py index cf4daefcf..8b0f39db0 100644 --- a/tests/unit/test_matching_cov.py +++ b/tests/unit/test_matching_cov.py @@ -12,7 +12,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING import pytest @@ -20,8 +19,7 @@ from tests import u from flext_tests import tm -from tests import p, t - +from tests import t class TestsFlextCliMatchingCov: diff --git a/tests/unit/test_options_cov.py b/tests/unit/test_options_cov.py index 73badcac6..792f08693 100644 --- a/tests/unit/test_options_cov.py +++ b/tests/unit/test_options_cov.py @@ -113,7 +113,7 @@ def _noop_handler(_params: t.Cli.ModelLike) -> bool: return True @staticmethod - def _option_spec(command: t.Cli.CliCommand, param_name: str) -> p.Cli.CliOptionSpec: + def _option_spec(command: t.Cli.Command, param_name: str) -> p.Cli.OptionSpec: """Return the Typer option object the builder placed on the command signature.""" spec = inspect.signature(command).parameters[param_name].default tm.that(spec.param_decls, none=False) diff --git a/tests/unit/test_options_public_cov.py b/tests/unit/test_options_public_cov.py index 0c642e6e5..28d6cca37 100644 --- a/tests/unit/test_options_public_cov.py +++ b/tests/unit/test_options_public_cov.py @@ -13,7 +13,7 @@ import pytest from flext_cli import c, m -from tests import p, t +from tests import t from tests import u from flext_tests import tm @@ -63,7 +63,7 @@ def test_resolve_typer_annotation_maps_string_sequence_to_list_of_str(self) -> N ], ) def test_normalize_cli_atom_returns_typer_ready_value_or_none( - self, value: t.Cli.CliDefaultSource, expected: t.Cli.DefaultAtom | None + self, value: t.Cli.DefaultSource, expected: t.Cli.DefaultAtom | None ) -> None: """Normalize supported CLI atoms and reject unsupported values.""" tm.that(u.Cli.cli_normalize_atom(value), eq=expected) @@ -81,7 +81,7 @@ def test_normalize_cli_atom_returns_typer_ready_value_or_none( ], ) def test_is_string_sequence_recognizes_only_str_sequences( - self, value: t.Cli.CliDefaultSource, *, expected: bool + self, value: t.Cli.DefaultSource, *, expected: bool ) -> None: """Recognize only sequences whose every member is a string.""" tm.that(u.Cli.is_string_sequence(value), eq=expected) diff --git a/tests/unit/test_params_branch_cov.py b/tests/unit/test_params_branch_cov.py index 60a69e376..9b0e6a037 100644 --- a/tests/unit/test_params_branch_cov.py +++ b/tests/unit/test_params_branch_cov.py @@ -20,24 +20,24 @@ class TestsFlextCliParams: # -- params_resolve ----------------------------------------------------- def test_resolve_merges_model_with_kwargs(self) -> None: - params = m.Cli.CliParamsConfig(debug=True) + params = m.Cli.ParamsConfig(debug=True) resolved = u.Cli.params_resolve(params, {"verbose": True}) - tm.that(resolved, is_=m.Cli.CliParamsConfig) + tm.that(resolved, is_=m.Cli.ParamsConfig) tm.that(resolved.debug, eq=True) tm.that(resolved.verbose, eq=True) def test_resolve_with_none_params_uses_kwargs_only(self) -> None: resolved = u.Cli.params_resolve(None, {"quiet": True}) - tm.that(resolved, is_=m.Cli.CliParamsConfig) + tm.that(resolved, is_=m.Cli.ParamsConfig) tm.that(resolved.quiet, eq=True) def test_resolve_kwargs_override_model_values(self) -> None: - params = m.Cli.CliParamsConfig(debug=True) + params = m.Cli.ParamsConfig(debug=True) resolved = u.Cli.params_resolve(params, {"debug": False}) tm.that(resolved.debug, eq=False) def test_resolve_is_idempotent_for_same_inputs(self) -> None: - params = m.Cli.CliParamsConfig(debug=True, verbose=True) + params = m.Cli.ParamsConfig(debug=True, verbose=True) first = u.Cli.params_resolve(params, {}) second = u.Cli.params_resolve(params, {}) tm.that(first.model_dump(), eq=second.model_dump()) @@ -46,7 +46,7 @@ def test_resolve_is_idempotent_for_same_inputs(self) -> None: def test_set_bool_applies_root_and_cli_flags(self) -> None: settings = FlextCliSettings.model_validate({}) - params = m.Cli.CliParamsConfig( + params = m.Cli.ParamsConfig( debug=True, trace=True, verbose=True, quiet=True, no_color=True ) result = u.Cli.params_set_bool(settings, params) @@ -59,14 +59,14 @@ def test_set_bool_applies_root_and_cli_flags(self) -> None: def test_set_bool_trace_without_debug_fails(self) -> None: settings = FlextCliSettings.model_validate({}) - params = m.Cli.CliParamsConfig(trace=True) + params = m.Cli.ParamsConfig(trace=True) result = u.Cli.params_set_bool(settings, params) tm.fail(result) tm.that(result.error, eq=tc.Cli.CLI_PARAM_ERR_TRACE_REQUIRES_DEBUG) def test_set_bool_no_flags_returns_settings_unchanged(self) -> None: settings = FlextCliSettings.model_validate({}) - result = u.Cli.params_set_bool(settings, m.Cli.CliParamsConfig()) + result = u.Cli.params_set_bool(settings, m.Cli.ParamsConfig()) tm.ok(result) assert result.value.debug is settings.debug assert result.value.cli_verbose is settings.cli_verbose @@ -76,20 +76,20 @@ def test_set_bool_no_flags_returns_settings_unchanged(self) -> None: @pytest.mark.parametrize("level", ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]) def test_set_log_level_applies_valid_level(self, level: str) -> None: settings = FlextCliSettings.model_validate({}) - params = m.Cli.CliParamsConfig(log_level=level) + params = m.Cli.ParamsConfig(log_level=level) result = u.Cli.params_set_log_level(settings, params) tm.ok(result) tm.that(result.value.cli_log_level, eq=level) def test_set_log_level_none_returns_settings_unchanged(self) -> None: settings = FlextCliSettings.model_validate({}) - result = u.Cli.params_set_log_level(settings, m.Cli.CliParamsConfig()) + result = u.Cli.params_set_log_level(settings, m.Cli.ParamsConfig()) tm.ok(result) tm.that(result.value.cli_log_level, eq=settings.cli_log_level) def test_set_log_level_invalid_fails_with_options_message(self) -> None: settings = FlextCliSettings.model_validate({}) - params = m.Cli.CliParamsConfig(log_level="BOGUS") + params = m.Cli.ParamsConfig(log_level="BOGUS") result = u.Cli.params_set_log_level(settings, params) tm.fail(result) expected = c.Cli.CLI_PARAM_ERR_INVALID_WITH_OPTIONS_FMT.format( @@ -104,7 +104,7 @@ def test_set_log_level_invalid_fails_with_options_message(self) -> None: @pytest.mark.parametrize("log_format", ["compact", "detailed", "full"]) def test_set_format_applies_valid_log_format(self, log_format: str) -> None: settings = FlextCliSettings.model_validate({}) - params = m.Cli.CliParamsConfig(log_format=log_format) + params = m.Cli.ParamsConfig(log_format=log_format) result = u.Cli.params_set_format(settings, params) tm.ok(result) tm.that(result.value.cli_log_verbosity, eq=log_format) @@ -114,21 +114,21 @@ def test_set_format_applies_valid_log_format(self, log_format: str) -> None: ) def test_set_format_applies_valid_output_format(self, output_format: str) -> None: settings = FlextCliSettings.model_validate({}) - params = m.Cli.CliParamsConfig(output_format=output_format) + params = m.Cli.ParamsConfig(output_format=output_format) result = u.Cli.params_set_format(settings, params) tm.ok(result) tm.that(result.value.cli_output_format, eq=output_format) def test_set_format_none_returns_settings_unchanged(self) -> None: settings = FlextCliSettings.model_validate({}) - result = u.Cli.params_set_format(settings, m.Cli.CliParamsConfig()) + result = u.Cli.params_set_format(settings, m.Cli.ParamsConfig()) tm.ok(result) tm.that(result.value.cli_log_verbosity, eq=settings.cli_log_verbosity) tm.that(result.value.cli_output_format, eq=settings.cli_output_format) def test_set_format_invalid_log_format_fails(self) -> None: settings = FlextCliSettings.model_validate({}) - params = m.Cli.CliParamsConfig(log_format="BAD") + params = m.Cli.ParamsConfig(log_format="BAD") result = u.Cli.params_set_format(settings, params) tm.fail(result) expected = c.Cli.CLI_PARAM_ERR_INVALID_WITH_VALID_FMT.format( @@ -140,7 +140,7 @@ def test_set_format_invalid_log_format_fails(self) -> None: def test_set_format_invalid_output_format_fails(self) -> None: settings = FlextCliSettings.model_validate({}) - params = m.Cli.CliParamsConfig(output_format="BAD") + params = m.Cli.ParamsConfig(output_format="BAD") result = u.Cli.params_set_format(settings, params) tm.fail(result) expected = c.Cli.CLI_PARAM_ERR_INVALID_WITH_VALID_FMT.format( @@ -154,7 +154,7 @@ def test_set_format_invalid_output_format_fails(self) -> None: def test_apply_chains_all_stages_on_valid_params(self) -> None: settings = FlextCliSettings.model_validate({}) - params = m.Cli.CliParamsConfig( + params = m.Cli.ParamsConfig( debug=True, log_level="INFO", output_format="yaml", log_format="detailed" ) result = u.Cli.params_apply(settings, params) @@ -167,14 +167,14 @@ def test_apply_chains_all_stages_on_valid_params(self) -> None: def test_apply_short_circuits_on_first_stage_failure(self) -> None: settings = FlextCliSettings.model_validate({}) - params = m.Cli.CliParamsConfig(trace=True) + params = m.Cli.ParamsConfig(trace=True) result = u.Cli.params_apply(settings, params) tm.fail(result) tm.that(result.error, eq=tc.Cli.CLI_PARAM_ERR_TRACE_REQUIRES_DEBUG) def test_apply_returns_result_type(self) -> None: settings = FlextCliSettings.model_validate({}) - result = u.Cli.params_apply(settings, m.Cli.CliParamsConfig()) + result = u.Cli.params_apply(settings, m.Cli.ParamsConfig()) tm.that(result, is_=p.Result) tm.ok(result) diff --git a/tests/unit/test_prompts_cov.py b/tests/unit/test_prompts_cov.py index 152e483f8..92a93dc9b 100644 --- a/tests/unit/test_prompts_cov.py +++ b/tests/unit/test_prompts_cov.py @@ -8,7 +8,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING import pytest from flext_tests import tm @@ -20,7 +19,6 @@ from tests import p - class TestsFlextCliPromptsCov: """Behavior contract for the prompt service public surface.""" diff --git a/tests/unit/test_rules_cov.py b/tests/unit/test_rules_cov.py index 66abf4a57..277fb820a 100644 --- a/tests/unit/test_rules_cov.py +++ b/tests/unit/test_rules_cov.py @@ -9,7 +9,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING import pytest @@ -19,8 +18,7 @@ from pathlib import Path -from tests import p, t - +from tests import t class TestsFlextCliRulesCov: diff --git a/tests/unit/test_runtime_utilities_core.py b/tests/unit/test_runtime_utilities_core.py index 1ea9c185b..68beb363a 100644 --- a/tests/unit/test_runtime_utilities_core.py +++ b/tests/unit/test_runtime_utilities_core.py @@ -3,7 +3,6 @@ from __future__ import annotations import sys -from typing import TYPE_CHECKING import pytest from flext_tests import tm @@ -16,7 +15,6 @@ from tests import p, t - class TestsFlextCliRuntimeUtilitiesCore: """Behavior contract for test_runtime_utilities_core.""" diff --git a/tests/unit/test_runtime_utilities_extra.py b/tests/unit/test_runtime_utilities_extra.py index e63e047b8..94d034f8e 100644 --- a/tests/unit/test_runtime_utilities_extra.py +++ b/tests/unit/test_runtime_utilities_extra.py @@ -7,7 +7,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING import pytest from flext_tests import tm @@ -18,7 +17,6 @@ from pathlib import Path - class TestsFlextCliRuntimeUtilitiesExtra: """Public-contract behavior for ``u.Cli`` runtime helpers and output model.""" diff --git a/tests/unit/test_services_auth_branch_cov.py b/tests/unit/test_services_auth_branch_cov.py index 5800c89e1..7dd695575 100644 --- a/tests/unit/test_services_auth_branch_cov.py +++ b/tests/unit/test_services_auth_branch_cov.py @@ -9,7 +9,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING import pytest from flext_tests import tm @@ -21,7 +20,6 @@ from pathlib import Path - class TestsFlextCliServicesAuth: """Public authentication behavior of the FlextCli facade.""" diff --git a/tests/unit/test_services_auth_cov.py b/tests/unit/test_services_auth_cov.py index efb59c69a..d28087d84 100644 --- a/tests/unit/test_services_auth_cov.py +++ b/tests/unit/test_services_auth_cov.py @@ -12,7 +12,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING import pytest @@ -27,7 +26,6 @@ from tests import p - class TestsFlextCliServicesAuthCov: """Behavioral tests for the FlextCliAuth authentication service.""" diff --git a/tests/unit/test_services_tables_branch_cov.py b/tests/unit/test_services_tables_branch_cov.py index a5bdbe050..6c4089121 100644 --- a/tests/unit/test_services_tables_branch_cov.py +++ b/tests/unit/test_services_tables_branch_cov.py @@ -7,7 +7,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING import pytest @@ -15,8 +14,7 @@ from tests import c from flext_tests import tm -from flext_cli import p, t - +from flext_cli import t class TestsFlextCliServicesTablesBranchCov: diff --git a/tests/unit/test_tables.py b/tests/unit/test_tables.py index b2ca0299f..0c813c950 100644 --- a/tests/unit/test_tables.py +++ b/tests/unit/test_tables.py @@ -8,7 +8,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING import pytest from flext_tests import tm @@ -16,8 +15,7 @@ from flext_cli import cli from tests import c -from flext_cli import p, t - +from flext_cli import t class TestsFlextCliTables: diff --git a/tests/unit/test_tables_cov.py b/tests/unit/test_tables_cov.py index 5b62b567c..2325ac419 100644 --- a/tests/unit/test_tables_cov.py +++ b/tests/unit/test_tables_cov.py @@ -10,7 +10,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING import pytest @@ -19,8 +18,7 @@ from tests import u from flext_tests import tm -from tests import p, t - +from tests import t class TestsFlextCliTables: diff --git a/tests/unit/test_toml_cov.py b/tests/unit/test_toml_cov.py index e90a138a8..9df7dd64e 100644 --- a/tests/unit/test_toml_cov.py +++ b/tests/unit/test_toml_cov.py @@ -12,7 +12,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING import pytest @@ -23,7 +22,6 @@ from pathlib import Path - class TestsFlextCliTomlCov: """Observable-behavior tests for the ``u.Cli.toml_*`` helpers.""" diff --git a/tests/unit/test_toml_sync_cov.py b/tests/unit/test_toml_sync_cov.py index 8204be7c0..bbc740ad3 100644 --- a/tests/unit/test_toml_sync_cov.py +++ b/tests/unit/test_toml_sync_cov.py @@ -15,7 +15,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING import pytest @@ -24,8 +23,7 @@ from tomlkit.items import Table -from tests import p, t - +from tests import t class TestsFlextCliTomlSyncCoverage: diff --git a/tests/unit/test_toml_utilities.py b/tests/unit/test_toml_utilities.py index e30c2aaf4..2b771eafa 100644 --- a/tests/unit/test_toml_utilities.py +++ b/tests/unit/test_toml_utilities.py @@ -12,15 +12,13 @@ import stat import tomllib from pathlib import Path -from typing import TYPE_CHECKING import pytest from flext_tests import tm from tests import u -from tests import p, t - +from tests import t class TestsFlextCliTomlUtilities: diff --git a/tests/unit/test_typings.py b/tests/unit/test_typings.py index 6cb951086..2ba6758b2 100644 --- a/tests/unit/test_typings.py +++ b/tests/unit/test_typings.py @@ -11,7 +11,6 @@ from __future__ import annotations from collections.abc import Sequence -from typing import TYPE_CHECKING import pytest from flext_tests import tm @@ -22,7 +21,6 @@ from pathlib import Path - class TestsFlextCliTypings: """Behavioural contract of flext_cli.typings.FlextCliTypes.""" diff --git a/tests/unit/test_utilities_cov.py b/tests/unit/test_utilities_cov.py index 769b2bc09..29b1ab6b1 100644 --- a/tests/unit/test_utilities_cov.py +++ b/tests/unit/test_utilities_cov.py @@ -13,7 +13,7 @@ import pytest from flext_tests import tm -from tests import p, t +from tests import t from tests import u @@ -87,7 +87,7 @@ def test_validate_not_empty_fails_for_empty_inputs(self, value: str | None) -> N @pytest.mark.parametrize("value", ["name", " padded ", 0, 42]) def test_validate_not_empty_succeeds_for_present_values( - self, value: t.Cli.CliValue + self, value: t.Cli.Value ) -> None: result = u.Cli.validate_not_empty(value, name="project") tm.ok(result) diff --git a/tests/unit/test_yaml_cov.py b/tests/unit/test_yaml_cov.py index dcb1c6600..626bf10b8 100644 --- a/tests/unit/test_yaml_cov.py +++ b/tests/unit/test_yaml_cov.py @@ -14,7 +14,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING import pytest @@ -25,8 +24,7 @@ from pathlib import Path -from tests import p, t - +from tests import t class TestsFlextCliYamlCov: diff --git a/tests/unit/test_yaml_roundtrip.py b/tests/unit/test_yaml_roundtrip.py index a5e9c0c17..57cb9ee87 100644 --- a/tests/unit/test_yaml_roundtrip.py +++ b/tests/unit/test_yaml_roundtrip.py @@ -9,19 +9,17 @@ from __future__ import annotations -from typing import TYPE_CHECKING import pytest from ruamel.yaml.comments import CommentedMap, CommentedSeq -from tests import p, t +from tests import t from tests import u from flext_tests import tm from pathlib import Path - class TestsFlextCliYamlRoundtripLoad: """Load/dump round-trip contract of ``u.Cli.yaml_roundtrip_*``.""" From 50e6bfe4e542ebb4364e05a4248fab02a1a2dfe0 Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Thu, 16 Jul 2026 22:06:18 -0300 Subject: [PATCH 25/37] fixes --- tests/unit/test_model_commands_cov.py | 12 ++++++------ tests/unit/test_protocols.py | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/unit/test_model_commands_cov.py b/tests/unit/test_model_commands_cov.py index 4893c26ca..0041b1d75 100644 --- a/tests/unit/test_model_commands_cov.py +++ b/tests/unit/test_model_commands_cov.py @@ -34,7 +34,7 @@ class TestsFlextCliModelCommandsCov: ) def test_derive_model_from_source_model_applies_defaults( self, - payload: p.Tests.ModelCommandSource, + payload: m.Tests.ModelCommandSource, expected_name: str, expected_value: int, ) -> None: @@ -94,7 +94,7 @@ def test_model_command_returns_callable(self) -> None: tm.that(callable(cmd), eq=True) def test_model_command_dispatches_to_handler_with_bound_model(self) -> None: - def handler(model: p.Tests.ModelCommandSample) -> str: + def handler(model: m.Tests.ModelCommandSample) -> str: return f"{model.name}-{model.value}" cmd = cli.model_command(m.Tests.ModelCommandSample, handler) @@ -102,7 +102,7 @@ def handler(model: p.Tests.ModelCommandSample) -> str: tm.that(cmd(name="x", value=3), eq="x-3") def test_model_command_applies_field_default_for_omitted_optional(self) -> None: - def handler(model: p.Tests.ModelCommandSample) -> int: + def handler(model: m.Tests.ModelCommandSample) -> int: return model.value cmd = cli.model_command(m.Tests.ModelCommandSample, handler) @@ -115,7 +115,7 @@ def test_model_command_resolves_values_without_mutating_settings(self) -> None: # resolved values reach the handler through the validated model. settings = m.Tests.ModelCommandSample(name="from_settings", value=0) - def handler(model: p.Tests.ModelCommandSample) -> str: + def handler(model: m.Tests.ModelCommandSample) -> str: return model.name cmd = cli.model_command(m.Tests.ModelCommandSample, handler, settings=settings) @@ -126,7 +126,7 @@ def handler(model: p.Tests.ModelCommandSample) -> str: tm.that(settings.value, eq=0) def test_model_command_raises_validation_error_for_missing_required(self) -> None: - def handler(model: p.Tests.ModelCommandRequired) -> str: + def handler(model: m.Tests.ModelCommandRequired) -> str: return model.key cmd = cli.model_command(m.Tests.ModelCommandRequired, handler) @@ -135,7 +135,7 @@ def handler(model: p.Tests.ModelCommandRequired) -> str: cmd() def test_model_command_binds_all_required_fields_to_model(self) -> None: - def handler(model: p.Tests.ModelCommandRequired) -> str: + def handler(model: m.Tests.ModelCommandRequired) -> str: return f"{model.key}={model.count}" cmd = cli.model_command(m.Tests.ModelCommandRequired, handler) diff --git a/tests/unit/test_protocols.py b/tests/unit/test_protocols.py index 19f95f4b6..6827b0ab9 100644 --- a/tests/unit/test_protocols.py +++ b/tests/unit/test_protocols.py @@ -20,7 +20,7 @@ import pytest -from flext_cli import p, t +from flext_cli import t from tests import p, u from flext_tests import tm From 5494e417713876a497ea47cc274f94b2bc1c6540 Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Fri, 17 Jul 2026 01:19:07 -0300 Subject: [PATCH 26/37] style(flext-cli): D421 property docstring noun-phrase via codemod (Check-if->Whether + verb-strip) --- .../_protocols/_base/flextcliprotocolsbase_part_03.py | 10 +++++----- src/flext_cli/_protocols/settings.py | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_03.py b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_03.py index 3203d2614..c095487fa 100644 --- a/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_03.py +++ b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_03.py @@ -101,7 +101,7 @@ class ParamsConfig(Protocol): @property def debug(self) -> bool | None: - """Check if debug mode is enabled.""" + """Whether debug mode is enabled.""" ... @property @@ -116,7 +116,7 @@ def log_level(self) -> str | None: @property def no_color(self) -> bool | None: - """Check if color is disabled.""" + """Whether color is disabled.""" ... @property @@ -131,17 +131,17 @@ def params(self) -> t.JsonMapping: @property def quiet(self) -> bool | None: - """Check if quiet mode is enabled.""" + """Whether quiet mode is enabled.""" ... @property def trace(self) -> bool | None: - """Check if trace mode is enabled.""" + """Whether trace mode is enabled.""" ... @property def verbose(self) -> bool | None: - """Check if verbose mode is enabled.""" + """Whether verbose mode is enabled.""" ... diff --git a/src/flext_cli/_protocols/settings.py b/src/flext_cli/_protocols/settings.py index 8e06f9c2c..a8225d1b6 100644 --- a/src/flext_cli/_protocols/settings.py +++ b/src/flext_cli/_protocols/settings.py @@ -89,12 +89,12 @@ def cli_verbose(self) -> bool: @property def debug(self) -> bool: - """Check if debug mode is enabled.""" + """Whether debug mode is enabled.""" ... @property def trace(self) -> bool: - """Check if trace mode is enabled.""" + """Whether trace mode is enabled.""" ... @classmethod From e298e62acef00f3b195e93bc45d935e30c942a65 Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Fri, 17 Jul 2026 06:46:31 -0300 Subject: [PATCH 27/37] refactor(cli): align imports (I001) and format across src/tests/examples --- examples/__init__.py | 73 +++++-------------- examples/_models_parts/__init__.py | 21 ++---- examples/_models_parts/examples_advanced.py | 48 ++++-------- examples/_models_parts/examples_common.py | 55 ++++---------- examples/_models_parts/examples_database.py | 23 ++---- examples/constants.py | 4 +- examples/ex_04_file_operations.py | 45 ++++-------- examples/ex_06_settings.py | 41 ++++------- examples/ex_11_complete_integration.py | 20 ++--- examples/models.py | 5 +- examples/protocols.py | 23 ++---- examples/typings.py | 11 +-- examples/utilities.py | 24 ++---- src/flext_cli/__init__.py | 2 +- src/flext_cli/_config.py | 2 +- src/flext_cli/_models/toml.py | 3 +- .../_base/flextcliprotocolsbase_part_03.py | 1 - .../_base/flextcliprotocolsbase_part_04.py | 3 +- .../_base/flextcliprotocolsbase_part_05.py | 1 - src/flext_cli/_protocols/settings.py | 1 + ...liutilitiesfiletesthelpersmixin_part_02.py | 1 - ...liutilitiesfiletesthelpersmixin_part_03.py | 3 +- ...liutilitiesfiletesthelpersmixin_part_04.py | 3 +- src/flext_cli/_utilities/_json/_navigate.py | 4 +- src/flext_cli/_utilities/_rules/_loaders.py | 3 +- src/flext_cli/_utilities/_rules/_matchers.py | 4 +- .../_toml/flextcliutilitiestoml_part_04.py | 8 +- .../_toml/flextcliutilitiestoml_part_05.py | 3 +- .../_toml/flextcliutilitiestoml_part_06.py | 3 +- .../_toml/flextcliutilitiestoml_part_07.py | 3 +- src/flext_cli/_utilities/_xlxx/xlsx_recalc.py | 2 +- .../_utilities/_xlxx/xlsx_style_builders.py | 4 +- src/flext_cli/_utilities/_yaml/_engine.py | 3 +- src/flext_cli/_utilities/commands.py | 4 +- src/flext_cli/_utilities/formatters.py | 1 + src/flext_cli/_utilities/framework.py | 4 +- src/flext_cli/_utilities/model_commands.py | 3 +- src/flext_cli/constants.py | 3 +- src/flext_cli/protocols.py | 2 +- .../services/_cli/flextclicli_part_03.py | 2 +- .../services/_cli/flextclicli_part_05.py | 5 +- src/flext_cli/services/_prompts_support.py | 3 +- tests/_constants_parts/tests_core.py | 1 - tests/_constants_parts/tests_yaml_output.py | 1 - tests/_models_parts/__init__.py | 1 - tests/conftest.py | 1 - tests/protocols.py | 2 - tests/test_yaml_model_write.py | 3 +- .../testsflextcliservice_part_01.py | 13 +--- .../testsflextcliservice_part_02.py | 13 +--- .../testsflextcliservice_part_03.py | 3 +- .../testsflextcliservice_part_04.py | 7 +- .../testsflextcliservice_part_05.py | 8 +- .../testsflextcliexamplessmoke_part_01.py | 4 +- .../testsflextcliexamplessmoke_part_02.py | 8 +- .../testsflextcliexamplessmoke_part_03.py | 3 +- .../testsflextcliexamplessmoke_part_04.py | 6 +- .../testsflextclifilescov_part_01.py | 9 +-- .../testsflextclifilescov_part_02.py | 3 +- .../testsflextclijsoncov_part_01.py | 7 +- .../testsflextclijsoncov_part_02.py | 2 +- .../testsflextclioutputcov_part_01.py | 3 +- .../testsflextclioutputcov_part_02.py | 6 +- .../testsflextclipipeline_part_01.py | 10 +-- .../testsflextclipipeline_part_02.py | 10 +-- .../testsflextclipipeline_part_03.py | 9 +-- .../testsflextcliprompts_part_01.py | 7 +- .../testsflextcliprompts_part_02.py | 7 +- ...flextclipubliccontractscoverage_part_01.py | 6 +- ...flextclipubliccontractscoverage_part_02.py | 10 +-- ...flextclipubliccontractscoverage_part_03.py | 8 +- .../testsflextclirulescov_part_01.py | 2 +- .../testsflextclirulescov_part_02.py | 3 +- .../testsflextclirulescov_part_03.py | 5 +- .../testsflextclirulescov_part_04.py | 6 +- .../testsflextclitomlutilities_part_01.py | 7 +- .../testsflextclitomlutilities_part_02.py | 5 +- .../testsflextclitomlutilities_part_03.py | 7 +- tests/unit/conftest.py | 7 +- tests/unit/test_auth_utils_cov.py | 5 +- tests/unit/test_base.py | 2 +- tests/unit/test_cli_params.py | 4 +- tests/unit/test_cmd.py | 6 +- tests/unit/test_cmd_cov.py | 5 +- .../test_cmd_runtime_validation_branch_cov.py | 7 +- tests/unit/test_commands_utils_cov.py | 6 +- tests/unit/test_config_engine.py | 5 +- tests/unit/test_constants.py | 3 +- tests/unit/test_conversion_cov.py | 6 +- .../test_examples_models_utilities_cov.py | 3 +- tests/unit/test_file_tools_yaml.py | 4 +- tests/unit/test_files_cov.py | 9 +-- tests/unit/test_formatters_cov.py | 7 +- tests/unit/test_json_cov.py | 7 +- tests/unit/test_matching_cov.py | 6 +- tests/unit/test_model_commands_cov.py | 2 +- tests/unit/test_options_cov.py | 6 +- tests/unit/test_options_public_cov.py | 5 +- tests/unit/test_output_cov.py | 5 +- tests/unit/test_params_branch_cov.py | 2 +- tests/unit/test_prompts_cov.py | 7 +- tests/unit/test_protocols.py | 2 +- tests/unit/test_rules_cov.py | 8 +- tests/unit/test_runtime_utilities_core.py | 8 +- tests/unit/test_runtime_utilities_extra.py | 6 +- tests/unit/test_services_auth_branch_cov.py | 5 +- tests/unit/test_services_auth_cov.py | 11 +-- tests/unit/test_services_output_cov.py | 2 +- tests/unit/test_services_tables_branch_cov.py | 7 +- tests/unit/test_services_tables_cov.py | 2 +- tests/unit/test_settings.py | 3 +- tests/unit/test_tables.py | 5 +- tests/unit/test_tables_branch_cov.py | 7 +- tests/unit/test_tables_cov.py | 7 +- tests/unit/test_toml_sync_cov.py | 6 +- tests/unit/test_toml_utilities.py | 4 +- tests/unit/test_typings.py | 6 +- tests/unit/test_utilities_cov.py | 3 +- tests/unit/test_yaml_cov.py | 9 +-- tests/unit/test_yaml_roundtrip.py | 8 +- tests/utilities.py | 3 +- 121 files changed, 271 insertions(+), 643 deletions(-) diff --git a/examples/__init__.py b/examples/__init__.py index f10f5f4ce..1cf408b84 100644 --- a/examples/__init__.py +++ b/examples/__init__.py @@ -44,53 +44,25 @@ from flext_cli import d as d, e as e, h as h, r as r, s as s, x as x _LAZY_IMPORTS = merge_lazy_imports( ("._models_parts",), - build_lazy_import_map( - { - "._models_parts": ("_models_parts",), - "._models_parts.examples_advanced": ( - "ExamplesFlextCliModelsExamplesAdvanced", - ), - "._models_parts.examples_common": ("ExamplesFlextCliModelsExamplesCommon",), - "._models_parts.examples_database": ( - "ExamplesFlextCliModelsExamplesDatabase", - ), - ".constants": ( - "ExamplesFlextCliConstants", - "c", - ), - ".ex_01_getting_started": ("ExamplesFlextCliGettingStarted",), - ".ex_02_output_formatting": ("ex_02_output_formatting",), - ".ex_04_file_operations": ("ex_04_file_operations",), - ".ex_05_authentication": ("Ex05Authentication",), - ".ex_06_settings": ("Ex06Settings",), - ".ex_11_complete_integration": ("DataManagerCLI",), - ".ex_12_pydantic_driven_cli": ("ex_12_pydantic_driven_cli",), - ".models": ( - "ExamplesFlextCliModels", - "m", - ), - ".protocols": ( - "ExamplesFlextCliProtocols", - "p", - ), - ".typings": ( - "ExamplesFlextCliTypes", - "t", - ), - ".utilities": ( - "ExamplesFlextCliUtilities", - "u", - ), - "flext_cli": ( - "d", - "e", - "h", - "r", - "s", - "x", - ), - }, - ), + build_lazy_import_map({ + "._models_parts": ("_models_parts",), + "._models_parts.examples_advanced": ("ExamplesFlextCliModelsExamplesAdvanced",), + "._models_parts.examples_common": ("ExamplesFlextCliModelsExamplesCommon",), + "._models_parts.examples_database": ("ExamplesFlextCliModelsExamplesDatabase",), + ".constants": ("ExamplesFlextCliConstants", "c"), + ".ex_01_getting_started": ("ExamplesFlextCliGettingStarted",), + ".ex_02_output_formatting": ("ex_02_output_formatting",), + ".ex_04_file_operations": ("ex_04_file_operations",), + ".ex_05_authentication": ("Ex05Authentication",), + ".ex_06_settings": ("Ex06Settings",), + ".ex_11_complete_integration": ("DataManagerCLI",), + ".ex_12_pydantic_driven_cli": ("ex_12_pydantic_driven_cli",), + ".models": ("ExamplesFlextCliModels", "m"), + ".protocols": ("ExamplesFlextCliProtocols", "p"), + ".typings": ("ExamplesFlextCliTypes", "t"), + ".utilities": ("ExamplesFlextCliUtilities", "u"), + "flext_cli": ("d", "e", "h", "r", "s", "x"), + }), exclude_names=( "cleanup_submodule_namespace", "install_lazy_exports", @@ -114,9 +86,4 @@ ) -install_lazy_exports( - __name__, - globals(), - _LAZY_IMPORTS, - publish_all=False, -) +install_lazy_exports(__name__, globals(), _LAZY_IMPORTS, publish_all=False) diff --git a/examples/_models_parts/__init__.py b/examples/_models_parts/__init__.py index fb664d7bb..c91d239b0 100644 --- a/examples/_models_parts/__init__.py +++ b/examples/_models_parts/__init__.py @@ -5,19 +5,12 @@ from flext_core.lazy import build_lazy_import_map, install_lazy_exports -_LAZY_IMPORTS = build_lazy_import_map( - { - ".examples_advanced": ("ExamplesFlextCliModelsExamplesAdvanced",), - ".examples_common": ("ExamplesFlextCliModelsExamplesCommon",), - ".examples_database": ("ExamplesFlextCliModelsExamplesDatabase",), - ".examplesflextclimodels_part_01": ("ExamplesFlextCliModels",), - }, -) +_LAZY_IMPORTS = build_lazy_import_map({ + ".examples_advanced": ("ExamplesFlextCliModelsExamplesAdvanced",), + ".examples_common": ("ExamplesFlextCliModelsExamplesCommon",), + ".examples_database": ("ExamplesFlextCliModelsExamplesDatabase",), + ".examplesflextclimodels_part_01": ("ExamplesFlextCliModels",), +}) -install_lazy_exports( - __name__, - globals(), - _LAZY_IMPORTS, - publish_all=False, -) +install_lazy_exports(__name__, globals(), _LAZY_IMPORTS, publish_all=False) diff --git a/examples/_models_parts/examples_advanced.py b/examples/_models_parts/examples_advanced.py index b649450af..71962ea99 100644 --- a/examples/_models_parts/examples_advanced.py +++ b/examples/_models_parts/examples_advanced.py @@ -2,6 +2,7 @@ from __future__ import annotations +from collections.abc import MutableSequence from pathlib import Path from typing import TYPE_CHECKING, Annotated, ClassVar @@ -9,9 +10,6 @@ from examples._models_parts.examples_common import ExamplesFlextCliModelsExamplesCommon from flext_cli import m, p, u -from collections.abc import MutableSequence - - class ExamplesFlextCliModelsExamplesAdvanced: """Split example model advanced namespace.""" @@ -20,41 +18,26 @@ class AppSettingsAdvanced(m.Value): """Advanced application settings — Pydantic v2 only.""" model_config: ClassVar[t.ConfigDict] = m.ConfigDict( - extra="forbid", - validate_assignment=True, + extra="forbid", validate_assignment=True + ) + database_url: Annotated[str, m.Field(description="Database URL")] = ( + c.EXAMPLE_DEFAULT_DB_URL + ) + redis_url: Annotated[str, m.Field(description="Redis URL")] = ( + c.EXAMPLE_DEFAULT_REDIS_URL ) - database_url: Annotated[ - str, - m.Field( - description="Database URL", - ), - ] = c.EXAMPLE_DEFAULT_DB_URL - redis_url: Annotated[ - str, - m.Field( - description="Redis URL", - ), - ] = c.EXAMPLE_DEFAULT_REDIS_URL api_key: Annotated[str, m.Field(description="API key")] = "" environment: Annotated[ - c.DeploymentEnvironment, - m.Field(description="Deployment environment"), + c.DeploymentEnvironment, m.Field(description="Deployment environment") ] = c.EXAMPLE_DEFAULT_ENVIRONMENT max_workers: Annotated[ int, - m.Field( - ge=1, - le=c.EXAMPLE_MAX_CONNECTION_POOL, - description="Max workers", - ), + m.Field(ge=1, le=c.EXAMPLE_MAX_CONNECTION_POOL, description="Max workers"), ] = c.EXAMPLE_DEFAULT_MAX_WORKERS enable_metrics: Annotated[bool, m.Field(description="Enable metrics")] = True - log_level: Annotated[ - str, - m.Field( - description="Log level", - ), - ] = c.EXAMPLE_DEFAULT_LOG_LEVEL + log_level: Annotated[str, m.Field(description="Log level")] = ( + c.EXAMPLE_DEFAULT_LOG_LEVEL + ) temp_dir: Path = m.Field( Path.home() / c.Cli.PATH_FLEXT_DIR_NAME / c.EXAMPLE_DEFAULT_TEMP_SUBDIR, description="Temp directory", @@ -63,10 +46,7 @@ class AppSettingsAdvanced(m.Value): @u.model_validator(mode="before") @classmethod - def _inject_env( - cls, - data: t.ExampleModelInput, - ) -> t.ExampleModelInput: + def _inject_env(cls, data: t.ExampleModelInput) -> t.ExampleModelInput: return ExamplesFlextCliModelsExamplesCommon.merge_env_overrides( data, c.EXAMPLE_ENV_MAP_ADVANCED_APP, diff --git a/examples/_models_parts/examples_common.py b/examples/_models_parts/examples_common.py index d5a663e36..82eecaed7 100644 --- a/examples/_models_parts/examples_common.py +++ b/examples/_models_parts/examples_common.py @@ -29,15 +29,11 @@ def merge_env_overrides( if env_name not in os.environ or field_name not in field_types: continue validated_value: t.EnvValue = m.TypeAdapter( - field_types[field_name], - ).validate_python( - os.environ[env_name], - ) + field_types[field_name] + ).validate_python(os.environ[env_name]) if isinstance(validated_value, Mapping): env_overrides[field_name] = dict( - t.JSON_DICT_ADAPTER.validate_python( - validated_value, - ), + t.JSON_DICT_ADAPTER.validate_python(validated_value) ) continue if isinstance(validated_value, Path | str | int | float | bool): @@ -55,37 +51,22 @@ class MyAppSettings(m.Value): """Custom settings for YOUR CLI application — Pydantic v2 only.""" model_config: ClassVar[t.ConfigDict] = m.ConfigDict( - extra="forbid", - validate_assignment=True, + extra="forbid", validate_assignment=True + ) + app_name: Annotated[str, m.Field(description="Application name")] = ( + c.EXAMPLE_DEFAULT_TOOL_NAME ) - app_name: Annotated[ - str, - m.Field( - description="Application name", - ), - ] = c.EXAMPLE_DEFAULT_TOOL_NAME api_key: Annotated[str, m.Field(description="API key")] = "" - max_workers: Annotated[ - int, - m.Field( - ge=1, - description="Max workers", - ), - ] = c.EXAMPLE_DEFAULT_MAX_WORKERS - timeout: Annotated[ - int, - m.Field( - ge=1, - description="Timeout in seconds", - ), - ] = c.EXAMPLE_DEFAULT_TIMEOUT_SECONDS + max_workers: Annotated[int, m.Field(ge=1, description="Max workers")] = ( + c.EXAMPLE_DEFAULT_MAX_WORKERS + ) + timeout: Annotated[int, m.Field(ge=1, description="Timeout in seconds")] = ( + c.EXAMPLE_DEFAULT_TIMEOUT_SECONDS + ) @u.model_validator(mode="before") @classmethod - def _inject_env( - cls, - data: t.ExampleModelInput, - ) -> t.ExampleModelInput: + def _inject_env(cls, data: t.ExampleModelInput) -> t.ExampleModelInput: return ExamplesFlextCliModelsExamplesCommon.merge_env_overrides( data, c.EXAMPLE_ENV_MAP_MY_APP, @@ -105,17 +86,13 @@ def display(self, cli: t.CliApi) -> None: "Debug": str(settings.debug), "App": settings.cli_app_name, } - payload = m.Cli.DisplayData( - data=payload_data, - ) + payload = m.Cli.DisplayData(data=payload_data) if isinstance(payload.data, dict): safe_data: t.Cli.TableMappingRow = { k: str(v) for k, v in payload.data.items() } cli.show_table( - safe_data, - show_header=True, - title="⚙️ Application Settings", + safe_data, show_header=True, title="⚙️ Application Settings" ) diff --git a/examples/_models_parts/examples_database.py b/examples/_models_parts/examples_database.py index ce880db66..6fa71ba42 100644 --- a/examples/_models_parts/examples_database.py +++ b/examples/_models_parts/examples_database.py @@ -16,14 +16,9 @@ class AdvancedDatabaseConfig(m.Value): """Database configuration with advanced validation.""" model_config: ClassVar[t.ConfigDict] = m.ConfigDict( - extra="forbid", - validate_assignment=True, - ) - host: str = m.Field( - ..., - description="Database host", - validate_default=True, + extra="forbid", validate_assignment=True ) + host: str = m.Field(..., description="Database host", validate_default=True) port: int = m.Field( c.EXAMPLE_DEFAULT_DB_PORT, description="Database port", @@ -32,16 +27,10 @@ class AdvancedDatabaseConfig(m.Value): validate_default=True, ) name: str = m.Field( - ..., - description="Database name", - min_length=1, - validate_default=True, + ..., description="Database name", min_length=1, validate_default=True ) username: str = m.Field( - ..., - description="Database username", - min_length=1, - validate_default=True, + ..., description="Database username", min_length=1, validate_default=True ) password: str = m.Field( ..., @@ -50,9 +39,7 @@ class AdvancedDatabaseConfig(m.Value): validate_default=True, ) ssl_enabled: bool = m.Field( - True, - description="Enable SSL", - validate_default=True, + True, description="Enable SSL", validate_default=True ) connection_pool: int = m.Field( c.EXAMPLE_DEFAULT_CONNECTION_POOL, diff --git a/examples/constants.py b/examples/constants.py index 21699704d..363e64357 100644 --- a/examples/constants.py +++ b/examples/constants.py @@ -7,10 +7,8 @@ from types import MappingProxyType from typing import TYPE_CHECKING, Final -from flext_cli import c - from examples import p, t - +from flext_cli import c class ExamplesFlextCliConstants(c): diff --git a/examples/ex_04_file_operations.py b/examples/ex_04_file_operations.py index f87f61b3e..362065971 100644 --- a/examples/ex_04_file_operations.py +++ b/examples/ex_04_file_operations.py @@ -7,16 +7,12 @@ from __future__ import annotations -from collections.abc import ( - Mapping, -) +from collections.abc import Mapping +from pathlib import Path from typing import TYPE_CHECKING from flext_cli import c, cli, m, p, r, t, u -from pathlib import Path - - _EXAMPLE_REQUIRED_DATA_FIELDS: t.VariadicTuple[str] = ("id", "name", "value") # ============================================================================ @@ -25,8 +21,7 @@ def save_user_preferences( - preferences: t.MappingKV[str, t.JsonPayloadCollectionValue], - config_dir: Path, + preferences: t.MappingKV[str, t.JsonPayloadCollectionValue], config_dir: Path ) -> bool: """Save user preferences to JSON in YOUR app.""" config_file = config_dir / "preferences.json" @@ -36,8 +31,7 @@ def save_user_preferences( # json.dump(preferences, f) write_result = cli.json_write_file( - config_file, - u.normalize_to_json_value(preferences), + config_file, u.normalize_to_json_value(preferences) ) if write_result.failure: @@ -48,8 +42,7 @@ def save_user_preferences( return False cli.print( - f"✅ Saved preferences to {config_file.name}", - style=c.Cli.MessageStyles.GREEN, + f"✅ Saved preferences to {config_file.name}", style=c.Cli.MessageStyles.GREEN ) return True @@ -62,11 +55,10 @@ def load_user_preferences(config_dir: Path) -> p.Result[p.Cli.LoadedConfig]: if read_result.failure: cli.print( - f"⚠️ Could not load: {read_result.error}", - style=c.Cli.MessageStyles.YELLOW, + f"⚠️ Could not load: {read_result.error}", style=c.Cli.MessageStyles.YELLOW ) return r[p.Cli.LoadedConfig].fail( - read_result.error or "Could not load preferences", + read_result.error or "Could not load preferences" ) if not isinstance(read_result.value, Mapping): return r[p.Cli.LoadedConfig].fail("Preferences content must be a mapping") @@ -75,9 +67,7 @@ def load_user_preferences(config_dir: Path) -> p.Result[p.Cli.LoadedConfig]: f"✅ Loaded preferences from {config_file.name}", style=c.Cli.MessageStyles.GREEN, ) - return r[p.Cli.LoadedConfig].ok( - m.Cli.LoadedConfig(content=dict(read_result.value)), - ) + return r[p.Cli.LoadedConfig].ok(m.Cli.LoadedConfig(content=dict(read_result.value))) # ============================================================================ @@ -86,8 +76,7 @@ def load_user_preferences(config_dir: Path) -> p.Result[p.Cli.LoadedConfig]: def save_deployment_config( - settings: t.MappingKV[str, t.JsonPayloadCollectionValue], - config_file: Path, + settings: t.MappingKV[str, t.JsonPayloadCollectionValue], config_file: Path ) -> bool: """Save deployment settings to YAML in YOUR tool.""" # Instead of: @@ -95,10 +84,7 @@ def save_deployment_config( # yaml.dump(settings, f) # Normalize the mapping into the CLI JSON contract before writing YAML. - write_result = cli.yaml_write_file( - config_file, - u.normalize_to_json_value(settings), - ) + write_result = cli.yaml_write_file(config_file, u.normalize_to_json_value(settings)) if write_result.failure: cli.print( @@ -123,9 +109,7 @@ def load_deployment_config(config_file: Path) -> p.Result[p.Cli.LoadedConfig]: return r[p.Cli.LoadedConfig].fail(load_result.error or "Config load failed") cli.print("✅ Loaded deployment settings", style=c.Cli.MessageStyles.GREEN) - return r[p.Cli.LoadedConfig].ok( - m.Cli.LoadedConfig(content=load_result.value), - ) + return r[p.Cli.LoadedConfig].ok(m.Cli.LoadedConfig(content=load_result.value)) def validate_and_import_data(input_file: Path) -> p.Result[p.Cli.LoadedConfig]: @@ -134,8 +118,7 @@ def validate_and_import_data(input_file: Path) -> p.Result[p.Cli.LoadedConfig]: if read_result.failure: cli.print( - f"❌ Read failed: {read_result.error}", - style=c.Cli.MessageStyles.BOLD_RED, + f"❌ Read failed: {read_result.error}", style=c.Cli.MessageStyles.BOLD_RED ) return r[p.Cli.LoadedConfig].fail(read_result.error or "Read failed") @@ -148,6 +131,4 @@ def validate_and_import_data(input_file: Path) -> p.Result[p.Cli.LoadedConfig]: return r[p.Cli.LoadedConfig].fail(f"Missing required field: {field}") cli.print("✅ Data validated successfully", style=c.Cli.MessageStyles.GREEN) - return r[p.Cli.LoadedConfig].ok( - m.Cli.LoadedConfig(content=data), - ) + return r[p.Cli.LoadedConfig].ok(m.Cli.LoadedConfig(content=data)) diff --git a/examples/ex_06_settings.py b/examples/ex_06_settings.py index b193b34a6..3d9c71390 100644 --- a/examples/ex_06_settings.py +++ b/examples/ex_06_settings.py @@ -39,21 +39,16 @@ class Ex06Settings: def show_cli_settings() -> p.Cli.Settings: """Access flext-cli settings in YOUR application.""" cli.print("📋 Current Settings:", style=c.Cli.MessageStyles.BOLD_CYAN) + cli.print(f" Debug Mode: {settings.debug}", style=c.Cli.MessageStyles.CYAN) cli.print( - f" Debug Mode: {settings.debug}", - style=c.Cli.MessageStyles.CYAN, - ) - cli.print( - f" Log Level: {settings.cli_log_level}", - style=c.Cli.MessageStyles.CYAN, + f" Log Level: {settings.cli_log_level}", style=c.Cli.MessageStyles.CYAN ) cli.print( f" Output Format: {settings.cli_output_format}", style=c.Cli.MessageStyles.CYAN, ) cli.print( - f" App Name: {settings.cli_app_name}", - style=c.Cli.MessageStyles.CYAN, + f" App Name: {settings.cli_app_name}", style=c.Cli.MessageStyles.CYAN ) return settings @@ -69,8 +64,7 @@ def show_settings_locations() -> p.Cli.DisplayData: "Token Exists": "Yes" if token_file_path.exists() else "No", }) u.display_config_table( - config_data=display_payload, - headers=("Location", "Path"), + config_data=display_payload, headers=("Location", "Path") ) return display_payload @@ -93,10 +87,7 @@ def load_profile_settings( case _: debug = profile_name == c.DeploymentEnvironment.DEVELOPMENT output_format = c.Cli.OutputFormats.TABLE - profile_config = settings.clone( - debug=debug, - cli_output_format=output_format, - ) + profile_config = settings.clone(debug=debug, cli_output_format=output_format) cli.print( f"✅ Profile '{profile_name.value}' loaded successfully", style=c.Cli.MessageStyles.GREEN, @@ -107,7 +98,7 @@ def load_profile_settings( "Debug": str(profile_config.debug), "Output": profile_config.cli_output_format, "App Name": profile_config.cli_app_name, - }), + }) ) return r[p.Cli.Settings].ok(profile_config) @@ -115,21 +106,19 @@ def load_profile_settings( def load_application_settings(cls) -> p.Result[t.MappingKV[str, t.JsonValue]]: """Load, validate, and derive application settings from the canonical model.""" cli.print( - "\n⚙️ Loading Application Settings:", - style=c.Cli.MessageStyles.BOLD_CYAN, + "\n⚙️ Loading Application Settings:", style=c.Cli.MessageStyles.BOLD_CYAN ) settings_obj = m.Examples.AppSettingsAdvanced() cli.print("✅ Settings model created", style=c.Cli.MessageStyles.GREEN) validate_result = settings_obj.validate_to_mapping() if validate_result.failure: return r[t.MappingKV[str, t.JsonValue]].fail( - validate_result.error or c.EXAMPLE_ERR_FAILED_LOAD_CONFIG, + validate_result.error or c.EXAMPLE_ERR_FAILED_LOAD_CONFIG ) cli.print("✅ Settings validated", style=c.Cli.MessageStyles.GREEN) try: overridden_data = cls.apply_environment_overrides( - validate_result.value, - settings_obj.environment, + validate_result.value, settings_obj.environment ) except (TypeError, ValueError) as exc: return r[t.MappingKV[str, t.JsonValue]].fail(str(exc)) @@ -144,25 +133,21 @@ def load_application_settings(cls) -> p.Result[t.MappingKV[str, t.JsonValue]]: @staticmethod def apply_environment_overrides( - settings: t.MappingKV[str, t.JsonValue], - environment: c.DeploymentEnvironment, + settings: t.MappingKV[str, t.JsonValue], environment: c.DeploymentEnvironment ) -> t.MappingKV[str, t.JsonValue]: """Apply environment-specific settings overrides.""" result = dict(settings) match environment: case c.DeploymentEnvironment.PRODUCTION: max_workers_value = result.get( - "max_workers", - c.EXAMPLE_DEFAULT_MAX_WORKERS, + "max_workers", c.EXAMPLE_DEFAULT_MAX_WORKERS ) if isinstance(max_workers_value, bool) or not isinstance( - max_workers_value, - int, + max_workers_value, int ): raise TypeError(c.EXAMPLE_ERR_MAX_WORKERS_MUST_BE_INTEGER) result["max_workers"] = min( - max_workers_value, - c.EXAMPLE_PRODUCTION_MAX_WORKERS_CAP, + max_workers_value, c.EXAMPLE_PRODUCTION_MAX_WORKERS_CAP ) result["enable_metrics"] = True case c.DeploymentEnvironment.TESTING: diff --git a/examples/ex_11_complete_integration.py b/examples/ex_11_complete_integration.py index 5581ddb0d..371ee22c7 100644 --- a/examples/ex_11_complete_integration.py +++ b/examples/ex_11_complete_integration.py @@ -53,12 +53,9 @@ def add_entry(self) -> p.Result[t.JsonMapping]: if value_result.failure: return r[t.JsonMapping].fail(f"Prompt failed: {value_result.error}") value = value_result.value - cli.print( - f"✅ Created entry: {key} = {value}", - style=c.Cli.MessageStyles.GREEN, - ) + cli.print(f"✅ Created entry: {key} = {value}", style=c.Cli.MessageStyles.GREEN) return r[t.JsonMapping].ok( - t.Cli.JSON_MAPPING_ADAPTER.validate_python({key: value}), + t.Cli.JSON_MAPPING_ADAPTER.validate_python({key: value}) ) def load_data(self) -> p.Result[t.JsonMapping]: @@ -69,14 +66,11 @@ def load_data(self) -> p.Result[t.JsonMapping]: if read_result.failure: error_msg = read_result.error or "Unknown error" cli.print( - f"❌ Load failed: {error_msg}", - style=c.Cli.MessageStyles.BOLD_RED, + f"❌ Load failed: {error_msg}", style=c.Cli.MessageStyles.BOLD_RED ) return r[t.JsonMapping].fail(error_msg) if not isinstance(read_result.value, Mapping): - return r[t.JsonMapping].fail( - _EXAMPLE_ERR_DATA_FILE_MUST_BE_MAPPING, - ) + return r[t.JsonMapping].fail(_EXAMPLE_ERR_DATA_FILE_MUST_BE_MAPPING) cli.print("✅ Data loaded successfully", style=c.Cli.MessageStyles.GREEN) return r[t.JsonMapping].ok(read_result.value) @@ -86,13 +80,11 @@ def save_data(self, data: t.JsonMapping) -> p.Result[bool]: if write_result.failure: error_msg = write_result.error or "Unknown error" cli.print( - f"❌ Save failed: {error_msg}", - style=c.Cli.MessageStyles.BOLD_RED, + f"❌ Save failed: {error_msg}", style=c.Cli.MessageStyles.BOLD_RED ) return r[bool].fail(error_msg) cli.print( - f"✅ Data saved to {self.data_file.name}", - style=c.Cli.MessageStyles.GREEN, + f"✅ Data saved to {self.data_file.name}", style=c.Cli.MessageStyles.GREEN ) return r[bool].ok(value=True) diff --git a/examples/models.py b/examples/models.py index a258d9209..c892a4c8f 100644 --- a/examples/models.py +++ b/examples/models.py @@ -16,10 +16,7 @@ from flext_cli import m as flext_cli_m -class ExamplesFlextCliModels( - ExamplesFlextCliModelsPart01, - flext_cli_m, -): +class ExamplesFlextCliModels(ExamplesFlextCliModelsPart01, flext_cli_m): """Public facade for ExamplesFlextCliModels.""" diff --git a/examples/protocols.py b/examples/protocols.py index ff8abe1c9..88b826dc5 100644 --- a/examples/protocols.py +++ b/examples/protocols.py @@ -2,15 +2,11 @@ from __future__ import annotations +from collections.abc import Callable from typing import TYPE_CHECKING, Protocol, runtime_checkable from flext_cli import p -from collections.abc import ( - Callable, -) - - class ExamplesFlextCliProtocols(p): """Public examples protocol facade extending flext-cli protocols.""" @@ -31,17 +27,13 @@ class CliMainWithGroups(Protocol): """ def command( - self, - *args: str, - **kwargs: str, + self, *args: str, **kwargs: str ) -> Callable[[Callable[..., None]], Callable[..., None]]: """Create a command decorator.""" ... def group( - self, - *args: str, - **kwargs: str, + self, *args: str, **kwargs: str ) -> Callable[[Callable[..., None]], Callable[..., None]]: """Create a command group decorator.""" ... @@ -62,9 +54,7 @@ class GroupWithCommands(Protocol): """ def command( - self, - *args: str, - **kwargs: str, + self, *args: str, **kwargs: str ) -> Callable[[Callable[..., None]], Callable[..., None]]: """Create a command decorator.""" ... @@ -72,7 +62,4 @@ def command( p = ExamplesFlextCliProtocols -__all__: list[str] = [ - "ExamplesFlextCliProtocols", - "p", -] +__all__: list[str] = ["ExamplesFlextCliProtocols", "p"] diff --git a/examples/typings.py b/examples/typings.py index 8184b7f8a..5c3cbae8e 100644 --- a/examples/typings.py +++ b/examples/typings.py @@ -2,9 +2,7 @@ from __future__ import annotations -from collections.abc import ( - Callable, -) +from collections.abc import Callable from typing import ClassVar from flext_cli import FlextCli, t @@ -22,13 +20,10 @@ class ExamplesFlextCliTypes(t): type DataProcessor = Callable[[str], str] type ProcessorRegistry = t.MappingKV[str, DataProcessor] JSON_DICT_ADAPTER: ClassVar[t.ValueAdapter[t.JsonMapping]] = m.TypeAdapter( - t.JsonMapping, + t.JsonMapping ) t = ExamplesFlextCliTypes -__all__: list[str] = [ - "ExamplesFlextCliTypes", - "t", -] +__all__: list[str] = ["ExamplesFlextCliTypes", "t"] diff --git a/examples/utilities.py b/examples/utilities.py index 1a9ae4b50..c7bc860a1 100644 --- a/examples/utilities.py +++ b/examples/utilities.py @@ -11,28 +11,21 @@ from __future__ import annotations +from collections.abc import MutableSequence from typing import TYPE_CHECKING from examples import c, m, p, t from flext_cli import cli, u -from collections.abc import ( - MutableSequence, -) - - class ExamplesFlextCliUtilities(u): """Public examples utility facade extending flext-cli utilities.""" @classmethod - def to_json_dict( - cls, - data: t.JsonMapping, - ) -> p.Cli.DisplayData: + def to_json_dict(cls, data: t.JsonMapping) -> p.Cli.DisplayData: """Normalize settings/mapping to DisplayData for create_table/display_config_table.""" json_value: t.JsonValue = t.Cli.JSON_VALUE_ADAPTER.validate_python( - cls.normalize_to_json_value(data), + cls.normalize_to_json_value(data) ) normalized = m.Cli.JsonNormalized(json_value).root resolved = m.Cli.JsonNormalizedList(value=normalized, default={}).resolved @@ -60,8 +53,7 @@ def print_demo_completion( @staticmethod def display_config_table( - config_data: p.Cli.DisplayData | m.Value, - headers: t.StrSequence | None = None, + config_data: p.Cli.DisplayData | m.Value, headers: t.StrSequence | None = None ) -> None: """Display configuration as a table using canonical example models.""" if headers is None: @@ -78,8 +70,7 @@ def display_config_table( @staticmethod def display_success_summary( - operation: str, - details: p.Cli.SuccessSummaryDetails | None = None, + operation: str, details: p.Cli.SuccessSummaryDetails | None = None ) -> None: """Display a standardized success summary using cli.""" cli.print( @@ -93,7 +84,4 @@ def display_success_summary( u = ExamplesFlextCliUtilities -__all__: t.MutableSequenceOf[str] = [ - "ExamplesFlextCliUtilities", - "u", -] +__all__: t.MutableSequenceOf[str] = ["ExamplesFlextCliUtilities", "u"] diff --git a/src/flext_cli/__init__.py b/src/flext_cli/__init__.py index 5033e3967..f9145e478 100644 --- a/src/flext_cli/__init__.py +++ b/src/flext_cli/__init__.py @@ -5,7 +5,6 @@ from typing import TYPE_CHECKING -from flext_core.lazy import build_lazy_import_map, install_lazy_exports from flext_cli.__version__ import ( __author__, __author_email__, @@ -16,6 +15,7 @@ __version__, __version_info__, ) +from flext_core.lazy import build_lazy_import_map, install_lazy_exports if TYPE_CHECKING: from flext_core import d, e, h, r, x diff --git a/src/flext_cli/_config.py b/src/flext_cli/_config.py index e537e63fb..bdc8c16ec 100644 --- a/src/flext_cli/_config.py +++ b/src/flext_cli/_config.py @@ -17,11 +17,11 @@ from typing import ClassVar from flext_cli._models.config import FlextCliConfigModels -from flext_core import FlextConfig # NOTE (multi-agent): accessor typed by PROTOCOL (p), never the model # class; the protocol module enters under TYPE_CHECKING only (§2.5/§3.4). from flext_cli._protocols.config import FlextCliProtocolsConfig +from flext_core import FlextConfig class FlextCliConfig(FlextConfig): diff --git a/src/flext_cli/_models/toml.py b/src/flext_cli/_models/toml.py index 0e4574c06..cb70961be 100644 --- a/src/flext_cli/_models/toml.py +++ b/src/flext_cli/_models/toml.py @@ -15,9 +15,8 @@ from itertools import chain from typing import Annotated, Literal, Self -from flext_core import m, t - from flext_cli._constants.enums import FlextCliConstantsEnums as _enum +from flext_core import m, t # Pyproject "tool" table name — the default TOML root for tool configuration. _TOOL_TABLE: str = "tool" diff --git a/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_03.py b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_03.py index c095487fa..2a3e5ee47 100644 --- a/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_03.py +++ b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_03.py @@ -12,7 +12,6 @@ from flext_cli._protocols._base.flextcliprotocolsbase_part_02 import ( FlextCliProtocolsBase as FlextCliProtocolsBasePart02, ) - from flext_core import p, t diff --git a/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_04.py b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_04.py index 1eb0e1ecd..2e3b81692 100644 --- a/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_04.py +++ b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_04.py @@ -11,8 +11,7 @@ from flext_cli._protocols._base.flextcliprotocolsbase_part_03 import ( FlextCliProtocolsBase as FlextCliProtocolsBasePart03, ) -from flext_core import p -from flext_core import t +from flext_core import p, t class FlextCliProtocolsBase(FlextCliProtocolsBasePart03): diff --git a/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_05.py b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_05.py index f9e20b95d..50c5ccb54 100644 --- a/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_05.py +++ b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_05.py @@ -11,7 +11,6 @@ from flext_cli._protocols._base.flextcliprotocolsbase_part_04 import ( FlextCliProtocolsBase as FlextCliProtocolsBasePart04, ) - from flext_core import t diff --git a/src/flext_cli/_protocols/settings.py b/src/flext_cli/_protocols/settings.py index a8225d1b6..14d9463e4 100644 --- a/src/flext_cli/_protocols/settings.py +++ b/src/flext_cli/_protocols/settings.py @@ -11,6 +11,7 @@ from __future__ import annotations from typing import Protocol, runtime_checkable + from flext_core import p diff --git a/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_02.py b/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_02.py index ff1a49fdf..5e31405ab 100644 --- a/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_02.py +++ b/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_02.py @@ -9,7 +9,6 @@ from __future__ import annotations import os - from pathlib import Path diff --git a/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_03.py b/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_03.py index 3374a45b7..cc053cdd2 100644 --- a/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_03.py +++ b/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_03.py @@ -9,6 +9,7 @@ from __future__ import annotations from collections.abc import Mapping, MutableMapping +from pathlib import Path from flext_cli import c, p, r from flext_cli._utilities._file_test_helper.flextcliutilitiesfiletesthelpersmixin_part_04 import ( @@ -16,8 +17,6 @@ ) from flext_cli._utilities.files import FlextCliUtilitiesFiles -from pathlib import Path - class FlextCliUtilitiesFileTestHelpersMixin: """Implementation part for FlextCliUtilitiesFileTestHelpersMixin.""" diff --git a/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_04.py b/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_04.py index 3f010176c..809548cf7 100644 --- a/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_04.py +++ b/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_04.py @@ -8,14 +8,13 @@ from __future__ import annotations +from pathlib import Path from flext_cli import c, p, r from flext_cli._utilities.json import FlextCliUtilitiesJson as uj from flext_cli._utilities.toml import FlextCliUtilitiesToml as ut from flext_cli._utilities.yaml import FlextCliUtilitiesYaml as uy -from pathlib import Path - class FlextCliUtilitiesFileTestHelpersMixin: """Implementation part for FlextCliUtilitiesFileTestHelpersMixin.""" diff --git a/src/flext_cli/_utilities/_json/_navigate.py b/src/flext_cli/_utilities/_json/_navigate.py index def33acfe..cfbb8df73 100644 --- a/src/flext_cli/_utilities/_json/_navigate.py +++ b/src/flext_cli/_utilities/_json/_navigate.py @@ -10,13 +10,11 @@ from __future__ import annotations - +from flext_cli import t from flext_core import u from ._core import FlextCliUtilitiesJsonCoreMixin -from flext_cli import t - class FlextCliUtilitiesJsonNavigateMixin(FlextCliUtilitiesJsonCoreMixin): """Navigate nested JSON mappings and extract typed scalar values.""" diff --git a/src/flext_cli/_utilities/_rules/_loaders.py b/src/flext_cli/_utilities/_rules/_loaders.py index 083a6d413..dc4bebea9 100644 --- a/src/flext_cli/_utilities/_rules/_loaders.py +++ b/src/flext_cli/_utilities/_rules/_loaders.py @@ -11,6 +11,7 @@ from __future__ import annotations +from pathlib import Path from flext_cli import c, m, p, r, t from flext_cli._utilities.json import FlextCliUtilitiesJson as uj @@ -18,8 +19,6 @@ from ._matchers import FlextCliUtilitiesRulesMatchersMixin -from pathlib import Path - class FlextCliUtilitiesRulesLoadersMixin(FlextCliUtilitiesRulesMatchersMixin): """Load and normalize declarative local rule definitions from YAML.""" diff --git a/src/flext_cli/_utilities/_rules/_matchers.py b/src/flext_cli/_utilities/_rules/_matchers.py index aa3183e6a..431e3f348 100644 --- a/src/flext_cli/_utilities/_rules/_matchers.py +++ b/src/flext_cli/_utilities/_rules/_matchers.py @@ -13,12 +13,10 @@ import fnmatch from collections.abc import Mapping, MutableSequence - -from flext_cli._utilities.json import FlextCliUtilitiesJson as uj - from pathlib import Path from flext_cli import t +from flext_cli._utilities.json import FlextCliUtilitiesJson as uj class FlextCliUtilitiesRulesMatchersMixin: diff --git a/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_04.py b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_04.py index 416ed4ab7..10f207809 100644 --- a/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_04.py +++ b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_04.py @@ -2,7 +2,10 @@ from __future__ import annotations +from tomlkit.items import Table +from tomlkit.toml_document import TOMLDocument +from flext_cli import t from flext_cli._utilities._toml.flextcliutilitiestoml_part_01 import ( FlextCliUtilitiesToml as FlextCliUtilitiesTomlPart01, ) @@ -11,11 +14,6 @@ ) from flext_core import u -from tomlkit.items import Table -from tomlkit.toml_document import TOMLDocument - -from flext_cli import t - class FlextCliUtilitiesToml: """Implementation part for FlextCliUtilitiesToml.""" diff --git a/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_05.py b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_05.py index 6badfe6fc..759801623 100644 --- a/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_05.py +++ b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_05.py @@ -7,6 +7,7 @@ from tomlkit.items import Item, Table from tomlkit.toml_document import TOMLDocument +from flext_cli import t from flext_cli._utilities._toml.flextcliutilitiestoml_part_01 import ( FlextCliUtilitiesToml as FlextCliUtilitiesTomlPart01, ) @@ -18,8 +19,6 @@ ) from flext_core import u -from flext_cli import t - class FlextCliUtilitiesToml: """Implementation part for FlextCliUtilitiesToml.""" diff --git a/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_06.py b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_06.py index b526fe620..7a859dd8a 100644 --- a/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_06.py +++ b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_06.py @@ -2,6 +2,7 @@ from __future__ import annotations +from pathlib import Path import tomlkit from tomlkit.toml_document import TOMLDocument @@ -13,8 +14,6 @@ from flext_cli._utilities.runtime import FlextCliUtilitiesRuntime as ur from flext_core import u -from pathlib import Path - class FlextCliUtilitiesToml: """Implementation part for FlextCliUtilitiesToml.""" diff --git a/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_07.py b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_07.py index 3ffb0bba6..cea5171f9 100644 --- a/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_07.py +++ b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_07.py @@ -2,6 +2,7 @@ from __future__ import annotations +from pathlib import Path from flext_cli import c, e, p, r, t from flext_cli._utilities._toml.flextcliutilitiestoml_part_01 import ( @@ -11,8 +12,6 @@ FlextCliUtilitiesToml as FlextCliUtilitiesTomlPart06, ) -from pathlib import Path - class FlextCliUtilitiesToml: """Implementation part for FlextCliUtilitiesToml.""" diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_recalc.py b/src/flext_cli/_utilities/_xlxx/xlsx_recalc.py index 2105cf92c..dcebfd238 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_recalc.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_recalc.py @@ -6,8 +6,8 @@ from pathlib import Path from flext_cli import c, m, p, r - from flext_cli._utilities.processes import FlextCliUtilitiesProcesses + from .xlsx_recalc_evidence import FlextCliUtilitiesXlsxRecalcEvidence from .xlsx_snapshot import FlextCliUtilitiesXlsxSnapshot diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_style_builders.py b/src/flext_cli/_utilities/_xlxx/xlsx_style_builders.py index 0b85f26f0..d9d451642 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_style_builders.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_style_builders.py @@ -1,11 +1,13 @@ """Translate typed visual style models into openpyxl objects.""" from __future__ import annotations -from flext_cli import p + from openpyxl.styles import Alignment, Border, Color, Font, GradientFill, NamedStyle from openpyxl.styles.borders import Side from openpyxl.styles.fills import PatternFill, Stop +from flext_cli import p + class FlextCliUtilitiesXlsxStyleBuilders: """Build external visual styles only from validated model fields.""" diff --git a/src/flext_cli/_utilities/_yaml/_engine.py b/src/flext_cli/_utilities/_yaml/_engine.py index 5888e4540..add30dc00 100644 --- a/src/flext_cli/_utilities/_yaml/_engine.py +++ b/src/flext_cli/_utilities/_yaml/_engine.py @@ -22,6 +22,7 @@ from __future__ import annotations import io +from pathlib import Path from typing import TextIO import ruamel.yaml @@ -31,8 +32,6 @@ from ._convert import FlextCliUtilitiesYamlConvertMixin -from pathlib import Path - def _roundtrip_yaml() -> ruamel.yaml.YAML: """Build a fresh comment/quote-preserving round-trip engine. diff --git a/src/flext_cli/_utilities/commands.py b/src/flext_cli/_utilities/commands.py index a7c1e1de2..d53deefad 100644 --- a/src/flext_cli/_utilities/commands.py +++ b/src/flext_cli/_utilities/commands.py @@ -5,12 +5,10 @@ import traceback # mro-j47u (codex): formatter contracts are owned once by the t facade. -from flext_cli import c, r, t +from flext_cli import c, p, r, t from flext_cli._utilities.output import FlextCliUtilitiesOutput as uo from flext_core import u -from flext_cli import p - class FlextCliUtilitiesCommands: """Helpers for result-command messaging in the public Typer DSL.""" diff --git a/src/flext_cli/_utilities/formatters.py b/src/flext_cli/_utilities/formatters.py index e33c6f6ec..c4661b105 100644 --- a/src/flext_cli/_utilities/formatters.py +++ b/src/flext_cli/_utilities/formatters.py @@ -7,6 +7,7 @@ from rich.console import Console from rich.panel import Panel from rich.table import Table as RichTable + from flext_cli import p diff --git a/src/flext_cli/_utilities/framework.py b/src/flext_cli/_utilities/framework.py index 478fe09c3..dbfc4a0c4 100644 --- a/src/flext_cli/_utilities/framework.py +++ b/src/flext_cli/_utilities/framework.py @@ -15,9 +15,7 @@ from typer.testing import CliRunner # mro-j47u (codex): consume every public facade through the package root. -from flext_cli import c, e, r, t - -from flext_cli import m, p +from flext_cli import c, e, m, p, r, t class _TyperApplication: diff --git a/src/flext_cli/_utilities/model_commands.py b/src/flext_cli/_utilities/model_commands.py index dad5f8eca..94fd715a2 100644 --- a/src/flext_cli/_utilities/model_commands.py +++ b/src/flext_cli/_utilities/model_commands.py @@ -14,8 +14,7 @@ from collections.abc import Callable, Mapping from typing import cast -from flext_cli import settings, t -from flext_cli import p +from flext_cli import p, settings, t class FlextCliUtilitiesModelCommands: diff --git a/src/flext_cli/constants.py b/src/flext_cli/constants.py index f7ab5351d..34a2eeb04 100644 --- a/src/flext_cli/constants.py +++ b/src/flext_cli/constants.py @@ -2,6 +2,8 @@ from __future__ import annotations +from flext_core import c, t + # NOTE (mro-0ftd.3.7.2, operator-authorized cross-lane fix): import direct from # submodules (mirrors models.py) because the generated ._constants barrel is empty # (__all__ = ()); the codegen that would repopulate it is itself blocked by this break. @@ -16,7 +18,6 @@ from ._constants.settings import FlextCliConstantsSettings from ._constants.xlsx import FlextCliConstantsXlsx from ._constants.xlsx_future_functions import FlextCliConstantsXlsxFutureFunctions -from flext_core import c, t class FlextCliConstants(c): diff --git a/src/flext_cli/protocols.py b/src/flext_cli/protocols.py index 99f5e4d4a..73691125e 100644 --- a/src/flext_cli/protocols.py +++ b/src/flext_cli/protocols.py @@ -8,8 +8,8 @@ from flext_cli._protocols.framework import FlextCliProtocolsFramework from flext_cli._protocols.pipeline import FlextCliProtocolsPipeline from flext_cli._protocols.settings import FlextCliProtocolsSettings -from flext_cli._protocols.xlsx import FlextCliProtocolsXlsx from flext_cli._protocols.toml import FlextCliProtocolsToml +from flext_cli._protocols.xlsx import FlextCliProtocolsXlsx from flext_core import p diff --git a/src/flext_cli/services/_cli/flextclicli_part_03.py b/src/flext_cli/services/_cli/flextclicli_part_03.py index 58b8c82fc..4463cb399 100644 --- a/src/flext_cli/services/_cli/flextclicli_part_03.py +++ b/src/flext_cli/services/_cli/flextclicli_part_03.py @@ -9,11 +9,11 @@ from inspect import Parameter from flext_cli import c, p, r, t, u -from flext_cli.services._cli.flextclicli_part_02 import FlextCliCli as FlextCliCliPart02 # mro-j47u (codex): the earlier MRO part is referenced only by annotation; # inspect.Parameter remains runtime because it constructs the CLI signature. from flext_cli.services._cli.flextclicli_part_01 import FlextCliCli as FlextCliCliPart01 +from flext_cli.services._cli.flextclicli_part_02 import FlextCliCli as FlextCliCliPart02 class FlextCliCli(FlextCliCliPart02): diff --git a/src/flext_cli/services/_cli/flextclicli_part_05.py b/src/flext_cli/services/_cli/flextclicli_part_05.py index acfcfa40e..dc291c01e 100644 --- a/src/flext_cli/services/_cli/flextclicli_part_05.py +++ b/src/flext_cli/services/_cli/flextclicli_part_05.py @@ -6,12 +6,9 @@ from __future__ import annotations - -from flext_cli import c, r, settings, t, u +from flext_cli import c, p, r, settings, t, u from flext_cli.services._cli.flextclicli_part_04 import FlextCliCli as FlextCliCliPart04 -from flext_cli import p - class FlextCliCli(FlextCliCliPart04): """Implementation part for FlextCliCli.""" diff --git a/src/flext_cli/services/_prompts_support.py b/src/flext_cli/services/_prompts_support.py index 883a752fd..29bb947b8 100644 --- a/src/flext_cli/services/_prompts_support.py +++ b/src/flext_cli/services/_prompts_support.py @@ -10,12 +10,11 @@ from __future__ import annotations import getpass +from collections.abc import Callable from typing import Annotated, Self from flext_cli import c, m, p, r, s, settings, t, u -from collections.abc import Callable - class FlextCliPromptsSupport(s): """Support owner for prompt runtime state, logging, and input readers.""" diff --git a/tests/_constants_parts/tests_core.py b/tests/_constants_parts/tests_core.py index 75b20a93b..24d355bce 100644 --- a/tests/_constants_parts/tests_core.py +++ b/tests/_constants_parts/tests_core.py @@ -8,7 +8,6 @@ from typing import Final from flext_cli import c - from tests import t diff --git a/tests/_constants_parts/tests_yaml_output.py b/tests/_constants_parts/tests_yaml_output.py index 1f70a090c..5324bac25 100644 --- a/tests/_constants_parts/tests_yaml_output.py +++ b/tests/_constants_parts/tests_yaml_output.py @@ -5,7 +5,6 @@ from typing import Final from flext_cli import c - from tests import t diff --git a/tests/_models_parts/__init__.py b/tests/_models_parts/__init__.py index 9f6412dcc..6a7447859 100644 --- a/tests/_models_parts/__init__.py +++ b/tests/_models_parts/__init__.py @@ -34,4 +34,3 @@ install_lazy_exports(__name__, globals(), _LAZY_IMPORTS, publish_all=False) - diff --git a/tests/conftest.py b/tests/conftest.py index 44420a134..6b7f7410f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,7 +2,6 @@ from __future__ import annotations - import pytest from tests import t diff --git a/tests/protocols.py b/tests/protocols.py index d882cf297..b92167a9c 100644 --- a/tests/protocols.py +++ b/tests/protocols.py @@ -11,8 +11,6 @@ from flext_tests import FlextTestsProtocols from flext_cli import p - - from tests import t diff --git a/tests/test_yaml_model_write.py b/tests/test_yaml_model_write.py index 528533e7d..c81deb5b6 100644 --- a/tests/test_yaml_model_write.py +++ b/tests/test_yaml_model_write.py @@ -2,13 +2,12 @@ from __future__ import annotations +from pathlib import Path from flext_tests import tm from flext_cli import cli, m -from pathlib import Path - def test_write_yaml_model_round_trips_the_same_model_contract(tmp_path: Path) -> None: """The only owned payload is a validated model on both sides of YAML.""" diff --git a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_01.py b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_01.py index 943be14ea..381e00ce6 100644 --- a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_01.py +++ b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_01.py @@ -2,19 +2,14 @@ from __future__ import annotations - -from flext_tests import tm -from tests import c -from tests import m - -from flext_cli import cli - # NOTE (multi-agent, mro-wkii.19.4): app creation owns the settings singleton. # mro-wkii.17.26 (codex): exercise CLI flows through the public invocation facade. - from collections.abc import MutableSequence -from tests import p, t +from flext_tests import tm +from tests import c, m, p, t + +from flext_cli import cli class TestsFlextCliService: diff --git a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_02.py b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_02.py index 88dc30d8c..2534cbcb6 100644 --- a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_02.py +++ b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_02.py @@ -2,19 +2,14 @@ from __future__ import annotations - -from flext_tests import tm -from tests import c -from tests import m - -from flext_cli import cli - # NOTE (multi-agent, mro-wkii.19.4): app creation owns the settings singleton. # mro-wkii.17.26 (codex): exercise CLI flows through the public invocation facade. - from collections.abc import MutableSequence -from tests import p, t +from flext_tests import tm +from tests import c, m, p, t + +from flext_cli import cli class TestsFlextCliService: diff --git a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_03.py b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_03.py index 1a4d6f922..e847158de 100644 --- a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_03.py +++ b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_03.py @@ -3,8 +3,7 @@ from __future__ import annotations from flext_tests import tm -from tests import c -from tests import m +from tests import c, m from flext_cli import cli, settings diff --git a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_04.py b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_04.py index db0134868..ccc71fd6a 100644 --- a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_04.py +++ b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_04.py @@ -2,15 +2,12 @@ from __future__ import annotations - from flext_tests import tm -from tests import m - -from flext_cli import cli # NOTE (multi-agent, mro-wkii.19.4): app creation owns the settings singleton. +from tests import m, p, t -from tests import p, t +from flext_cli import cli class TestsFlextCliService: diff --git a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_05.py b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_05.py index 69ad769f2..98c6cbce7 100644 --- a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_05.py +++ b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_05.py @@ -2,17 +2,13 @@ from __future__ import annotations - from flext_tests import tm -from tests import c -from tests import m - -from flext_cli import cli, r # NOTE (multi-agent, mro-wkii.19.4): app creation owns the settings singleton. # mro-wkii.17.26 (codex): exercise CLI flows through the public invocation facade. +from tests import c, m, p -from tests import p +from flext_cli import cli, r class TestsFlextCliService: diff --git a/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_01.py b/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_01.py index b23ac6650..2480ea597 100644 --- a/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_01.py +++ b/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_01.py @@ -2,6 +2,7 @@ from __future__ import annotations +from pathlib import Path from examples import ExamplesFlextCliGettingStarted from examples.ex_02_output_formatting import export_report @@ -17,9 +18,6 @@ from flext_cli import cli -from pathlib import Path - - # NOTE (multi-agent, mro-wkii.17 / agent: make_ssot_audit): file fixtures are # validated models, serialized once at egress and validated once at ingress. diff --git a/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_02.py b/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_02.py index aa60626b5..aa6be5fe0 100644 --- a/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_02.py +++ b/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_02.py @@ -2,7 +2,8 @@ from __future__ import annotations -from collections.abc import Mapping +from collections.abc import Iterator, Mapping +from pathlib import Path import pytest from examples import Ex05Authentication, Ex06Settings, c as ec, p as ep @@ -13,12 +14,9 @@ validate_and_import_data, ) from flext_tests import tm - -from flext_cli import cli, settings from tests import c -from collections.abc import Iterator -from pathlib import Path +from flext_cli import cli, settings class TestsFlextCliExamplesSmoke: diff --git a/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_03.py b/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_03.py index d275e64bf..4c7704aa9 100644 --- a/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_03.py +++ b/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_03.py @@ -2,6 +2,7 @@ from __future__ import annotations +from collections.abc import Iterator from pathlib import Path import pytest @@ -10,8 +11,6 @@ from flext_cli import cli, settings -from collections.abc import Iterator - class TestsFlextCliExamplesSmoke: """Implementation part for TestsFlextCliExamplesSmoke.""" diff --git a/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_04.py b/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_04.py index 977ee39c0..72464df43 100644 --- a/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_04.py +++ b/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_04.py @@ -2,17 +2,15 @@ from __future__ import annotations +from pathlib import Path from unittest.mock import patch from examples import DataManagerCLI from flext_tests import r, tm +from tests import p from flext_cli import cli -from pathlib import Path - -from tests import p - class TestsFlextCliExamplesSmoke: """Implementation part for TestsFlextCliExamplesSmoke.""" diff --git a/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_01.py b/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_01.py index 1fdc034bb..458da07be 100644 --- a/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_01.py +++ b/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_01.py @@ -2,19 +2,14 @@ from __future__ import annotations +from pathlib import Path import pytest from flext_tests import tm -from tests import c -from tests import m -from tests import u +from tests import c, m, t, u from flext_cli import cli -from pathlib import Path - -from tests import t - class TestsFlextCliFilesCov: """Implementation part for TestsFlextCliFilesCov.""" diff --git a/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_02.py b/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_02.py index 487cef0c2..a0f4054fb 100644 --- a/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_02.py +++ b/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_02.py @@ -2,14 +2,13 @@ from __future__ import annotations +from pathlib import Path from flext_tests import tm from tests import u from flext_cli import cli -from pathlib import Path - class TestsFlextCliFilesCov: """Implementation part for TestsFlextCliFilesCov.""" diff --git a/tests/unit/_cases/test_json_cov/testsflextclijsoncov_part_01.py b/tests/unit/_cases/test_json_cov/testsflextclijsoncov_part_01.py index b35fe2123..20c4374cd 100644 --- a/tests/unit/_cases/test_json_cov/testsflextclijsoncov_part_01.py +++ b/tests/unit/_cases/test_json_cov/testsflextclijsoncov_part_01.py @@ -2,13 +2,10 @@ from __future__ import annotations +from pathlib import Path -from tests import m -from tests import t -from tests import u from flext_tests import tm - -from pathlib import Path +from tests import m, t, u class TestsFlextCliJsonCov: diff --git a/tests/unit/_cases/test_json_cov/testsflextclijsoncov_part_02.py b/tests/unit/_cases/test_json_cov/testsflextclijsoncov_part_02.py index 03b55b2eb..7c3401d06 100644 --- a/tests/unit/_cases/test_json_cov/testsflextclijsoncov_part_02.py +++ b/tests/unit/_cases/test_json_cov/testsflextclijsoncov_part_02.py @@ -2,8 +2,8 @@ from __future__ import annotations -from tests import u from flext_tests import tm +from tests import u class TestsFlextCliJsonCov: diff --git a/tests/unit/_cases/test_output_cov/testsflextclioutputcov_part_01.py b/tests/unit/_cases/test_output_cov/testsflextclioutputcov_part_01.py index ae5708fee..73bf0df8b 100644 --- a/tests/unit/_cases/test_output_cov/testsflextclioutputcov_part_01.py +++ b/tests/unit/_cases/test_output_cov/testsflextclioutputcov_part_01.py @@ -3,9 +3,8 @@ from __future__ import annotations import pytest -from tests import c -from tests import u from flext_tests import tm +from tests import c, u class TestsFlextCliOutputCov: diff --git a/tests/unit/_cases/test_output_cov/testsflextclioutputcov_part_02.py b/tests/unit/_cases/test_output_cov/testsflextclioutputcov_part_02.py index 0d2e2ec72..aa6ac86d2 100644 --- a/tests/unit/_cases/test_output_cov/testsflextclioutputcov_part_02.py +++ b/tests/unit/_cases/test_output_cov/testsflextclioutputcov_part_02.py @@ -4,11 +4,9 @@ from pathlib import Path -from tests import c -from tests import u -from flext_tests import tm - import pytest +from flext_tests import tm +from tests import c, u class TestsFlextCliOutputCov: diff --git a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_01.py b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_01.py index 4c4eb0a30..fca84f289 100644 --- a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_01.py +++ b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_01.py @@ -2,16 +2,12 @@ from __future__ import annotations +from pathlib import Path -from tests import c - -from flext_cli import cli, r from flext_tests import tm +from tests import c, p, t -from pathlib import Path - -from tests import p -from tests import t +from flext_cli import cli, r class TestsFlextCliPipeline: diff --git a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_02.py b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_02.py index 92aaf43ff..5ce3d5498 100644 --- a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_02.py +++ b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_02.py @@ -2,16 +2,12 @@ from __future__ import annotations +from pathlib import Path -from tests import c - -from flext_cli import cli, r from flext_tests import tm +from tests import c, p, t -from pathlib import Path - -from tests import p -from tests import t +from flext_cli import cli, r class TestsFlextCliPipeline: diff --git a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_03.py b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_03.py index 59cc9784f..7fb4862f9 100644 --- a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_03.py +++ b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_03.py @@ -2,15 +2,12 @@ from __future__ import annotations - -from flext_cli import cli -from flext_tests import tm - from pathlib import Path -from tests import p -from tests import t +from flext_tests import tm +from tests import p, t +from flext_cli import cli # ── Fixtures ──────────────────────────────────────────────────────── diff --git a/tests/unit/_cases/test_prompts/testsflextcliprompts_part_01.py b/tests/unit/_cases/test_prompts/testsflextcliprompts_part_01.py index 5851656d5..08e70237d 100644 --- a/tests/unit/_cases/test_prompts/testsflextcliprompts_part_01.py +++ b/tests/unit/_cases/test_prompts/testsflextcliprompts_part_01.py @@ -2,14 +2,11 @@ from __future__ import annotations +from collections.abc import Callable import pytest from flext_tests import tm -from tests import c - -from collections.abc import Callable - -from tests import p +from tests import c, p class TestsFlextCliPrompts: diff --git a/tests/unit/_cases/test_prompts/testsflextcliprompts_part_02.py b/tests/unit/_cases/test_prompts/testsflextcliprompts_part_02.py index 60c688f98..bc794f1ed 100644 --- a/tests/unit/_cases/test_prompts/testsflextcliprompts_part_02.py +++ b/tests/unit/_cases/test_prompts/testsflextcliprompts_part_02.py @@ -3,14 +3,11 @@ from __future__ import annotations import time +from collections.abc import Callable import pytest from flext_tests import tm -from tests import c - -from collections.abc import Callable - -from tests import p +from tests import c, p class TestsFlextCliPrompts: diff --git a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_01.py b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_01.py index 8ba25c958..feb1f4d40 100644 --- a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_01.py +++ b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_01.py @@ -4,12 +4,10 @@ import inspect -from tests import c -from tests import p -from tests import u +from flext_tests import tm +from tests import c, p, u from flext_cli import FlextCliSettings, cli, m, settings -from flext_tests import tm class TestsFlextCliPublicContractsCoverage: diff --git a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_02.py b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_02.py index c9c749384..8a905dca9 100644 --- a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_02.py +++ b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_02.py @@ -2,16 +2,12 @@ from __future__ import annotations +from pathlib import Path -from tests import c -from tests import m - -from flext_cli import r from flext_tests import tm +from tests import c, m, p -from pathlib import Path - -from tests import p +from flext_cli import r class TestsFlextCliPublicContractsCoverage: diff --git a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_03.py b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_03.py index 41228e223..2fa3652fb 100644 --- a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_03.py +++ b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_03.py @@ -2,14 +2,12 @@ from __future__ import annotations +from pathlib import Path -from tests import c -from tests import p - -from flext_cli import cli, m, r from flext_tests import tm +from tests import c, p -from pathlib import Path +from flext_cli import cli, m, r class TestsFlextCliPublicContractsCoverage: diff --git a/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_01.py b/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_01.py index 87ee4cea0..ff683bdff 100644 --- a/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_01.py +++ b/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_01.py @@ -6,8 +6,8 @@ from pathlib import Path import pytest -from tests import c, t, u from flext_tests import tm +from tests import c, t, u class TestsFlextCliRulesCov: diff --git a/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_02.py b/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_02.py index 248b2b2c3..523a46c6e 100644 --- a/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_02.py +++ b/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_02.py @@ -5,9 +5,8 @@ import tempfile from pathlib import Path -from tests import c -from tests import u from flext_tests import tm +from tests import c, u class TestsFlextCliRulesCov: diff --git a/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_03.py b/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_03.py index 78fec93e0..d78c3d131 100644 --- a/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_03.py +++ b/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_03.py @@ -6,11 +6,8 @@ from pathlib import Path import pytest -from tests import c -from tests import u from flext_tests import tm - -from tests import t +from tests import c, t, u class TestsFlextCliRulesCov: diff --git a/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_04.py b/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_04.py index 2f8d486f4..aed3c76ca 100644 --- a/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_04.py +++ b/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_04.py @@ -2,12 +2,8 @@ from __future__ import annotations - -from tests import c -from tests import u from flext_tests import tm - -from tests import t +from tests import c, t, u class TestsFlextCliRulesCov: diff --git a/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_01.py b/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_01.py index aaf423569..57a54ec3f 100644 --- a/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_01.py +++ b/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_01.py @@ -4,15 +4,12 @@ import os import stat +from collections.abc import Generator from contextlib import contextmanager from pathlib import Path from flext_tests import tm -from tests import u - -from collections.abc import Generator - -from tests import t +from tests import t, u class TestsFlextCliTomlUtilities: diff --git a/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_02.py b/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_02.py index cd4464d30..0297bc4c2 100644 --- a/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_02.py +++ b/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_02.py @@ -2,11 +2,8 @@ from __future__ import annotations - from flext_tests import tm -from tests import u - -from tests import t +from tests import t, u class TestsFlextCliTomlUtilities: diff --git a/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_03.py b/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_03.py index 7c1256e69..880676bb7 100644 --- a/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_03.py +++ b/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_03.py @@ -3,13 +3,10 @@ from __future__ import annotations import tomllib - -from flext_tests import tm -from tests import u - from pathlib import Path -from tests import t +from flext_tests import tm +from tests import t, u class TestsFlextCliTomlUtilities: diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py index 3c2dbcb3e..21676144e 100644 --- a/tests/unit/conftest.py +++ b/tests/unit/conftest.py @@ -2,17 +2,14 @@ from __future__ import annotations +from collections.abc import Callable from typing import Self, override import pytest from flext_cli import FlextCliSettings from flext_cli.services.prompts import FlextCliPrompts -from tests import m - -from collections.abc import Callable - -from tests import t +from tests import m, t class TestsFlextCliScriptedPrompts(FlextCliPrompts): diff --git a/tests/unit/test_auth_utils_cov.py b/tests/unit/test_auth_utils_cov.py index 423362710..fc0726318 100644 --- a/tests/unit/test_auth_utils_cov.py +++ b/tests/unit/test_auth_utils_cov.py @@ -17,12 +17,9 @@ from pathlib import Path import pytest - -from tests import c -from tests import u from flext_tests import tm -from tests import t +from tests import c, t, u class TestsFlextCliAuthUtilsCov: diff --git a/tests/unit/test_base.py b/tests/unit/test_base.py index 90fccb8c2..e8045ad2b 100644 --- a/tests/unit/test_base.py +++ b/tests/unit/test_base.py @@ -22,8 +22,8 @@ from pydantic import BaseModel from flext_cli import FlextCli, cli, settings -from tests.base import s from tests import p +from tests.base import s class TestsFlextCliBase: diff --git a/tests/unit/test_cli_params.py b/tests/unit/test_cli_params.py index 23d70cdac..736bc54ec 100644 --- a/tests/unit/test_cli_params.py +++ b/tests/unit/test_cli_params.py @@ -14,9 +14,7 @@ from flext_tests import tm from flext_cli import cli -from tests import c -from tests import p -from tests import u +from tests import c, p, u class TestsFlextCliCliParams: diff --git a/tests/unit/test_cmd.py b/tests/unit/test_cmd.py index 5a54f6346..1db81cf3d 100644 --- a/tests/unit/test_cmd.py +++ b/tests/unit/test_cmd.py @@ -18,15 +18,13 @@ from __future__ import annotations from datetime import datetime +from pathlib import Path import pytest from flext_tests import tm from flext_cli import cli, m -from tests import c -from tests import p - -from pathlib import Path +from tests import c, p class TestsFlextCliCmd: diff --git a/tests/unit/test_cmd_cov.py b/tests/unit/test_cmd_cov.py index dd1fd3297..bbeef8fa6 100644 --- a/tests/unit/test_cmd_cov.py +++ b/tests/unit/test_cmd_cov.py @@ -10,7 +10,9 @@ from __future__ import annotations import os +from collections.abc import Generator from contextlib import contextmanager +from pathlib import Path import pytest from flext_tests import tm @@ -18,9 +20,6 @@ from flext_cli import cli from tests import c -from collections.abc import Generator -from pathlib import Path - class TestsFlextCliCmdCov: """Contract tests for the settings commands exposed on ``FlextCli``.""" diff --git a/tests/unit/test_cmd_runtime_validation_branch_cov.py b/tests/unit/test_cmd_runtime_validation_branch_cov.py index 7d528703a..1b8ddd058 100644 --- a/tests/unit/test_cmd_runtime_validation_branch_cov.py +++ b/tests/unit/test_cmd_runtime_validation_branch_cov.py @@ -11,13 +11,10 @@ from collections.abc import Callable import pytest - -from tests import c -from tests import m -from tests import t -from tests import u from flext_tests import tm +from tests import c, m, t, u + type MappingProcessor = Callable[[str, int], int] diff --git a/tests/unit/test_commands_utils_cov.py b/tests/unit/test_commands_utils_cov.py index 872684aa2..44a221618 100644 --- a/tests/unit/test_commands_utils_cov.py +++ b/tests/unit/test_commands_utils_cov.py @@ -16,12 +16,10 @@ from __future__ import annotations import pytest +from flext_tests import tm from flext_cli import r -from flext_tests import tm -from tests import c -from tests import t -from tests import u +from tests import c, t, u class TestsFlextCliCommands: diff --git a/tests/unit/test_config_engine.py b/tests/unit/test_config_engine.py index cdec02ebd..5941855d8 100644 --- a/tests/unit/test_config_engine.py +++ b/tests/unit/test_config_engine.py @@ -10,11 +10,10 @@ import os from pathlib import Path -from tests import c -from tests import m -from tests import u from flext_tests import tm +from tests import c, m, u + class TestsFlextCliConfigEngine: """Group the TestsFlextCliConfigEngine test behavior.""" diff --git a/tests/unit/test_constants.py b/tests/unit/test_constants.py index fe51e44a3..bce5dfa80 100644 --- a/tests/unit/test_constants.py +++ b/tests/unit/test_constants.py @@ -21,8 +21,7 @@ import pytest from flext_tests import tm -from tests import c -from tests import u +from tests import c, u class TestsFlextCliConstants: diff --git a/tests/unit/test_conversion_cov.py b/tests/unit/test_conversion_cov.py index f771c0590..8b2f64eac 100644 --- a/tests/unit/test_conversion_cov.py +++ b/tests/unit/test_conversion_cov.py @@ -7,11 +7,7 @@ import pytest from flext_tests import tm -from tests import c -from tests import m -from tests import u - -from tests import t +from tests import c, m, t, u class TestsFlextCliConversion: diff --git a/tests/unit/test_examples_models_utilities_cov.py b/tests/unit/test_examples_models_utilities_cov.py index f5b9ee672..6b400c18c 100644 --- a/tests/unit/test_examples_models_utilities_cov.py +++ b/tests/unit/test_examples_models_utilities_cov.py @@ -18,9 +18,8 @@ import pytest from flext_tests import tm -from tests import c as tc - from flext_cli import cli +from tests import c as tc _PROJECT_ROOT = Path(__file__).resolve().parents[2] if str(_PROJECT_ROOT) not in sys.path: diff --git a/tests/unit/test_file_tools_yaml.py b/tests/unit/test_file_tools_yaml.py index 8a7591457..f268d6bf6 100644 --- a/tests/unit/test_file_tools_yaml.py +++ b/tests/unit/test_file_tools_yaml.py @@ -2,13 +2,13 @@ from __future__ import annotations +from pathlib import Path + from flext_tests import tm from flext_cli import cli from tests import m -from pathlib import Path - class TestsFlextCliYamlModelLoading: """Observable contracts for model-first YAML file ingress.""" diff --git a/tests/unit/test_files_cov.py b/tests/unit/test_files_cov.py index 926196702..ec85949e3 100644 --- a/tests/unit/test_files_cov.py +++ b/tests/unit/test_files_cov.py @@ -9,18 +9,13 @@ from __future__ import annotations +from pathlib import Path import pytest from flext_tests import tm from flext_cli import cli -from tests import c -from tests import m -from tests import u - -from pathlib import Path - -from tests import t +from tests import c, m, t, u class TestsFlextCliFilesCov: diff --git a/tests/unit/test_formatters_cov.py b/tests/unit/test_formatters_cov.py index aca91a2ce..2d0205d06 100644 --- a/tests/unit/test_formatters_cov.py +++ b/tests/unit/test_formatters_cov.py @@ -13,14 +13,11 @@ from __future__ import annotations - import pytest - -from flext_cli import cli -from tests import c from flext_tests import tm -from tests import t +from flext_cli import cli +from tests import c, t class TestsFlextCliFormattersCov: diff --git a/tests/unit/test_json_cov.py b/tests/unit/test_json_cov.py index a70551cb7..99bd67200 100644 --- a/tests/unit/test_json_cov.py +++ b/tests/unit/test_json_cov.py @@ -2,15 +2,12 @@ from __future__ import annotations +from pathlib import Path import pytest - -from tests import m -from tests import t -from tests import u from flext_tests import tm -from pathlib import Path +from tests import m, t, u class TestsFlextCliJsonCov: diff --git a/tests/unit/test_matching_cov.py b/tests/unit/test_matching_cov.py index 4e59db0b0..a0d40468d 100644 --- a/tests/unit/test_matching_cov.py +++ b/tests/unit/test_matching_cov.py @@ -12,14 +12,10 @@ from __future__ import annotations - import pytest - -from tests import c -from tests import u from flext_tests import tm -from tests import t +from tests import c, t, u class TestsFlextCliMatchingCov: diff --git a/tests/unit/test_model_commands_cov.py b/tests/unit/test_model_commands_cov.py index b03d49900..f067f2d0b 100644 --- a/tests/unit/test_model_commands_cov.py +++ b/tests/unit/test_model_commands_cov.py @@ -10,10 +10,10 @@ from __future__ import annotations import pytest +from flext_tests import tm from flext_cli import cli from tests import m -from flext_tests import tm # NOTE (multi-agent, mro-wkii.17 / agent: make_ssot_audit): model-command # coverage consumes the owning field-only test models directly. diff --git a/tests/unit/test_options_cov.py b/tests/unit/test_options_cov.py index 93231f179..53239e632 100644 --- a/tests/unit/test_options_cov.py +++ b/tests/unit/test_options_cov.py @@ -20,12 +20,10 @@ from typing import Annotated, ClassVar import pytest +from flext_tests import tm from flext_cli import cli, m -from tests import c -from tests import t -from tests import u -from flext_tests import tm +from tests import c, t, u class TestsFlextCliOptionsUtilsCov: diff --git a/tests/unit/test_options_public_cov.py b/tests/unit/test_options_public_cov.py index 044eb6f71..e38d927b9 100644 --- a/tests/unit/test_options_public_cov.py +++ b/tests/unit/test_options_public_cov.py @@ -11,11 +11,10 @@ from pathlib import Path import pytest +from flext_tests import tm from flext_cli import c, m -from tests import t -from tests import u -from flext_tests import tm +from tests import t, u class TestsFlextCliOptions: diff --git a/tests/unit/test_output_cov.py b/tests/unit/test_output_cov.py index 67bf1e07d..84cbc469e 100644 --- a/tests/unit/test_output_cov.py +++ b/tests/unit/test_output_cov.py @@ -5,11 +5,10 @@ from pathlib import Path import pytest - -from tests import c -from tests import u from flext_tests import tm +from tests import c, u + class TestsFlextCliOutputCov: """Contract of the pure builders and stdout emitters exposed via ``u.Cli``.""" diff --git a/tests/unit/test_params_branch_cov.py b/tests/unit/test_params_branch_cov.py index d8121ec4e..897c1e258 100644 --- a/tests/unit/test_params_branch_cov.py +++ b/tests/unit/test_params_branch_cov.py @@ -8,10 +8,10 @@ from __future__ import annotations import pytest +from flext_tests import tm from flext_cli import FlextCliSettings, c, m, p, u from tests import c as tc -from flext_tests import tm class TestsFlextCliParams: diff --git a/tests/unit/test_prompts_cov.py b/tests/unit/test_prompts_cov.py index ade9d6c62..9cdbec251 100644 --- a/tests/unit/test_prompts_cov.py +++ b/tests/unit/test_prompts_cov.py @@ -8,15 +8,12 @@ from __future__ import annotations +from collections.abc import Callable import pytest from flext_tests import tm -from tests import c - -from collections.abc import Callable - -from tests import p +from tests import c, p class TestsFlextCliPromptsCov: diff --git a/tests/unit/test_protocols.py b/tests/unit/test_protocols.py index 08080863a..b4aa041b1 100644 --- a/tests/unit/test_protocols.py +++ b/tests/unit/test_protocols.py @@ -19,10 +19,10 @@ from pathlib import Path import pytest +from flext_tests import tm from flext_cli import t from tests import p, u -from flext_tests import tm class _ConformingSummary: diff --git a/tests/unit/test_rules_cov.py b/tests/unit/test_rules_cov.py index 391b93d96..e5b58fcb4 100644 --- a/tests/unit/test_rules_cov.py +++ b/tests/unit/test_rules_cov.py @@ -9,16 +9,12 @@ from __future__ import annotations +from pathlib import Path import pytest - -from tests import c -from tests import u from flext_tests import tm -from pathlib import Path - -from tests import t +from tests import c, t, u class TestsFlextCliRulesCov: diff --git a/tests/unit/test_runtime_utilities_core.py b/tests/unit/test_runtime_utilities_core.py index 1e29b2531..4c4741f5f 100644 --- a/tests/unit/test_runtime_utilities_core.py +++ b/tests/unit/test_runtime_utilities_core.py @@ -3,16 +3,12 @@ from __future__ import annotations import sys +from pathlib import Path import pytest from flext_tests import tm -from tests import m -from tests import u - -from pathlib import Path - -from tests import p +from tests import m, p, u class TestsFlextCliRuntimeUtilitiesCore: diff --git a/tests/unit/test_runtime_utilities_extra.py b/tests/unit/test_runtime_utilities_extra.py index d8ac5fe11..0596232ce 100644 --- a/tests/unit/test_runtime_utilities_extra.py +++ b/tests/unit/test_runtime_utilities_extra.py @@ -7,14 +7,12 @@ from __future__ import annotations +from pathlib import Path import pytest from flext_tests import tm -from tests import m -from tests import u - -from pathlib import Path +from tests import m, u class TestsFlextCliRuntimeUtilitiesExtra: diff --git a/tests/unit/test_services_auth_branch_cov.py b/tests/unit/test_services_auth_branch_cov.py index 56c7d4b50..773c13ed1 100644 --- a/tests/unit/test_services_auth_branch_cov.py +++ b/tests/unit/test_services_auth_branch_cov.py @@ -9,6 +9,8 @@ from __future__ import annotations +from collections.abc import Iterator +from pathlib import Path import pytest from flext_tests import tm @@ -16,9 +18,6 @@ from flext_cli import FlextCli, cli, settings from tests import c -from collections.abc import Iterator -from pathlib import Path - class TestsFlextCliServicesAuth: """Public authentication behavior of the FlextCli facade.""" diff --git a/tests/unit/test_services_auth_cov.py b/tests/unit/test_services_auth_cov.py index 8160430ef..91bd49234 100644 --- a/tests/unit/test_services_auth_cov.py +++ b/tests/unit/test_services_auth_cov.py @@ -12,18 +12,15 @@ from __future__ import annotations +from collections.abc import Iterator +from pathlib import Path import pytest +from flext_tests import tm from flext_cli import settings from flext_cli.services.auth import FlextCliAuth -from tests import c -from flext_tests import tm - -from collections.abc import Iterator -from pathlib import Path - -from tests import p +from tests import c, p class TestsFlextCliServicesAuthCov: diff --git a/tests/unit/test_services_output_cov.py b/tests/unit/test_services_output_cov.py index 4eb518122..01cdaff89 100644 --- a/tests/unit/test_services_output_cov.py +++ b/tests/unit/test_services_output_cov.py @@ -14,10 +14,10 @@ from __future__ import annotations import pytest +from flext_tests import tm from flext_cli import cli from tests import c -from flext_tests import tm type Capture = pytest.CaptureFixture[str] diff --git a/tests/unit/test_services_tables_branch_cov.py b/tests/unit/test_services_tables_branch_cov.py index d80fc7be2..9c061f8a6 100644 --- a/tests/unit/test_services_tables_branch_cov.py +++ b/tests/unit/test_services_tables_branch_cov.py @@ -7,14 +7,11 @@ from __future__ import annotations - import pytest - -from flext_cli import cli, m -from tests import c from flext_tests import tm -from flext_cli import t +from flext_cli import cli, m, t +from tests import c class TestsFlextCliServicesTablesBranchCov: diff --git a/tests/unit/test_services_tables_cov.py b/tests/unit/test_services_tables_cov.py index f16665c90..69e9b13bd 100644 --- a/tests/unit/test_services_tables_cov.py +++ b/tests/unit/test_services_tables_cov.py @@ -12,9 +12,9 @@ from __future__ import annotations import pytest +from flext_tests import tm from flext_cli import c, cli, m, t -from flext_tests import tm class TestsFlextCliServicesTablesCov: diff --git a/tests/unit/test_settings.py b/tests/unit/test_settings.py index e183f3ab0..ad7a67d5f 100644 --- a/tests/unit/test_settings.py +++ b/tests/unit/test_settings.py @@ -19,8 +19,7 @@ from flext_tests import tm from flext_cli import FlextCliSettings, settings, t, u -from tests import c -from tests import p +from tests import c, p class TestsFlextCliSettingsUnit: diff --git a/tests/unit/test_tables.py b/tests/unit/test_tables.py index 0c813c950..e4503dc7e 100644 --- a/tests/unit/test_tables.py +++ b/tests/unit/test_tables.py @@ -8,15 +8,12 @@ from __future__ import annotations - import pytest from flext_tests import tm -from flext_cli import cli +from flext_cli import cli, t from tests import c -from flext_cli import t - class TestsFlextCliTables: """Regression coverage for the public table helpers.""" diff --git a/tests/unit/test_tables_branch_cov.py b/tests/unit/test_tables_branch_cov.py index 252dc5bbc..1ded2542f 100644 --- a/tests/unit/test_tables_branch_cov.py +++ b/tests/unit/test_tables_branch_cov.py @@ -3,13 +3,10 @@ from __future__ import annotations import pytest - -from tests import c -from tests import m -from tests import p, t -from tests import u from flext_tests import tm +from tests import c, m, p, t, u + class TestsFlextCliTablesBranchCov: """Assert the observable contract of the ``u.Cli`` table helpers.""" diff --git a/tests/unit/test_tables_cov.py b/tests/unit/test_tables_cov.py index 2e97c65ef..bba9efdca 100644 --- a/tests/unit/test_tables_cov.py +++ b/tests/unit/test_tables_cov.py @@ -10,15 +10,10 @@ from __future__ import annotations - import pytest - -from tests import c -from tests import m -from tests import u from flext_tests import tm -from tests import t +from tests import c, m, t, u class TestsFlextCliTables: diff --git a/tests/unit/test_toml_sync_cov.py b/tests/unit/test_toml_sync_cov.py index efc737ed4..b7cf52bec 100644 --- a/tests/unit/test_toml_sync_cov.py +++ b/tests/unit/test_toml_sync_cov.py @@ -15,15 +15,11 @@ from __future__ import annotations - import pytest - -from tests import u from flext_tests import tm - from tomlkit.items import Table -from tests import t +from tests import t, u class TestsFlextCliTomlSyncCoverage: diff --git a/tests/unit/test_toml_utilities.py b/tests/unit/test_toml_utilities.py index 67416047f..a0c2833a4 100644 --- a/tests/unit/test_toml_utilities.py +++ b/tests/unit/test_toml_utilities.py @@ -16,9 +16,7 @@ import pytest from flext_tests import tm -from tests import u - -from tests import t +from tests import t, u class TestsFlextCliTomlUtilities: diff --git a/tests/unit/test_typings.py b/tests/unit/test_typings.py index c4fc83eb2..e451b245f 100644 --- a/tests/unit/test_typings.py +++ b/tests/unit/test_typings.py @@ -11,14 +11,12 @@ from __future__ import annotations from collections.abc import Sequence +from pathlib import Path import pytest from flext_tests import tm -from tests import m -from tests import p, t - -from pathlib import Path +from tests import m, p, t class TestsFlextCliTypings: diff --git a/tests/unit/test_utilities_cov.py b/tests/unit/test_utilities_cov.py index dc057da6a..cffcffa83 100644 --- a/tests/unit/test_utilities_cov.py +++ b/tests/unit/test_utilities_cov.py @@ -13,8 +13,7 @@ import pytest from flext_tests import tm -from tests import t -from tests import u +from tests import t, u def _raise_on_zero(value: int) -> int: diff --git a/tests/unit/test_yaml_cov.py b/tests/unit/test_yaml_cov.py index 228b4776e..e9e0b6e7c 100644 --- a/tests/unit/test_yaml_cov.py +++ b/tests/unit/test_yaml_cov.py @@ -14,17 +14,12 @@ from __future__ import annotations +from pathlib import Path import pytest - -from tests import c -from tests import m -from tests import u from flext_tests import tm -from pathlib import Path - -from tests import t +from tests import c, m, t, u class TestsFlextCliYamlCov: diff --git a/tests/unit/test_yaml_roundtrip.py b/tests/unit/test_yaml_roundtrip.py index 8073e0b02..92393fedf 100644 --- a/tests/unit/test_yaml_roundtrip.py +++ b/tests/unit/test_yaml_roundtrip.py @@ -10,15 +10,13 @@ from __future__ import annotations from concurrent.futures import ThreadPoolExecutor +from pathlib import Path import pytest -from ruamel.yaml.comments import CommentedMap, CommentedSeq - -from tests import t -from tests import u from flext_tests import tm +from ruamel.yaml.comments import CommentedMap, CommentedSeq -from pathlib import Path +from tests import t, u class TestsFlextCliYamlRoundtripLoad: diff --git a/tests/utilities.py b/tests/utilities.py index c975751d6..bb168c057 100644 --- a/tests/utilities.py +++ b/tests/utilities.py @@ -15,8 +15,7 @@ from flext_tests import FlextTestsUtilities, r from flext_cli import cli, u -from tests import c -from tests import p +from tests import c, p from tests.settings import TestsFlextCliSettings From c5cd8eac29c7e7329522a41d5266ca2873ac1884 Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Fri, 17 Jul 2026 08:45:34 -0300 Subject: [PATCH 28/37] refactor fixes --- src/flext_cli/_config.py | 6 ++++-- src/flext_cli/_constants/base.py | 6 ++++-- src/flext_cli/_constants/files.py | 6 ++++-- src/flext_cli/_constants/pipeline.py | 6 ++++-- .../_models/_base/flextclimodelsbase_part_05.py | 6 ++++-- .../_models/_base/flextclimodelsbase_part_06.py | 6 ++++-- src/flext_cli/_models/_xlx/xlsx_archive.py | 6 ++++-- src/flext_cli/_models/_xlx/xlsx_cells.py | 10 ++++++---- src/flext_cli/_models/_xlx/xlsx_layout.py | 6 ++++-- src/flext_cli/_models/_xlx/xlsx_rules.py | 8 +++++--- src/flext_cli/_models/_xlx/xlsx_snapshot.py | 6 ++++-- src/flext_cli/_models/_xlx/xlsx_style_catalog.py | 6 ++++-- src/flext_cli/_models/_xlx/xlsx_style_fills.py | 6 ++++-- src/flext_cli/_models/_xlx/xlsx_tables.py | 6 ++++-- src/flext_cli/_models/_xlx/xlsx_validation.py | 6 ++++-- src/flext_cli/_models/_xlx/xlsx_workbook.py | 14 ++++++++------ src/flext_cli/_models/pipeline.py | 8 +++++--- src/flext_cli/_models/rules.py | 6 ++++-- src/flext_cli/_models/template.py | 6 ++++-- src/flext_cli/_models/toml.py | 6 ++++-- .../_base/flextcliprotocolsbase_part_03.py | 8 +++++--- .../_base/flextcliprotocolsbase_part_05.py | 6 ++++-- src/flext_cli/_protocols/_xlx/xlsx_archive.py | 6 ++++-- src/flext_cli/_protocols/_xlx/xlsx_snapshot.py | 6 ++++-- src/flext_cli/_protocols/_xlx/xlsx_workbook.py | 11 ++++++----- src/flext_cli/_protocols/domain.py | 8 +++++--- src/flext_cli/_protocols/framework.py | 6 ++++-- src/flext_cli/_protocols/pipeline.py | 12 +++++++----- src/flext_cli/_protocols/toml.py | 10 ++++++---- src/flext_cli/_protocols/xlsx.py | 8 +++++--- src/flext_cli/_typings/domain.py | 2 +- ...lextcliutilitiesfiletesthelpersmixin_part_02.py | 5 ++++- ...lextcliutilitiesfiletesthelpersmixin_part_03.py | 5 ++++- ...lextcliutilitiesfiletesthelpersmixin_part_04.py | 5 ++++- src/flext_cli/_utilities/_json/_core.py | 6 ++++-- src/flext_cli/_utilities/_json/_navigate.py | 5 ++++- src/flext_cli/_utilities/_rules/_loaders.py | 5 ++++- src/flext_cli/_utilities/_rules/_matchers.py | 7 +++++-- .../_toml/flextcliutilitiestoml_part_02.py | 6 ++++-- .../_toml/flextcliutilitiestoml_part_03.py | 7 +++++-- .../_toml/flextcliutilitiestoml_part_04.py | 9 ++++++--- .../_toml/flextcliutilitiestoml_part_05.py | 5 ++++- .../_toml/flextcliutilitiestoml_part_06.py | 5 ++++- .../_toml/flextcliutilitiestoml_part_07.py | 5 ++++- src/flext_cli/_utilities/_xlxx/xlsx_cells.py | 5 ++++- src/flext_cli/_utilities/_xlxx/xlsx_conditional.py | 5 ++++- src/flext_cli/_utilities/_xlxx/xlsx_layout.py | 5 ++++- src/flext_cli/_utilities/_xlxx/xlsx_protection.py | 5 ++++- src/flext_cli/_utilities/_xlxx/xlsx_renderer.py | 5 ++++- src/flext_cli/_utilities/_xlxx/xlsx_rules.py | 5 ++++- .../_utilities/_xlxx/xlsx_snapshot_sheet.py | 6 ++++-- .../_utilities/_xlxx/xlsx_snapshot_structure.py | 7 +++++-- .../_utilities/_xlxx/xlsx_snapshot_values.py | 5 ++++- .../_utilities/_xlxx/xlsx_style_builders.py | 5 ++++- .../_utilities/_xlxx/xlsx_style_readers.py | 7 +++++-- src/flext_cli/_utilities/_xlxx/xlsx_tables.py | 7 +++++-- src/flext_cli/_utilities/_xlxx/xlsx_validations.py | 5 ++++- src/flext_cli/_utilities/_yaml/_convert.py | 13 +++++++++++-- src/flext_cli/_utilities/_yaml/_editing.py | 6 ++++-- src/flext_cli/_utilities/_yaml/_engine.py | 6 ++++-- src/flext_cli/_utilities/config.py | 5 ++++- src/flext_cli/_utilities/formatters.py | 6 ++++-- src/flext_cli/_utilities/framework.py | 8 +++++--- src/flext_cli/_utilities/processes.py | 5 ++++- src/flext_cli/_utilities/validation.py | 8 +++++--- src/flext_cli/_utilities/yaml.py | 6 ++++-- src/flext_cli/base.py | 2 +- src/flext_cli/constants.py | 6 +++++- src/flext_cli/models.py | 5 ++++- src/flext_cli/services/_cli/flextclicli_part_01.py | 5 ++++- src/flext_cli/services/_cli/flextclicli_part_02.py | 5 ++++- src/flext_cli/services/_cli/flextclicli_part_03.py | 9 +++++++-- src/flext_cli/services/_prompts_support.py | 6 ++++-- src/flext_cli/services/file_tools.py | 5 ++++- src/flext_cli/services/pipeline.py | 5 ++++- .../testsflextcliservice_part_05.py | 2 +- 76 files changed, 333 insertions(+), 146 deletions(-) diff --git a/src/flext_cli/_config.py b/src/flext_cli/_config.py index bdc8c16ec..361c27be2 100644 --- a/src/flext_cli/_config.py +++ b/src/flext_cli/_config.py @@ -14,15 +14,17 @@ from functools import cached_property from pathlib import Path -from typing import ClassVar +from typing import ClassVar, TYPE_CHECKING from flext_cli._models.config import FlextCliConfigModels # NOTE (multi-agent): accessor typed by PROTOCOL (p), never the model # class; the protocol module enters under TYPE_CHECKING only (§2.5/§3.4). -from flext_cli._protocols.config import FlextCliProtocolsConfig from flext_core import FlextConfig +if TYPE_CHECKING: + from flext_cli._protocols.config import FlextCliProtocolsConfig + class FlextCliConfig(FlextConfig): """Cli config auto-loaded from ``config/*.yaml`` and validated via models.""" diff --git a/src/flext_cli/_constants/base.py b/src/flext_cli/_constants/base.py index 92cfb4bfa..f73120bbf 100644 --- a/src/flext_cli/_constants/base.py +++ b/src/flext_cli/_constants/base.py @@ -8,9 +8,11 @@ from __future__ import annotations import re -from typing import ClassVar, Final +from typing import ClassVar, Final, TYPE_CHECKING -from flext_core import t + +if TYPE_CHECKING: + from flext_core import t class FlextCliConstantsBase: diff --git a/src/flext_cli/_constants/files.py b/src/flext_cli/_constants/files.py index a152a6308..41c7e1d3b 100644 --- a/src/flext_cli/_constants/files.py +++ b/src/flext_cli/_constants/files.py @@ -8,9 +8,11 @@ from enum import StrEnum, unique from types import MappingProxyType -from typing import Final +from typing import Final, TYPE_CHECKING -from flext_core import t + +if TYPE_CHECKING: + from flext_core import t class FlextCliConstantsFiles: diff --git a/src/flext_cli/_constants/pipeline.py b/src/flext_cli/_constants/pipeline.py index b140bbf68..ab490b508 100644 --- a/src/flext_cli/_constants/pipeline.py +++ b/src/flext_cli/_constants/pipeline.py @@ -2,9 +2,11 @@ from __future__ import annotations -from typing import Final +from typing import Final, TYPE_CHECKING -from flext_core import t + +if TYPE_CHECKING: + from flext_core import t class FlextCliConstantsPipeline: diff --git a/src/flext_cli/_models/_base/flextclimodelsbase_part_05.py b/src/flext_cli/_models/_base/flextclimodelsbase_part_05.py index 8af8f40c3..bc2cb4c4e 100644 --- a/src/flext_cli/_models/_base/flextclimodelsbase_part_05.py +++ b/src/flext_cli/_models/_base/flextclimodelsbase_part_05.py @@ -2,11 +2,13 @@ from __future__ import annotations -from typing import Annotated, ClassVar +from typing import Annotated, ClassVar, TYPE_CHECKING -from flext_cli import t from flext_core import m +if TYPE_CHECKING: + from flext_cli import t + class FlextCliModelsBase: """Implementation part for FlextCliModelsBase.""" diff --git a/src/flext_cli/_models/_base/flextclimodelsbase_part_06.py b/src/flext_cli/_models/_base/flextclimodelsbase_part_06.py index e1f086198..022d666e5 100644 --- a/src/flext_cli/_models/_base/flextclimodelsbase_part_06.py +++ b/src/flext_cli/_models/_base/flextclimodelsbase_part_06.py @@ -2,11 +2,13 @@ from __future__ import annotations -from typing import Annotated, ClassVar +from typing import Annotated, ClassVar, TYPE_CHECKING -from flext_cli import t from flext_core import m +if TYPE_CHECKING: + from flext_cli import t + class FlextCliModelsBase: """Implementation part for FlextCliModelsBase.""" diff --git a/src/flext_cli/_models/_xlx/xlsx_archive.py b/src/flext_cli/_models/_xlx/xlsx_archive.py index 6716ae96f..635ea4908 100644 --- a/src/flext_cli/_models/_xlx/xlsx_archive.py +++ b/src/flext_cli/_models/_xlx/xlsx_archive.py @@ -2,12 +2,14 @@ from __future__ import annotations -from typing import Annotated +from typing import Annotated, TYPE_CHECKING # mro-j47u (kimi): models consume the local t facade; m -> t is forward at runtime. -from flext_cli import t from flext_core import m +if TYPE_CHECKING: + from flext_cli import t + class FlextCliModelsXlsxArchive: """Immutable archive policies and inspection evidence.""" diff --git a/src/flext_cli/_models/_xlx/xlsx_cells.py b/src/flext_cli/_models/_xlx/xlsx_cells.py index 5a35cd38f..a53b59db1 100644 --- a/src/flext_cli/_models/_xlx/xlsx_cells.py +++ b/src/flext_cli/_models/_xlx/xlsx_cells.py @@ -2,13 +2,15 @@ from __future__ import annotations -import datetime as dt -from decimal import Decimal -from typing import Annotated, Literal +from typing import Annotated, Literal, TYPE_CHECKING -from flext_cli import t from flext_core import m +if TYPE_CHECKING: + from flext_cli import t + from decimal import Decimal + import datetime as dt + class FlextCliModelsXlsxCells: """Immutable cell coordinates, values, and write plans.""" diff --git a/src/flext_cli/_models/_xlx/xlsx_layout.py b/src/flext_cli/_models/_xlx/xlsx_layout.py index d983d4afb..8fa5efcaa 100644 --- a/src/flext_cli/_models/_xlx/xlsx_layout.py +++ b/src/flext_cli/_models/_xlx/xlsx_layout.py @@ -2,11 +2,13 @@ from __future__ import annotations -from typing import Annotated, Literal +from typing import Annotated, Literal, TYPE_CHECKING from flext_core import m -from .xlsx_cells import FlextCliModelsXlsxCells + +if TYPE_CHECKING: + from .xlsx_cells import FlextCliModelsXlsxCells class FlextCliModelsXlsxLayout: diff --git a/src/flext_cli/_models/_xlx/xlsx_rules.py b/src/flext_cli/_models/_xlx/xlsx_rules.py index 2d5d4b9aa..21b5b1e50 100644 --- a/src/flext_cli/_models/_xlx/xlsx_rules.py +++ b/src/flext_cli/_models/_xlx/xlsx_rules.py @@ -2,12 +2,14 @@ from __future__ import annotations -from typing import Annotated, Literal +from typing import Annotated, Literal, TYPE_CHECKING from flext_core import m -from .xlsx_cells import FlextCliModelsXlsxCells -from .xlsx_validation import FlextCliModelsXlsxValidation + +if TYPE_CHECKING: + from .xlsx_cells import FlextCliModelsXlsxCells + from .xlsx_validation import FlextCliModelsXlsxValidation class FlextCliModelsXlsxRules: diff --git a/src/flext_cli/_models/_xlx/xlsx_snapshot.py b/src/flext_cli/_models/_xlx/xlsx_snapshot.py index 251c8cfae..3aa988c61 100644 --- a/src/flext_cli/_models/_xlx/xlsx_snapshot.py +++ b/src/flext_cli/_models/_xlx/xlsx_snapshot.py @@ -2,11 +2,13 @@ from __future__ import annotations -from typing import Annotated, Literal +from typing import Annotated, Literal, TYPE_CHECKING from flext_core import m -from .xlsx_cells import FlextCliModelsXlsxCells + +if TYPE_CHECKING: + from .xlsx_cells import FlextCliModelsXlsxCells class FlextCliModelsXlsxSnapshot: diff --git a/src/flext_cli/_models/_xlx/xlsx_style_catalog.py b/src/flext_cli/_models/_xlx/xlsx_style_catalog.py index d214d7119..94a5ef376 100644 --- a/src/flext_cli/_models/_xlx/xlsx_style_catalog.py +++ b/src/flext_cli/_models/_xlx/xlsx_style_catalog.py @@ -2,11 +2,13 @@ from __future__ import annotations -from typing import Annotated +from typing import Annotated, TYPE_CHECKING from flext_core import m -from .xlsx_styles import FlextCliModelsXlsxStyles + +if TYPE_CHECKING: + from .xlsx_styles import FlextCliModelsXlsxStyles class FlextCliModelsXlsxStyleCatalog: diff --git a/src/flext_cli/_models/_xlx/xlsx_style_fills.py b/src/flext_cli/_models/_xlx/xlsx_style_fills.py index 31ccc9ee1..863b0840f 100644 --- a/src/flext_cli/_models/_xlx/xlsx_style_fills.py +++ b/src/flext_cli/_models/_xlx/xlsx_style_fills.py @@ -2,11 +2,13 @@ from __future__ import annotations -from typing import Annotated, Literal +from typing import Annotated, Literal, TYPE_CHECKING from flext_core import m -from .xlsx_style_primitives import FlextCliModelsXlsxStylePrimitives + +if TYPE_CHECKING: + from .xlsx_style_primitives import FlextCliModelsXlsxStylePrimitives class FlextCliModelsXlsxStyleFills: diff --git a/src/flext_cli/_models/_xlx/xlsx_tables.py b/src/flext_cli/_models/_xlx/xlsx_tables.py index 99414e026..9462118b1 100644 --- a/src/flext_cli/_models/_xlx/xlsx_tables.py +++ b/src/flext_cli/_models/_xlx/xlsx_tables.py @@ -2,11 +2,13 @@ from __future__ import annotations -from typing import Annotated, Literal +from typing import Annotated, Literal, TYPE_CHECKING from flext_core import m -from .xlsx_cells import FlextCliModelsXlsxCells + +if TYPE_CHECKING: + from .xlsx_cells import FlextCliModelsXlsxCells class FlextCliModelsXlsxTables: diff --git a/src/flext_cli/_models/_xlx/xlsx_validation.py b/src/flext_cli/_models/_xlx/xlsx_validation.py index 14a7cb649..e858659af 100644 --- a/src/flext_cli/_models/_xlx/xlsx_validation.py +++ b/src/flext_cli/_models/_xlx/xlsx_validation.py @@ -2,11 +2,13 @@ from __future__ import annotations -from typing import Annotated, Literal +from typing import Annotated, Literal, TYPE_CHECKING from flext_core import m -from .xlsx_cells import FlextCliModelsXlsxCells + +if TYPE_CHECKING: + from .xlsx_cells import FlextCliModelsXlsxCells class FlextCliModelsXlsxValidation: diff --git a/src/flext_cli/_models/_xlx/xlsx_workbook.py b/src/flext_cli/_models/_xlx/xlsx_workbook.py index 9aeb5b3fb..d4ce36cf4 100644 --- a/src/flext_cli/_models/_xlx/xlsx_workbook.py +++ b/src/flext_cli/_models/_xlx/xlsx_workbook.py @@ -2,15 +2,17 @@ from __future__ import annotations -from typing import Annotated +from typing import Annotated, TYPE_CHECKING from flext_core import m -from .xlsx_cells import FlextCliModelsXlsxCells -from .xlsx_layout import FlextCliModelsXlsxLayout -from .xlsx_rules import FlextCliModelsXlsxRules -from .xlsx_styles import FlextCliModelsXlsxStyles -from .xlsx_tables import FlextCliModelsXlsxTables + +if TYPE_CHECKING: + from .xlsx_cells import FlextCliModelsXlsxCells + from .xlsx_tables import FlextCliModelsXlsxTables + from .xlsx_layout import FlextCliModelsXlsxLayout + from .xlsx_styles import FlextCliModelsXlsxStyles + from .xlsx_rules import FlextCliModelsXlsxRules class FlextCliModelsXlsxWorkbook: diff --git a/src/flext_cli/_models/pipeline.py b/src/flext_cli/_models/pipeline.py index f56e41c2e..18223f0c8 100644 --- a/src/flext_cli/_models/pipeline.py +++ b/src/flext_cli/_models/pipeline.py @@ -2,14 +2,16 @@ from __future__ import annotations -from collections.abc import Callable -from pathlib import Path from types import MappingProxyType -from typing import Annotated, ClassVar +from typing import Annotated, ClassVar, TYPE_CHECKING from flext_cli import c, p, t from flext_core import m, u +if TYPE_CHECKING: + from pathlib import Path + from collections.abc import Callable + class FlextCliModelsPipeline: """Pipeline models namespace — flat in m.Cli.*.""" diff --git a/src/flext_cli/_models/rules.py b/src/flext_cli/_models/rules.py index cb04efb25..5e24b4861 100644 --- a/src/flext_cli/_models/rules.py +++ b/src/flext_cli/_models/rules.py @@ -2,12 +2,14 @@ from __future__ import annotations -from pathlib import Path -from typing import Annotated +from typing import Annotated, TYPE_CHECKING from flext_cli import c, t from flext_core import m +if TYPE_CHECKING: + from pathlib import Path + class FlextCliModelsRules: """Rules models namespace exposed through ``m.Cli``.""" diff --git a/src/flext_cli/_models/template.py b/src/flext_cli/_models/template.py index 2b90eb2af..8a6f75ab9 100644 --- a/src/flext_cli/_models/template.py +++ b/src/flext_cli/_models/template.py @@ -10,11 +10,13 @@ from __future__ import annotations -from pathlib import Path -from typing import Annotated +from typing import Annotated, TYPE_CHECKING from flext_core import m +if TYPE_CHECKING: + from pathlib import Path + class FlextCliModelsTemplate: """Generic template-engine models, flat in ``m.Cli.*``.""" diff --git a/src/flext_cli/_models/toml.py b/src/flext_cli/_models/toml.py index cb70961be..3ffadd63a 100644 --- a/src/flext_cli/_models/toml.py +++ b/src/flext_cli/_models/toml.py @@ -11,13 +11,15 @@ from __future__ import annotations -from collections.abc import Callable from itertools import chain -from typing import Annotated, Literal, Self +from typing import Annotated, Literal, Self, TYPE_CHECKING from flext_cli._constants.enums import FlextCliConstantsEnums as _enum from flext_core import m, t +if TYPE_CHECKING: + from collections.abc import Callable + # Pyproject "tool" table name — the default TOML root for tool configuration. _TOOL_TABLE: str = "tool" diff --git a/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_03.py b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_03.py index 2a3e5ee47..9f628da16 100644 --- a/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_03.py +++ b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_03.py @@ -6,13 +6,15 @@ from __future__ import annotations -from pathlib import Path -from typing import Protocol, runtime_checkable +from typing import Protocol, runtime_checkable, TYPE_CHECKING from flext_cli._protocols._base.flextcliprotocolsbase_part_02 import ( FlextCliProtocolsBase as FlextCliProtocolsBasePart02, ) -from flext_core import p, t + +if TYPE_CHECKING: + from flext_core import p, t + from pathlib import Path class FlextCliProtocolsBase(FlextCliProtocolsBasePart02): diff --git a/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_05.py b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_05.py index 50c5ccb54..e67bd1ab3 100644 --- a/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_05.py +++ b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_05.py @@ -6,12 +6,14 @@ from __future__ import annotations -from typing import Protocol, runtime_checkable +from typing import Protocol, runtime_checkable, TYPE_CHECKING from flext_cli._protocols._base.flextcliprotocolsbase_part_04 import ( FlextCliProtocolsBase as FlextCliProtocolsBasePart04, ) -from flext_core import t + +if TYPE_CHECKING: + from flext_core import t class FlextCliProtocolsBase(FlextCliProtocolsBasePart04): diff --git a/src/flext_cli/_protocols/_xlx/xlsx_archive.py b/src/flext_cli/_protocols/_xlx/xlsx_archive.py index 5f7a7ab17..4d635c6ee 100644 --- a/src/flext_cli/_protocols/_xlx/xlsx_archive.py +++ b/src/flext_cli/_protocols/_xlx/xlsx_archive.py @@ -2,8 +2,10 @@ from __future__ import annotations -from collections.abc import Iterator, Sequence -from typing import Protocol, Self, overload, runtime_checkable +from typing import Protocol, Self, overload, runtime_checkable, TYPE_CHECKING + +if TYPE_CHECKING: + from collections.abc import Iterator, Sequence class FlextCliProtocolsXlsxArchive: diff --git a/src/flext_cli/_protocols/_xlx/xlsx_snapshot.py b/src/flext_cli/_protocols/_xlx/xlsx_snapshot.py index 6236e24a5..9644493fa 100644 --- a/src/flext_cli/_protocols/_xlx/xlsx_snapshot.py +++ b/src/flext_cli/_protocols/_xlx/xlsx_snapshot.py @@ -2,12 +2,14 @@ from __future__ import annotations -from typing import Protocol, runtime_checkable +from typing import Protocol, runtime_checkable, TYPE_CHECKING -from flext_core import p from .xlsx_snapshot_structure import FlextCliProtocolsXlsxSnapshotStructure +if TYPE_CHECKING: + from flext_core import p + class FlextCliProtocolsXlsxSnapshot(FlextCliProtocolsXlsxSnapshotStructure): """Consumer-facing protocols for workbook parity evidence.""" diff --git a/src/flext_cli/_protocols/_xlx/xlsx_workbook.py b/src/flext_cli/_protocols/_xlx/xlsx_workbook.py index 2e9dd71fb..a8871ace7 100644 --- a/src/flext_cli/_protocols/_xlx/xlsx_workbook.py +++ b/src/flext_cli/_protocols/_xlx/xlsx_workbook.py @@ -2,13 +2,14 @@ from __future__ import annotations -from collections.abc import Iterable, Sequence -from io import BytesIO -from typing import Protocol, runtime_checkable +from typing import Protocol, runtime_checkable, TYPE_CHECKING -from flext_cli import t -from .xlsx_rules import FlextCliProtocolsXlsxRules +if TYPE_CHECKING: + from .xlsx_rules import FlextCliProtocolsXlsxRules + from flext_cli import t + from io import BytesIO + from collections.abc import Iterable, Sequence class FlextCliProtocolsXlsxWorkbook: diff --git a/src/flext_cli/_protocols/domain.py b/src/flext_cli/_protocols/domain.py index cde856f63..117e37441 100644 --- a/src/flext_cli/_protocols/domain.py +++ b/src/flext_cli/_protocols/domain.py @@ -2,11 +2,13 @@ from __future__ import annotations -from pathlib import Path -from typing import Protocol, runtime_checkable +from typing import Protocol, runtime_checkable, TYPE_CHECKING from flext_cli import t -from flext_cli._protocols.base import FlextCliProtocolsBase + +if TYPE_CHECKING: + from flext_cli._protocols.base import FlextCliProtocolsBase + from pathlib import Path class FlextCliProtocolsDomain: diff --git a/src/flext_cli/_protocols/framework.py b/src/flext_cli/_protocols/framework.py index 854ab40a9..d85e0d72e 100644 --- a/src/flext_cli/_protocols/framework.py +++ b/src/flext_cli/_protocols/framework.py @@ -3,11 +3,13 @@ from __future__ import annotations from collections.abc import Callable -from typing import Protocol, runtime_checkable +from typing import Protocol, runtime_checkable, TYPE_CHECKING # mro-j47u (codex): consume the earlier local t facade through the package root. from flext_cli import t -from flext_core import p + +if TYPE_CHECKING: + from flext_core import p class FlextCliProtocolsFramework: diff --git a/src/flext_cli/_protocols/pipeline.py b/src/flext_cli/_protocols/pipeline.py index 12967b369..d7d466fc3 100644 --- a/src/flext_cli/_protocols/pipeline.py +++ b/src/flext_cli/_protocols/pipeline.py @@ -2,12 +2,14 @@ from __future__ import annotations -from collections.abc import Callable -from pathlib import Path -from typing import Protocol, runtime_checkable +from typing import Protocol, runtime_checkable, TYPE_CHECKING -from flext_cli._constants.enums import FlextCliConstantsEnums as ce -from flext_core import p, t + +if TYPE_CHECKING: + from flext_core import p, t + from flext_cli._constants.enums import FlextCliConstantsEnums as ce + from pathlib import Path + from collections.abc import Callable class FlextCliProtocolsPipeline: diff --git a/src/flext_cli/_protocols/toml.py b/src/flext_cli/_protocols/toml.py index dd56191c2..94798315b 100644 --- a/src/flext_cli/_protocols/toml.py +++ b/src/flext_cli/_protocols/toml.py @@ -10,11 +10,13 @@ from __future__ import annotations -from collections.abc import Callable -from typing import Protocol, runtime_checkable +from typing import Protocol, runtime_checkable, TYPE_CHECKING -from flext_cli._constants.enums import FlextCliConstantsEnums as ce -from flext_core import t + +if TYPE_CHECKING: + from flext_core import t + from flext_cli._constants.enums import FlextCliConstantsEnums as ce + from collections.abc import Callable class FlextCliProtocolsToml: diff --git a/src/flext_cli/_protocols/xlsx.py b/src/flext_cli/_protocols/xlsx.py index d002fd383..af60f7b32 100644 --- a/src/flext_cli/_protocols/xlsx.py +++ b/src/flext_cli/_protocols/xlsx.py @@ -2,16 +2,18 @@ from __future__ import annotations -from typing import Protocol, runtime_checkable +from typing import Protocol, runtime_checkable, TYPE_CHECKING -from flext_cli._typings.xlsx import FlextCliTypesXlsx as tx -from flext_core import p from ._xlx.xlsx_archive import FlextCliProtocolsXlsxArchive from ._xlx.xlsx_rules import FlextCliProtocolsXlsxRules from ._xlx.xlsx_snapshot import FlextCliProtocolsXlsxSnapshot from ._xlx.xlsx_workbook import FlextCliProtocolsXlsxWorkbook +if TYPE_CHECKING: + from flext_core import p + from flext_cli._typings.xlsx import FlextCliTypesXlsx as tx + class FlextCliProtocolsXlsx( FlextCliProtocolsXlsxArchive, diff --git a/src/flext_cli/_typings/domain.py b/src/flext_cli/_typings/domain.py index 05f6358da..93e8d715a 100644 --- a/src/flext_cli/_typings/domain.py +++ b/src/flext_cli/_typings/domain.py @@ -24,7 +24,7 @@ class FlextCliTypesDomain: - """Composite CLI aliases built from canonical protocols and core types.""" + """Composite CLI aliases built from canonical and core types.""" type YamlScalar = _YamlScalar type YamlValue = _YamlValue diff --git a/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_02.py b/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_02.py index 5e31405ab..af932d2a8 100644 --- a/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_02.py +++ b/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_02.py @@ -9,7 +9,10 @@ from __future__ import annotations import os -from pathlib import Path +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from pathlib import Path class FlextCliUtilitiesFileTestHelpersMixin: diff --git a/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_03.py b/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_03.py index cc053cdd2..ad511ad60 100644 --- a/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_03.py +++ b/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_03.py @@ -9,13 +9,16 @@ from __future__ import annotations from collections.abc import Mapping, MutableMapping -from pathlib import Path from flext_cli import c, p, r from flext_cli._utilities._file_test_helper.flextcliutilitiesfiletesthelpersmixin_part_04 import ( FlextCliUtilitiesFileTestHelpersMixin as FlextCliUtilitiesFileTestHelpersMixinPart04, ) from flext_cli._utilities.files import FlextCliUtilitiesFiles +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from pathlib import Path class FlextCliUtilitiesFileTestHelpersMixin: diff --git a/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_04.py b/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_04.py index 809548cf7..6c21c9b4e 100644 --- a/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_04.py +++ b/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_04.py @@ -8,12 +8,15 @@ from __future__ import annotations -from pathlib import Path from flext_cli import c, p, r from flext_cli._utilities.json import FlextCliUtilitiesJson as uj from flext_cli._utilities.toml import FlextCliUtilitiesToml as ut from flext_cli._utilities.yaml import FlextCliUtilitiesYaml as uy +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from pathlib import Path class FlextCliUtilitiesFileTestHelpersMixin: diff --git a/src/flext_cli/_utilities/_json/_core.py b/src/flext_cli/_utilities/_json/_core.py index 483615092..f32f12e24 100644 --- a/src/flext_cli/_utilities/_json/_core.py +++ b/src/flext_cli/_utilities/_json/_core.py @@ -12,13 +12,15 @@ from __future__ import annotations from collections.abc import Mapping, Sequence -from pathlib import Path from types import MappingProxyType -from typing import ClassVar +from typing import ClassVar, TYPE_CHECKING from flext_cli import c, m, p, r, t from flext_core import u +if TYPE_CHECKING: + from pathlib import Path + _EMPTY_JSON_MAPPING: t.JsonMapping = MappingProxyType({}) _EMPTY_JSON_SEQUENCE: t.SequenceOf[t.JsonValue] = () diff --git a/src/flext_cli/_utilities/_json/_navigate.py b/src/flext_cli/_utilities/_json/_navigate.py index cfbb8df73..68ee8cdb2 100644 --- a/src/flext_cli/_utilities/_json/_navigate.py +++ b/src/flext_cli/_utilities/_json/_navigate.py @@ -10,10 +10,13 @@ from __future__ import annotations -from flext_cli import t from flext_core import u from ._core import FlextCliUtilitiesJsonCoreMixin +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from flext_cli import t class FlextCliUtilitiesJsonNavigateMixin(FlextCliUtilitiesJsonCoreMixin): diff --git a/src/flext_cli/_utilities/_rules/_loaders.py b/src/flext_cli/_utilities/_rules/_loaders.py index dc4bebea9..0ec5a12d5 100644 --- a/src/flext_cli/_utilities/_rules/_loaders.py +++ b/src/flext_cli/_utilities/_rules/_loaders.py @@ -11,13 +11,16 @@ from __future__ import annotations -from pathlib import Path from flext_cli import c, m, p, r, t from flext_cli._utilities.json import FlextCliUtilitiesJson as uj from flext_cli._utilities.yaml import FlextCliUtilitiesYaml as uy from ._matchers import FlextCliUtilitiesRulesMatchersMixin +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from pathlib import Path class FlextCliUtilitiesRulesLoadersMixin(FlextCliUtilitiesRulesMatchersMixin): diff --git a/src/flext_cli/_utilities/_rules/_matchers.py b/src/flext_cli/_utilities/_rules/_matchers.py index 431e3f348..71fdb4888 100644 --- a/src/flext_cli/_utilities/_rules/_matchers.py +++ b/src/flext_cli/_utilities/_rules/_matchers.py @@ -13,10 +13,13 @@ import fnmatch from collections.abc import Mapping, MutableSequence -from pathlib import Path -from flext_cli import t from flext_cli._utilities.json import FlextCliUtilitiesJson as uj +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from flext_cli import t + from pathlib import Path class FlextCliUtilitiesRulesMatchersMixin: diff --git a/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_02.py b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_02.py index af8ae6f03..457d118e1 100644 --- a/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_02.py +++ b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_02.py @@ -2,13 +2,15 @@ from __future__ import annotations -from typing import TypeIs +from typing import TypeIs, TYPE_CHECKING import tomlkit from tomlkit.items import AoT, Item, Table from tomlkit.toml_document import TOMLDocument -from flext_cli import t + +if TYPE_CHECKING: + from flext_cli import t class FlextCliUtilitiesToml: diff --git a/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_03.py b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_03.py index deb2a680a..ae337e18a 100644 --- a/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_03.py +++ b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_03.py @@ -4,8 +4,6 @@ from collections.abc import MutableMapping -from tomlkit.items import Table -from tomlkit.toml_document import TOMLDocument from flext_cli import t from flext_cli._utilities._toml.flextcliutilitiestoml_part_01 import ( @@ -15,6 +13,11 @@ FlextCliUtilitiesToml as FlextCliUtilitiesTomlPart02, ) from flext_core import u +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from tomlkit.toml_document import TOMLDocument + from tomlkit.items import Table class FlextCliUtilitiesToml: diff --git a/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_04.py b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_04.py index 10f207809..1c3a2d4b7 100644 --- a/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_04.py +++ b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_04.py @@ -2,10 +2,7 @@ from __future__ import annotations -from tomlkit.items import Table -from tomlkit.toml_document import TOMLDocument -from flext_cli import t from flext_cli._utilities._toml.flextcliutilitiestoml_part_01 import ( FlextCliUtilitiesToml as FlextCliUtilitiesTomlPart01, ) @@ -13,6 +10,12 @@ FlextCliUtilitiesToml as FlextCliUtilitiesTomlPart03, ) from flext_core import u +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from flext_cli import t + from tomlkit.toml_document import TOMLDocument + from tomlkit.items import Table class FlextCliUtilitiesToml: diff --git a/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_05.py b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_05.py index 759801623..8332759ef 100644 --- a/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_05.py +++ b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_05.py @@ -7,7 +7,6 @@ from tomlkit.items import Item, Table from tomlkit.toml_document import TOMLDocument -from flext_cli import t from flext_cli._utilities._toml.flextcliutilitiestoml_part_01 import ( FlextCliUtilitiesToml as FlextCliUtilitiesTomlPart01, ) @@ -18,6 +17,10 @@ FlextCliUtilitiesToml as FlextCliUtilitiesTomlPart03, ) from flext_core import u +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from flext_cli import t class FlextCliUtilitiesToml: diff --git a/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_06.py b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_06.py index 7a859dd8a..75d595254 100644 --- a/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_06.py +++ b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_06.py @@ -2,7 +2,6 @@ from __future__ import annotations -from pathlib import Path import tomlkit from tomlkit.toml_document import TOMLDocument @@ -13,6 +12,10 @@ ) from flext_cli._utilities.runtime import FlextCliUtilitiesRuntime as ur from flext_core import u +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from pathlib import Path class FlextCliUtilitiesToml: diff --git a/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_07.py b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_07.py index cea5171f9..a63ed6589 100644 --- a/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_07.py +++ b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_07.py @@ -2,7 +2,6 @@ from __future__ import annotations -from pathlib import Path from flext_cli import c, e, p, r, t from flext_cli._utilities._toml.flextcliutilitiestoml_part_01 import ( @@ -11,6 +10,10 @@ from flext_cli._utilities._toml.flextcliutilitiestoml_part_06 import ( FlextCliUtilitiesToml as FlextCliUtilitiesTomlPart06, ) +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from pathlib import Path class FlextCliUtilitiesToml: diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_cells.py b/src/flext_cli/_utilities/_xlxx/xlsx_cells.py index ac3e203b9..4f068d026 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_cells.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_cells.py @@ -4,12 +4,15 @@ from openpyxl.cell.cell import Cell from openpyxl.utils.exceptions import IllegalCharacterError -from openpyxl.worksheet.worksheet import Worksheet # mro-j47u (kimi): utilities consume local facades only, never private modules. from flext_cli import c, p, r, t from .xlsx_formula_codec import FlextCliUtilitiesXlsxFormulaCodec +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from openpyxl.worksheet.worksheet import Worksheet class FlextCliUtilitiesXlsxCells: diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_conditional.py b/src/flext_cli/_utilities/_xlxx/xlsx_conditional.py index 3ff2ac041..b6acf9bd3 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_conditional.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_conditional.py @@ -6,7 +6,6 @@ from openpyxl.formatting.rule import Rule from openpyxl.styles.differential import DifferentialStyle from openpyxl.styles.numbers import NumberFormat, builtin_format_id -from openpyxl.worksheet.worksheet import Worksheet # mro-j47u (kimi): utilities consume local facades only, never private modules. from flext_cli import c, m, p, r @@ -15,6 +14,10 @@ from .xlsx_formula_codec import FlextCliUtilitiesXlsxFormulaCodec from .xlsx_style_codec import FlextCliUtilitiesXlsxStyleCodec from .xlsx_validations import FlextCliUtilitiesXlsxValidations +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from openpyxl.worksheet.worksheet import Worksheet class FlextCliUtilitiesXlsxConditional( diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_layout.py b/src/flext_cli/_utilities/_xlxx/xlsx_layout.py index 79c814d44..6d99bb8a0 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_layout.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_layout.py @@ -4,11 +4,14 @@ from openpyxl.cell.cell import Cell from openpyxl.comments import Comment -from openpyxl.worksheet.worksheet import Worksheet from flext_cli import c, p, r, t from .xlsx_addresses import FlextCliUtilitiesXlsxAddresses +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from openpyxl.worksheet.worksheet import Worksheet class FlextCliUtilitiesXlsxLayout(FlextCliUtilitiesXlsxAddresses): diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_protection.py b/src/flext_cli/_utilities/_xlxx/xlsx_protection.py index ea6cdd43b..e5e6da4ba 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_protection.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_protection.py @@ -3,9 +3,12 @@ from __future__ import annotations from openpyxl.styles import Protection -from openpyxl.worksheet.worksheet import Worksheet from flext_cli import c, p, r +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from openpyxl.worksheet.worksheet import Worksheet class FlextCliUtilitiesXlsxProtection: diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_renderer.py b/src/flext_cli/_utilities/_xlxx/xlsx_renderer.py index b01d71934..5bb912f50 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_renderer.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_renderer.py @@ -2,7 +2,6 @@ from __future__ import annotations -from openpyxl import Workbook from flext_cli import c, m, p, r @@ -11,6 +10,10 @@ from .xlsx_rules import FlextCliUtilitiesXlsxRules from .xlsx_tables import FlextCliUtilitiesXlsxTables from .xlsx_workbook_plan import FlextCliUtilitiesXlsxWorkbookPlan +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from openpyxl import Workbook class FlextCliUtilitiesXlsxRenderer( diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_rules.py b/src/flext_cli/_utilities/_xlxx/xlsx_rules.py index fa88bcb2f..d17e64d58 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_rules.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_rules.py @@ -2,13 +2,16 @@ from __future__ import annotations -from openpyxl.worksheet.worksheet import Worksheet from flext_cli import p, r from .xlsx_conditional import FlextCliUtilitiesXlsxConditional from .xlsx_protection import FlextCliUtilitiesXlsxProtection from .xlsx_validations import FlextCliUtilitiesXlsxValidations +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from openpyxl.worksheet.worksheet import Worksheet class FlextCliUtilitiesXlsxRules( diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_sheet.py b/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_sheet.py index f5128d8b6..d75debf6c 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_sheet.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_sheet.py @@ -2,9 +2,8 @@ from __future__ import annotations -from typing import Literal +from typing import Literal, TYPE_CHECKING -from openpyxl.worksheet.worksheet import Worksheet from pydantic import ValidationError from flext_cli import m, p, r @@ -12,6 +11,9 @@ from .xlsx_snapshot_structure import FlextCliUtilitiesXlsxSnapshotStructure from .xlsx_snapshot_values import FlextCliUtilitiesXlsxSnapshotValues +if TYPE_CHECKING: + from openpyxl.worksheet.worksheet import Worksheet + class FlextCliUtilitiesXlsxSnapshotSheet( FlextCliUtilitiesXlsxSnapshotValues, FlextCliUtilitiesXlsxSnapshotStructure diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_structure.py b/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_structure.py index de50ce67a..cc56ff090 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_structure.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_structure.py @@ -2,14 +2,17 @@ from __future__ import annotations -from openpyxl import Workbook from openpyxl.utils.cell import column_index_from_string from openpyxl.workbook.defined_name import DefinedName from openpyxl.worksheet.table import Table -from openpyxl.worksheet.worksheet import Worksheet from pydantic import ValidationError from flext_cli import m, p, r +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from openpyxl.worksheet.worksheet import Worksheet + from openpyxl import Workbook class FlextCliUtilitiesXlsxSnapshotStructure: diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_values.py b/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_values.py index cefb4963c..d7566f9df 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_values.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_values.py @@ -6,10 +6,13 @@ from decimal import Decimal, InvalidOperation from openpyxl.cell.cell import Cell, MergedCell -from openpyxl.worksheet.worksheet import Worksheet from pydantic import ValidationError from flext_cli import c, m, p, r, t +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from openpyxl.worksheet.worksheet import Worksheet class FlextCliUtilitiesXlsxSnapshotValues: diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_style_builders.py b/src/flext_cli/_utilities/_xlxx/xlsx_style_builders.py index d9d451642..cdcf84b7e 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_style_builders.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_style_builders.py @@ -6,7 +6,10 @@ from openpyxl.styles.borders import Side from openpyxl.styles.fills import PatternFill, Stop -from flext_cli import p +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from flext_cli import p class FlextCliUtilitiesXlsxStyleBuilders: diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_style_readers.py b/src/flext_cli/_utilities/_xlxx/xlsx_style_readers.py index 0fd85c250..54023ba3c 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_style_readers.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_style_readers.py @@ -5,12 +5,15 @@ from copy import copy from openpyxl.styles import Alignment, Border, Color, Font, GradientFill -from openpyxl.styles.borders import Side from openpyxl.styles.fills import Fill, PatternFill, Stop -from openpyxl.styles.styleable import StyleableObject from pydantic import ValidationError from flext_cli import m, p, r +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from openpyxl.styles.styleable import StyleableObject + from openpyxl.styles.borders import Side class FlextCliUtilitiesXlsxStyleReaders: diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_tables.py b/src/flext_cli/_utilities/_xlxx/xlsx_tables.py index b860ec63e..59d0d6e3a 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_tables.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_tables.py @@ -2,15 +2,18 @@ from __future__ import annotations -from openpyxl import Workbook from openpyxl.workbook.defined_name import DefinedName from openpyxl.worksheet.table import Table, TableStyleInfo -from openpyxl.worksheet.worksheet import Worksheet from flext_cli import c, p, r from .xlsx_addresses import FlextCliUtilitiesXlsxAddresses from .xlsx_formula_codec import FlextCliUtilitiesXlsxFormulaCodec +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from openpyxl.worksheet.worksheet import Worksheet + from openpyxl import Workbook class FlextCliUtilitiesXlsxTables(FlextCliUtilitiesXlsxAddresses): diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_validations.py b/src/flext_cli/_utilities/_xlxx/xlsx_validations.py index bd78fe315..096dd8ab9 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_validations.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_validations.py @@ -3,12 +3,15 @@ from __future__ import annotations from openpyxl.worksheet.datavalidation import DataValidation -from openpyxl.worksheet.worksheet import Worksheet from flext_cli import c, m, p, r, t from .xlsx_addresses import FlextCliUtilitiesXlsxAddresses from .xlsx_formula_codec import FlextCliUtilitiesXlsxFormulaCodec +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from openpyxl.worksheet.worksheet import Worksheet class FlextCliUtilitiesXlsxValidations(FlextCliUtilitiesXlsxAddresses): diff --git a/src/flext_cli/_utilities/_yaml/_convert.py b/src/flext_cli/_utilities/_yaml/_convert.py index 09a84b9aa..6291024e4 100644 --- a/src/flext_cli/_utilities/_yaml/_convert.py +++ b/src/flext_cli/_utilities/_yaml/_convert.py @@ -14,12 +14,21 @@ from __future__ import annotations from collections.abc import Mapping -from typing import SupportsFloat, SupportsIndex, SupportsInt, TypeGuard, overload +from typing import ( + SupportsFloat, + SupportsIndex, + SupportsInt, + TypeGuard, + overload, + TYPE_CHECKING, +) from ruamel.yaml.comments import CommentedMap, CommentedSeq from ruamel.yaml.scalarstring import DoubleQuotedScalarString, LiteralScalarString -from flext_cli import t + +if TYPE_CHECKING: + from flext_cli import t #: YAML 1.1 boolean/null tokens that must be quoted to survive a round-trip. #: Single consumer (``yaml_deep_to_commented``); promote to ``c.Cli`` if a diff --git a/src/flext_cli/_utilities/_yaml/_editing.py b/src/flext_cli/_utilities/_yaml/_editing.py index b789589dc..07e052313 100644 --- a/src/flext_cli/_utilities/_yaml/_editing.py +++ b/src/flext_cli/_utilities/_yaml/_editing.py @@ -17,16 +17,18 @@ import copy from collections.abc import Mapping -from typing import ClassVar, TypeGuard +from typing import ClassVar, TypeGuard, TYPE_CHECKING from ruamel.yaml.comments import CommentedMap, CommentedSeq from ruamel.yaml.tokens import CommentToken as RuamelCommentToken -from flext_cli import p, t from flext_core import u from ._engine import FlextCliUtilitiesYamlEngineMixin +if TYPE_CHECKING: + from flext_cli import p, t + class FlextCliUtilitiesYamlEditingMixin(FlextCliUtilitiesYamlEngineMixin): """Comment/anchor-aware editing operations on parsed YAML trees.""" diff --git a/src/flext_cli/_utilities/_yaml/_engine.py b/src/flext_cli/_utilities/_yaml/_engine.py index add30dc00..c929d47ae 100644 --- a/src/flext_cli/_utilities/_yaml/_engine.py +++ b/src/flext_cli/_utilities/_yaml/_engine.py @@ -22,8 +22,7 @@ from __future__ import annotations import io -from pathlib import Path -from typing import TextIO +from typing import TextIO, TYPE_CHECKING import ruamel.yaml from ruamel.yaml.comments import CommentedMap @@ -32,6 +31,9 @@ from ._convert import FlextCliUtilitiesYamlConvertMixin +if TYPE_CHECKING: + from pathlib import Path + def _roundtrip_yaml() -> ruamel.yaml.YAML: """Build a fresh comment/quote-preserving round-trip engine. diff --git a/src/flext_cli/_utilities/config.py b/src/flext_cli/_utilities/config.py index f58c239dd..ac201ed18 100644 --- a/src/flext_cli/_utilities/config.py +++ b/src/flext_cli/_utilities/config.py @@ -13,7 +13,6 @@ from __future__ import annotations import os -from pathlib import Path from jsonschema import Draft202012Validator from jsonschema.exceptions import SchemaError, ValidationError @@ -25,6 +24,10 @@ from flext_cli._utilities.json import FlextCliUtilitiesJson from flext_cli._utilities.yaml import FlextCliUtilitiesYaml from flext_core import u +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from pathlib import Path class FlextCliUtilitiesConfig: diff --git a/src/flext_cli/_utilities/formatters.py b/src/flext_cli/_utilities/formatters.py index c4661b105..e1a7edf6c 100644 --- a/src/flext_cli/_utilities/formatters.py +++ b/src/flext_cli/_utilities/formatters.py @@ -2,13 +2,15 @@ from __future__ import annotations -from typing import ClassVar +from typing import ClassVar, TYPE_CHECKING from rich.console import Console from rich.panel import Panel from rich.table import Table as RichTable -from flext_cli import p + +if TYPE_CHECKING: + from flext_cli import p class FlextCliUtilitiesFormatters: diff --git a/src/flext_cli/_utilities/framework.py b/src/flext_cli/_utilities/framework.py index dbfc4a0c4..efc0e3593 100644 --- a/src/flext_cli/_utilities/framework.py +++ b/src/flext_cli/_utilities/framework.py @@ -6,17 +6,19 @@ from collections.abc import Callable from contextvars import ContextVar from inspect import Parameter -from types import EllipsisType, GenericAlias -from typing import Never +from typing import Never, TYPE_CHECKING import click import typer -from typer.models import OptionInfo +from typer import OptionInfo from typer.testing import CliRunner # mro-j47u (codex): consume every public facade through the package root. from flext_cli import c, e, m, p, r, t +if TYPE_CHECKING: + from types import EllipsisType, GenericAlias + class _TyperApplication: """Private application implementation hidden behind ``p.Cli.Application``.""" diff --git a/src/flext_cli/_utilities/processes.py b/src/flext_cli/_utilities/processes.py index b55cbfaf4..a88d5272c 100644 --- a/src/flext_cli/_utilities/processes.py +++ b/src/flext_cli/_utilities/processes.py @@ -4,12 +4,15 @@ import shlex import subprocess -from collections.abc import Mapping from pathlib import Path from types import MappingProxyType from flext_cli import c, p, r, t from flext_cli._utilities.runtime import FlextCliUtilitiesRuntime +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from collections.abc import Mapping class FlextCliUtilitiesProcesses: diff --git a/src/flext_cli/_utilities/validation.py b/src/flext_cli/_utilities/validation.py index 904536310..131105bf3 100644 --- a/src/flext_cli/_utilities/validation.py +++ b/src/flext_cli/_utilities/validation.py @@ -2,14 +2,16 @@ from __future__ import annotations -from collections.abc import MutableMapping -from typing import ClassVar +from typing import ClassVar, TYPE_CHECKING -from pydantic import ValidationError as PydanticValidationError from flext_cli import c, p, r, t from flext_core import u +if TYPE_CHECKING: + from pydantic import ValidationError as PydanticValidationError + from collections.abc import MutableMapping + class FlextCliUtilitiesValidation: """Validation methods exposed directly on ``u.Cli``.""" diff --git a/src/flext_cli/_utilities/yaml.py b/src/flext_cli/_utilities/yaml.py index 413690644..c69a7d0c7 100644 --- a/src/flext_cli/_utilities/yaml.py +++ b/src/flext_cli/_utilities/yaml.py @@ -9,9 +9,8 @@ from __future__ import annotations -from pathlib import Path from types import MappingProxyType -from typing import ClassVar +from typing import ClassVar, TYPE_CHECKING from yaml import safe_dump, safe_load @@ -20,6 +19,9 @@ from flext_cli._utilities.json import FlextCliUtilitiesJson from flext_core import u +if TYPE_CHECKING: + from pathlib import Path + _EMPTY_JSON_MAPPING: t.JsonMapping = MappingProxyType({}) _EMPTY_JSON_SEQUENCE: t.SequenceOf[t.JsonValue] = () diff --git a/src/flext_cli/base.py b/src/flext_cli/base.py index 1b9286db7..8341fe70d 100644 --- a/src/flext_cli/base.py +++ b/src/flext_cli/base.py @@ -13,7 +13,7 @@ from flext_core import p, s -class FlextCliServiceBase[TDomainResult: p.Base = m.Cli.RuntimeStatus]( +class FlextCliServiceBase[TDomainResult: p.ModelBase = m.Cli.RuntimeStatus]( s[TDomainResult] ): """Base class for flext-cli services with typed configuration access. diff --git a/src/flext_cli/constants.py b/src/flext_cli/constants.py index 34a2eeb04..6487bc4c3 100644 --- a/src/flext_cli/constants.py +++ b/src/flext_cli/constants.py @@ -2,7 +2,7 @@ from __future__ import annotations -from flext_core import c, t +from flext_core import c # NOTE (mro-0ftd.3.7.2, operator-authorized cross-lane fix): import direct from # submodules (mirrors models.py) because the generated ._constants barrel is empty @@ -18,6 +18,10 @@ from ._constants.settings import FlextCliConstantsSettings from ._constants.xlsx import FlextCliConstantsXlsx from ._constants.xlsx_future_functions import FlextCliConstantsXlsxFutureFunctions +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from flext_core import t class FlextCliConstants(c): diff --git a/src/flext_cli/models.py b/src/flext_cli/models.py index 821fdcc0e..5c62684b8 100644 --- a/src/flext_cli/models.py +++ b/src/flext_cli/models.py @@ -2,7 +2,6 @@ from __future__ import annotations -from flext_cli import t from flext_cli._models.base import FlextCliModelsBase from flext_cli._models.pipeline import FlextCliModelsPipeline from flext_cli._models.rules import FlextCliModelsRules @@ -10,6 +9,10 @@ from flext_cli._models.toml import FlextCliModelsToml from flext_cli._models.xlsx import FlextCliModelsXlsx from flext_core import m +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from flext_cli import t class FlextCliModels(m): diff --git a/src/flext_cli/services/_cli/flextclicli_part_01.py b/src/flext_cli/services/_cli/flextclicli_part_01.py index 6a8a3fcbb..6aa53a37f 100644 --- a/src/flext_cli/services/_cli/flextclicli_part_01.py +++ b/src/flext_cli/services/_cli/flextclicli_part_01.py @@ -8,9 +8,12 @@ from collections.abc import Mapping, Sequence from inspect import Parameter, Signature -from types import GenericAlias from flext_cli import m, p, t, u +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from types import GenericAlias class FlextCliCli: diff --git a/src/flext_cli/services/_cli/flextclicli_part_02.py b/src/flext_cli/services/_cli/flextclicli_part_02.py index d661b2cce..ffb48d0cd 100644 --- a/src/flext_cli/services/_cli/flextclicli_part_02.py +++ b/src/flext_cli/services/_cli/flextclicli_part_02.py @@ -6,11 +6,14 @@ from __future__ import annotations -from inspect import Parameter from flext_cli import m, p, settings, t, u from flext_cli.services._cli.flextclicli_part_01 import FlextCliCli as FlextCliCliPart01 from flext_cli.services.cli_params import FlextCliCommonParams +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from inspect import Parameter class FlextCliCli(FlextCliCliPart01): diff --git a/src/flext_cli/services/_cli/flextclicli_part_03.py b/src/flext_cli/services/_cli/flextclicli_part_03.py index 4463cb399..dba23f1e7 100644 --- a/src/flext_cli/services/_cli/flextclicli_part_03.py +++ b/src/flext_cli/services/_cli/flextclicli_part_03.py @@ -6,14 +6,19 @@ from __future__ import annotations -from inspect import Parameter from flext_cli import c, p, r, t, u # mro-j47u (codex): the earlier MRO part is referenced only by annotation; # inspect.Parameter remains runtime because it constructs the CLI signature. -from flext_cli.services._cli.flextclicli_part_01 import FlextCliCli as FlextCliCliPart01 from flext_cli.services._cli.flextclicli_part_02 import FlextCliCli as FlextCliCliPart02 +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from flext_cli.services._cli.flextclicli_part_01 import ( + FlextCliCli as FlextCliCliPart01, + ) + from inspect import Parameter class FlextCliCli(FlextCliCliPart02): diff --git a/src/flext_cli/services/_prompts_support.py b/src/flext_cli/services/_prompts_support.py index 29bb947b8..7a3d8f026 100644 --- a/src/flext_cli/services/_prompts_support.py +++ b/src/flext_cli/services/_prompts_support.py @@ -10,11 +10,13 @@ from __future__ import annotations import getpass -from collections.abc import Callable -from typing import Annotated, Self +from typing import Annotated, Self, TYPE_CHECKING from flext_cli import c, m, p, r, s, settings, t, u +if TYPE_CHECKING: + from collections.abc import Callable + class FlextCliPromptsSupport(s): """Support owner for prompt runtime state, logging, and input readers.""" diff --git a/src/flext_cli/services/file_tools.py b/src/flext_cli/services/file_tools.py index 1bcef0e1e..61a0ad3e1 100644 --- a/src/flext_cli/services/file_tools.py +++ b/src/flext_cli/services/file_tools.py @@ -2,10 +2,13 @@ from __future__ import annotations -from collections.abc import Sequence from pathlib import Path from flext_cli import c, p, r, s, t, u +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from collections.abc import Sequence class FlextCliFileTools(s): diff --git a/src/flext_cli/services/pipeline.py b/src/flext_cli/services/pipeline.py index 31c959812..f077a1b1e 100644 --- a/src/flext_cli/services/pipeline.py +++ b/src/flext_cli/services/pipeline.py @@ -2,10 +2,13 @@ from __future__ import annotations -from pathlib import Path from flext_cli import c, m, p, r, s, t from flext_cli._utilities.pipeline import FlextCliUtilitiesPipeline +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from pathlib import Path class FlextCliPipeline(s, FlextCliUtilitiesPipeline): diff --git a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_05.py b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_05.py index 98c6cbce7..1dec4dbf6 100644 --- a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_05.py +++ b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_05.py @@ -69,7 +69,7 @@ def build_fail_route() -> p.Cli.ResultCommandRoute: tm.that(fail_invocation.stdout, has="Username cannot be empty") def test_register_result_routes_propagates_real_failure(self) -> None: - """Preserve structured failures from registered result routes.""" + """Preserve structured failures from registered routes.""" app = cli.create_app_with_common_params( name="result-app", help_text="Result application" ) From 9469d2d5f5072df0981fce74c7ff9b0c2ad518ec Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Fri, 17 Jul 2026 08:52:09 -0300 Subject: [PATCH 29/37] refactor fixes --- src/flext_cli/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flext_cli/base.py b/src/flext_cli/base.py index 8341fe70d..3f1a000a8 100644 --- a/src/flext_cli/base.py +++ b/src/flext_cli/base.py @@ -13,7 +13,7 @@ from flext_core import p, s -class FlextCliServiceBase[TDomainResult: p.ModelBase = m.Cli.RuntimeStatus]( +class FlextCliServiceBase[TDomainResult: p.BaseModel = m.Cli.RuntimeStatus]( s[TDomainResult] ): """Base class for flext-cli services with typed configuration access. From dd12a0bc089cfc5977238a4c5ab6836e429d2d91 Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Fri, 17 Jul 2026 09:29:26 -0300 Subject: [PATCH 30/37] fix(cli): import OptionInfo from typer.models (typer 0.26 API move) (mro-wkii.17.26.12) typer 0.26.8 moved OptionInfo from the typer package root to typer.models; 'from typer import OptionInfo' raised ImportError blocking flext-cli u facade -> cascaded to every flext-cli consumer fleet-wide. --- src/flext_cli/_utilities/framework.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flext_cli/_utilities/framework.py b/src/flext_cli/_utilities/framework.py index efc0e3593..f4bbc24bb 100644 --- a/src/flext_cli/_utilities/framework.py +++ b/src/flext_cli/_utilities/framework.py @@ -10,7 +10,7 @@ import click import typer -from typer import OptionInfo +from typer.models import OptionInfo from typer.testing import CliRunner # mro-j47u (codex): consume every public facade through the package root. From 4553aa85ad9e404196f6a7ec1ea11f2c4f2b1145 Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Sat, 18 Jul 2026 10:59:24 -0300 Subject: [PATCH 31/37] =?UTF-8?q?fix(models):=20OptionSpec=20loading-order?= =?UTF-8?q?=20=E2=80=94=20import=20t=20at=20runtime=20so=20codegen=20trans?= =?UTF-8?q?action=20probe=20resolves?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TARGET: flext-cli _models/_base OptionSpec (t.StrSequence/t.Cli.Value fields). IMPACT: non-breaking (moves 't' TYPE_CHECKING->runtime; model resolves at class-build). RISK: low - OptionSpec __pydantic_complete__=True; ruff clean. The codegen transaction-worktree import-probe checks out committed HEAD; with 't' under TYPE_CHECKING the generated OptionSpec was 'not fully defined' at CLI command-build time, breaking 'flext-infra codegen init'. Runtime import fixes it. mro-28cb --- src/flext_cli/_models/_base/flextclimodelsbase_part_06.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/flext_cli/_models/_base/flextclimodelsbase_part_06.py b/src/flext_cli/_models/_base/flextclimodelsbase_part_06.py index 022d666e5..e1f086198 100644 --- a/src/flext_cli/_models/_base/flextclimodelsbase_part_06.py +++ b/src/flext_cli/_models/_base/flextclimodelsbase_part_06.py @@ -2,13 +2,11 @@ from __future__ import annotations -from typing import Annotated, ClassVar, TYPE_CHECKING +from typing import Annotated, ClassVar +from flext_cli import t from flext_core import m -if TYPE_CHECKING: - from flext_cli import t - class FlextCliModelsBase: """Implementation part for FlextCliModelsBase.""" From b2982ba59679cea6f98ceeae91374a9ac8255708 Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Sat, 18 Jul 2026 11:10:38 -0300 Subject: [PATCH 32/37] fix(models): resolve loading-order via runtime field-type imports (pipeline/rules/template/toml/base) TARGET: flext-cli _models pipeline/rules/template/toml/_base_part_05. IMPACT: non-breaking (Path/Callable/t field-types moved TYPE_CHECKING->runtime so Pydantic resolves at class-build; no model_rebuild). RISK: low - full facade import OK; ruff clean; models resolve (only cross-cutting AutoSettings pending in settings.py). Same loading-order class as flext-core mro-rs10: models with future-annotations + field types under TYPE_CHECKING left __pydantic_complete__=False. Move runtime-needed field-type imports to module runtime. --- src/flext_cli/_models/_base/flextclimodelsbase_part_05.py | 6 ++---- src/flext_cli/_models/pipeline.py | 8 +++----- src/flext_cli/_models/rules.py | 6 ++---- src/flext_cli/_models/template.py | 6 ++---- src/flext_cli/_models/toml.py | 7 ++----- 5 files changed, 11 insertions(+), 22 deletions(-) diff --git a/src/flext_cli/_models/_base/flextclimodelsbase_part_05.py b/src/flext_cli/_models/_base/flextclimodelsbase_part_05.py index bc2cb4c4e..8af8f40c3 100644 --- a/src/flext_cli/_models/_base/flextclimodelsbase_part_05.py +++ b/src/flext_cli/_models/_base/flextclimodelsbase_part_05.py @@ -2,13 +2,11 @@ from __future__ import annotations -from typing import Annotated, ClassVar, TYPE_CHECKING +from typing import Annotated, ClassVar +from flext_cli import t from flext_core import m -if TYPE_CHECKING: - from flext_cli import t - class FlextCliModelsBase: """Implementation part for FlextCliModelsBase.""" diff --git a/src/flext_cli/_models/pipeline.py b/src/flext_cli/_models/pipeline.py index 18223f0c8..0f66fa371 100644 --- a/src/flext_cli/_models/pipeline.py +++ b/src/flext_cli/_models/pipeline.py @@ -3,14 +3,12 @@ from __future__ import annotations from types import MappingProxyType -from typing import Annotated, ClassVar, TYPE_CHECKING +from typing import Annotated, ClassVar from flext_cli import c, p, t from flext_core import m, u - -if TYPE_CHECKING: - from pathlib import Path - from collections.abc import Callable +from pathlib import Path +from collections.abc import Callable class FlextCliModelsPipeline: diff --git a/src/flext_cli/_models/rules.py b/src/flext_cli/_models/rules.py index 5e24b4861..0f06f986a 100644 --- a/src/flext_cli/_models/rules.py +++ b/src/flext_cli/_models/rules.py @@ -2,13 +2,11 @@ from __future__ import annotations -from typing import Annotated, TYPE_CHECKING +from typing import Annotated from flext_cli import c, t from flext_core import m - -if TYPE_CHECKING: - from pathlib import Path +from pathlib import Path class FlextCliModelsRules: diff --git a/src/flext_cli/_models/template.py b/src/flext_cli/_models/template.py index 8a6f75ab9..2b97e69dc 100644 --- a/src/flext_cli/_models/template.py +++ b/src/flext_cli/_models/template.py @@ -10,12 +10,10 @@ from __future__ import annotations -from typing import Annotated, TYPE_CHECKING +from typing import Annotated from flext_core import m - -if TYPE_CHECKING: - from pathlib import Path +from pathlib import Path class FlextCliModelsTemplate: diff --git a/src/flext_cli/_models/toml.py b/src/flext_cli/_models/toml.py index 3ffadd63a..c800257fe 100644 --- a/src/flext_cli/_models/toml.py +++ b/src/flext_cli/_models/toml.py @@ -12,14 +12,11 @@ from __future__ import annotations from itertools import chain -from typing import Annotated, Literal, Self, TYPE_CHECKING +from typing import Annotated, Literal, Self from flext_cli._constants.enums import FlextCliConstantsEnums as _enum from flext_core import m, t - -if TYPE_CHECKING: - from collections.abc import Callable - +from collections.abc import Callable # Pyproject "tool" table name — the default TOML root for tool configuration. _TOOL_TABLE: str = "tool" From 189f313939465b10756fafc7c13dcbafdf279bf2 Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Sun, 19 Jul 2026 10:02:41 -0300 Subject: [PATCH 33/37] fixes --- AGENTS.md | 35 ++++++++++++++++++++++++----------- src/flext_cli/base.py | 8 +++----- tests/unit/test_base.py | 19 ++++++++++++++++++- 3 files changed, 45 insertions(+), 17 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 895efb423..707d713ac 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -308,17 +308,30 @@ These rules are inviolable for every FLEXT project and MUST always be followed. **Facade layering (strict order `c -> t -> p -> m -> u`):** -- Forward direction (a higher layer importing a lower one) MAY use a direct runtime - import: `u` may import `m,p,t,c`; `m` may import `p,t,c`; `p` may import `t,c`; - `t` may import `c`; `c` imports nothing from the others at runtime. -- Reverse direction (a lower layer needing a higher layer's type) is FORBIDDEN at - runtime and MUST be done only under `if TYPE_CHECKING:`. -- `m` (models) imports `c` (constants) only via a lazy import. -- `c` (constants) NEVER imports `m` (models) at runtime — only under `TYPE_CHECKING`. -- `t` (typings) imports `p` and `m` only under `TYPE_CHECKING` (to improve typing). -- `p` (protocols) imports `m` only under `TYPE_CHECKING` (to improve typing). -- `c` may compose from the project's own leaf base modules (`_constants/base`, …) - following this same rule. +- Forward direction (a higher-index layer importing a lower one) uses a direct + RUNTIME import: `u` may import `m,p,t,c`; `m` may import `p,t,c`; `p` may import + `t,c`; `t` may import `c`; `c` imports nothing from the others at runtime. +- Reverse direction (a lower-index layer importing a higher one) is FORBIDDEN + entirely — not at runtime and NOT under `if TYPE_CHECKING:` (ADR-011, + Runtime-Forward Annotation Law). A reverse edge is a mis-placed artifact: move + it to the layer of its highest-index referent. +- Every name in a runtime-evaluated annotation (Pydantic field, PEP 526 annotated + assignment, beartype-decorated signature, PEP 695 `type` alias RHS) MUST be a + top-level RUNTIME import. No `TYPE_CHECKING` gating of an annotation name; no + `from __future__ import annotations` used to evade runtime resolution. +- `m` (models) imports `c`, `t`, and `p` at RUNTIME (all forward). Data/payload + and nested/composed fields are concrete `m.*`; collaborator/DI fields are `p.*` + (base sets `arbitrary_types_allowed=True`). No `model_rebuild()`; no ad-hoc + lazy imports (only the root PEP 562 facade map is sanctioned). +- `c` (constants) NEVER imports `m`/`t`/`p` (reverse, forbidden); it composes only + from its own leaf base modules (`_constants/base`, …) and the standard library. +- `t` (typings) is pure vocabulary: imports only `c`, the standard library, and + `t`. It NEVER imports `p` or `m`. A composite alias that names a `p.*` lives in + `p`; one that names an `m.*` lives in `m`. +- `p` (protocols) NEVER imports `m` (reverse, forbidden); it bounds generics and + members with `p.BaseModel` and other `p.*`, and imports `t,c` at runtime. +- `u`/`services`/`api` signatures type models by `p.*` protocols (imported at + runtime, `u → p` forward) and pass the concrete `m.*` instance through unchanged. - Internal leaf modules may, in SPECIAL cases and with EXTREME care, import directly from one another to break a cyclic import — escape hatch, never the default. diff --git a/src/flext_cli/base.py b/src/flext_cli/base.py index 3f1a000a8..74d129168 100644 --- a/src/flext_cli/base.py +++ b/src/flext_cli/base.py @@ -9,13 +9,11 @@ from __future__ import annotations -from flext_cli import m, p, t -from flext_core import p, s +from flext_cli import m, t +from flext_core import s -class FlextCliServiceBase[TDomainResult: p.BaseModel = m.Cli.RuntimeStatus]( - s[TDomainResult] -): +class FlextCliServiceBase[TDomainResult = m.Cli.RuntimeStatus](s[TDomainResult]): """Base class for flext-cli services with typed configuration access. Note: This is an abstract base class. Subclasses must implement the diff --git a/tests/unit/test_base.py b/tests/unit/test_base.py index e8045ad2b..0a5bafa44 100644 --- a/tests/unit/test_base.py +++ b/tests/unit/test_base.py @@ -17,11 +17,14 @@ from __future__ import annotations +from typing import override + import pytest +from flext_core import r from flext_tests import tm from pydantic import BaseModel -from flext_cli import FlextCli, cli, settings +from flext_cli import FlextCli, FlextCliServiceBase, cli, p as cli_p, settings from tests import p from tests.base import s @@ -29,6 +32,14 @@ class TestsFlextCliBase: """Verify base-service public guarantees through the CLI facade.""" + class ScalarService(FlextCliServiceBase[str]): + """CLI service returning a scalar through the canonical public base.""" + + @override + def execute(self) -> cli_p.Result[str]: + """Return a successful scalar result.""" + return r[str].ok("ready") + @pytest.fixture def facade(self) -> FlextCli: """Return a fresh instance of the public CLI facade type.""" @@ -40,6 +51,12 @@ def test_facade_instantiates_as_its_own_type(self) -> None: service = tm.not_none(service) tm.that(service, is_=type(cli)) + def test_scalar_service_executes_through_public_base(self) -> None: + """A scalar specialization executes without a model-only upper bound.""" + result = self.ScalarService().execute() + + tm.that(result.unwrap(), eq="ready") + def test_canonical_settings_satisfies_cli_protocol(self) -> None: """The canonical ``settings`` singleton satisfies the Cli settings protocol.""" resolved_settings = tm.not_none(settings) From 5972373783e1d2a770f9d36278652879fa1ed8f1 Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Mon, 20 Jul 2026 12:51:24 -0300 Subject: [PATCH 34/37] chore(baseline): checkpoint WIP for 0.20.0-dev stabilization --- src/flext_cli/services/_cli/flextclicli_part_02.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/flext_cli/services/_cli/flextclicli_part_02.py b/src/flext_cli/services/_cli/flextclicli_part_02.py index ffb48d0cd..d523441eb 100644 --- a/src/flext_cli/services/_cli/flextclicli_part_02.py +++ b/src/flext_cli/services/_cli/flextclicli_part_02.py @@ -38,8 +38,6 @@ def _apply_common_params_to_config(self, *, params: p.Cli.ParamsConfig) -> None: # protocol — the old isinstance guard was dead code (pyright # reportUnnecessaryIsInstance). Settings are flat scalars (§2.6): # field-level diff drives ``update_global`` directly. - if updated_settings is settings: - return overrides: dict[str, t.SettingsOverride | None] = {} if updated_settings.debug != settings.debug: overrides["debug"] = updated_settings.debug From 76786a3cbb8b2fd19ce11597deae51b7202101b0 Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Tue, 21 Jul 2026 12:00:06 -0300 Subject: [PATCH 35/37] chore(lint): zero Ruff lint+format; consistent pyrefly facade suppression - Fix real src bugs (undefined names, dup p-imports, MappingProxyType import, dup __all__, over-indent, dup class field) and restore flext_cli _utilities/env (0.20.0-dev referenced a deleted module) - Fix undefined-name in tests by importing the used facade (p/m/t/settings) - Bound tests/** per-file-ignores in flext-infra tooling SSOT; make the modernizer authoritative over stale pyproject per-file-ignores - Move pyrefly missing-attribute/-module-attribute to disabled-errors to match mypy attr-defined and pyright reportAttributeAccessIssue (lazy-facade limit) - Regenerate managed pyproject/base.mk/.gitignore/Makefiles --- .gitignore | 36 +- examples/_models_parts/examples_advanced.py | 2 +- examples/_models_parts/examples_common.py | 2 +- examples/_models_parts/examples_database.py | 2 +- examples/constants.py | 4 +- examples/ex_04_file_operations.py | 1 - examples/protocols.py | 2 +- examples/utilities.py | 1 - pyproject.toml | 574 +++++++++++------- src/flext_cli/_config.py | 2 +- src/flext_cli/_constants/base.py | 3 +- src/flext_cli/_constants/files.py | 3 +- src/flext_cli/_constants/pipeline.py | 3 +- src/flext_cli/_models/_xlx/xlsx_archive.py | 2 +- src/flext_cli/_models/_xlx/xlsx_cells.py | 7 +- src/flext_cli/_models/_xlx/xlsx_layout.py | 3 +- src/flext_cli/_models/_xlx/xlsx_rules.py | 3 +- src/flext_cli/_models/_xlx/xlsx_snapshot.py | 3 +- .../_models/_xlx/xlsx_style_catalog.py | 3 +- .../_models/_xlx/xlsx_style_fills.py | 3 +- src/flext_cli/_models/_xlx/xlsx_tables.py | 3 +- src/flext_cli/_models/_xlx/xlsx_validation.py | 3 +- src/flext_cli/_models/_xlx/xlsx_workbook.py | 7 +- src/flext_cli/_models/docx_document.py | 3 +- src/flext_cli/_models/pipeline.py | 4 +- src/flext_cli/_models/rules.py | 2 +- src/flext_cli/_models/template.py | 2 +- src/flext_cli/_models/toml.py | 3 +- .../_base/flextcliprotocolsbase_part_03.py | 5 +- .../_base/flextcliprotocolsbase_part_05.py | 2 +- src/flext_cli/_protocols/_xlx/xlsx_archive.py | 2 +- .../_protocols/_xlx/xlsx_snapshot.py | 3 +- .../_protocols/_xlx/xlsx_workbook.py | 11 +- src/flext_cli/_protocols/domain.py | 5 +- src/flext_cli/_protocols/framework.py | 2 +- src/flext_cli/_protocols/pipeline.py | 10 +- src/flext_cli/_protocols/toml.py | 8 +- src/flext_cli/_protocols/xlsx.py | 5 +- src/flext_cli/_utilities/_cli_namespace.py | 2 +- src/flext_cli/_utilities/_docx/_reader.py | 2 +- src/flext_cli/_utilities/_docx/_renderer.py | 1 + ...liutilitiesfiletesthelpersmixin_part_03.py | 2 +- ...liutilitiesfiletesthelpersmixin_part_04.py | 2 +- src/flext_cli/_utilities/_json/_core.py | 2 +- src/flext_cli/_utilities/_json/_navigate.py | 3 +- src/flext_cli/_utilities/_pptx/_renderer.py | 3 +- src/flext_cli/_utilities/_rules/_loaders.py | 2 +- src/flext_cli/_utilities/_rules/_matchers.py | 5 +- .../_toml/flextcliutilitiestoml_part_02.py | 3 +- .../_toml/flextcliutilitiestoml_part_03.py | 5 +- .../_toml/flextcliutilitiestoml_part_04.py | 7 +- .../_toml/flextcliutilitiestoml_part_05.py | 2 +- .../_toml/flextcliutilitiestoml_part_06.py | 2 +- .../_toml/flextcliutilitiestoml_part_07.py | 2 +- src/flext_cli/_utilities/_xlxx/xlsx_cells.py | 3 +- .../_utilities/_xlxx/xlsx_conditional.py | 3 +- src/flext_cli/_utilities/_xlxx/xlsx_layout.py | 3 +- .../_utilities/_xlxx/xlsx_protection.py | 3 +- .../_utilities/_xlxx/xlsx_renderer.py | 2 +- src/flext_cli/_utilities/_xlxx/xlsx_rules.py | 2 +- .../_utilities/_xlxx/xlsx_snapshot_sheet.py | 2 +- .../_xlxx/xlsx_snapshot_structure.py | 5 +- .../_utilities/_xlxx/xlsx_snapshot_values.py | 2 +- .../_utilities/_xlxx/xlsx_style_builders.py | 4 +- .../_utilities/_xlxx/xlsx_style_readers.py | 4 +- src/flext_cli/_utilities/_xlxx/xlsx_tables.py | 5 +- .../_utilities/_xlxx/xlsx_validations.py | 3 +- src/flext_cli/_utilities/_yaml/_convert.py | 3 +- src/flext_cli/_utilities/_yaml/_editing.py | 2 +- src/flext_cli/_utilities/_yaml/_engine.py | 2 +- src/flext_cli/_utilities/config.py | 2 +- src/flext_cli/_utilities/env.py | 52 ++ src/flext_cli/_utilities/formatters.py | 3 +- src/flext_cli/_utilities/framework.py | 2 +- src/flext_cli/_utilities/processes.py | 2 +- src/flext_cli/_utilities/validation.py | 6 +- src/flext_cli/_utilities/yaml.py | 2 +- src/flext_cli/api.py | 2 +- src/flext_cli/models.py | 3 +- .../services/_cli/flextclicli_part_01.py | 2 +- .../services/_cli/flextclicli_part_02.py | 2 +- .../services/_cli/flextclicli_part_03.py | 5 +- src/flext_cli/services/_prompts_support.py | 2 +- src/flext_cli/services/file_tools.py | 2 +- src/flext_cli/services/pipeline.py | 2 +- .../testsflextclimodels_part_01.py | 1 - .../testsflextcliservice_part_01.py | 2 +- .../testsflextcliservice_part_02.py | 2 +- .../testsflextcliservice_part_03.py | 2 +- .../testsflextcliservice_part_04.py | 4 +- .../testsflextcliservice_part_05.py | 4 +- .../testsflextcliexamplessmoke_part_01.py | 2 +- .../testsflextcliexamplessmoke_part_02.py | 2 +- .../testsflextcliexamplessmoke_part_04.py | 2 +- .../testsflextclifilescov_part_01.py | 2 +- .../testsflextclifilescov_part_02.py | 2 +- .../testsflextclijsoncov_part_01.py | 1 + .../testsflextclijsoncov_part_02.py | 1 + .../testsflextclioutputcov_part_01.py | 1 + .../testsflextclioutputcov_part_02.py | 1 + .../testsflextclipipeline_part_01.py | 2 +- .../testsflextclipipeline_part_02.py | 2 +- .../testsflextclipipeline_part_03.py | 2 +- .../testsflextcliprompts_part_01.py | 1 + .../testsflextcliprompts_part_02.py | 1 + ...flextclipubliccontractscoverage_part_01.py | 2 +- ...flextclipubliccontractscoverage_part_02.py | 2 +- ...flextclipubliccontractscoverage_part_03.py | 2 +- .../testsflextclirulescov_part_01.py | 1 + .../testsflextclirulescov_part_02.py | 1 + .../testsflextclirulescov_part_03.py | 1 + .../testsflextclirulescov_part_04.py | 1 + .../testsflextclitomlutilities_part_01.py | 1 + .../testsflextclitomlutilities_part_02.py | 1 + .../testsflextclitomlutilities_part_03.py | 1 + tests/unit/test_base.py | 2 +- 116 files changed, 606 insertions(+), 367 deletions(-) create mode 100644 src/flext_cli/_utilities/env.py diff --git a/.gitignore b/.gitignore index 2e528791b..bb604d3bd 100644 --- a/.gitignore +++ b/.gitignore @@ -124,7 +124,6 @@ backup/ .cursorignore .aider* .serena/ -.claude/ .copilot/ .github/copilot-instructions.md *_REPORT*.md @@ -249,11 +248,7 @@ Desktop.ini # ============================================================================ # COMMON PATTERNS: Artifacts inside allowed directories # ============================================================================ -.pytest_cache/ -.mypy_cache/ -.ruff_cache/ .hypothesis/ -.coverage htmlcov/ dist/ build/ @@ -290,7 +285,6 @@ build/ *.temp temp/ staging/ -.cache/ # IDE and editor files .vscode/ @@ -300,7 +294,6 @@ staging/ *~ # Claude AI files -.claude/ .github/*.rej @@ -309,10 +302,39 @@ staging/ !base.mk # --- workspace-sync: required ignores (auto-managed) --- +.agents/ +.beads/ +.benchmarks/ +.cache/ +.claude/ +.code-review-graph/ +.codegraph/ +.coverage +.debug-journal.md .direnv/ +.dolt/ +.dolt_dropped_databases/ +.doltcfg/ +.mcp.json +.mypy_cache/ +.omo/ +.pytest_cache/ .reports/ +.ropeproject/ +.ruff_cache/ +.scope/ +.sisyphus/ +.state/ +.superpowers/ +.trash/ +.turbo/ +.venv.bak/ +.venv.uv3/ .venv/ +CLAUDE.local.md +__pycache__/ base.mk +skill-create-output/ !/config/ !/config/** !/tests/ diff --git a/examples/_models_parts/examples_advanced.py b/examples/_models_parts/examples_advanced.py index 71962ea99..63c10e864 100644 --- a/examples/_models_parts/examples_advanced.py +++ b/examples/_models_parts/examples_advanced.py @@ -4,7 +4,7 @@ from collections.abc import MutableSequence from pathlib import Path -from typing import TYPE_CHECKING, Annotated, ClassVar +from typing import Annotated, ClassVar from examples import c, p, r, t from examples._models_parts.examples_common import ExamplesFlextCliModelsExamplesCommon diff --git a/examples/_models_parts/examples_common.py b/examples/_models_parts/examples_common.py index 82eecaed7..3bdd27729 100644 --- a/examples/_models_parts/examples_common.py +++ b/examples/_models_parts/examples_common.py @@ -7,7 +7,7 @@ from pathlib import Path from typing import Annotated, ClassVar -from examples import c, p, t +from examples import c, t from flext_cli import m, settings, u diff --git a/examples/_models_parts/examples_database.py b/examples/_models_parts/examples_database.py index 6fa71ba42..65f88671a 100644 --- a/examples/_models_parts/examples_database.py +++ b/examples/_models_parts/examples_database.py @@ -6,7 +6,7 @@ from typing import ClassVar from examples import c -from flext_cli import m, p, u +from flext_cli import m, u class ExamplesFlextCliModelsExamplesDatabase: diff --git a/examples/constants.py b/examples/constants.py index 363e64357..c178e6c7d 100644 --- a/examples/constants.py +++ b/examples/constants.py @@ -5,9 +5,9 @@ import re from enum import StrEnum, unique from types import MappingProxyType -from typing import TYPE_CHECKING, Final +from typing import Final -from examples import p, t +from examples import t from flext_cli import c diff --git a/examples/ex_04_file_operations.py b/examples/ex_04_file_operations.py index 362065971..56d35f437 100644 --- a/examples/ex_04_file_operations.py +++ b/examples/ex_04_file_operations.py @@ -9,7 +9,6 @@ from collections.abc import Mapping from pathlib import Path -from typing import TYPE_CHECKING from flext_cli import c, cli, m, p, r, t, u diff --git a/examples/protocols.py b/examples/protocols.py index 88b826dc5..b5cf575f5 100644 --- a/examples/protocols.py +++ b/examples/protocols.py @@ -3,7 +3,7 @@ from __future__ import annotations from collections.abc import Callable -from typing import TYPE_CHECKING, Protocol, runtime_checkable +from typing import Protocol, runtime_checkable from flext_cli import p diff --git a/examples/utilities.py b/examples/utilities.py index c7bc860a1..a730687bb 100644 --- a/examples/utilities.py +++ b/examples/utilities.py @@ -12,7 +12,6 @@ from __future__ import annotations from collections.abc import MutableSequence -from typing import TYPE_CHECKING from examples import c, m, p, t from flext_cli import cli, u diff --git a/pyproject.toml b/pyproject.toml index d737ec8d0..9b2f33967 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ # [MANAGED] build system [build-system] build-backend = "hatchling.build" -requires = [ "hatchling" ] +requires = ["hatchling"] # [CUSTOM] project metadata [project] @@ -19,29 +19,29 @@ classifiers = [ "Typing :: Typed", ] dependencies = [ - "cachetools>=6.2,<7.0", - "click>=8.3.3", - "defusedxml>=0.7.1", - "flext-core @ git+https://github.com/flext-sh/flext-core.git@0.20.0-dev", - "jinja2>=3.1.6", - "jsonschema>=4.26.0", - "openpyxl>=3.1.5", - "pluggy>=1.6.0", - "prompt-toolkit>=3.0.52", - "pydantic-core>=2.46.3", - "pydantic-settings>=2.14.0", - "pydantic>=2.13.3", - "pyyaml>=6.0.3", - "python-docx>=1.1.2", - "python-pptx>=1.0.2", - "rich>=14,<15", - "ruamel.yaml>=0.18.16", - "tabulate>=0.10.0", - "tomlkit>=0.14.0", - "typer>=0.25.1", + "cachetools>=6.2,<7.0", + "click>=8.3.3", + "defusedxml>=0.7.1", + "flext-core @ git+https://github.com/flext-sh/flext-core.git@0.20.0-dev", + "jinja2>=3.1.6", + "jsonschema>=4.26.0", + "openpyxl>=3.1.5", + "pluggy>=1.6.0", + "prompt-toolkit>=3.0.52", + "pydantic-core>=2.46.3", + "pydantic-settings>=2.14.0", + "pydantic>=2.13.3", + "pyyaml>=6.0.3", + "python-docx>=1.1.2", + "python-pptx>=1.0.2", + "rich>=14,<15", + "ruamel.yaml>=0.18.16", + "tabulate>=0.10.0", + "tomlkit>=0.14.0", + "typer>=0.25.1", ] description = "FLEXT CLI - Developer Command Line Interface" -keywords = [ "cli", "command-line", "enterprise", "flext", "tools", "typed" ] +keywords = ["cli", "command-line", "enterprise", "flext", "tools", "typed"] license = "MIT" name = "flext-cli" readme = "README.md" @@ -147,25 +147,33 @@ ignore-words-list = "crate,nd" # [MANAGED] coverage [tool.coverage.report] -exclude_also = [ "if TYPE_CHECKING:", "if _t.TYPE_CHECKING:", "if typing.TYPE_CHECKING:" ] +exclude_also = [ + "if TYPE_CHECKING:", + "if _t.TYPE_CHECKING:", + "if typing.TYPE_CHECKING:", +] fail_under = 15 precision = 2 show_missing = true skip_covered = false [tool.coverage.run] -omit = [ "*/dependency_injector/providers.pyx" ] +omit = ["*/dependency_injector/providers.pyx"] +source = ["src"] # [MANAGED] deptry [tool.deptry] -known_first_party = [ "flext_cli", "flext_core" ] -pep621_dev_dependency_groups = [ "dev" ] +known_first_party = ["flext_cli", "flext_core", "flext_infra"] +pep621_dev_dependency_groups = ["dev"] [tool.flext.docs] project_class = "platform" +[tool.hatch.build.targets.sdist] +only-include = ["src/flext_cli"] + [tool.hatch.build.targets.wheel] -packages = [ "src/flext_cli" ] +packages = ["src/flext_cli"] [tool.hatch.metadata] allow-direct-references = true @@ -182,8 +190,6 @@ allow-direct-references = true # FLEXT mypy[no-any-return]: Facade returns widen to Any only in Mypy; Pyright and Pyrefly resolve them. # FLEXT mypy[no-redef]: Canonical c-t-p-m-u facades intentionally rebind their inherited short alias. # FLEXT mypy[prop-decorator]: Mypy loses Pydantic computed-field descriptors across composed MRO. -# FLEXT mypy[type-var]: Mypy 1.20 drops T from inherited p.ResultLike; the direct owner passes. -# FLEXT mypy[unreachable]: Mypy over-narrows facade values and rejects live defensive guards. # FLEXT mypy[valid-type]: Mypy rejects facade namespaces used as owners in valid PEP 695 aliases. check_untyped_defs = true disable_error_code = [ @@ -196,21 +202,19 @@ disable_error_code = [ "no-any-return", "no-redef", "prop-decorator", - "type-var", - "unreachable", "valid-type", ] -exclude = "^(?:tests|examples|legado)(?:/|$)" +exclude = "^legado(?:/|$)" explicit_package_bases = true extra_checks = true follow_imports = "normal" ignore_missing_imports = true local_partial_types = true -mypy_path = [ ".", "src" ] +mypy_path = [".", "src"] namespace_packages = true no_implicit_reexport = true -overrides = [ ] -plugins = [ "pydantic.mypy", "returns.contrib.mypy.returns_plugin" ] +overrides = [] +plugins = ["pydantic.mypy", "returns.contrib.mypy.returns_plugin"] python_version = "3.13" strict_equality = true warn_redundant_casts = true @@ -230,18 +234,14 @@ warn_untyped_fields = true # [MANAGED] pyrefly [tool.pyrefly] disable-project-excludes-heuristics = true -ignore-errors-in-generated-code = true +ignore-errors-in-generated-code = false project-excludes = [ - "**/*_pb2*.py", - "**/*_pb2_grpc*.py", "**/.venv/**", "**/__pycache__", "**/__pyrefly_virtual__/**", - "**/examples/**", "**/legado/**", "**/node_modules", "**/site-packages/**", - "**/tests/**", "**/typings/**", "**/vendor/**", "**/venv/**", @@ -249,10 +249,10 @@ project-excludes = [ "typings/**", "vendor/**", ] -project-includes = [ "src/**/*.py*" ] +project-includes = ["examples/**/*.py*", "src/**/*.py*", "tests/**/*.py*"] python-interpreter-path = "../.venv/bin/python" python-version = "3.13" -search-path = [ ".", "src" ] +search-path = [".", "../flext-core/src", "src"] use-ignore-files = false [tool.pyrefly.errors] @@ -357,15 +357,13 @@ exclude = [ "**/__pyrefly_virtual__/**", "**/dist-packages", "**/dist-packages/**", - "**/examples", - "**/examples/**", "**/legado", "**/legado/**", "**/node_modules", "**/site-packages", "**/site-packages/**", - "**/tests", - "**/tests/**", + "**/tests/fixtures", + "**/tests/fixtures/**", "**/venv", "**/venv/**", ".git", @@ -373,8 +371,8 @@ exclude = [ ".venv", "vendor", ] -extraPaths = [ ".", "src" ] -include = [ "src" ] +extraPaths = [".", "src"] +include = ["examples", "src", "tests"] pythonPlatform = "Linux" pythonVersion = "3.13" reportArgumentType = "none" @@ -410,7 +408,7 @@ venv = ".venv" venvPath = ".." [[tool.pyright.executionEnvironments]] -extraPaths = [ "src" ] +extraPaths = ["src"] reportAssignmentType = "none" reportAttributeAccessIssue = "none" reportGeneralTypeIssues = "none" @@ -426,28 +424,46 @@ reportUnknownVariableType = "none" reportUnusedImport = "none" root = "src" +[[tool.pyright.executionEnvironments]] +extraPaths = [".", "src"] +reportArgumentType = "none" +reportAssignmentType = "none" +reportAttributeAccessIssue = "none" +reportGeneralTypeIssues = "none" +reportInvalidTypeForm = "none" +reportPrivateImportUsage = "none" +reportPrivateUsage = "none" +reportReturnType = "none" +reportUnknownArgumentType = "none" +reportUnknownLambdaType = "none" +reportUnknownMemberType = "none" +reportUnknownParameterType = "none" +reportUnknownVariableType = "none" +reportUnusedImport = "none" +root = "tests" + +[[tool.pyright.executionEnvironments]] +extraPaths = [".", "src"] +reportArgumentType = "none" +reportAssignmentType = "none" +reportAttributeAccessIssue = "none" +reportGeneralTypeIssues = "none" +reportInvalidTypeForm = "none" +reportPrivateImportUsage = "none" +reportPrivateUsage = "none" +reportReturnType = "none" +reportUnknownArgumentType = "none" +reportUnknownLambdaType = "none" +reportUnknownMemberType = "none" +reportUnknownParameterType = "none" +reportUnknownVariableType = "none" +reportUnusedImport = "none" +root = "examples" + # [MANAGED] pytest [tool.pytest.ini_options] -addopts = [ - "--cov-report=term-missing:skip-covered", - "--cov=.", - "--durations=10", - "--ignore-glob=*/tests/_constants/*", - "--ignore-glob=*/tests/_models/*", - "--ignore-glob=*/tests/_protocols/*", - "--ignore-glob=*/tests/_typings/*", - "--ignore-glob=*/tests/_utilities/*", - "--ignore-glob=*/tests/constants.py", - "--ignore-glob=*/tests/models.py", - "--ignore-glob=*/tests/protocols.py", - "--ignore-glob=*/tests/typings.py", - "--ignore-glob=*/tests/utilities.py", - "--markdown-docs", - "--strict-markers", -] -filterwarnings = [ - "ignore:.*cannot collect test class.*because it has a __init__ constructor.*:pytest.PytestCollectionWarning", -] +addopts = ["--durations=10", "--strict-markers"] +filterwarnings = ["error"] markers = [ "docker: tests requiring Docker", "e2e: end-to-end integration tests", @@ -461,8 +477,9 @@ markers = [ "unit: unit tests", ] minversion = "8.0" -python_classes = [ "Test*" ] -python_files = [ "*_test.py", "*_tests.py", "test_*.py" ] +python_classes = ["Test*"] +python_files = ["*_test.py", "*_tests.py", "test_*.py"] +testpaths = ["tests"] # [MANAGED] ruff [tool.ruff] @@ -478,21 +495,20 @@ exclude = [ "backup", "build", "dist", - "examples", "htmlcov", "legado", "temp-backup", - "tests", "typings", "vendor", "venv", ] -fix = false +fix = true line-length = 88 +namespace-packages = ["tests"] preview = true respect-gitignore = true show-fixes = true -src = [ "src" ] +src = ["examples", "src", "tests"] target-version = "py313" [tool.ruff.format] @@ -504,65 +520,63 @@ skip-magic-trailing-comma = true [tool.ruff.lint] # FLEXT Ruff suppression rationale (validated against semantic facet order): -# FLEXT ruff[I001]: Ruff sorts TYPE_CHECKING imports lexically and reverses the mandatory semantic c-t-p-m-u dependency order in FLEXT facades. -# FLEXT ruff[PLC0415]: Public facade models are imported lazily only at validation and construction sites to preserve the c-t-p-m-u graph and prevent runtime cycles. +# FLEXT ruff[import-outside-top-level]: Public facade models are imported lazily only at validation and construction sites to preserve the c-t-p-m-u graph and prevent runtime cycles. +# FLEXT ruff[unsorted-imports]: Ruff sorts TYPE_CHECKING imports lexically and reverses the mandatory semantic c-t-p-m-u dependency order in FLEXT facades. ignore = [ - "ANN202", - "B009", - "B010", - "B017", - "BLE001", - "C901", - "COM812", - "CPY001", - "D203", - "D213", - "D401", - "D417", - "DOC201", - "DOC202", - "DOC402", - "DOC501", - "DOC502", - "E501", - "ERA001", - "FBT003", - "G004", - "I001", - "N805", - "N813", - "N816", - "PIE790", - "PLC0415", - "PLR0904", - "PLR0911", - "PLR0912", - "PLR0913", - "PLR0914", - "PLR0915", - "PLR0917", - "PLR1702", - "PLR6301", - "PLW0108", - "PLW2901", - "PLW3201", - "PYI042", - "Q000", - "RUF001", - "RUF002", - "RUF003", - "RUF005", - "S608", - "TC001", - "TC002", - "TC003", - "TRY003", - "TRY300", - "TRY301", - "UP040", - "W293", -] -select = [ "ALL" ] + "ambiguous-unicode-character-comment", + "ambiguous-unicode-character-docstring", + "ambiguous-unicode-character-string", + "assert-raises-exception", + "bad-dunder-method-name", + "bad-quotes-inline-string", + "blank-line-with-whitespace", + "blind-except", + "boolean-positional-value-in-call", + "camelcase-imported-as-lowercase", + "collection-literal-concatenation", + "commented-out-code", + "complex-structure", + "docstring-extraneous-exception", + "docstring-extraneous-returns", + "docstring-missing-exception", + "docstring-missing-returns", + "docstring-missing-yields", + "get-attr-with-constant", + "hardcoded-sql-expression", + "incorrect-blank-line-before-class", + "invalid-first-argument-name-for-method", + "line-too-long", + "logging-f-string", + "missing-copyright-notice", + "missing-return-type-private-function", + "missing-trailing-comma", + "mixed-case-variable-in-global-scope", + "multi-line-summary-second-line", + "no-self-use", + "non-imperative-mood", + "non-pep695-type-alias", + "raise-vanilla-args", + "raise-within-try", + "redefined-loop-name", + "set-attr-with-constant", + "snake-case-type-alias", + "too-many-arguments", + "too-many-branches", + "too-many-locals", + "too-many-nested-blocks", + "too-many-positional-arguments", + "too-many-public-methods", + "too-many-return-statements", + "too-many-statements", + "try-consider-else", + "typing-only-first-party-import", + "typing-only-standard-library-import", + "typing-only-third-party-import", + "undocumented-param", + "unnecessary-lambda", + "unnecessary-placeholder", +] +select = ["ALL"] [tool.ruff.lint.flake8-tidy-imports.banned-api.argparse] msg = "Use cli.register_result_command + Pydantic model from flext_cli." @@ -579,96 +593,236 @@ msg = "Use cli.create_app_with_common_params / cli.register_command from flext_c [tool.ruff.lint.isort] combine-as-imports = true force-single-line = false -known-first-party = [ "flext_cli", "flext_core" ] +known-first-party = ["flext_cli", "flext_core", "flext_infra"] split-on-trailing-comma = false [tool.ruff.lint.per-file-ignores] -"**/.vulture_whitelist.py" = [ "ALL" ] -"**/*_pb2*.py" = [ "ALL" ] -"**/*dispatcher*" = [ ] -"**/*docs*" = [ "INP001", "S404", "S603", "T201" ] -"**/*exceptions*" = [ "A001", "S105", "SLF001" ] -"**/*handlers*" = [ ] -"**/*instrumentation*" = [ "C901", "FBT001", "SLF001" ] -"**/*loggings*" = [ "PLR0904", "PLW0603" ] -"**/*middleware*" = [ "ANN401", "FBT001", "FBT002", "PLC2801", "S107" ] -"**/*models*" = [ "ANN401", "FBT001", "PLC2701", "PLR0206", "PLW0603" ] -"**/*oracle*" = [ "DTZ007" ] -"**/*result*" = [ "PLC2701", "SLF001" ] -"**/*runtime*" = [ ] +"**/.vulture_whitelist.py" = ["ALL"] +"**/*_pb2*.py" = ["ALL"] +"**/*dispatcher*" = [] +"**/*docs*" = [ + "implicit-namespace-package", + "print", + "subprocess-without-shell-equals-true", + "suspicious-subprocess-import", +] +"**/*exceptions*" = [ + "builtin-variable-shadowing", + "hardcoded-password-string", + "private-member-access", +] +"**/*handlers*" = ["import-outside-top-level"] +"**/*instrumentation*" = [ + "boolean-type-hint-positional-argument", + "complex-structure", + "private-member-access", +] +"**/*loggings*" = ["global-statement", "too-many-public-methods"] +"**/*middleware*" = [ + "any-type", + "boolean-default-value-positional-argument", + "boolean-type-hint-positional-argument", + "hardcoded-password-default", + "unnecessary-dunder-call", +] +"**/*models*" = [ + "any-type", + "boolean-type-hint-positional-argument", + "global-statement", + "import-private-name", + "property-with-parameters", +] +"**/*oracle*" = ["call-datetime-strptime-without-zone"] +"**/*result*" = ["import-private-name", "private-member-access"] +"**/*runtime*" = [] "**/*scripts*" = [ - "EXE001", - "FIX002", - "INP001", - "PLR0911", - "PLR0912", - "PLR0915", - "PLR2004", - "PLW2901", - "S105", - "S107", - "S404", - "S603", - "T201", - "TID252", -] -"**/*service*" = [ "N815", "PLC2801", "S404", "S603", "SLF001" ] -"**/*subprocess_utils*" = [ "S404", "S603" ] -"**/*typings*" = [ "ANN401" ] -"**/*utilities*" = [ "C901", "E402", "PLC2801", "PLW1510", "S404", "S603" ] + "hardcoded-password-default", + "hardcoded-password-string", + "implicit-namespace-package", + "line-contains-todo", + "magic-value-comparison", + "print", + "redefined-loop-name", + "relative-imports", + "shebang-not-executable", + "subprocess-without-shell-equals-true", + "suspicious-subprocess-import", + "too-many-branches", + "too-many-return-statements", + "too-many-statements", +] +"**/*service*" = [ + "mixed-case-variable-in-class-scope", + "private-member-access", + "subprocess-without-shell-equals-true", + "suspicious-subprocess-import", + "unnecessary-dunder-call", +] +"**/*subprocess_utils*" = [ + "subprocess-without-shell-equals-true", + "suspicious-subprocess-import", +] +"**/*typings*" = ["any-type"] +"**/*utilities*" = [ + "complex-structure", + "module-import-not-at-top-of-file", + "subprocess-run-without-check", + "subprocess-without-shell-equals-true", + "suspicious-subprocess-import", + "unnecessary-dunder-call", +] "**/__init__.py" = [ - "A004", - "ANN401", - "D107", - "F401", - "F403", - "F405", - "F822", - "INP001", - "N999", - "PLC2701", - "RUF067", - "TC004", -] -"**/_config.py" = [ "N802" ] -"**/_constants/*.py" = [ "S105" ] -"**/_protocols/*.py" = [ "N802" ] -"**/_settings.py" = [ "N802" ] -"**/_utilities/parser.py" = [ "ARG004", "FBT001" ] -"**/alert_manager*.py" = [ "S310" ] -"**/constants.py" = [ "S105" ] -"**/container.py" = [ "ANN401", "SLF001" ] -"**/context.py" = [ ] -"**/external_command*.py" = [ "S404", "S603" ] -"**/file_tools.py" = [ "D102" ] -"**/flext_cli/_protocols/framework.py" = [ "A002" ] -"**/flext_cli/_utilities/formatters.py" = [ "TID251" ] -"**/flext_cli/_utilities/framework.py" = [ "A002", "TID251" ] -"**/managers.py" = [ "S105" ] -"**/models.py" = [ "PLC2801", "S102", "S105" ] -"**/orchestrator*.py" = [ "S404", "S603" ] -"**/output.py" = [ "FBT001" ] -"**/plugins/*.py" = [ "FBT001", "FBT002", "S404", "S603", "S607", "TID252" ] -"**/protocol_impls/*.py" = [ "SLF001" ] -"**/providers/*.py" = [ "S106", "S107" ] -"**/services/prompts.py" = [ "D102", "D107" ] -"**/settings.py" = [ "ANN401", "FBT001", "SLF001" ] -"**/singer/*.py" = [ "S404", "S603" ] -"**/tools/*.py" = [ "FBT001", "FBT002", "N802", "S404", "S603", "S607", "T201" ] -"**/tools/**/*.py" = [ "FBT001", "FBT002", "N802", "S404", "S603", "S607", "T201" ] -"**/typings.py" = [ "RUF036" ] -"**/workspace/*.py" = [ "S404", "S603", "S607" ] + "any-type", + "builtin-import-shadowing", + "implicit-namespace-package", + "import-private-name", + "invalid-module-name", + "non-empty-init-module", + "runtime-import-in-type-checking-block", + "undefined-export", + "undefined-local-with-import-star", + "undefined-local-with-import-star-usage", + "undocumented-public-init", + "unused-import", +] +"**/_config.py" = ["invalid-function-name"] +"**/_constants/*.py" = ["hardcoded-password-string"] +"**/_protocols/*.py" = ["invalid-function-name"] +"**/_settings.py" = ["invalid-function-name"] +"**/_utilities/parser.py" = [ + "boolean-type-hint-positional-argument", + "unused-static-method-argument", +] +"**/alert_manager*.py" = ["suspicious-url-open-usage"] +"**/constants.py" = ["hardcoded-password-string"] +"**/container.py" = ["any-type", "private-member-access"] +"**/context.py" = [] +"**/external_command*.py" = [ + "subprocess-without-shell-equals-true", + "suspicious-subprocess-import", +] +"**/file_tools.py" = ["undocumented-public-method"] +"**/flext_cli/_protocols/framework.py" = ["builtin-argument-shadowing"] +"**/flext_cli/_utilities/formatters.py" = ["banned-api"] +"**/flext_cli/_utilities/framework.py" = [ + "banned-api", + "builtin-argument-shadowing", + "import-outside-top-level", +] +"**/managers.py" = ["hardcoded-password-string"] +"**/models.py" = [ + "exec-builtin", + "hardcoded-password-string", + "unnecessary-dunder-call", +] +"**/orchestrator*.py" = [ + "subprocess-without-shell-equals-true", + "suspicious-subprocess-import", +] +"**/output.py" = ["boolean-type-hint-positional-argument"] +"**/plugins/*.py" = [ + "boolean-default-value-positional-argument", + "boolean-type-hint-positional-argument", + "relative-imports", + "start-process-with-partial-path", + "subprocess-without-shell-equals-true", + "suspicious-subprocess-import", +] +"**/protocol_impls/*.py" = ["private-member-access"] +"**/providers/*.py" = [ + "hardcoded-password-default", + "hardcoded-password-func-arg", +] +"**/services/prompts.py" = [ + "undocumented-public-init", + "undocumented-public-method", +] +"**/settings.py" = [ + "any-type", + "boolean-type-hint-positional-argument", + "private-member-access", +] +"**/singer/*.py" = [ + "subprocess-without-shell-equals-true", + "suspicious-subprocess-import", +] +"**/tools/*.py" = [ + "boolean-default-value-positional-argument", + "boolean-type-hint-positional-argument", + "invalid-function-name", + "print", + "start-process-with-partial-path", + "subprocess-without-shell-equals-true", + "suspicious-subprocess-import", +] +"**/tools/**/*.py" = [ + "boolean-default-value-positional-argument", + "boolean-type-hint-positional-argument", + "invalid-function-name", + "print", + "start-process-with-partial-path", + "subprocess-without-shell-equals-true", + "suspicious-subprocess-import", +] +"**/typings.py" = ["none-not-at-end-of-union"] +"**/workspace/*.py" = [ + "start-process-with-partial-path", + "subprocess-without-shell-equals-true", + "suspicious-subprocess-import", +] +"**/rope_patch/*.py" = ["private-member-access"] +"**/tests/**/*.py" = [ + "assert", + "boolean-positional-value-in-call", + "boolean-type-hint-positional-argument", + "compare-to-empty-string", + "constant-imported-as-non-constant", + "f-string-in-exception", + "hardcoded-bind-all-interfaces", + "hardcoded-password-default", + "hardcoded-password-func-arg", + "hardcoded-password-string", + "hardcoded-temp-file", + "import-outside-top-level", + "import-private-name", + "line-contains-todo", + "magic-value-comparison", + "private-member-access", + "pytest-raises-too-broad", + "suppressible-exception", + "too-many-blank-lines", + "undocumented-public-class", + "undocumented-public-function", + "undocumented-public-method", + "undocumented-public-module", + "unused-function-argument", + "unused-lambda-argument", + "unused-method-argument", +] +"**/conftest.py" = [ + "undocumented-public-function", + "undocumented-public-method", + "unused-function-argument", + "unused-method-argument", +] +"**/handler.py" = ["import-outside-top-level"] + +[tool.ruff.lint.pydoclint] +ignore-one-line-docstrings = true + +[tool.ruff.lint.pydocstyle] +convention = "google" # [MANAGED] tomlsort [tool.tomlsort] all = true in_place = true -sort_first = [ "build-system", "dependency-groups", "project", "tool" ] +sort_first = ["build-system", "dependency-groups", "project", "tool"] [tool.vulture] -exclude = [ "*/_protocols/*" ] +exclude = ["*/_protocols/*"] min_confidence = 100 -paths = [ "src" ] +paths = ["examples", "src", "tests"] verbose = false # [MANAGED] yamlfix diff --git a/src/flext_cli/_config.py b/src/flext_cli/_config.py index 361c27be2..e7d49c891 100644 --- a/src/flext_cli/_config.py +++ b/src/flext_cli/_config.py @@ -14,7 +14,7 @@ from functools import cached_property from pathlib import Path -from typing import ClassVar, TYPE_CHECKING +from typing import TYPE_CHECKING, ClassVar from flext_cli._models.config import FlextCliConfigModels diff --git a/src/flext_cli/_constants/base.py b/src/flext_cli/_constants/base.py index f73120bbf..60453fc40 100644 --- a/src/flext_cli/_constants/base.py +++ b/src/flext_cli/_constants/base.py @@ -8,8 +8,7 @@ from __future__ import annotations import re -from typing import ClassVar, Final, TYPE_CHECKING - +from typing import TYPE_CHECKING, ClassVar, Final if TYPE_CHECKING: from flext_core import t diff --git a/src/flext_cli/_constants/files.py b/src/flext_cli/_constants/files.py index 41c7e1d3b..e7ecc3fb0 100644 --- a/src/flext_cli/_constants/files.py +++ b/src/flext_cli/_constants/files.py @@ -8,8 +8,7 @@ from enum import StrEnum, unique from types import MappingProxyType -from typing import Final, TYPE_CHECKING - +from typing import TYPE_CHECKING, Final if TYPE_CHECKING: from flext_core import t diff --git a/src/flext_cli/_constants/pipeline.py b/src/flext_cli/_constants/pipeline.py index ab490b508..3ec574ae7 100644 --- a/src/flext_cli/_constants/pipeline.py +++ b/src/flext_cli/_constants/pipeline.py @@ -2,8 +2,7 @@ from __future__ import annotations -from typing import Final, TYPE_CHECKING - +from typing import TYPE_CHECKING, Final if TYPE_CHECKING: from flext_core import t diff --git a/src/flext_cli/_models/_xlx/xlsx_archive.py b/src/flext_cli/_models/_xlx/xlsx_archive.py index 635ea4908..090d5b551 100644 --- a/src/flext_cli/_models/_xlx/xlsx_archive.py +++ b/src/flext_cli/_models/_xlx/xlsx_archive.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Annotated, TYPE_CHECKING +from typing import TYPE_CHECKING, Annotated # mro-j47u (kimi): models consume the local t facade; m -> t is forward at runtime. from flext_core import m diff --git a/src/flext_cli/_models/_xlx/xlsx_cells.py b/src/flext_cli/_models/_xlx/xlsx_cells.py index a53b59db1..0c0ee81ea 100644 --- a/src/flext_cli/_models/_xlx/xlsx_cells.py +++ b/src/flext_cli/_models/_xlx/xlsx_cells.py @@ -2,14 +2,15 @@ from __future__ import annotations -from typing import Annotated, Literal, TYPE_CHECKING +from typing import TYPE_CHECKING, Annotated, Literal from flext_core import m if TYPE_CHECKING: - from flext_cli import t - from decimal import Decimal import datetime as dt + from decimal import Decimal + + from flext_cli import t class FlextCliModelsXlsxCells: diff --git a/src/flext_cli/_models/_xlx/xlsx_layout.py b/src/flext_cli/_models/_xlx/xlsx_layout.py index 8fa5efcaa..54f4330a6 100644 --- a/src/flext_cli/_models/_xlx/xlsx_layout.py +++ b/src/flext_cli/_models/_xlx/xlsx_layout.py @@ -2,11 +2,10 @@ from __future__ import annotations -from typing import Annotated, Literal, TYPE_CHECKING +from typing import TYPE_CHECKING, Annotated, Literal from flext_core import m - if TYPE_CHECKING: from .xlsx_cells import FlextCliModelsXlsxCells diff --git a/src/flext_cli/_models/_xlx/xlsx_rules.py b/src/flext_cli/_models/_xlx/xlsx_rules.py index 21b5b1e50..c209fd969 100644 --- a/src/flext_cli/_models/_xlx/xlsx_rules.py +++ b/src/flext_cli/_models/_xlx/xlsx_rules.py @@ -2,11 +2,10 @@ from __future__ import annotations -from typing import Annotated, Literal, TYPE_CHECKING +from typing import TYPE_CHECKING, Annotated, Literal from flext_core import m - if TYPE_CHECKING: from .xlsx_cells import FlextCliModelsXlsxCells from .xlsx_validation import FlextCliModelsXlsxValidation diff --git a/src/flext_cli/_models/_xlx/xlsx_snapshot.py b/src/flext_cli/_models/_xlx/xlsx_snapshot.py index 3aa988c61..e00622ea0 100644 --- a/src/flext_cli/_models/_xlx/xlsx_snapshot.py +++ b/src/flext_cli/_models/_xlx/xlsx_snapshot.py @@ -2,11 +2,10 @@ from __future__ import annotations -from typing import Annotated, Literal, TYPE_CHECKING +from typing import TYPE_CHECKING, Annotated, Literal from flext_core import m - if TYPE_CHECKING: from .xlsx_cells import FlextCliModelsXlsxCells diff --git a/src/flext_cli/_models/_xlx/xlsx_style_catalog.py b/src/flext_cli/_models/_xlx/xlsx_style_catalog.py index 94a5ef376..7803e4cfd 100644 --- a/src/flext_cli/_models/_xlx/xlsx_style_catalog.py +++ b/src/flext_cli/_models/_xlx/xlsx_style_catalog.py @@ -2,11 +2,10 @@ from __future__ import annotations -from typing import Annotated, TYPE_CHECKING +from typing import TYPE_CHECKING, Annotated from flext_core import m - if TYPE_CHECKING: from .xlsx_styles import FlextCliModelsXlsxStyles diff --git a/src/flext_cli/_models/_xlx/xlsx_style_fills.py b/src/flext_cli/_models/_xlx/xlsx_style_fills.py index 863b0840f..6c7bdcd2e 100644 --- a/src/flext_cli/_models/_xlx/xlsx_style_fills.py +++ b/src/flext_cli/_models/_xlx/xlsx_style_fills.py @@ -2,11 +2,10 @@ from __future__ import annotations -from typing import Annotated, Literal, TYPE_CHECKING +from typing import TYPE_CHECKING, Annotated, Literal from flext_core import m - if TYPE_CHECKING: from .xlsx_style_primitives import FlextCliModelsXlsxStylePrimitives diff --git a/src/flext_cli/_models/_xlx/xlsx_tables.py b/src/flext_cli/_models/_xlx/xlsx_tables.py index 9462118b1..f73da888a 100644 --- a/src/flext_cli/_models/_xlx/xlsx_tables.py +++ b/src/flext_cli/_models/_xlx/xlsx_tables.py @@ -2,11 +2,10 @@ from __future__ import annotations -from typing import Annotated, Literal, TYPE_CHECKING +from typing import TYPE_CHECKING, Annotated, Literal from flext_core import m - if TYPE_CHECKING: from .xlsx_cells import FlextCliModelsXlsxCells diff --git a/src/flext_cli/_models/_xlx/xlsx_validation.py b/src/flext_cli/_models/_xlx/xlsx_validation.py index e858659af..01a85f16b 100644 --- a/src/flext_cli/_models/_xlx/xlsx_validation.py +++ b/src/flext_cli/_models/_xlx/xlsx_validation.py @@ -2,11 +2,10 @@ from __future__ import annotations -from typing import Annotated, Literal, TYPE_CHECKING +from typing import TYPE_CHECKING, Annotated, Literal from flext_core import m - if TYPE_CHECKING: from .xlsx_cells import FlextCliModelsXlsxCells diff --git a/src/flext_cli/_models/_xlx/xlsx_workbook.py b/src/flext_cli/_models/_xlx/xlsx_workbook.py index d4ce36cf4..959ed1ac8 100644 --- a/src/flext_cli/_models/_xlx/xlsx_workbook.py +++ b/src/flext_cli/_models/_xlx/xlsx_workbook.py @@ -2,17 +2,16 @@ from __future__ import annotations -from typing import Annotated, TYPE_CHECKING +from typing import TYPE_CHECKING, Annotated from flext_core import m - if TYPE_CHECKING: from .xlsx_cells import FlextCliModelsXlsxCells - from .xlsx_tables import FlextCliModelsXlsxTables from .xlsx_layout import FlextCliModelsXlsxLayout - from .xlsx_styles import FlextCliModelsXlsxStyles from .xlsx_rules import FlextCliModelsXlsxRules + from .xlsx_styles import FlextCliModelsXlsxStyles + from .xlsx_tables import FlextCliModelsXlsxTables class FlextCliModelsXlsxWorkbook: diff --git a/src/flext_cli/_models/docx_document.py b/src/flext_cli/_models/docx_document.py index 545ce85cb..8773c184f 100644 --- a/src/flext_cli/_models/docx_document.py +++ b/src/flext_cli/_models/docx_document.py @@ -2,8 +2,9 @@ from __future__ import annotations -from typing import Annotated from types import MappingProxyType +from typing import Annotated + from flext_cli import t from flext_core import m diff --git a/src/flext_cli/_models/pipeline.py b/src/flext_cli/_models/pipeline.py index 0f66fa371..f56e41c2e 100644 --- a/src/flext_cli/_models/pipeline.py +++ b/src/flext_cli/_models/pipeline.py @@ -2,13 +2,13 @@ from __future__ import annotations +from collections.abc import Callable +from pathlib import Path from types import MappingProxyType from typing import Annotated, ClassVar from flext_cli import c, p, t from flext_core import m, u -from pathlib import Path -from collections.abc import Callable class FlextCliModelsPipeline: diff --git a/src/flext_cli/_models/rules.py b/src/flext_cli/_models/rules.py index 0f06f986a..cb04efb25 100644 --- a/src/flext_cli/_models/rules.py +++ b/src/flext_cli/_models/rules.py @@ -2,11 +2,11 @@ from __future__ import annotations +from pathlib import Path from typing import Annotated from flext_cli import c, t from flext_core import m -from pathlib import Path class FlextCliModelsRules: diff --git a/src/flext_cli/_models/template.py b/src/flext_cli/_models/template.py index 2b97e69dc..2b90eb2af 100644 --- a/src/flext_cli/_models/template.py +++ b/src/flext_cli/_models/template.py @@ -10,10 +10,10 @@ from __future__ import annotations +from pathlib import Path from typing import Annotated from flext_core import m -from pathlib import Path class FlextCliModelsTemplate: diff --git a/src/flext_cli/_models/toml.py b/src/flext_cli/_models/toml.py index c800257fe..cb70961be 100644 --- a/src/flext_cli/_models/toml.py +++ b/src/flext_cli/_models/toml.py @@ -11,12 +11,13 @@ from __future__ import annotations +from collections.abc import Callable from itertools import chain from typing import Annotated, Literal, Self from flext_cli._constants.enums import FlextCliConstantsEnums as _enum from flext_core import m, t -from collections.abc import Callable + # Pyproject "tool" table name — the default TOML root for tool configuration. _TOOL_TABLE: str = "tool" diff --git a/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_03.py b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_03.py index 9f628da16..bfc95edeb 100644 --- a/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_03.py +++ b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_03.py @@ -6,16 +6,17 @@ from __future__ import annotations -from typing import Protocol, runtime_checkable, TYPE_CHECKING +from typing import TYPE_CHECKING, Protocol, runtime_checkable from flext_cli._protocols._base.flextcliprotocolsbase_part_02 import ( FlextCliProtocolsBase as FlextCliProtocolsBasePart02, ) if TYPE_CHECKING: - from flext_core import p, t from pathlib import Path + from flext_core import p, t + class FlextCliProtocolsBase(FlextCliProtocolsBasePart02): """Implementation part for FlextCliProtocolsBase.""" diff --git a/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_05.py b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_05.py index e67bd1ab3..ec741f253 100644 --- a/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_05.py +++ b/src/flext_cli/_protocols/_base/flextcliprotocolsbase_part_05.py @@ -6,7 +6,7 @@ from __future__ import annotations -from typing import Protocol, runtime_checkable, TYPE_CHECKING +from typing import TYPE_CHECKING, Protocol, runtime_checkable from flext_cli._protocols._base.flextcliprotocolsbase_part_04 import ( FlextCliProtocolsBase as FlextCliProtocolsBasePart04, diff --git a/src/flext_cli/_protocols/_xlx/xlsx_archive.py b/src/flext_cli/_protocols/_xlx/xlsx_archive.py index 4d635c6ee..cf386a9f4 100644 --- a/src/flext_cli/_protocols/_xlx/xlsx_archive.py +++ b/src/flext_cli/_protocols/_xlx/xlsx_archive.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Protocol, Self, overload, runtime_checkable, TYPE_CHECKING +from typing import TYPE_CHECKING, Protocol, Self, overload, runtime_checkable if TYPE_CHECKING: from collections.abc import Iterator, Sequence diff --git a/src/flext_cli/_protocols/_xlx/xlsx_snapshot.py b/src/flext_cli/_protocols/_xlx/xlsx_snapshot.py index 9644493fa..80a9a30d3 100644 --- a/src/flext_cli/_protocols/_xlx/xlsx_snapshot.py +++ b/src/flext_cli/_protocols/_xlx/xlsx_snapshot.py @@ -2,8 +2,7 @@ from __future__ import annotations -from typing import Protocol, runtime_checkable, TYPE_CHECKING - +from typing import TYPE_CHECKING, Protocol, runtime_checkable from .xlsx_snapshot_structure import FlextCliProtocolsXlsxSnapshotStructure diff --git a/src/flext_cli/_protocols/_xlx/xlsx_workbook.py b/src/flext_cli/_protocols/_xlx/xlsx_workbook.py index a8871ace7..7591e475d 100644 --- a/src/flext_cli/_protocols/_xlx/xlsx_workbook.py +++ b/src/flext_cli/_protocols/_xlx/xlsx_workbook.py @@ -2,14 +2,15 @@ from __future__ import annotations -from typing import Protocol, runtime_checkable, TYPE_CHECKING - +from typing import TYPE_CHECKING, Protocol, runtime_checkable if TYPE_CHECKING: - from .xlsx_rules import FlextCliProtocolsXlsxRules - from flext_cli import t - from io import BytesIO from collections.abc import Iterable, Sequence + from io import BytesIO + + from flext_cli import t + + from .xlsx_rules import FlextCliProtocolsXlsxRules class FlextCliProtocolsXlsxWorkbook: diff --git a/src/flext_cli/_protocols/domain.py b/src/flext_cli/_protocols/domain.py index 117e37441..6d94981d6 100644 --- a/src/flext_cli/_protocols/domain.py +++ b/src/flext_cli/_protocols/domain.py @@ -2,14 +2,15 @@ from __future__ import annotations -from typing import Protocol, runtime_checkable, TYPE_CHECKING +from typing import TYPE_CHECKING, Protocol, runtime_checkable from flext_cli import t if TYPE_CHECKING: - from flext_cli._protocols.base import FlextCliProtocolsBase from pathlib import Path + from flext_cli._protocols.base import FlextCliProtocolsBase + class FlextCliProtocolsDomain: """CLI domain protocols layered on top of base callable contracts.""" diff --git a/src/flext_cli/_protocols/framework.py b/src/flext_cli/_protocols/framework.py index d85e0d72e..1a3518372 100644 --- a/src/flext_cli/_protocols/framework.py +++ b/src/flext_cli/_protocols/framework.py @@ -3,7 +3,7 @@ from __future__ import annotations from collections.abc import Callable -from typing import Protocol, runtime_checkable, TYPE_CHECKING +from typing import TYPE_CHECKING, Protocol, runtime_checkable # mro-j47u (codex): consume the earlier local t facade through the package root. from flext_cli import t diff --git a/src/flext_cli/_protocols/pipeline.py b/src/flext_cli/_protocols/pipeline.py index d7d466fc3..6735de62e 100644 --- a/src/flext_cli/_protocols/pipeline.py +++ b/src/flext_cli/_protocols/pipeline.py @@ -2,14 +2,14 @@ from __future__ import annotations -from typing import Protocol, runtime_checkable, TYPE_CHECKING - +from typing import TYPE_CHECKING, Protocol, runtime_checkable if TYPE_CHECKING: - from flext_core import p, t - from flext_cli._constants.enums import FlextCliConstantsEnums as ce - from pathlib import Path from collections.abc import Callable + from pathlib import Path + + from flext_cli._constants.enums import FlextCliConstantsEnums as ce + from flext_core import p, t class FlextCliProtocolsPipeline: diff --git a/src/flext_cli/_protocols/toml.py b/src/flext_cli/_protocols/toml.py index 94798315b..522304292 100644 --- a/src/flext_cli/_protocols/toml.py +++ b/src/flext_cli/_protocols/toml.py @@ -10,14 +10,14 @@ from __future__ import annotations -from typing import Protocol, runtime_checkable, TYPE_CHECKING - +from typing import TYPE_CHECKING, Protocol, runtime_checkable if TYPE_CHECKING: - from flext_core import t - from flext_cli._constants.enums import FlextCliConstantsEnums as ce from collections.abc import Callable + from flext_cli._constants.enums import FlextCliConstantsEnums as ce + from flext_core import t + class FlextCliProtocolsToml: """TOML operation protocol namespace (structural; flat in ``p.Cli.Toml*``).""" diff --git a/src/flext_cli/_protocols/xlsx.py b/src/flext_cli/_protocols/xlsx.py index af60f7b32..a787c99e1 100644 --- a/src/flext_cli/_protocols/xlsx.py +++ b/src/flext_cli/_protocols/xlsx.py @@ -2,8 +2,7 @@ from __future__ import annotations -from typing import Protocol, runtime_checkable, TYPE_CHECKING - +from typing import TYPE_CHECKING, Protocol, runtime_checkable from ._xlx.xlsx_archive import FlextCliProtocolsXlsxArchive from ._xlx.xlsx_rules import FlextCliProtocolsXlsxRules @@ -11,8 +10,8 @@ from ._xlx.xlsx_workbook import FlextCliProtocolsXlsxWorkbook if TYPE_CHECKING: - from flext_core import p from flext_cli._typings.xlsx import FlextCliTypesXlsx as tx + from flext_core import p class FlextCliProtocolsXlsx( diff --git a/src/flext_cli/_utilities/_cli_namespace.py b/src/flext_cli/_utilities/_cli_namespace.py index ec077a622..cfd80c508 100644 --- a/src/flext_cli/_utilities/_cli_namespace.py +++ b/src/flext_cli/_utilities/_cli_namespace.py @@ -10,6 +10,7 @@ from flext_cli._utilities.commands import FlextCliUtilitiesCommands from flext_cli._utilities.config import FlextCliUtilitiesConfig from flext_cli._utilities.conversion import FlextCliUtilitiesConversion +from flext_cli._utilities.docx import FlextCliUtilitiesDocx from flext_cli._utilities.env import FlextCliUtilitiesEnv from flext_cli._utilities.file_test_helpers import FlextCliUtilitiesFileTestHelpersMixin from flext_cli._utilities.files import FlextCliUtilitiesFiles @@ -31,7 +32,6 @@ from flext_cli._utilities.toml import FlextCliUtilitiesToml from flext_cli._utilities.validation import FlextCliUtilitiesValidation from flext_cli._utilities.xlsx import FlextCliUtilitiesXlsx -from flext_cli._utilities.docx import FlextCliUtilitiesDocx from flext_cli._utilities.yaml import FlextCliUtilitiesYaml from flext_cli._utilities.yaml_model import FlextCliUtilitiesYamlModel diff --git a/src/flext_cli/_utilities/_docx/_reader.py b/src/flext_cli/_utilities/_docx/_reader.py index 063cd4b46..af65cf241 100644 --- a/src/flext_cli/_utilities/_docx/_reader.py +++ b/src/flext_cli/_utilities/_docx/_reader.py @@ -3,8 +3,8 @@ from __future__ import annotations from io import BytesIO -from typing import Literal, TYPE_CHECKING from types import MappingProxyType +from typing import TYPE_CHECKING, Literal from zipfile import BadZipFile from docx import Document diff --git a/src/flext_cli/_utilities/_docx/_renderer.py b/src/flext_cli/_utilities/_docx/_renderer.py index d698b1e86..0f31b1ef4 100644 --- a/src/flext_cli/_utilities/_docx/_renderer.py +++ b/src/flext_cli/_utilities/_docx/_renderer.py @@ -15,6 +15,7 @@ if TYPE_CHECKING: from collections.abc import Sequence + from docx.text.paragraph import Paragraph, ParagraphFormat from docx.text.run import Font diff --git a/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_03.py b/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_03.py index ad511ad60..2dd482264 100644 --- a/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_03.py +++ b/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_03.py @@ -9,13 +9,13 @@ from __future__ import annotations from collections.abc import Mapping, MutableMapping +from typing import TYPE_CHECKING from flext_cli import c, p, r from flext_cli._utilities._file_test_helper.flextcliutilitiesfiletesthelpersmixin_part_04 import ( FlextCliUtilitiesFileTestHelpersMixin as FlextCliUtilitiesFileTestHelpersMixinPart04, ) from flext_cli._utilities.files import FlextCliUtilitiesFiles -from typing import TYPE_CHECKING if TYPE_CHECKING: from pathlib import Path diff --git a/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_04.py b/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_04.py index 6c21c9b4e..7821dc382 100644 --- a/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_04.py +++ b/src/flext_cli/_utilities/_file_test_helper/flextcliutilitiesfiletesthelpersmixin_part_04.py @@ -8,12 +8,12 @@ from __future__ import annotations +from typing import TYPE_CHECKING from flext_cli import c, p, r from flext_cli._utilities.json import FlextCliUtilitiesJson as uj from flext_cli._utilities.toml import FlextCliUtilitiesToml as ut from flext_cli._utilities.yaml import FlextCliUtilitiesYaml as uy -from typing import TYPE_CHECKING if TYPE_CHECKING: from pathlib import Path diff --git a/src/flext_cli/_utilities/_json/_core.py b/src/flext_cli/_utilities/_json/_core.py index f32f12e24..c373ee40a 100644 --- a/src/flext_cli/_utilities/_json/_core.py +++ b/src/flext_cli/_utilities/_json/_core.py @@ -13,7 +13,7 @@ from collections.abc import Mapping, Sequence from types import MappingProxyType -from typing import ClassVar, TYPE_CHECKING +from typing import TYPE_CHECKING, ClassVar from flext_cli import c, m, p, r, t from flext_core import u diff --git a/src/flext_cli/_utilities/_json/_navigate.py b/src/flext_cli/_utilities/_json/_navigate.py index 68ee8cdb2..6b3faf476 100644 --- a/src/flext_cli/_utilities/_json/_navigate.py +++ b/src/flext_cli/_utilities/_json/_navigate.py @@ -10,10 +10,11 @@ from __future__ import annotations +from typing import TYPE_CHECKING + from flext_core import u from ._core import FlextCliUtilitiesJsonCoreMixin -from typing import TYPE_CHECKING if TYPE_CHECKING: from flext_cli import t diff --git a/src/flext_cli/_utilities/_pptx/_renderer.py b/src/flext_cli/_utilities/_pptx/_renderer.py index 99053581b..d35a0216e 100644 --- a/src/flext_cli/_utilities/_pptx/_renderer.py +++ b/src/flext_cli/_utilities/_pptx/_renderer.py @@ -7,9 +7,8 @@ from pptx import Presentation from pptx.presentation import Presentation as PresentationType -from flext_cli._utilities._pptx._serializer import FlextCliUtilitiesPptxSerializer - from flext_cli import c, m, p, r, t +from flext_cli._utilities._pptx._serializer import FlextCliUtilitiesPptxSerializer class FlextCliUtilitiesPptxRenderer: diff --git a/src/flext_cli/_utilities/_rules/_loaders.py b/src/flext_cli/_utilities/_rules/_loaders.py index 0ec5a12d5..327098513 100644 --- a/src/flext_cli/_utilities/_rules/_loaders.py +++ b/src/flext_cli/_utilities/_rules/_loaders.py @@ -11,13 +11,13 @@ from __future__ import annotations +from typing import TYPE_CHECKING from flext_cli import c, m, p, r, t from flext_cli._utilities.json import FlextCliUtilitiesJson as uj from flext_cli._utilities.yaml import FlextCliUtilitiesYaml as uy from ._matchers import FlextCliUtilitiesRulesMatchersMixin -from typing import TYPE_CHECKING if TYPE_CHECKING: from pathlib import Path diff --git a/src/flext_cli/_utilities/_rules/_matchers.py b/src/flext_cli/_utilities/_rules/_matchers.py index 71fdb4888..bbf1f0177 100644 --- a/src/flext_cli/_utilities/_rules/_matchers.py +++ b/src/flext_cli/_utilities/_rules/_matchers.py @@ -13,14 +13,15 @@ import fnmatch from collections.abc import Mapping, MutableSequence +from typing import TYPE_CHECKING from flext_cli._utilities.json import FlextCliUtilitiesJson as uj -from typing import TYPE_CHECKING if TYPE_CHECKING: - from flext_cli import t from pathlib import Path + from flext_cli import t + class FlextCliUtilitiesRulesMatchersMixin: """Declarative rule matcher primitives: filter, resolve, match, validate.""" diff --git a/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_02.py b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_02.py index 457d118e1..4f08c3580 100644 --- a/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_02.py +++ b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_02.py @@ -2,13 +2,12 @@ from __future__ import annotations -from typing import TypeIs, TYPE_CHECKING +from typing import TYPE_CHECKING, TypeIs import tomlkit from tomlkit.items import AoT, Item, Table from tomlkit.toml_document import TOMLDocument - if TYPE_CHECKING: from flext_cli import t diff --git a/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_03.py b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_03.py index ae337e18a..7ceacee66 100644 --- a/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_03.py +++ b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_03.py @@ -3,7 +3,7 @@ from __future__ import annotations from collections.abc import MutableMapping - +from typing import TYPE_CHECKING from flext_cli import t from flext_cli._utilities._toml.flextcliutilitiestoml_part_01 import ( @@ -13,11 +13,10 @@ FlextCliUtilitiesToml as FlextCliUtilitiesTomlPart02, ) from flext_core import u -from typing import TYPE_CHECKING if TYPE_CHECKING: - from tomlkit.toml_document import TOMLDocument from tomlkit.items import Table + from tomlkit.toml_document import TOMLDocument class FlextCliUtilitiesToml: diff --git a/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_04.py b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_04.py index 1c3a2d4b7..72587f383 100644 --- a/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_04.py +++ b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_04.py @@ -2,6 +2,7 @@ from __future__ import annotations +from typing import TYPE_CHECKING from flext_cli._utilities._toml.flextcliutilitiestoml_part_01 import ( FlextCliUtilitiesToml as FlextCliUtilitiesTomlPart01, @@ -10,12 +11,12 @@ FlextCliUtilitiesToml as FlextCliUtilitiesTomlPart03, ) from flext_core import u -from typing import TYPE_CHECKING if TYPE_CHECKING: - from flext_cli import t - from tomlkit.toml_document import TOMLDocument from tomlkit.items import Table + from tomlkit.toml_document import TOMLDocument + + from flext_cli import t class FlextCliUtilitiesToml: diff --git a/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_05.py b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_05.py index 8332759ef..22bdd2efa 100644 --- a/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_05.py +++ b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_05.py @@ -3,6 +3,7 @@ from __future__ import annotations from collections.abc import Mapping +from typing import TYPE_CHECKING from tomlkit.items import Item, Table from tomlkit.toml_document import TOMLDocument @@ -17,7 +18,6 @@ FlextCliUtilitiesToml as FlextCliUtilitiesTomlPart03, ) from flext_core import u -from typing import TYPE_CHECKING if TYPE_CHECKING: from flext_cli import t diff --git a/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_06.py b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_06.py index 75d595254..50237567b 100644 --- a/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_06.py +++ b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_06.py @@ -2,6 +2,7 @@ from __future__ import annotations +from typing import TYPE_CHECKING import tomlkit from tomlkit.toml_document import TOMLDocument @@ -12,7 +13,6 @@ ) from flext_cli._utilities.runtime import FlextCliUtilitiesRuntime as ur from flext_core import u -from typing import TYPE_CHECKING if TYPE_CHECKING: from pathlib import Path diff --git a/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_07.py b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_07.py index a63ed6589..95b15e400 100644 --- a/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_07.py +++ b/src/flext_cli/_utilities/_toml/flextcliutilitiestoml_part_07.py @@ -2,6 +2,7 @@ from __future__ import annotations +from typing import TYPE_CHECKING from flext_cli import c, e, p, r, t from flext_cli._utilities._toml.flextcliutilitiestoml_part_01 import ( @@ -10,7 +11,6 @@ from flext_cli._utilities._toml.flextcliutilitiestoml_part_06 import ( FlextCliUtilitiesToml as FlextCliUtilitiesTomlPart06, ) -from typing import TYPE_CHECKING if TYPE_CHECKING: from pathlib import Path diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_cells.py b/src/flext_cli/_utilities/_xlxx/xlsx_cells.py index 4f068d026..d907e2c32 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_cells.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_cells.py @@ -2,6 +2,8 @@ from __future__ import annotations +from typing import TYPE_CHECKING + from openpyxl.cell.cell import Cell from openpyxl.utils.exceptions import IllegalCharacterError @@ -9,7 +11,6 @@ from flext_cli import c, p, r, t from .xlsx_formula_codec import FlextCliUtilitiesXlsxFormulaCodec -from typing import TYPE_CHECKING if TYPE_CHECKING: from openpyxl.worksheet.worksheet import Worksheet diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_conditional.py b/src/flext_cli/_utilities/_xlxx/xlsx_conditional.py index b6acf9bd3..e56a39333 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_conditional.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_conditional.py @@ -2,6 +2,8 @@ from __future__ import annotations +from typing import TYPE_CHECKING + from openpyxl.cell.cell import Cell from openpyxl.formatting.rule import Rule from openpyxl.styles.differential import DifferentialStyle @@ -14,7 +16,6 @@ from .xlsx_formula_codec import FlextCliUtilitiesXlsxFormulaCodec from .xlsx_style_codec import FlextCliUtilitiesXlsxStyleCodec from .xlsx_validations import FlextCliUtilitiesXlsxValidations -from typing import TYPE_CHECKING if TYPE_CHECKING: from openpyxl.worksheet.worksheet import Worksheet diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_layout.py b/src/flext_cli/_utilities/_xlxx/xlsx_layout.py index 6d99bb8a0..1645bb5a4 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_layout.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_layout.py @@ -2,13 +2,14 @@ from __future__ import annotations +from typing import TYPE_CHECKING + from openpyxl.cell.cell import Cell from openpyxl.comments import Comment from flext_cli import c, p, r, t from .xlsx_addresses import FlextCliUtilitiesXlsxAddresses -from typing import TYPE_CHECKING if TYPE_CHECKING: from openpyxl.worksheet.worksheet import Worksheet diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_protection.py b/src/flext_cli/_utilities/_xlxx/xlsx_protection.py index e5e6da4ba..2f34994e7 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_protection.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_protection.py @@ -2,10 +2,11 @@ from __future__ import annotations +from typing import TYPE_CHECKING + from openpyxl.styles import Protection from flext_cli import c, p, r -from typing import TYPE_CHECKING if TYPE_CHECKING: from openpyxl.worksheet.worksheet import Worksheet diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_renderer.py b/src/flext_cli/_utilities/_xlxx/xlsx_renderer.py index 5bb912f50..538f6151a 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_renderer.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_renderer.py @@ -2,6 +2,7 @@ from __future__ import annotations +from typing import TYPE_CHECKING from flext_cli import c, m, p, r @@ -10,7 +11,6 @@ from .xlsx_rules import FlextCliUtilitiesXlsxRules from .xlsx_tables import FlextCliUtilitiesXlsxTables from .xlsx_workbook_plan import FlextCliUtilitiesXlsxWorkbookPlan -from typing import TYPE_CHECKING if TYPE_CHECKING: from openpyxl import Workbook diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_rules.py b/src/flext_cli/_utilities/_xlxx/xlsx_rules.py index d17e64d58..295dfc970 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_rules.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_rules.py @@ -2,13 +2,13 @@ from __future__ import annotations +from typing import TYPE_CHECKING from flext_cli import p, r from .xlsx_conditional import FlextCliUtilitiesXlsxConditional from .xlsx_protection import FlextCliUtilitiesXlsxProtection from .xlsx_validations import FlextCliUtilitiesXlsxValidations -from typing import TYPE_CHECKING if TYPE_CHECKING: from openpyxl.worksheet.worksheet import Worksheet diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_sheet.py b/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_sheet.py index d75debf6c..f76a4e026 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_sheet.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_sheet.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Literal, TYPE_CHECKING +from typing import TYPE_CHECKING, Literal from pydantic import ValidationError diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_structure.py b/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_structure.py index cc56ff090..f0f9b8917 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_structure.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_structure.py @@ -2,17 +2,18 @@ from __future__ import annotations +from typing import TYPE_CHECKING + from openpyxl.utils.cell import column_index_from_string from openpyxl.workbook.defined_name import DefinedName from openpyxl.worksheet.table import Table from pydantic import ValidationError from flext_cli import m, p, r -from typing import TYPE_CHECKING if TYPE_CHECKING: - from openpyxl.worksheet.worksheet import Worksheet from openpyxl import Workbook + from openpyxl.worksheet.worksheet import Worksheet class FlextCliUtilitiesXlsxSnapshotStructure: diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_values.py b/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_values.py index d7566f9df..1dad609ec 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_values.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_snapshot_values.py @@ -4,12 +4,12 @@ import datetime as dt from decimal import Decimal, InvalidOperation +from typing import TYPE_CHECKING from openpyxl.cell.cell import Cell, MergedCell from pydantic import ValidationError from flext_cli import c, m, p, r, t -from typing import TYPE_CHECKING if TYPE_CHECKING: from openpyxl.worksheet.worksheet import Worksheet diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_style_builders.py b/src/flext_cli/_utilities/_xlxx/xlsx_style_builders.py index cdcf84b7e..8a1724ca2 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_style_builders.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_style_builders.py @@ -2,12 +2,12 @@ from __future__ import annotations +from typing import TYPE_CHECKING + from openpyxl.styles import Alignment, Border, Color, Font, GradientFill, NamedStyle from openpyxl.styles.borders import Side from openpyxl.styles.fills import PatternFill, Stop -from typing import TYPE_CHECKING - if TYPE_CHECKING: from flext_cli import p diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_style_readers.py b/src/flext_cli/_utilities/_xlxx/xlsx_style_readers.py index 54023ba3c..9e9ba0c50 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_style_readers.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_style_readers.py @@ -3,17 +3,17 @@ from __future__ import annotations from copy import copy +from typing import TYPE_CHECKING from openpyxl.styles import Alignment, Border, Color, Font, GradientFill from openpyxl.styles.fills import Fill, PatternFill, Stop from pydantic import ValidationError from flext_cli import m, p, r -from typing import TYPE_CHECKING if TYPE_CHECKING: - from openpyxl.styles.styleable import StyleableObject from openpyxl.styles.borders import Side + from openpyxl.styles.styleable import StyleableObject class FlextCliUtilitiesXlsxStyleReaders: diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_tables.py b/src/flext_cli/_utilities/_xlxx/xlsx_tables.py index 59d0d6e3a..ef6824e1a 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_tables.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_tables.py @@ -2,6 +2,8 @@ from __future__ import annotations +from typing import TYPE_CHECKING + from openpyxl.workbook.defined_name import DefinedName from openpyxl.worksheet.table import Table, TableStyleInfo @@ -9,11 +11,10 @@ from .xlsx_addresses import FlextCliUtilitiesXlsxAddresses from .xlsx_formula_codec import FlextCliUtilitiesXlsxFormulaCodec -from typing import TYPE_CHECKING if TYPE_CHECKING: - from openpyxl.worksheet.worksheet import Worksheet from openpyxl import Workbook + from openpyxl.worksheet.worksheet import Worksheet class FlextCliUtilitiesXlsxTables(FlextCliUtilitiesXlsxAddresses): diff --git a/src/flext_cli/_utilities/_xlxx/xlsx_validations.py b/src/flext_cli/_utilities/_xlxx/xlsx_validations.py index 096dd8ab9..08908c7ff 100644 --- a/src/flext_cli/_utilities/_xlxx/xlsx_validations.py +++ b/src/flext_cli/_utilities/_xlxx/xlsx_validations.py @@ -2,13 +2,14 @@ from __future__ import annotations +from typing import TYPE_CHECKING + from openpyxl.worksheet.datavalidation import DataValidation from flext_cli import c, m, p, r, t from .xlsx_addresses import FlextCliUtilitiesXlsxAddresses from .xlsx_formula_codec import FlextCliUtilitiesXlsxFormulaCodec -from typing import TYPE_CHECKING if TYPE_CHECKING: from openpyxl.worksheet.worksheet import Worksheet diff --git a/src/flext_cli/_utilities/_yaml/_convert.py b/src/flext_cli/_utilities/_yaml/_convert.py index 6291024e4..fe1b145f4 100644 --- a/src/flext_cli/_utilities/_yaml/_convert.py +++ b/src/flext_cli/_utilities/_yaml/_convert.py @@ -15,18 +15,17 @@ from collections.abc import Mapping from typing import ( + TYPE_CHECKING, SupportsFloat, SupportsIndex, SupportsInt, TypeGuard, overload, - TYPE_CHECKING, ) from ruamel.yaml.comments import CommentedMap, CommentedSeq from ruamel.yaml.scalarstring import DoubleQuotedScalarString, LiteralScalarString - if TYPE_CHECKING: from flext_cli import t diff --git a/src/flext_cli/_utilities/_yaml/_editing.py b/src/flext_cli/_utilities/_yaml/_editing.py index 07e052313..5f632b42e 100644 --- a/src/flext_cli/_utilities/_yaml/_editing.py +++ b/src/flext_cli/_utilities/_yaml/_editing.py @@ -17,7 +17,7 @@ import copy from collections.abc import Mapping -from typing import ClassVar, TypeGuard, TYPE_CHECKING +from typing import TYPE_CHECKING, ClassVar, TypeGuard from ruamel.yaml.comments import CommentedMap, CommentedSeq from ruamel.yaml.tokens import CommentToken as RuamelCommentToken diff --git a/src/flext_cli/_utilities/_yaml/_engine.py b/src/flext_cli/_utilities/_yaml/_engine.py index c929d47ae..aa45ae27b 100644 --- a/src/flext_cli/_utilities/_yaml/_engine.py +++ b/src/flext_cli/_utilities/_yaml/_engine.py @@ -22,7 +22,7 @@ from __future__ import annotations import io -from typing import TextIO, TYPE_CHECKING +from typing import TYPE_CHECKING, TextIO import ruamel.yaml from ruamel.yaml.comments import CommentedMap diff --git a/src/flext_cli/_utilities/config.py b/src/flext_cli/_utilities/config.py index ac201ed18..ee6adaf39 100644 --- a/src/flext_cli/_utilities/config.py +++ b/src/flext_cli/_utilities/config.py @@ -13,6 +13,7 @@ from __future__ import annotations import os +from typing import TYPE_CHECKING from jsonschema import Draft202012Validator from jsonschema.exceptions import SchemaError, ValidationError @@ -24,7 +25,6 @@ from flext_cli._utilities.json import FlextCliUtilitiesJson from flext_cli._utilities.yaml import FlextCliUtilitiesYaml from flext_core import u -from typing import TYPE_CHECKING if TYPE_CHECKING: from pathlib import Path diff --git a/src/flext_cli/_utilities/env.py b/src/flext_cli/_utilities/env.py new file mode 100644 index 000000000..4c8fd956c --- /dev/null +++ b/src/flext_cli/_utilities/env.py @@ -0,0 +1,52 @@ +"""Environment reading and interpolation primitives shared through ``u.Cli``.""" + +from __future__ import annotations + +import os +import re + +from flext_cli import p, r + +_VAR_PATTERN = re.compile(r"\$\{([^}]+)\}|\$([A-Za-z_][A-Za-z0-9_]*)") + + +class FlextCliUtilitiesEnv: + """Read and interpolate environment variables, exposed on ``u.Cli``.""" + + @staticmethod + def env_read(name: str) -> p.Result[str]: + """Read one environment variable by ``name`` from the process environment. + + Returns the variable's value, or an empty string when it is unset. Callers + pass the variable name as data (e.g. resolved from configuration) so no + consumer hardcodes a specific environment-variable identity. An empty or + missing variable is a legitimate empty-string state, not a failure; callers + decide whether an empty value is acceptable. + """ + return r[str].ok(os.environ.get(name, "")) + + @staticmethod + def env_expand(template: str) -> p.Result[str]: + """Interpolate ``${VAR}`` / ``$VAR`` / ``${VAR:-default}`` from the environment. + + Substitutes every environment reference in ``template`` with its + process-environment value, honouring ``${VAR:-default}`` fallbacks; an + unset variable without a default resolves to an empty segment. Callers + pass the template (e.g. a product's standard ``${HOME}/.tool`` path + resolved from configuration) as data and receive the absolute string, so + no consumer hardcodes an environment-variable identity. + """ + + def _replace(match: re.Match[str]) -> str: + token = ( + match.group(1) + if match.group(1) is not None + else (match.group(2) or "") + ) + key, _, default = token.partition(":-") + return os.environ.get(key, default) + + return r[str].ok(_VAR_PATTERN.sub(_replace, template)) + + +__all__: list[str] = ["FlextCliUtilitiesEnv"] diff --git a/src/flext_cli/_utilities/formatters.py b/src/flext_cli/_utilities/formatters.py index e1a7edf6c..b831de62d 100644 --- a/src/flext_cli/_utilities/formatters.py +++ b/src/flext_cli/_utilities/formatters.py @@ -2,13 +2,12 @@ from __future__ import annotations -from typing import ClassVar, TYPE_CHECKING +from typing import TYPE_CHECKING, ClassVar from rich.console import Console from rich.panel import Panel from rich.table import Table as RichTable - if TYPE_CHECKING: from flext_cli import p diff --git a/src/flext_cli/_utilities/framework.py b/src/flext_cli/_utilities/framework.py index f4bbc24bb..50df15334 100644 --- a/src/flext_cli/_utilities/framework.py +++ b/src/flext_cli/_utilities/framework.py @@ -6,7 +6,7 @@ from collections.abc import Callable from contextvars import ContextVar from inspect import Parameter -from typing import Never, TYPE_CHECKING +from typing import TYPE_CHECKING, Never import click import typer diff --git a/src/flext_cli/_utilities/processes.py b/src/flext_cli/_utilities/processes.py index a88d5272c..b487f3042 100644 --- a/src/flext_cli/_utilities/processes.py +++ b/src/flext_cli/_utilities/processes.py @@ -6,10 +6,10 @@ import subprocess from pathlib import Path from types import MappingProxyType +from typing import TYPE_CHECKING from flext_cli import c, p, r, t from flext_cli._utilities.runtime import FlextCliUtilitiesRuntime -from typing import TYPE_CHECKING if TYPE_CHECKING: from collections.abc import Mapping diff --git a/src/flext_cli/_utilities/validation.py b/src/flext_cli/_utilities/validation.py index 131105bf3..9fd6673bd 100644 --- a/src/flext_cli/_utilities/validation.py +++ b/src/flext_cli/_utilities/validation.py @@ -2,16 +2,16 @@ from __future__ import annotations -from typing import ClassVar, TYPE_CHECKING - +from typing import TYPE_CHECKING, ClassVar from flext_cli import c, p, r, t from flext_core import u if TYPE_CHECKING: - from pydantic import ValidationError as PydanticValidationError from collections.abc import MutableMapping + from pydantic import ValidationError as PydanticValidationError + class FlextCliUtilitiesValidation: """Validation methods exposed directly on ``u.Cli``.""" diff --git a/src/flext_cli/_utilities/yaml.py b/src/flext_cli/_utilities/yaml.py index c69a7d0c7..c03293a9e 100644 --- a/src/flext_cli/_utilities/yaml.py +++ b/src/flext_cli/_utilities/yaml.py @@ -10,7 +10,7 @@ from __future__ import annotations from types import MappingProxyType -from typing import ClassVar, TYPE_CHECKING +from typing import TYPE_CHECKING, ClassVar from yaml import safe_dump, safe_load diff --git a/src/flext_cli/api.py b/src/flext_cli/api.py index 3f8580b79..940ade535 100644 --- a/src/flext_cli/api.py +++ b/src/flext_cli/api.py @@ -18,8 +18,8 @@ from flext_cli.services.formatters import FlextCliFormatters from flext_cli.services.output import FlextCliOutput from flext_cli.services.pipeline import FlextCliPipeline -from flext_cli.services.prompts import FlextCliPrompts from flext_cli.services.pptx import FlextCliPptx +from flext_cli.services.prompts import FlextCliPrompts from flext_cli.services.rules import FlextCliRules from flext_cli.services.runtime import FlextCliRuntime from flext_cli.services.tables import FlextCliTables diff --git a/src/flext_cli/models.py b/src/flext_cli/models.py index 1ac1cc009..273dd4e21 100644 --- a/src/flext_cli/models.py +++ b/src/flext_cli/models.py @@ -2,6 +2,8 @@ from __future__ import annotations +from typing import TYPE_CHECKING + from flext_cli._models.base import FlextCliModelsBase from flext_cli._models.docx import FlextCliModelsDocx from flext_cli._models.pipeline import FlextCliModelsPipeline @@ -11,7 +13,6 @@ from flext_cli._models.toml import FlextCliModelsToml from flext_cli._models.xlsx import FlextCliModelsXlsx from flext_core import m -from typing import TYPE_CHECKING if TYPE_CHECKING: from flext_cli import t diff --git a/src/flext_cli/services/_cli/flextclicli_part_01.py b/src/flext_cli/services/_cli/flextclicli_part_01.py index 6aa53a37f..ee89c6836 100644 --- a/src/flext_cli/services/_cli/flextclicli_part_01.py +++ b/src/flext_cli/services/_cli/flextclicli_part_01.py @@ -8,9 +8,9 @@ from collections.abc import Mapping, Sequence from inspect import Parameter, Signature +from typing import TYPE_CHECKING from flext_cli import m, p, t, u -from typing import TYPE_CHECKING if TYPE_CHECKING: from types import GenericAlias diff --git a/src/flext_cli/services/_cli/flextclicli_part_02.py b/src/flext_cli/services/_cli/flextclicli_part_02.py index d523441eb..ae28aac89 100644 --- a/src/flext_cli/services/_cli/flextclicli_part_02.py +++ b/src/flext_cli/services/_cli/flextclicli_part_02.py @@ -6,11 +6,11 @@ from __future__ import annotations +from typing import TYPE_CHECKING from flext_cli import m, p, settings, t, u from flext_cli.services._cli.flextclicli_part_01 import FlextCliCli as FlextCliCliPart01 from flext_cli.services.cli_params import FlextCliCommonParams -from typing import TYPE_CHECKING if TYPE_CHECKING: from inspect import Parameter diff --git a/src/flext_cli/services/_cli/flextclicli_part_03.py b/src/flext_cli/services/_cli/flextclicli_part_03.py index dba23f1e7..26391b23b 100644 --- a/src/flext_cli/services/_cli/flextclicli_part_03.py +++ b/src/flext_cli/services/_cli/flextclicli_part_03.py @@ -6,19 +6,20 @@ from __future__ import annotations +from typing import TYPE_CHECKING from flext_cli import c, p, r, t, u # mro-j47u (codex): the earlier MRO part is referenced only by annotation; # inspect.Parameter remains runtime because it constructs the CLI signature. from flext_cli.services._cli.flextclicli_part_02 import FlextCliCli as FlextCliCliPart02 -from typing import TYPE_CHECKING if TYPE_CHECKING: + from inspect import Parameter + from flext_cli.services._cli.flextclicli_part_01 import ( FlextCliCli as FlextCliCliPart01, ) - from inspect import Parameter class FlextCliCli(FlextCliCliPart02): diff --git a/src/flext_cli/services/_prompts_support.py b/src/flext_cli/services/_prompts_support.py index 7a3d8f026..0dccea1c8 100644 --- a/src/flext_cli/services/_prompts_support.py +++ b/src/flext_cli/services/_prompts_support.py @@ -10,7 +10,7 @@ from __future__ import annotations import getpass -from typing import Annotated, Self, TYPE_CHECKING +from typing import TYPE_CHECKING, Annotated, Self from flext_cli import c, m, p, r, s, settings, t, u diff --git a/src/flext_cli/services/file_tools.py b/src/flext_cli/services/file_tools.py index 61a0ad3e1..e2c046964 100644 --- a/src/flext_cli/services/file_tools.py +++ b/src/flext_cli/services/file_tools.py @@ -3,9 +3,9 @@ from __future__ import annotations from pathlib import Path +from typing import TYPE_CHECKING from flext_cli import c, p, r, s, t, u -from typing import TYPE_CHECKING if TYPE_CHECKING: from collections.abc import Sequence diff --git a/src/flext_cli/services/pipeline.py b/src/flext_cli/services/pipeline.py index f077a1b1e..7226592db 100644 --- a/src/flext_cli/services/pipeline.py +++ b/src/flext_cli/services/pipeline.py @@ -2,10 +2,10 @@ from __future__ import annotations +from typing import TYPE_CHECKING from flext_cli import c, m, p, r, s, t from flext_cli._utilities.pipeline import FlextCliUtilitiesPipeline -from typing import TYPE_CHECKING if TYPE_CHECKING: from pathlib import Path diff --git a/tests/_models_parts/testsflextclimodels_part_01.py b/tests/_models_parts/testsflextclimodels_part_01.py index 446dd7122..00e868fa0 100644 --- a/tests/_models_parts/testsflextclimodels_part_01.py +++ b/tests/_models_parts/testsflextclimodels_part_01.py @@ -5,7 +5,6 @@ from flext_tests import m from tests._models_parts.tests_cli import TestsFlextCliModelsCli -from tests._models_parts.tests_fixtures import TestsFlextCliModelsFixtures from tests._models_parts.tests_runtime import TestsFlextCliModelsRuntime diff --git a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_01.py b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_01.py index 381e00ce6..43eaf1041 100644 --- a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_01.py +++ b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_01.py @@ -7,9 +7,9 @@ from collections.abc import MutableSequence from flext_tests import tm -from tests import c, m, p, t from flext_cli import cli +from tests import c, m, p, t class TestsFlextCliService: diff --git a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_02.py b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_02.py index 2534cbcb6..a3c4acb42 100644 --- a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_02.py +++ b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_02.py @@ -7,9 +7,9 @@ from collections.abc import MutableSequence from flext_tests import tm -from tests import c, m, p, t from flext_cli import cli +from tests import c, m, p, t class TestsFlextCliService: diff --git a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_03.py b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_03.py index e847158de..f7836f95b 100644 --- a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_03.py +++ b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_03.py @@ -3,9 +3,9 @@ from __future__ import annotations from flext_tests import tm -from tests import c, m from flext_cli import cli, settings +from tests import c, m # NOTE (multi-agent, mro-wkii.19.4): app creation owns the settings singleton. # NOTE (multi-agent, mro-wkii.17 / agent: make_ssot_audit): derive_model tests diff --git a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_04.py b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_04.py index ccc71fd6a..333e19c33 100644 --- a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_04.py +++ b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_04.py @@ -4,11 +4,11 @@ from flext_tests import tm +from flext_cli import cli + # NOTE (multi-agent, mro-wkii.19.4): app creation owns the settings singleton. from tests import m, p, t -from flext_cli import cli - class TestsFlextCliService: """Implementation part for TestsFlextCliService.""" diff --git a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_05.py b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_05.py index 1dec4dbf6..aee345d77 100644 --- a/tests/unit/_cases/test_cli_service/testsflextcliservice_part_05.py +++ b/tests/unit/_cases/test_cli_service/testsflextcliservice_part_05.py @@ -4,12 +4,12 @@ from flext_tests import tm +from flext_cli import cli, r + # NOTE (multi-agent, mro-wkii.19.4): app creation owns the settings singleton. # mro-wkii.17.26 (codex): exercise CLI flows through the public invocation facade. from tests import c, m, p -from flext_cli import cli, r - class TestsFlextCliService: """Implementation part for TestsFlextCliService.""" diff --git a/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_01.py b/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_01.py index 2480ea597..081d1942f 100644 --- a/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_01.py +++ b/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_01.py @@ -14,9 +14,9 @@ validate_and_import_data, ) from flext_tests import tm -from tests import m from flext_cli import cli +from tests import m # NOTE (multi-agent, mro-wkii.17 / agent: make_ssot_audit): file fixtures are # validated models, serialized once at egress and validated once at ingress. diff --git a/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_02.py b/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_02.py index aa6be5fe0..e3f0a58a1 100644 --- a/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_02.py +++ b/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_02.py @@ -14,9 +14,9 @@ validate_and_import_data, ) from flext_tests import tm -from tests import c from flext_cli import cli, settings +from tests import c class TestsFlextCliExamplesSmoke: diff --git a/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_04.py b/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_04.py index 72464df43..98a688e63 100644 --- a/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_04.py +++ b/tests/unit/_cases/test_examples_smoke/testsflextcliexamplessmoke_part_04.py @@ -7,9 +7,9 @@ from examples import DataManagerCLI from flext_tests import r, tm -from tests import p from flext_cli import cli +from tests import p class TestsFlextCliExamplesSmoke: diff --git a/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_01.py b/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_01.py index 458da07be..b5d78601f 100644 --- a/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_01.py +++ b/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_01.py @@ -6,9 +6,9 @@ import pytest from flext_tests import tm -from tests import c, m, t, u from flext_cli import cli +from tests import c, m, t, u class TestsFlextCliFilesCov: diff --git a/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_02.py b/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_02.py index a0f4054fb..7f6e66467 100644 --- a/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_02.py +++ b/tests/unit/_cases/test_files_cov/testsflextclifilescov_part_02.py @@ -5,9 +5,9 @@ from pathlib import Path from flext_tests import tm -from tests import u from flext_cli import cli +from tests import u class TestsFlextCliFilesCov: diff --git a/tests/unit/_cases/test_json_cov/testsflextclijsoncov_part_01.py b/tests/unit/_cases/test_json_cov/testsflextclijsoncov_part_01.py index 20c4374cd..87f2cd3c9 100644 --- a/tests/unit/_cases/test_json_cov/testsflextclijsoncov_part_01.py +++ b/tests/unit/_cases/test_json_cov/testsflextclijsoncov_part_01.py @@ -5,6 +5,7 @@ from pathlib import Path from flext_tests import tm + from tests import m, t, u diff --git a/tests/unit/_cases/test_json_cov/testsflextclijsoncov_part_02.py b/tests/unit/_cases/test_json_cov/testsflextclijsoncov_part_02.py index 7c3401d06..6dba59c8f 100644 --- a/tests/unit/_cases/test_json_cov/testsflextclijsoncov_part_02.py +++ b/tests/unit/_cases/test_json_cov/testsflextclijsoncov_part_02.py @@ -3,6 +3,7 @@ from __future__ import annotations from flext_tests import tm + from tests import u diff --git a/tests/unit/_cases/test_output_cov/testsflextclioutputcov_part_01.py b/tests/unit/_cases/test_output_cov/testsflextclioutputcov_part_01.py index 73bf0df8b..854bd1e8a 100644 --- a/tests/unit/_cases/test_output_cov/testsflextclioutputcov_part_01.py +++ b/tests/unit/_cases/test_output_cov/testsflextclioutputcov_part_01.py @@ -4,6 +4,7 @@ import pytest from flext_tests import tm + from tests import c, u diff --git a/tests/unit/_cases/test_output_cov/testsflextclioutputcov_part_02.py b/tests/unit/_cases/test_output_cov/testsflextclioutputcov_part_02.py index aa6ac86d2..131078f4c 100644 --- a/tests/unit/_cases/test_output_cov/testsflextclioutputcov_part_02.py +++ b/tests/unit/_cases/test_output_cov/testsflextclioutputcov_part_02.py @@ -6,6 +6,7 @@ import pytest from flext_tests import tm + from tests import c, u diff --git a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_01.py b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_01.py index fca84f289..38ff48adb 100644 --- a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_01.py +++ b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_01.py @@ -5,9 +5,9 @@ from pathlib import Path from flext_tests import tm -from tests import c, p, t from flext_cli import cli, r +from tests import c, p, t class TestsFlextCliPipeline: diff --git a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_02.py b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_02.py index 5ce3d5498..b929c36df 100644 --- a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_02.py +++ b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_02.py @@ -5,9 +5,9 @@ from pathlib import Path from flext_tests import tm -from tests import c, p, t from flext_cli import cli, r +from tests import c, p, t class TestsFlextCliPipeline: diff --git a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_03.py b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_03.py index 7fb4862f9..3650bb082 100644 --- a/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_03.py +++ b/tests/unit/_cases/test_pipeline/testsflextclipipeline_part_03.py @@ -5,9 +5,9 @@ from pathlib import Path from flext_tests import tm -from tests import p, t from flext_cli import cli +from tests import p, t # ── Fixtures ──────────────────────────────────────────────────────── diff --git a/tests/unit/_cases/test_prompts/testsflextcliprompts_part_01.py b/tests/unit/_cases/test_prompts/testsflextcliprompts_part_01.py index 08e70237d..b393fffb6 100644 --- a/tests/unit/_cases/test_prompts/testsflextcliprompts_part_01.py +++ b/tests/unit/_cases/test_prompts/testsflextcliprompts_part_01.py @@ -6,6 +6,7 @@ import pytest from flext_tests import tm + from tests import c, p diff --git a/tests/unit/_cases/test_prompts/testsflextcliprompts_part_02.py b/tests/unit/_cases/test_prompts/testsflextcliprompts_part_02.py index bc794f1ed..8782f0290 100644 --- a/tests/unit/_cases/test_prompts/testsflextcliprompts_part_02.py +++ b/tests/unit/_cases/test_prompts/testsflextcliprompts_part_02.py @@ -7,6 +7,7 @@ import pytest from flext_tests import tm + from tests import c, p diff --git a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_01.py b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_01.py index feb1f4d40..b0f717f08 100644 --- a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_01.py +++ b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_01.py @@ -5,9 +5,9 @@ import inspect from flext_tests import tm -from tests import c, p, u from flext_cli import FlextCliSettings, cli, m, settings +from tests import c, p, u class TestsFlextCliPublicContractsCoverage: diff --git a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_02.py b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_02.py index 8a905dca9..bb0e5f2d4 100644 --- a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_02.py +++ b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_02.py @@ -5,9 +5,9 @@ from pathlib import Path from flext_tests import tm -from tests import c, m, p from flext_cli import r +from tests import c, m, p class TestsFlextCliPublicContractsCoverage: diff --git a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_03.py b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_03.py index 2fa3652fb..c23d33509 100644 --- a/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_03.py +++ b/tests/unit/_cases/test_public_contracts_cov/testsflextclipubliccontractscoverage_part_03.py @@ -5,9 +5,9 @@ from pathlib import Path from flext_tests import tm -from tests import c, p from flext_cli import cli, m, r +from tests import c, p class TestsFlextCliPublicContractsCoverage: diff --git a/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_01.py b/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_01.py index ff683bdff..fd80c592a 100644 --- a/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_01.py +++ b/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_01.py @@ -7,6 +7,7 @@ import pytest from flext_tests import tm + from tests import c, t, u diff --git a/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_02.py b/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_02.py index 523a46c6e..bd5f07300 100644 --- a/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_02.py +++ b/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_02.py @@ -6,6 +6,7 @@ from pathlib import Path from flext_tests import tm + from tests import c, u diff --git a/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_03.py b/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_03.py index d78c3d131..63071bdc2 100644 --- a/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_03.py +++ b/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_03.py @@ -7,6 +7,7 @@ import pytest from flext_tests import tm + from tests import c, t, u diff --git a/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_04.py b/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_04.py index aed3c76ca..826f77284 100644 --- a/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_04.py +++ b/tests/unit/_cases/test_rules_cov/testsflextclirulescov_part_04.py @@ -3,6 +3,7 @@ from __future__ import annotations from flext_tests import tm + from tests import c, t, u diff --git a/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_01.py b/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_01.py index 57a54ec3f..9bf6fb4b4 100644 --- a/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_01.py +++ b/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_01.py @@ -9,6 +9,7 @@ from pathlib import Path from flext_tests import tm + from tests import t, u diff --git a/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_02.py b/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_02.py index 0297bc4c2..885f59911 100644 --- a/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_02.py +++ b/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_02.py @@ -3,6 +3,7 @@ from __future__ import annotations from flext_tests import tm + from tests import t, u diff --git a/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_03.py b/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_03.py index 880676bb7..ca436a44a 100644 --- a/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_03.py +++ b/tests/unit/_cases/test_toml_utilities/testsflextclitomlutilities_part_03.py @@ -6,6 +6,7 @@ from pathlib import Path from flext_tests import tm + from tests import t, u diff --git a/tests/unit/test_base.py b/tests/unit/test_base.py index 0a5bafa44..bad40917c 100644 --- a/tests/unit/test_base.py +++ b/tests/unit/test_base.py @@ -20,11 +20,11 @@ from typing import override import pytest -from flext_core import r from flext_tests import tm from pydantic import BaseModel from flext_cli import FlextCli, FlextCliServiceBase, cli, p as cli_p, settings +from flext_core import r from tests import p from tests.base import s From 4b9bb0a1b1e3b0f660eb55b55610e7edee1f660f Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Tue, 21 Jul 2026 12:10:50 -0300 Subject: [PATCH 36/37] chore(pyrefly): disable facade missing-attribute; honor allow-lint-regression - tooling SSOT: move pyrefly missing-attribute/-module-attribute to disabled-errors (lazy PEP 562 facades cannot be modeled statically; matches mypy attr-defined + pyright reportAttributeAccessIssue) - worktree transaction: honor request.allow_lint_regression (theirs' model field was passed by cli_transaction but ours' utility ignored it after the merge) - regenerate managed pyproject.toml across the workspace --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 9b2f33967..5225c7c0c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -300,9 +300,9 @@ invalid-type-var-tuple = "error" invalid-variance = "error" invalid-yield = "error" missing-argument = "error" -missing-attribute = "error" +missing-attribute = false missing-import = "error" -missing-module-attribute = "error" +missing-module-attribute = false missing-override-decorator = "error" missing-source = "error" missing-source-for-stubs = "error" From 78d958cf998c5cd1c2e931cd90d15f0a607728e4 Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Thu, 23 Jul 2026 22:08:04 -0300 Subject: [PATCH 37/37] fixes --- src/flext_cli/_utilities/env.py | 4 +--- tests/unit/test_toml_cov.py | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/flext_cli/_utilities/env.py b/src/flext_cli/_utilities/env.py index 4c8fd956c..5713e84eb 100644 --- a/src/flext_cli/_utilities/env.py +++ b/src/flext_cli/_utilities/env.py @@ -39,9 +39,7 @@ def env_expand(template: str) -> p.Result[str]: def _replace(match: re.Match[str]) -> str: token = ( - match.group(1) - if match.group(1) is not None - else (match.group(2) or "") + match.group(1) if match.group(1) is not None else (match.group(2) or "") ) key, _, default = token.partition(":-") return os.environ.get(key, default) diff --git a/tests/unit/test_toml_cov.py b/tests/unit/test_toml_cov.py index f0fb6dd8f..61fc0653a 100644 --- a/tests/unit/test_toml_cov.py +++ b/tests/unit/test_toml_cov.py @@ -100,9 +100,7 @@ def test_table_child_reads_out_of_order_fragmented_table(self) -> None: doc = tm.not_none(u.Cli.toml_parse_text(fragmented)) project = tm.not_none(u.Cli.toml_table_child(doc, "project")) tm.that(u.Cli.toml_value(project, "name"), eq="demo") - extras = tm.not_none( - u.Cli.toml_table_child(project, "optional-dependencies") - ) + extras = tm.not_none(u.Cli.toml_table_child(project, "optional-dependencies")) tm.that(list(u.Cli.toml_as_string_list(extras["extra"])), eq=["pkg"]) def test_ensure_table_consolidates_out_of_order_table_without_data_loss(