From 25774a652a9cb18d6983e1188d1c683fec2c3b89 Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Tue, 22 Sep 2026 18:10:30 -0300 Subject: [PATCH 1/8] chore(gen): adopt the conformance fixed-point render --- .markdownlintignore | 2 + .prettierignore | 2 + Makefile | 161 ++++++++++++++++------------------ examples/__init__.py | 21 +++-- pyproject.toml | 4 - src/flext_web/__init__.py | 18 ++-- tests/__init__.py | 58 +++++++++--- tests/fixtures/__init__.py | 44 +--------- tests/integration/__init__.py | 44 +--------- tests/unit/__init__.py | 44 +--------- 10 files changed, 152 insertions(+), 246 deletions(-) diff --git a/.markdownlintignore b/.markdownlintignore index ab70feca..2d43de7c 100644 --- a/.markdownlintignore +++ b/.markdownlintignore @@ -34,3 +34,5 @@ target/** docs/knowledge-index.md docs/architecture/communities/README.md docs/architecture/crg-reports/** +docs/api-reference/generated/** +docs/projects/generated/** diff --git a/.prettierignore b/.prettierignore index ab70feca..2d43de7c 100644 --- a/.prettierignore +++ b/.prettierignore @@ -34,3 +34,5 @@ target/** docs/knowledge-index.md docs/architecture/communities/README.md docs/architecture/crg-reports/** +docs/api-reference/generated/** +docs/projects/generated/** diff --git a/Makefile b/Makefile index 1f3afd38..f8e7583f 100644 --- a/Makefile +++ b/Makefile @@ -54,13 +54,13 @@ UV_LINK_MODE := copy # unconsumed variable is ignored. PYTEST_DIAG_ARGS := -rA --durations=0 --tb=long --showlocals PYTEST_REPORT_ARGS := -ra --durations=25 --durations-min=0.001 --tb=short -PYTEST_PROCESS_TIMEOUT_SECONDS := 660 +PYTEST_PROCESS_TIMEOUT_SECONDS := 2460 # mro-99ae: the pytest process inherits a hard wall-clock boundary, so a hung # run is terminated even if the runner itself stalls. PYTEST_BOUNDED = timeout --signal=TERM --kill-after=5s "$(PYTEST_PROCESS_TIMEOUT_SECONDS)s" PYTEST_REPORTS_DIR := .reports/tests override PYTEST_CASE_TIMEOUT_SECONDS := 10 -override PYTEST_RUN_TIMEOUT_SECONDS := 600 +override PYTEST_RUN_TIMEOUT_SECONDS := 2400 override PYTEST_TERMINATION_GRACE_SECONDS := 2 override PYTEST_TIMEOUT_EXIT_CODE := 124 override PYTEST_ENFORCEMENT_PLUGIN := flext_tests_enforcement @@ -84,14 +84,14 @@ override export FLEXT_PYTEST_REPORTS_RAW := $(value PYTEST_REPORTS_DIR) # superproject resolved RUFF_PATHS to the SUPERPROJECT's src/tests, so the # member linted files it does not even contain. With many shared worktrees that # silently validates the wrong tree. -SELF_MAKEFILE := $(abspath $(firstword $(MAKEFILE_LIST))) -MAKEFILE_ROOT := $(patsubst %/,%,$(dir $(SELF_MAKEFILE))) -PROJECT_ROOT := $(MAKEFILE_ROOT) +override SELF_MAKEFILE := $(realpath $(firstword $(MAKEFILE_LIST))) +override MAKEFILE_ROOT := $(patsubst %/,%,$(dir $(SELF_MAKEFILE))) +override PROJECT_ROOT := $(MAKEFILE_ROOT) SETUP_BIN := $(PROJECT_ROOT)/.bin ifeq ($(OS),Windows_NT) -TRACKED_MISE := $(PROJECT_ROOT)/bin/mise.cmd +override TRACKED_MISE := $(PROJECT_ROOT)/bin/mise.cmd else -TRACKED_MISE := $(PROJECT_ROOT)/bin/mise +override TRACKED_MISE := $(PROJECT_ROOT)/bin/mise endif override SETUP_MISE := $(TRACKED_MISE) override export FLEXT_PYTEST_TARGET_RAW := tests @@ -110,18 +110,13 @@ PROJECT_SCRATCH_ROOT := $(HOME)/tmp/.flext-runtime$(patsubst %/,%,$(PROJECT_SCRA TESTMON_DATAFILE := $(PROJECT_STATE_ROOT)/testmon/.testmondata export TESTMON_DATAFILE # === SECTION: REPOSITORY_ROOT isolation (managed) === -# Source: computed (rule: derive from current checkout unless caller overrides) -# Rule: REPOSITORY_ROOT is always derived from the current checkout unless the -# caller passed it on the command line or via an override origin. An inherited -# environment REPOSITORY_ROOT (e.g. a leaked .envrc export from a foreign checkout) -# must never redirect verbs to another working tree. The git queries therefore -# run inside MAKEFILE_ROOT: run from a foreign CWD they would report THAT -# checkout's topology and redirect the verb to the wrong tree. -ifeq ($(filter command line override,$(origin REPOSITORY_ROOT)),) +# Source: physical checkout topology; caller variables cannot select a workspace. ifneq ($(filter standalone,$(MAKE_PROFILE))$(GEN_INIT_ONLY),) -REPOSITORY_ROOT := $(MAKEFILE_ROOT) +override REPOSITORY_ROOT := $(MAKEFILE_ROOT) else -REPOSITORY_ROOT := $(shell cd "$(MAKEFILE_ROOT)" && root=$$(git rev-parse --show-superproject-working-tree 2>/dev/null); if [ -n "$$root" ]; then printf '%s\n' "$$root"; else git rev-parse --show-toplevel 2>/dev/null || printf '%s\n' "$(MAKEFILE_ROOT)"; fi) +override REPOSITORY_ROOT := $(shell cd "$(MAKEFILE_ROOT)" && root=$$(git rev-parse --show-superproject-working-tree) && if [ -n "$$root" ]; then cd "$$root" && pwd -P; else pwd -P; fi) +ifneq ($(.SHELLSTATUS),0) +$(error Cannot resolve the physical workspace for $(MAKEFILE_ROOT)) endif endif # End SECTION: REPOSITORY_ROOT isolation @@ -139,7 +134,7 @@ ifneq ($(.SHELLSTATUS),0) $(error Failed to inspect custom Make targets in $(CUSTOM_MAKEFILE)) endif endif -DOCS_ACTIONS := generate fix audit build validate +DOCS_ACTIONS := generate fix fmt validate audit # End SECTION: verb dispatch # === SECTION: lint/type paths (managed) === @@ -158,16 +153,13 @@ CALLER_VIRTUAL_ENV := $(patsubst %/,%,$(VIRTUAL_ENV)) # === SECTION: profile routing (managed) === # Source: repository topology. workspace has .gitmodules; standalone does not. # Attached members share their Git superproject runtime; standalone owns itself. -RUNTIME_ROOT := $(REPOSITORY_ROOT) +override RUNTIME_ROOT := $(REPOSITORY_ROOT) # End SECTION: profile routing -RUNTIME_VENV := $(RUNTIME_ROOT)/.venv -PROJECT_VENV := $(PROJECT_ROOT)/.venv -FLEXT_INFRA_RUNTIME_ROOT := $(if $(filter $(MAKEFILE_ROOT),$(PROJECT_ROOT)),$(RUNTIME_ROOT),$(MAKEFILE_ROOT)) +override RUNTIME_VENV := $(RUNTIME_ROOT)/.venv ifeq ($(OS),Windows_NT) -RUNTIME_BIN := $(RUNTIME_VENV)/Scripts -RUNTIME_PYTHON := $(RUNTIME_BIN)/python.exe -FLEXT_INFRA_RUNTIME_PYTHON := $(FLEXT_INFRA_RUNTIME_ROOT)/.venv/Scripts/python.exe +override RUNTIME_BIN := $(RUNTIME_VENV)/Scripts +override RUNTIME_PYTHON := $(RUNTIME_BIN)/python.exe NORMALIZED_CALLER_PATH := $(shell cygpath --path "$(CALLER_PATH)") ifneq ($(.SHELLSTATUS),0) $(error cygpath failed to normalize PATH) @@ -178,9 +170,8 @@ $(error cygpath failed to normalize VIRTUAL_ENV) endif CALLER_VIRTUAL_ENV_BIN := $(NORMALIZED_CALLER_VIRTUAL_ENV)/Scripts else -RUNTIME_BIN := $(RUNTIME_VENV)/bin -RUNTIME_PYTHON := $(RUNTIME_BIN)/python -FLEXT_INFRA_RUNTIME_PYTHON := $(FLEXT_INFRA_RUNTIME_ROOT)/.venv/bin/python +override RUNTIME_BIN := $(RUNTIME_VENV)/bin +override RUNTIME_PYTHON := $(RUNTIME_BIN)/python NORMALIZED_CALLER_PATH := $(CALLER_PATH) NORMALIZED_CALLER_VIRTUAL_ENV := $(CALLER_VIRTUAL_ENV) CALLER_VIRTUAL_ENV_BIN := $(NORMALIZED_CALLER_VIRTUAL_ENV)/bin @@ -193,7 +184,7 @@ ifeq ($(SANITIZED_CALLER_PATH),$(CALLER_VIRTUAL_ENV_BIN)) SANITIZED_CALLER_PATH := endif endif -override FLEXT_INFRA_PYTHON := $(FLEXT_INFRA_RUNTIME_PYTHON) +override FLEXT_INFRA_PYTHON := $(RUNTIME_PYTHON) override UV_PROJECT := $(RUNTIME_ROOT) override UV_PROJECT_ENVIRONMENT := $(RUNTIME_VENV) override VIRTUAL_ENV := $(RUNTIME_VENV) @@ -475,24 +466,16 @@ endif # Provisioning is declared once and shared by every profile. A venv records the # exact base interpreter used to create it, so setup replaces it when Mise moves # the configured Python minor line to a newer patch. -# A symlinked RUNTIME_VENV is a BORROWED environment: a linked worktree (a -# lane checkout) shares the primary checkout's environment so the two never -# diverge. Syncing it would rewrite the editable pointers the owner and every -# sibling lane resolve through, so the borrower provisions nothing and the owner -# stays the only writer. SETUP_ENVIRONMENT_RECIPE = set -eu; \ - if [ -L "$(RUNTIME_VENV)" ]; then \ - printf 'setup: borrowed environment %s is owned by another checkout\n' "$(RUNTIME_VENV)"; \ - else \ - desired_python=$$("$(SETUP_MISE)" -C "$(PROJECT_ROOT)" which python); \ - if [ ! -x "$(RUNTIME_PYTHON)" ]; then \ - $(UV) venv --python "$$desired_python" "$(RUNTIME_VENV)"; \ - elif [ "$$(readlink -f "$(RUNTIME_PYTHON)")" != "$$(readlink -f "$$desired_python")" ]; then \ - printf 'setup: replacing environment for Python %s\n' "$$desired_python"; \ - $(UV) venv --clear --python "$$desired_python" "$(RUNTIME_VENV)"; \ - fi; \ - $(UV) sync --project "$(PROJECT_ROOT)" $(UV_SYNC_FLAGS) --link-mode "$(UV_LINK_MODE)"; \ + $(REQUIRE_WORKSPACE_ENVIRONMENT); \ + desired_python=$$("$(SETUP_MISE)" -C "$(PROJECT_ROOT)" which python); \ + if [ ! -x "$(RUNTIME_PYTHON)" ]; then \ + $(UV) venv --python "$$desired_python" "$(RUNTIME_VENV)"; \ + elif [ "$$(readlink -f "$(RUNTIME_PYTHON)")" != "$$(readlink -f "$$desired_python")" ]; then \ + printf 'setup: replacing environment for Python %s\n' "$$desired_python"; \ + $(UV) venv --clear --python "$$desired_python" "$(RUNTIME_VENV)"; \ fi; \ + $(UV) sync --project "$(PROJECT_ROOT)" $(UV_SYNC_FLAGS) --link-mode "$(UV_LINK_MODE)"; \ XDG_DATA_HOME="$${SETUP_DIRENV_XDG_DATA_HOME:?missing persistent direnv data home}" \ "$${SETUP_DIRENV:?missing Mise-resolved direnv executable}" allow "$(PROJECT_ROOT)"; \ for member in $(WORKSPACE_SUBPROJECTS); do \ @@ -501,15 +484,23 @@ SETUP_ENVIRONMENT_RECIPE = set -eu; \ fi; \ done -# A delegated runtime lives in another checkout, so this project has no local -# environment of its own. Generated tooling still addresses the environment by -# its project-local name (`$${workspaceFolder}/.venv`), which must never be -# rewritten into a cross-project relative hop: the link makes that name resolve. -# Linking is provisioning, so a real local environment is never replaced. -BORROW_RUNTIME_VENV_RECIPE = set -eu; \ - if [ ! -e "$(PROJECT_VENV)" ] || [ -L "$(PROJECT_VENV)" ]; then \ - ln -sfn "$(RUNTIME_VENV)" "$(PROJECT_VENV)"; \ - fi +# Reject borrowed environments before bootstrap, activation or custom hooks. +# Members may use their containing workspace, never an unrelated checkout. +REQUIRE_WORKSPACE_ENVIRONMENT = case "$(PROJECT_ROOT)/" in \ + "$(RUNTIME_ROOT)/"*) ;; \ + *) printf 'ERROR: runtime workspace does not contain this project: %s\n' "$(RUNTIME_ROOT)" >&2; exit 2 ;; \ + esac; \ + for environment_path in "$(RUNTIME_VENV)" "$(RUNTIME_BIN)" "$(PROJECT_ROOT)/.venv"; do \ + if [ -L "$$environment_path" ]; then \ + printf 'ERROR: workspace environment must be physical, not a symlink: %s\n' "$$environment_path" >&2; exit 2; \ + fi; \ + done + +.PHONY: _builtin_require_workspace +_builtin_require_workspace: + @$(REQUIRE_WORKSPACE_ENVIRONMENT) + +_bootstrap_setup_tools: _builtin_require_workspace WORKSPACE_ORCHESTRATE = $(UV_RUN) python -m flext_infra workspace orchestrate # Workspace runs include the root project itself: `.` maps to the @@ -520,14 +511,10 @@ SELECTED_PROJECTS := $(DEFAULT_PROJECTS) WORKSPACE_PROJECT_ARGS := $(foreach project,$(SELECTED_PROJECTS),--projects $(project)) DOCS_PROJECT_ARGS := $(foreach project,$(SELECTED_PROJECTS),--projects $(project)) -# A borrowed RUNTIME_VENV keeps the primary editable install. Clearing -# PYTHONPATH would make `make test` in a linked worktree execute that primary -# tree instead of this checkout. Prefer PROJECT_ROOT/src so the Makefile owner -# always wins over the shared editable (terminus T4 / path-purity). # Execute the interpreter provisioned by setup without discovering a project # workspace or creating a dependency-resolution file during a runtime command. UV_RUN := env -u MYPYPATH -u VIRTUAL_ENV -u UV_PROJECT -u PROJECT_ROOT PYTHONPATH="$(PROJECT_ROOT)/src" $(UV) run --no-project --python "$(RUNTIME_PYTHON)" -PROJECT_INFRA_PYTHONPATH ?= $(MAKEFILE_ROOT)/src +override PROJECT_INFRA_PYTHONPATH := $(MAKEFILE_ROOT)/src PROJECT_INFRA_RUN := if [ ! -x "$(FLEXT_INFRA_PYTHON)" ]; then printf 'ERROR: FLEXT_INFRA_PYTHON must name an executable managed Python\n' >&2; exit 2; fi; "$(SETUP_MISE)" -C "$(PROJECT_ROOT)" exec -- env -u PYTHONPATH -u MYPYPATH -u VIRTUAL_ENV -u UV_PROJECT -u UV_PROJECT_ENVIRONMENT PYTHONPATH="$(PROJECT_INFRA_PYTHONPATH)" $(FLEXT_INFRA_PYTHON) PROJECT_FLEXT_INFRA := $(PROJECT_INFRA_RUN) -m flext_infra # Scaffold dev tools live in the validated optional dev @@ -578,7 +565,7 @@ help: $(call RUN_PUBLIC,help) -deps: +deps: _builtin_require_workspace +@direnv exec "$(PROJECT_ROOT)" $(SELF_MAKE) _activated-deps .PHONY: _activated-deps @@ -587,7 +574,7 @@ _activated-deps: _builtin_require_environment $(call RUN_PUBLIC,deps) -build: +build: _builtin_require_workspace +@direnv exec "$(PROJECT_ROOT)" $(SELF_MAKE) _activated-build .PHONY: _activated-build @@ -596,7 +583,7 @@ _activated-build: _builtin_require_environment $(call RUN_PUBLIC,build) -check: +check: _builtin_require_workspace +@direnv exec "$(PROJECT_ROOT)" $(SELF_MAKE) _activated-check .PHONY: _activated-check @@ -605,7 +592,7 @@ _activated-check: _builtin_require_environment $(call RUN_PUBLIC,check) -test: +test: _builtin_require_workspace +@direnv exec "$(PROJECT_ROOT)" $(SELF_MAKE) _activated-test .PHONY: _activated-test @@ -614,7 +601,7 @@ _activated-test: _builtin_require_environment $(call RUN_PUBLIC,test) -fmt: +fmt: _builtin_require_workspace +@direnv exec "$(PROJECT_ROOT)" $(SELF_MAKE) _activated-fmt .PHONY: _activated-fmt @@ -623,7 +610,7 @@ _activated-fmt: _builtin_require_environment $(call RUN_PUBLIC,fmt) -fix: +fix: _builtin_require_workspace +@direnv exec "$(PROJECT_ROOT)" $(SELF_MAKE) _activated-fix .PHONY: _activated-fix @@ -632,7 +619,7 @@ _activated-fix: _builtin_require_environment $(call RUN_PUBLIC,fix) -fix-enforcement: +fix-enforcement: _builtin_require_workspace +@direnv exec "$(PROJECT_ROOT)" $(SELF_MAKE) _activated-fix-enforcement .PHONY: _activated-fix-enforcement @@ -641,7 +628,7 @@ _activated-fix-enforcement: _builtin_require_environment $(call RUN_PUBLIC,fix-enforcement) -audit: +audit: _builtin_require_workspace +@direnv exec "$(PROJECT_ROOT)" $(SELF_MAKE) _activated-audit .PHONY: _activated-audit @@ -650,7 +637,7 @@ _activated-audit: _builtin_require_environment $(call RUN_PUBLIC,audit) -status: +status: _builtin_require_workspace +@direnv exec "$(PROJECT_ROOT)" $(SELF_MAKE) _activated-status .PHONY: _activated-status @@ -659,7 +646,7 @@ _activated-status: _builtin_require_environment $(call RUN_PUBLIC,status) -docs: +docs: _builtin_require_workspace +@direnv exec "$(PROJECT_ROOT)" $(SELF_MAKE) _activated-docs .PHONY: _activated-docs @@ -668,7 +655,7 @@ _activated-docs: _builtin_require_environment $(call RUN_PUBLIC,docs) -clean: +clean: _builtin_require_workspace +@direnv exec "$(PROJECT_ROOT)" $(SELF_MAKE) _activated-clean .PHONY: _activated-clean @@ -677,7 +664,7 @@ _activated-clean: _builtin_require_environment $(call RUN_PUBLIC,clean) -release-plan: +release-plan: _builtin_require_workspace +@direnv exec "$(PROJECT_ROOT)" $(SELF_MAKE) _activated-release-plan .PHONY: _activated-release-plan @@ -686,7 +673,7 @@ _activated-release-plan: _builtin_require_environment $(call RUN_PUBLIC,release-plan) -release-version: +release-version: _builtin_require_workspace +@direnv exec "$(PROJECT_ROOT)" $(SELF_MAKE) _activated-release-version .PHONY: _activated-release-version @@ -695,7 +682,7 @@ _activated-release-version: _builtin_require_environment $(call RUN_PUBLIC,release-version) -release-tag: +release-tag: _builtin_require_workspace +@direnv exec "$(PROJECT_ROOT)" $(SELF_MAKE) _activated-release-tag .PHONY: _activated-release-tag @@ -704,7 +691,7 @@ _activated-release-tag: _builtin_require_environment $(call RUN_PUBLIC,release-tag) -release-build: +release-build: _builtin_require_workspace +@direnv exec "$(PROJECT_ROOT)" $(SELF_MAKE) _activated-release-build .PHONY: _activated-release-build @@ -713,7 +700,7 @@ _activated-release-build: _builtin_require_environment $(call RUN_PUBLIC,release-build) -publication: +publication: _builtin_require_workspace +@direnv exec "$(PROJECT_ROOT)" $(SELF_MAKE) _activated-publication .PHONY: _activated-publication @@ -722,7 +709,7 @@ _activated-publication: _builtin_require_environment $(call RUN_PUBLIC,publication) -gen: +gen: _builtin_require_workspace +@direnv exec "$(PROJECT_ROOT)" $(SELF_MAKE) _activated-gen .PHONY: _activated-gen @@ -731,7 +718,7 @@ _activated-gen: _builtin_require_environment $(call RUN_PUBLIC,gen) -initialize: +initialize: _builtin_require_workspace +@direnv exec "$(PROJECT_ROOT)" $(SELF_MAKE) _activated-initialize .PHONY: _activated-initialize @@ -740,7 +727,7 @@ _activated-initialize: _builtin_require_environment $(call RUN_PUBLIC,initialize) -mod: +mod: _builtin_require_workspace +@direnv exec "$(PROJECT_ROOT)" $(SELF_MAKE) _activated-mod .PHONY: _activated-mod @@ -749,7 +736,7 @@ _activated-mod: _builtin_require_environment $(call RUN_PUBLIC,mod) -waza: +waza: _builtin_require_workspace +@direnv exec "$(PROJECT_ROOT)" $(SELF_MAKE) _activated-waza .PHONY: _activated-waza @@ -758,7 +745,7 @@ _activated-waza: _builtin_require_environment $(call RUN_PUBLIC,waza) -duplication: +duplication: _builtin_require_workspace +@direnv exec "$(PROJECT_ROOT)" $(SELF_MAKE) _activated-duplication .PHONY: _activated-duplication @@ -818,7 +805,7 @@ _builtin-help: @printf ' %-16s %s\n' 'status' 'Report the resolved runtime and repository state.'; - @printf ' %-16s %s\n' 'docs' 'Generate, repair, build, and validate documentation.'; + @printf ' %-16s %s\n' 'docs' 'Generate, fix, format, and check documentation.'; @printf ' %-16s %s\n' 'clean' 'Remove every declared disposable artifact.'; @@ -981,7 +968,7 @@ _builtin_setup_submodules: validate_submodule "$$root" "$$child_path"; \ done -_builtin_require_environment: +_builtin_require_environment: _builtin_require_workspace # Documenting the interface (`make help`) must not require the interpreter it # tells the operator how to provision. Only `make help` with no other goal # skips the check; any combined goal still demands the environment. @@ -1026,7 +1013,7 @@ _builtin_deps_upgrade: _builtin_require_environment set --; \ for project in $$selected; do set -- "$$@" --projects "$$project"; done; \ $(PROJECT_FLEXT_INFRA) deps modernize --repository-root "$(PROJECT_ROOT)" \ - --apply --rewrite-constraints --skip-check "$$@" + --apply --rewrite-constraints "$$@" $(call _run_for_all_projects,--check) @@ -1135,11 +1122,15 @@ _builtin_status_diagnostics: _builtin_require_environment fi @git -C "$(PROJECT_ROOT)" status --short -_builtin_docs_all: _builtin_gen_all +# Operator law 2026-09-22: `docs` is a docs-only lifecycle (generate, fix, +# fmt, validate, audit); the actions render from make.docs.actions and never +# depend on the workspace-wide codegen conform — docs actions render their +# own outputs from the live configuration and sources. +_builtin_docs_all: @set -eu; \ for action in $(DOCS_ACTIONS); do \ mode=; \ - case "$$action" in fix) mode=--apply ;; esac; \ + case "$$action" in fix|fmt) mode=--apply ;; esac; \ $(PROJECT_FLEXT_INFRA) docs "$$action" --repository-root "$(PROJECT_ROOT)" --output-dir ".reports/docs" $$mode $(DOCS_PROJECT_ARGS); \ done diff --git a/examples/__init__.py b/examples/__init__.py index 687306e3..abbf0ce2 100644 --- a/examples/__init__.py +++ b/examples/__init__.py @@ -10,7 +10,6 @@ if TYPE_CHECKING: from flext_cli import cli - from pydantic_core import from_json, to_json, to_jsonable_python from flext_core import ( core, @@ -25,11 +24,11 @@ ) from flext_web import c, config, m, main, p, s, settings, t, u, web - from .constants import FlextWebExamplesConstants, FlextWebExamplesConstants as c - from .models import FlextWebExamplesModels, FlextWebExamplesModels as m - from .protocols import FlextWebExamplesProtocols, FlextWebExamplesProtocols as p - from .typings import FlextWebExamplesTypes, FlextWebExamplesTypes as t - from .utilities import FlextWebExamplesUtilities, FlextWebExamplesUtilities as u + from .constants import FlextWebExamplesConstants + from .models import FlextWebExamplesModels + from .protocols import FlextWebExamplesProtocols + from .typings import FlextWebExamplesTypes + from .utilities import FlextWebExamplesUtilities __all__: tuple[str, ...] = ( "FlextWebExamplesConstants", "FlextWebExamplesModels", @@ -37,15 +36,24 @@ "FlextWebExamplesTypes", "FlextWebExamplesUtilities", "c", + "cli", + "config", + "core", "d", "e", "h", + "lazy", + "lazy_attribute", "m", + "main", + "normalize_lazy_imports", "p", "r", "s", + "settings", "t", "u", + "web", "x", ) @@ -81,7 +89,6 @@ "u", "web", ), - "pydantic_core": ("from_json", "to_json", "to_jsonable_python"), }), alias_groups=MappingProxyType({}), sort_keys=False, diff --git a/pyproject.toml b/pyproject.toml index 9c0a271f..db523b90 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -186,10 +186,6 @@ warn_unreachable = true warn_unused_ignores = true follow_imports = "normal" -[[tool.mypy.overrides]] -module = ["dcdoc._utilities._charts._matplotlib_renderer._renders_spec"] -disable_error_code = ["unreachable"] - [tool.pydantic-mypy] init_forbid_extra = true init_typed = true diff --git a/src/flext_web/__init__.py b/src/flext_web/__init__.py index 7875081b..e04e4fbc 100644 --- a/src/flext_web/__init__.py +++ b/src/flext_web/__init__.py @@ -21,28 +21,26 @@ if TYPE_CHECKING: from flext_cli import cli - from pydantic_core import from_json, to_json, to_jsonable_python from flext_core import core, d, e, h, lazy_attribute, r, x from . import services - from .__version__ import FlextWebVersion from ._config import FlextWebConfig, config from ._settings import FlextWebSettings, settings from .api import FlextWeb, web from .base import FlextWebServiceBase, FlextWebServiceBase as s from .cli import FlextWebCli, main - from .constants import FlextWebConstants, FlextWebConstants as c - from .models import FlextWebModels, FlextWebModels as m - from .protocols import FlextWebProtocols, FlextWebProtocols as p + from .constants import FlextWebConstants, c + from .models import FlextWebModels, m + from .protocols import FlextWebProtocols, p from .services.app import FlextWebApp from .services.auth import FlextWebAuth from .services.entities import FlextWebEntities from .services.handlers import FlextWebHandlers from .services.health import FlextWebHealth from .services.web import FlextWebServices - from .typings import FlextWebTypes, FlextWebTypes as t - from .utilities import FlextWebUtilities, FlextWebUtilities as u + from .typings import FlextWebTypes, t + from .utilities import FlextWebUtilities, u __all__: tuple[str, ...] = ( "FlextWeb", "FlextWebApp", @@ -60,7 +58,6 @@ "FlextWebSettings", "FlextWebTypes", "FlextWebUtilities", - "FlextWebVersion", "__author__", "__author_email__", "__description__", @@ -70,10 +67,13 @@ "__version__", "__version_info__", "c", + "cli", "config", + "core", "d", "e", "h", + "lazy_attribute", "m", "main", "p", @@ -90,7 +90,6 @@ _LAZY_IMPORTS = MappingProxyType( build_lazy_import_map( MappingProxyType({ - ".__version__": ("FlextWebVersion",), "._config": ("FlextWebConfig", "config"), "._settings": ("FlextWebSettings", "settings"), ".api": ("FlextWeb", "web"), @@ -110,7 +109,6 @@ ".utilities": ("FlextWebUtilities", "u"), "flext_cli": ("cli",), "flext_core": ("core", "d", "e", "h", "lazy_attribute", "r", "x"), - "pydantic_core": ("from_json", "to_json", "to_jsonable_python"), }), alias_groups=MappingProxyType({}), sort_keys=False, diff --git a/tests/__init__.py b/tests/__init__.py index bbec784a..03af28cb 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -9,18 +9,33 @@ from flext_core.lazy import build_lazy_import_map, install_lazy_exports if TYPE_CHECKING: - from flext_tests import FlextTestsConstants, d, e, h, r, s, td, tf, tk, tm, tv, x + from flext_cli import cli + from flext_tests import ( + active_rules, + api, + discover_repository_root, + install_local_packages, + load_infra_report, + split_csv, + td, + tf, + tk, + tm, + tv, + ) + + from flext_core import core, d, e, h, lazy_attribute, r, x + from flext_web import config, main, s, settings, web from . import fixtures, integration, unit from .base import TestsFlextWebServiceBase - from .constants import TestsFlextWebConstants, TestsFlextWebConstants as c - from .models import TestsFlextWebModels, TestsFlextWebModels as m - from .protocols import TestsFlextWebProtocols, TestsFlextWebProtocols as p + from .constants import TestsFlextWebConstants, c + from .models import TestsFlextWebModels, m + from .protocols import TestsFlextWebProtocols, p from .settings import TestsFlextWebSettings - from .typings import TestsFlextWebTypes, TestsFlextWebTypes as t - from .utilities import TestsFlextWebUtilities, TestsFlextWebUtilities as u + from .typings import TestsFlextWebTypes, t + from .utilities import TestsFlextWebUtilities, u __all__: tuple[str, ...] = ( - "FlextTestsConstants", "TestsFlextWebConstants", "TestsFlextWebModels", "TestsFlextWebProtocols", @@ -28,16 +43,28 @@ "TestsFlextWebSettings", "TestsFlextWebTypes", "TestsFlextWebUtilities", + "active_rules", + "api", "c", + "cli", + "config", + "core", "d", + "discover_repository_root", "e", "fixtures", "h", + "install_local_packages", "integration", + "lazy_attribute", + "load_infra_report", "m", + "main", "p", "r", "s", + "settings", + "split_csv", "t", "td", "tf", @@ -46,6 +73,7 @@ "tv", "u", "unit", + "web", "x", ) @@ -62,20 +90,22 @@ ".typings": ("TestsFlextWebTypes", "t"), ".unit": ("unit",), ".utilities": ("TestsFlextWebUtilities", "u"), + "flext_cli": ("cli",), + "flext_core": ("core", "d", "e", "h", "lazy_attribute", "r", "x"), "flext_tests": ( - "FlextTestsConstants", - "d", - "e", - "h", - "r", - "s", + "active_rules", + "api", + "discover_repository_root", + "install_local_packages", + "load_infra_report", + "split_csv", "td", "tf", "tk", "tm", "tv", - "x", ), + "flext_web": ("config", "main", "s", "settings", "web"), }), alias_groups=MappingProxyType({}), sort_keys=False, diff --git a/tests/fixtures/__init__.py b/tests/fixtures/__init__.py index 661bb8be..1a29ad1b 100644 --- a/tests/fixtures/__init__.py +++ b/tests/fixtures/__init__.py @@ -9,52 +9,12 @@ from flext_core.lazy import build_lazy_import_map, install_lazy_exports if TYPE_CHECKING: - from flext_tests import c, d, e, h, m, p, r, s, t, td, tf, tk, tm, tv, u, x - from .auth import TestsFlextWebAuthFixture -__all__: tuple[str, ...] = ( - "TestsFlextWebAuthFixture", - "c", - "d", - "e", - "h", - "m", - "p", - "r", - "s", - "t", - "td", - "tf", - "tk", - "tm", - "tv", - "u", - "x", -) +__all__: tuple[str, ...] = ("TestsFlextWebAuthFixture",) _LAZY_IMPORTS = MappingProxyType( build_lazy_import_map( - MappingProxyType({ - ".auth": ("TestsFlextWebAuthFixture",), - "flext_tests": ( - "c", - "d", - "e", - "h", - "m", - "p", - "r", - "s", - "t", - "td", - "tf", - "tk", - "tm", - "tv", - "u", - "x", - ), - }), + MappingProxyType({".auth": ("TestsFlextWebAuthFixture",)}), alias_groups=MappingProxyType({}), sort_keys=False, ) diff --git a/tests/integration/__init__.py b/tests/integration/__init__.py index b97690b3..a91663e0 100644 --- a/tests/integration/__init__.py +++ b/tests/integration/__init__.py @@ -4,53 +4,13 @@ from __future__ import annotations from types import MappingProxyType -from typing import TYPE_CHECKING from flext_core.lazy import build_lazy_import_map, install_lazy_exports - -if TYPE_CHECKING: - from flext_tests import c, d, e, h, m, p, r, s, t, td, tf, tk, tm, tv, u, x -__all__: tuple[str, ...] = ( - "c", - "d", - "e", - "h", - "m", - "p", - "r", - "s", - "t", - "td", - "tf", - "tk", - "tm", - "tv", - "u", - "x", -) +__all__: tuple[str, ...] = () _LAZY_IMPORTS = MappingProxyType( build_lazy_import_map( - MappingProxyType({ - "flext_tests": ( - "c", - "d", - "e", - "h", - "m", - "p", - "r", - "s", - "t", - "td", - "tf", - "tk", - "tm", - "tv", - "u", - "x", - ) - }), + MappingProxyType({}), alias_groups=MappingProxyType({}), sort_keys=False, ) diff --git a/tests/unit/__init__.py b/tests/unit/__init__.py index a3f20a35..2aa90c59 100644 --- a/tests/unit/__init__.py +++ b/tests/unit/__init__.py @@ -4,53 +4,13 @@ from __future__ import annotations from types import MappingProxyType -from typing import TYPE_CHECKING from flext_core.lazy import build_lazy_import_map, install_lazy_exports - -if TYPE_CHECKING: - from flext_tests import c, d, e, h, m, p, r, s, t, td, tf, tk, tm, tv, u, x -__all__: tuple[str, ...] = ( - "c", - "d", - "e", - "h", - "m", - "p", - "r", - "s", - "t", - "td", - "tf", - "tk", - "tm", - "tv", - "u", - "x", -) +__all__: tuple[str, ...] = () _LAZY_IMPORTS = MappingProxyType( build_lazy_import_map( - MappingProxyType({ - "flext_tests": ( - "c", - "d", - "e", - "h", - "m", - "p", - "r", - "s", - "t", - "td", - "tf", - "tk", - "tm", - "tv", - "u", - "x", - ) - }), + MappingProxyType({}), alias_groups=MappingProxyType({}), sort_keys=False, ) From 2c64b371c4e85cb608d25e246eef89529ab23adc Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Tue, 22 Sep 2026 23:43:28 -0300 Subject: [PATCH 2/8] chore(gen): land generator fixed-point output (pydantic-settings>=2.14.0,<2.15 + allow_redefinition facets) --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 0fba4cec..b35b329b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -171,6 +171,7 @@ exclude = "" mypy_path = ["src"] plugins = ["pydantic.mypy"] python_version = "3.13" +allow_redefinition = true check_untyped_defs = true explicit_package_bases = true extra_checks = true From 63d59502b5932dbe89f2d02693b1d852c02696ea Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Wed, 23 Sep 2026 00:23:49 -0300 Subject: [PATCH 3/8] chore(gen): converge wave-5 absorb to generator fixed point (fix/fmt clean) --- .github/workflows/ci.yml | 8 -------- tests/integration/__init__.py | 4 +++- tests/unit/__init__.py | 4 +++- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ccf748fc..124c09c5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,14 +36,6 @@ name: CI description: >- Optional GitHub App private key minting the short-lived installation token for cross-repo private git dependencies. - inputs: - CI_DEPENDENCIES_REQUIRED: - required: false - type: string - description: >- - Optional flag indicating if cross-repo dependency credentials are - required. When absent or falsy, missing secrets are recorded as - NOT EXECUTED. When truthy, missing secrets fail the job. # End SECTION: triggers # Why: one active run per workflow and branch prevents obsolete CI from consuming runners. diff --git a/tests/integration/__init__.py b/tests/integration/__init__.py index 92a8c754..32cf6ef4 100644 --- a/tests/integration/__init__.py +++ b/tests/integration/__init__.py @@ -11,7 +11,9 @@ _LAZY_IMPORTS = MappingProxyType( build_lazy_import_map( - MappingProxyType({}), alias_groups=MappingProxyType({}), sort_keys=False + MappingProxyType({}), + alias_groups=MappingProxyType({}), + sort_keys=False, ) ) diff --git a/tests/unit/__init__.py b/tests/unit/__init__.py index 6b84ab25..f090d7fe 100644 --- a/tests/unit/__init__.py +++ b/tests/unit/__init__.py @@ -11,7 +11,9 @@ _LAZY_IMPORTS = MappingProxyType( build_lazy_import_map( - MappingProxyType({}), alias_groups=MappingProxyType({}), sort_keys=False + MappingProxyType({}), + alias_groups=MappingProxyType({}), + sort_keys=False, ) ) From e7ee0115ae1051aea28abf20f3e86585be746f35 Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Wed, 23 Sep 2026 00:53:46 -0300 Subject: [PATCH 4/8] chore(gen): converge wave-6 absorb to generator fixed point --- pyproject.toml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index b35b329b..7f1c471e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -159,23 +159,27 @@ only-include = ["src/flext_web"] [tool.mypy] disable_error_code = [ + "arg-type", "assignment", "attr-defined", "call-arg", "misc", "name-defined", + "no-any-return", + "no-redef", "prop-decorator", + "type-var", + "unreachable", "valid-type", ] -exclude = "" +exclude = "^legado(?:/|$)" mypy_path = ["src"] -plugins = ["pydantic.mypy"] +plugins = ["pydantic.mypy", "returns.contrib.mypy.returns_plugin"] python_version = "3.13" allow_redefinition = true check_untyped_defs = true explicit_package_bases = true extra_checks = true -follow_untyped_imports = true local_partial_types = true namespace_packages = true no_implicit_reexport = true From e162a916210b33a17c1114899098dec7fbed6908 Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Wed, 23 Sep 2026 01:58:11 -0300 Subject: [PATCH 5/8] chore(gen): converge wave-7 absorb to generator fixed point --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 7f1c471e..c93ea076 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -174,7 +174,7 @@ disable_error_code = [ ] exclude = "^legado(?:/|$)" mypy_path = ["src"] -plugins = ["pydantic.mypy", "returns.contrib.mypy.returns_plugin"] +plugins = ["pydantic.mypy"] python_version = "3.13" allow_redefinition = true check_untyped_defs = true From 60361410eaf2cc89753c5b7869678d071549965e Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Wed, 23 Sep 2026 02:30:07 -0300 Subject: [PATCH 6/8] chore(gen): converge wave-8 absorb to generator fixed point --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index c93ea076..6708255f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -63,6 +63,7 @@ dev = [ "actionlint-py>=1.7.12.24", "bandit>=1.9.4", "deptry", + "editables>=0.6", "flext-tests @ git+https://github.com/flext-sh/flext-tests.git@0.12.0-dev", "hypothesis", "mkdocs", From 89a18f06038fdced6acebef3348d7bf8b67ab08c Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Wed, 23 Sep 2026 14:58:04 -0300 Subject: [PATCH 7/8] fixes --- tests/integration/__init__.py | 4 +--- tests/unit/__init__.py | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/tests/integration/__init__.py b/tests/integration/__init__.py index 32cf6ef4..92a8c754 100644 --- a/tests/integration/__init__.py +++ b/tests/integration/__init__.py @@ -11,9 +11,7 @@ _LAZY_IMPORTS = MappingProxyType( build_lazy_import_map( - MappingProxyType({}), - alias_groups=MappingProxyType({}), - sort_keys=False, + MappingProxyType({}), alias_groups=MappingProxyType({}), sort_keys=False ) ) diff --git a/tests/unit/__init__.py b/tests/unit/__init__.py index f090d7fe..6b84ab25 100644 --- a/tests/unit/__init__.py +++ b/tests/unit/__init__.py @@ -11,9 +11,7 @@ _LAZY_IMPORTS = MappingProxyType( build_lazy_import_map( - MappingProxyType({}), - alias_groups=MappingProxyType({}), - sort_keys=False, + MappingProxyType({}), alias_groups=MappingProxyType({}), sort_keys=False ) ) From 8ef190ecf84651bc683efc4601154acd8260f476 Mon Sep 17 00:00:00 2001 From: Marlon Costa Date: Wed, 23 Sep 2026 16:03:30 -0300 Subject: [PATCH 8/8] chore(gen): render standalone-mode projections for CI fixed point --- .gitignore | 1 + .sonarcloud.properties | 17 +++++++++++++++++ tests/integration/__init__.py | 4 +++- tests/unit/__init__.py | 4 +++- 4 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 .sonarcloud.properties diff --git a/.gitignore b/.gitignore index cb02fead..c7ff229c 100644 --- a/.gitignore +++ b/.gitignore @@ -372,6 +372,7 @@ CLAUDE.local.md !.github/workflows/release.yml !.qlty/ !.qlty/qlty.toml +!.sonarcloud.properties !.vscode/settings.json !config/ !config/gitleaks-release.toml diff --git a/.sonarcloud.properties b/.sonarcloud.properties new file mode 100644 index 00000000..eba1ee7a --- /dev/null +++ b/.sonarcloud.properties @@ -0,0 +1,17 @@ +# @flext-regenerate: make gen +# @flext-ssot: flext-infra/config/codegen.yaml + flext-infra/src/flext_infra/templates/project/base/sonarcloud.properties.j2 +# @flext-maintenance: do not edit generated projections; edit the SSOT and regenerate +# Generated by flext_infra codegen conform. +# +# SonarCloud automatic analysis honors only the scope keys below. + +sonar.sources=. +sonar.tests=tests +sonar.test.inclusions=tests/**/*.py +sonar.sourceEncoding=UTF-8 +sonar.exclusions=**/.venv/**,**/__pycache__/**,**/*.py[cod],**/build/**,**/dist/**,**/*.egg-info/**,**/.pytest_cache/**,**/.reports/**,**/node_modules/**,**/.scannerwork/**,tests/** +sonar.cpd.exclusions=tests/** + +# Server-side issue exclusions: applied through SonarCloud project settings, +# which automatic analysis requires; they are not file properties. +# text:S8565 on pyproject.toml: fleet lockfile ban (operator order); dependency ranges live in pyproject.toml; bead flext-c8yle diff --git a/tests/integration/__init__.py b/tests/integration/__init__.py index 92a8c754..32cf6ef4 100644 --- a/tests/integration/__init__.py +++ b/tests/integration/__init__.py @@ -11,7 +11,9 @@ _LAZY_IMPORTS = MappingProxyType( build_lazy_import_map( - MappingProxyType({}), alias_groups=MappingProxyType({}), sort_keys=False + MappingProxyType({}), + alias_groups=MappingProxyType({}), + sort_keys=False, ) ) diff --git a/tests/unit/__init__.py b/tests/unit/__init__.py index 6b84ab25..f090d7fe 100644 --- a/tests/unit/__init__.py +++ b/tests/unit/__init__.py @@ -11,7 +11,9 @@ _LAZY_IMPORTS = MappingProxyType( build_lazy_import_map( - MappingProxyType({}), alias_groups=MappingProxyType({}), sort_keys=False + MappingProxyType({}), + alias_groups=MappingProxyType({}), + sort_keys=False, ) )