Skip to content

Refactor and improve configuration handling across the project - #23

Merged
plmick merged 33 commits into
mainfrom
feat/modularity_run
Oct 14, 2026
Merged

plmick merged 33 commits into
mainfrom
feat/modularity_run

Conversation

@pawkedzia

Copy link
Copy Markdown
Collaborator

Summary of Changes

  • Added unit tests for payload handling, router client behavior, Milvus index settings, and environment configuration parsing.
  • Consolidated and refactored router client logic to standardize URL formatting and authentication handling.
  • Restructured configuration files and environmental settings management for improved readability and maintainability.
  • Introduced security and accessibility improvements such as binding services to all interfaces and ensuring initialization of config files.
  • Added integrity and validation checks for both client-side and server-side configurations.
  • Updated and clarified documentation, examples, and dependency management for better usability and clarity.
  • Fixed several latent bugs related to configuration imports, URL routing, and server adaptation.
  • Enhanced CI workflows, code linting, and documentation for new repository layout.
  • Improved maintainability with refactored code layouts and streamlined logic for common tasks like index handling and token management.

pawkedzia and others added 30 commits October 9, 2026 03:34
The suite had no way to run: the repo referenced a
DJANGO_SETTINGS_MODULE pytest option that was never defined, and the
Django test modules (chat, data, engine, authorization) all fail at
import with ImproperlyConfigured.

Introduce sse_rest_api/tests/settings_django.py: an in-memory SQLite
configuration with every app installed, Keycloak as the active auth
provider (authorization.core.handlers raises at import unless one is),
and a SYSTEM_HANDLER stub. Wire it up via [tool.pytest.ini_options] so
a plain 'python -m pytest' from the repo root collects and runs the
whole suite.

Also implement the contract tests in tests/test_env_utils.py were
written against: bool_config_value, split_list_value and list_env_values
were missing from main/src/env_utils, so importing the test module
failed outright.
authorization/models.py defines SessionState and Token, but
authorization/migrations/ was empty, so 'manage.py migrate' never
created the authorization_token and authorization_sessionstate tables.
The introspection code path in authorization.core.handlers raises
'no such table' at runtime.

Generate 0001_initial.py. Existing deployments that already created the
tables manually should run 'python manage.py migrate
authorization --fake 0001_initial' (or --fake-initial) to align state.
tests/test_config_examples.py and engine/tests/test_similarity.py
reference config templates that did not exist, so they failed at
collection. Create the five *.example.* files the guard tests pin:
django-config.example.json (production-safe), milvus_config.example.json,
auth-config.example.json, user-group-organisation.example.json and
secret-key.example.txt. Every secret carries a CHANGE_ME placeholder so
a template can never leak a real credential.

.gitignore now explicitly un-ignores the *.example.* templates; the real
configs (django-config.json, secret-key.txt, ...) stay untracked.
The repository carried three different source roots and relied on ad-hoc
sys.path bootstrapping: the Django apps were imported as top-level
modules (chat, data, engine, system, main), sse_apps reached them by
inserting sse_rest_api into sys.path, and scripts/ copied Python files
next to itself before running them.

New layout:

  src/sse_api/     Django project (was sse_rest_api/)
    config/        settings, urls, wsgi, asgi, celery (was main/)
    core/          shared utilities (was main/src/)
    chat|data|engine|system|authorization|content_supervisor/
  src/sse_tools/   CLI tools (was sse_apps/)
  configs/         runtime configuration, was sse_rest_api/configs/
  scripts/         thin entry points, no more copy-and-run

The project is now installed with 'pip install -e .' so every module is
importable from anywhere and the sys.path hacks are gone.

Import safety:
  - every Django AppConfig pins label = <app>, so app_label, migration
    dependencies, content types and existing database tables are unchanged;
  - migration files and cross-app model references keep the bare label;
  - authorization/__init__ keeps app_name as the module path used for the
    middleware and authentication class dotted paths.

Runtime configuration is now located through SSE_CONFIG_DIR (default
'configs'), replacing the implicit assumption that the process starts in
sse_rest_api/. Dockerfile, docker-compose.yml, run.sh, run-en.sh,
initialize.sh, run-api*.sh and gunicorn.conf.py all follow.

Also fixes configs/generative-models.json, which was not valid JSON
(trailing commas) and therefore crashed every import of the generative
model controller.

Co-Authored-By: Codex <noreply@openai.com>
engine/ was the only app carrying two layer packages at once: core/
(errors, middleware) and engine_core/ (protocols, search engine, query
pipeline, config, generative). The doubled name added nothing and made
import paths needlessly long.

Move every engine_core module into engine.core and re-point the nine
modules that imported it. engine/ now follows the same shape as the
other apps: api.py, controllers/, core/, models.py, urls.py (plus a
database/ adapter layer).

No behaviour change; the full suite still passes.
The client library referenced the old server module paths
(main.src.*, sse_rest_api/) in its docstrings, README and the
endpoint-contract test that reads the Django route files. Re-point them to
sse_api.* and src/sse_api/ so the contract test still validates the
library against the backend routes.

No behaviour change; the sse_lib suite still passes (104 tests).
Lint configuration was spread across four files with overlapping
coverage: [tool.black] and [tool.bandit] in pyproject.toml, [flake8] in
tox.ini, [bandit] in .bandit, [mypy] in mypy.ini and a 639-line .pylintrc
that also carried a [MESSAGES CONTROL] section.

Consolidate everything that has a TOML home into pyproject.toml
(black, bandit, pylint, mypy). flake8 cannot read TOML, so its options
move to setup.cfg. The redundant tox.ini and mypy.ini are deleted.

check-dev.sh now takes a mode argument (format / lint / types / test)
instead of running everything with no way to narrow it down, and bandit
is scoped to src/ and scripts/ so it does not scan the vendored docs.

Add the CI workflow that .github/workflows/ was pointing at but never
contained: a 3.10/3.11/3.12 test matrix plus a lint job running the same
checks check-dev.sh runs, so local and CI agree on the verdict.
README.md still documented the pre-refactor structure (apps_sse/,
main/, semantic_search_engine/, flat app packages), and SETUP.md,
DEPENDENCIES.md, EVALUATE.md, sse_lib/README.md, .env.example and the
per-app READMEs all pointed at sse_rest_api/ paths, main.src modules
and a bare manage.py.

Rewrite the README directory layout to match src/sse_api, src/sse_tools
and configs/, and re-point every remaining reference:

  sse_rest_api/            -> src/sse_api/
  sse_rest_api/configs/    -> configs/
  main.src.*               -> sse_api.core.*
  main.settings            -> sse_api.config.settings
  manage.py <cmd>          -> python -m sse_api.manage <cmd>
  apps_sse/*               -> src/sse_tools/*

No stale references to the old layout remain anywhere in the repo.
- fix NameError in chat/controllers/message.py: add missing logging import
- fix NameError in engine/controllers/models_logic/generative.py:
  percentage_rank_gen_qa -> percentage_rank_mass
- fix F821 in config/settings.py: import authorization properly
- remove unused imports (F401), reflow long imports (E501/E128)
- fix whitespace (E302/E303/E306) and star-import noqa placement
- fix F541 f-string without placeholders in tests_loader.py
- flake8 config: max-line-length 100, per-file-ignores for re-exports
- .bandit was written in INI style, but bandit >= 1.7 parses it as a YAML
  profile ('key: value' is not valid YAML), so every bandit run - locally
  via check-dev.sh and in CI - aborted with a parse error. Rewrite it as a
  YAML profile; excluded dirs now come from the command line.
- Remove the dead [tool.bandit] section from pyproject.toml (bandit has
  never read TOML) and drop strict=true from [tool.mypy]: the codebase is
  untyped and strict mode reports 1500+ errors, so the mypy CI job could
  never pass. Non-strict mypy stays the gate (opt-in locally, advisory in
  CI).
- flake8 scope: exclude sse_lib (standalone package with its own setup)
  like the original tox.ini did, instead of scanning it with the app's
  settings.
- mypy target src/sse_lib does not exist; the package lives at sse_lib/.
  Fix it in both CI and check-dev.sh.
- .pylintrc was a 600-line dump of every default option; keep only the
  deviations (py-version, message control, line length).
black --check . now passes (32 files reformatted). The flake8 gate covers
the whole repo (except sse_lib), so the remaining pre-existing E501 lines
are wrapped: Polish prompt strings in message.py and evaluate_rag_llm.py,
date-filter expressions in template.py, a long assertion in
test_input_validation.py, docstring/comment lines in protocols.py and
vector_store_adapter.py, and a commented-out sample in
evaluate_text_to_human.py.

Docs: point EVALUATE.md / SETUP.md / DEPENDENCIES.md / README.md at the
new src/ paths (the sse_apps/not_tested and main/ references were stale
after the layout refactor).
`sse_api.tests.settings_django` defined no ROOT_URLCONF, so every test had to
call a view directly through APIRequestFactory. That made a whole class of
defect invisible: `GET /api/healthz`, polled by nginx and by the container
HEALTHCHECK, shipped without ever being registered and nothing noticed.

Inert for the tests that exist today — Django loads the URLconf lazily on the
first request, and no current test makes one.
The Dockerfile HEALTHCHECK curls /api/healthz, nginx/sse.conf routes that path
to the api upstream and docker-compose gates services on service_healthy, yet
no urls.py registered it. The probe answers 404, `curl -f` fails on it, so
every container reports unhealthy from the first deploy. The dependency checks
were already written in system/core/health.py — they just had no caller.

SSEHealthCheck exposes them: public, because a probe carries no token, and
200/503 so that `curl -f` and service_healthy react to it. It is registered
both under the configured API root and as a bare /healthz, so turning on
api.major_version (which makes the root api/v1) cannot silence health reporting
in silence. An exception raised inside a check yields 503 instead of a 500 with
a traceback.

The body is {"healthy": bool, "checks": {...}} rather than the usual envelope
key `status`: sse_lib detects the envelope by `payload["status"] is True`, so a
probe replying {"status": "ok"} would be read as a failed API call by its own
client on a perfectly healthy server.

sse_lib gains health() and is_healthy() so a deployment can ask the same
question in code. The server route and the client-side endpoint constant land
in one commit because test_contract.py asserts the two route sets are equal in
both directions; either half alone leaves the suite red.

Adds 8 server tests and 10 client tests. Suite: 348 passed, 144 subtests;
flake8 and black clean.
RdlAuthStateHandler and RdlAuthGrantAccTokenHandler open
configs/auth-config.json from their constructors, and the views held them as
class attributes. Importing sse_api.authorization.urls therefore raised
FileNotFoundError on any machine without a deployment config file, which is
exactly when Django does it — while loading the URLconf.
AuthAuthenticationMiddleware had the same defect through
GATokenAuthentication().

Views now resolve their handler via cached_property (DRF builds the view per
request, so no handler is shared across threads any more) and the middleware
builds its collaborator in __init__, where Django already guarantees settings
are configured and still only once per process.

test_endpoint_input.py patched RdlAuthConfig.load_config purely to be able to
import the views; that scaffolding is gone and the provider is patched on its
class instead of on the instance the view used to expose.

Verified: authorization.urls and authorization.core.middleware now import with
no config file present. Suite 348 passed, 144 subtests; flake8 and black clean.
config.urls assembles a different route set per authentication mode (token,
Keycloak, OAuth v1, OAuth v2) and nothing exercised that switch — each branch
was only reachable by hand-editing a deployment config file. With all four
modes in scope for the production release, they need tests.

Characterization tests: they pin what each mode produces today. Writing them
turned up a defect worth recording, so it is pinned explicitly rather than
fixed here: in every external-auth mode api/login is registered twice — once
by system/urls.py for username/password, once by authorization/urls.py for the
OAuth code exchange — and config.urls appends the authorization routes before
the system ones, so Django resolves the code-exchange view and
OrganisationLogin is unreachable. sse_lib.login() still posts credentials to
that path. The test documents the collision and says to update it when fixed.

Possible now that authorization.urls no longer reads config at import time.
Suite: 357 passed, 157 subtests; stable in both run orders; flake8, black clean.
The server validates both keys of every text document with required_text
(core/validation.py: texts -> filepath, relative_filepath), so the
default text_document(relative_path="") made every index_documents() call
invalid before it was even sent. An omitted path now falls back to the
document name.

One test asserted the old shape and was pinning a payload the server rejects;
updated, plus a test that the field is never blank.

The class docstring example gained the percentage_rank_mass the server
requires in query_options, so the documented quickstart no longer teaches a
request that is guaranteed to fail validation, and the transport= argument
now says plainly that api_prefix/timeout/verify/session/headers/max_retries
are ignored when a transport is handed in rather than silently dropped.

Suite: 358 passed, 160 subtests; flake8 and black clean.
max_tokens_in_chunk and number_of_overlap_tokens go through identifier()/
number() in the data app, and percentage_rank_mass through generation_options()
in the engine; all three reject None. The option builders sent None, so every
index_documents()/upload_files() call without explicit options, and the
documented generate_answer() example, failed server-side validation with an
error that named none of the fields.

The client now checks the same rules before it sends anything and raises
SSEValueError naming the missing field. Validation is applied per endpoint, not
per option class, because the two paths disagree on purpose: generative_answer
validates query_options with generation_options while add_user_message accepts
any object, so a class-level rule would reject chat requests that work today.
A test pins that from the other side.

No defaults are invented. Chunk size follows the context window of whichever
embedder a deployment is configured with, which a client library cannot know,
so callers pass it explicitly or set default_indexing_options once; both
READMEs now show the call that actually works instead of one that cannot.

9 tests that asserted the rejected payloads were updated, 13 added covering the
new errors and the non-over-constrained chat path. Suite: 370 passed, 162
subtests; flake8 and black clean.
- Automatically activate virtual environments (`.venv` or `venv`) in all relevant scripts.
- Introduce reusable `docker_cmd` wrapper to handle scenarios where `sudo` may be required for Docker commands.
- Enhance Python and pip discovery by adding logic to prioritize virtual environment paths.
- Update scripts to ensure configuration is reusable across multiple environments and to adapt to deployment scenarios without manual intervention.
…cripts to include new `config` command and `bs4` dependency
…cripts to include new `config` command and `bs4` dependency
…ability, set default `DJANGO_SETTINGS_MODULE`, and enhance URI schema handling across scripts and modules
…ved accessibility and update allowed hosts in configuration
…rect environment and JSON config handling

- Simplify settings retrieval by directly checking environment variables and JSON configuration.
- Remove the unnecessary use of `_get_configuration_for_variable` in favor of explicit methods.
- Enhance code readability and maintainability by consolidating configuration parsing logic.
…support

- Introduce test cases for validating default and custom index parameters in `MilvusHandler`.
- Ensure proper invocation of Milvus client methods for index creation and collection handling.
- Enhance test readability with structured assertions and mock-based isolation.
…ndex metadata

- Update `_FakeMilvusClient` and `MilvusHandler` to handle metric types dynamically.
- Add helper method `__prepare_search_params` for extracting metric type from existing indexes.
- Introduce and enhance unit tests to validate dynamic metric type behavior for searches.
…dize URL handling

- Add `_create_router_client` to encapsulate client creation logic with support for token authentication.
- Standardize URL formatting across active model and API configurations.
- Update environmental variables and documentation to reflect new token support.
…ayload handling and router client behavior

- Add comprehensive test cases to validate router client creation, typed payload processing, and environmental variable configuration.
- Ensure proper handling of model configs, scheme-less hosts, and conversation workflows.
@pawkedzia
pawkedzia requested a review from plmick October 13, 2026 22:37
@pawkedzia pawkedzia self-assigned this Oct 13, 2026
@pawkedzia pawkedzia added bug Something isn't working documentation Improvements or additions to documentation enhancement New feature or request refactoring labels Oct 13, 2026
@plmick
plmick merged commit b6fda67 into main Oct 14, 2026
0 of 4 checks passed
@pawkedzia
pawkedzia deleted the feat/modularity_run branch October 15, 2026 00:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working documentation Improvements or additions to documentation enhancement New feature or request refactoring

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants