Files
temp/features/steps/settings_missing_spec_fields_steps.py
freemo da0c5f14b5 fix(config): add server_url, server_token, format, and default_estimation_actor fields to Settings
Add four spec-required environment variable fields to the Settings class
that were previously missing, causing AttributeError when accessed:

- server_url: str | None — maps to CLEVERAGENTS_SERVER_URL (spec: server.url)
- server_token: str | None — maps to CLEVERAGENTS_SERVER_TOKEN (spec: server.token)
- format: str | None — maps to CLEVERAGENTS_FORMAT (spec: core.format)
- default_estimation_actor: str | None — maps to CLEVERAGENTS_DEFAULT_ESTIMATION_ACTOR
  (spec: core.default_estimation_actor)

All fields default to None when the corresponding env var is unset, and
are fully statically typed (no type: ignore). BDD scenarios cover env var
binding, default value, type validation, and model_fields presence for
each new field.

ISSUES CLOSED: #2866
2026-04-05 07:15:48 +00:00

156 lines
5.5 KiB
Python

"""Step definitions for Settings spec-required env var fields (issue #2866)."""
from __future__ import annotations
import os
from behave import given, then, when
from cleveragents.config.settings import Settings
_SPEC_FIELD_ENV_VARS = [
"CLEVERAGENTS_SERVER_URL",
"CLEVERAGENTS_SERVER_TOKEN",
"CLEVERAGENTS_FORMAT",
"CLEVERAGENTS_DEFAULT_ESTIMATION_ACTOR",
]
@given("no CleverAgents spec-field env vars are set")
def step_clear_spec_field_env_vars(context):
"""Remove all spec-field env vars so Settings starts from a clean slate."""
for key in _SPEC_FIELD_ENV_VARS:
os.environ.pop(key, None)
if not hasattr(context, "env_vars_to_clean"):
context.env_vars_to_clean = []
context.env_vars_to_clean.extend(_SPEC_FIELD_ENV_VARS)
@when("I instantiate Settings for spec fields")
def step_instantiate_settings_for_spec_fields(context):
"""Create a fresh Settings instance (bypassing the singleton)."""
Settings._instance = None
context.settings = Settings()
@when("I inspect Settings.model_fields")
def step_inspect_model_fields(context):
"""Capture the model_fields mapping for assertion."""
context.model_fields = Settings.model_fields
# ── server_url assertions ────────────────────────────────────────────────────
@then("settings.server_url should be None")
def step_server_url_is_none(context):
assert context.settings.server_url is None, (
f"Expected server_url to be None, got {context.settings.server_url!r}"
)
@then('settings.server_url should be "{expected}"')
def step_server_url_equals(context, expected):
assert context.settings.server_url == expected, (
f"Expected server_url={expected!r}, got {context.settings.server_url!r}"
)
# ── server_token assertions ──────────────────────────────────────────────────
@then("settings.server_token should be None")
def step_server_token_is_none(context):
assert context.settings.server_token is None, (
f"Expected server_token to be None, got {context.settings.server_token!r}"
)
@then('settings.server_token should be "{expected}"')
def step_server_token_equals(context, expected):
assert context.settings.server_token == expected, (
f"Expected server_token={expected!r}, got {context.settings.server_token!r}"
)
# ── format assertions ────────────────────────────────────────────────────────
@then("settings.format should be None")
def step_format_is_none(context):
assert context.settings.format is None, (
f"Expected format to be None, got {context.settings.format!r}"
)
@then('settings.format should be "{expected}"')
def step_format_equals(context, expected):
assert context.settings.format == expected, (
f"Expected format={expected!r}, got {context.settings.format!r}"
)
# ── default_estimation_actor assertions ──────────────────────────────────────
@then("settings.default_estimation_actor should be None")
def step_default_estimation_actor_is_none(context):
assert context.settings.default_estimation_actor is None, (
"Expected default_estimation_actor to be None, "
f"got {context.settings.default_estimation_actor!r}"
)
@then('settings.default_estimation_actor should be "{expected}"')
def step_default_estimation_actor_equals(context, expected):
assert context.settings.default_estimation_actor == expected, (
f"Expected default_estimation_actor={expected!r}, "
f"got {context.settings.default_estimation_actor!r}"
)
# ── model_fields presence assertions ─────────────────────────────────────────
@then('"{field_name}" should be present in model_fields')
def step_field_in_model_fields(context, field_name):
assert field_name in context.model_fields, (
f"Expected '{field_name}' to be in Settings.model_fields, "
f"but only found: {sorted(context.model_fields.keys())}"
)
# ── type annotation assertions ───────────────────────────────────────────────
@then("settings.server_url should be of type str or None")
def step_server_url_type(context):
value = context.settings.server_url
assert value is None or isinstance(value, str), (
f"Expected server_url to be str | None, got {type(value)}"
)
@then("settings.server_token should be of type str or None")
def step_server_token_type(context):
value = context.settings.server_token
assert value is None or isinstance(value, str), (
f"Expected server_token to be str | None, got {type(value)}"
)
@then("settings.format should be of type str or None")
def step_format_type(context):
value = context.settings.format
assert value is None or isinstance(value, str), (
f"Expected format to be str | None, got {type(value)}"
)
@then("settings.default_estimation_actor should be of type str or None")
def step_default_estimation_actor_type(context):
value = context.settings.default_estimation_actor
assert value is None or isinstance(value, str), (
f"Expected default_estimation_actor to be str | None, got {type(value)}"
)