"""Step definitions for DomainBaseModel shared configuration tests. Only steps that are NOT already defined in other step modules are defined here. Steps shared with aimodelscredentials_steps.py, aimodelserrors_steps.py, and aimodelsproviders_steps.py are reused automatically by Behave's global step registry. """ from behave import then, when from pydantic import BaseModel from cleveragents.domain.models.base import DomainBaseModel # --------------------------------------------------------------------------- # Shared expected config values # --------------------------------------------------------------------------- _EXPECTED_CONFIG: dict[str, object] = { "str_strip_whitespace": True, "validate_assignment": True, "arbitrary_types_allowed": False, "populate_by_name": True, "use_enum_values": True, } # --------------------------------------------------------------------------- # When — new imports (not defined in existing step files) # --------------------------------------------------------------------------- @when("I import DomainBaseModel from the domain models base module") def step_import_domain_base_model(context: object) -> None: """Import DomainBaseModel and store on context.""" context.domain_base_model_class = DomainBaseModel context.imported_class = DomainBaseModel @when("I inspect the DomainBaseModel model_config") def step_inspect_domain_base_model_config(context: object) -> None: """Store the DomainBaseModel model_config on context.""" context.inspected_config = DomainBaseModel.model_config @when("I import ModelError from aimodelserrors") def step_import_model_error(context: object) -> None: """Import ModelError.""" from cleveragents.domain.models.aimodelserrors.ai_models_errors import ModelError context.imported_class = ModelError @when("I import FallbackResult from aimodelserrors") def step_import_fallback_result(context: object) -> None: """Import FallbackResult.""" from cleveragents.domain.models.aimodelserrors.ai_models_errors import ( FallbackResult, ) context.imported_class = FallbackResult @when("I import ModelProviderExtraAuthVars from aimodelsproviders") def step_import_model_provider_extra_auth_vars(context: object) -> None: """Import ModelProviderExtraAuthVars.""" from cleveragents.domain.models.aimodelsproviders.ai_models_providers import ( ModelProviderExtraAuthVars, ) context.imported_class = ModelProviderExtraAuthVars @when("I import ModelProviderConfigSchema from aimodelsproviders") def step_import_model_provider_config_schema(context: object) -> None: """Import ModelProviderConfigSchema.""" from cleveragents.domain.models.aimodelsproviders.ai_models_providers import ( ModelProviderConfigSchema, ) context.imported_class = ModelProviderConfigSchema @when("I import AuthHeader from auth") def step_import_auth_header(context: object) -> None: """Import AuthHeader.""" from cleveragents.domain.models.auth.auth import AuthHeader context.imported_class = AuthHeader @when("I import TrialPlansExceededError from auth") def step_import_trial_plans_exceeded_error(context: object) -> None: """Import TrialPlansExceededError.""" from cleveragents.domain.models.auth.auth import TrialPlansExceededError context.imported_class = TrialPlansExceededError @when("I import TrialMessagesExceededError from auth") def step_import_trial_messages_exceeded_error(context: object) -> None: """Import TrialMessagesExceededError.""" from cleveragents.domain.models.auth.auth import TrialMessagesExceededError context.imported_class = TrialMessagesExceededError @when("I import BillingError from auth") def step_import_billing_error(context: object) -> None: """Import BillingError.""" from cleveragents.domain.models.auth.auth import BillingError context.imported_class = BillingError @when("I import ApiError from auth") def step_import_api_error(context: object) -> None: """Import ApiError.""" from cleveragents.domain.models.auth.auth import ApiError context.imported_class = ApiError @when("I import ClientAccount from auth") def step_import_client_account(context: object) -> None: """Import ClientAccount.""" from cleveragents.domain.models.auth.auth import ClientAccount context.imported_class = ClientAccount @when("I import ClientAuth from auth") def step_import_client_auth(context: object) -> None: """Import ClientAuth.""" from cleveragents.domain.models.auth.auth import ClientAuth context.imported_class = ClientAuth @when("I import PlanConfig from planconfig") def step_import_plan_config(context: object) -> None: """Import PlanConfig.""" from cleveragents.domain.models.planconfig.plan_config import PlanConfig context.imported_class = PlanConfig @when("I import ConfigSetting from planconfig") def step_import_config_setting(context: object) -> None: """Import ConfigSetting.""" from cleveragents.domain.models.planconfig.plan_config import ConfigSetting context.imported_class = ConfigSetting # When — class definition inspection @when("I inspect the ModelProviderOption class definition") def step_inspect_model_provider_option(context: object) -> None: """Store ModelProviderOption for inspection.""" from cleveragents.domain.models.aimodelscredentials.ai_models_credentials import ( ModelProviderOption, ) context.inspected_class = ModelProviderOption @when("I inspect the ModelError class definition") def step_inspect_model_error(context: object) -> None: """Store ModelError for inspection.""" from cleveragents.domain.models.aimodelserrors.ai_models_errors import ModelError context.inspected_class = ModelError @when("I inspect the ModelProviderConfigSchema class definition") def step_inspect_model_provider_config_schema_def(context: object) -> None: """Store ModelProviderConfigSchema for inspection.""" from cleveragents.domain.models.aimodelsproviders.ai_models_providers import ( ModelProviderConfigSchema, ) context.inspected_class = ModelProviderConfigSchema @when("I inspect the AuthHeader class definition") def step_inspect_auth_header(context: object) -> None: """Store AuthHeader for inspection.""" from cleveragents.domain.models.auth.auth import AuthHeader context.inspected_class = AuthHeader @when("I inspect the PlanConfig class definition") def step_inspect_plan_config(context: object) -> None: """Store PlanConfig for inspection.""" from cleveragents.domain.models.planconfig.plan_config import PlanConfig context.inspected_class = PlanConfig # --------------------------------------------------------------------------- # Then — DomainBaseModel assertions # --------------------------------------------------------------------------- @then("the DomainBaseModel class should be available") def step_domain_base_model_available(context: object) -> None: """Verify DomainBaseModel is available.""" assert context.domain_base_model_class is not None assert context.domain_base_model_class.__name__ == "DomainBaseModel" @then("DomainBaseModel should be a subclass of pydantic BaseModel") def step_domain_base_model_is_pydantic(context: object) -> None: """Verify DomainBaseModel inherits from pydantic BaseModel.""" assert issubclass(context.domain_base_model_class, BaseModel) @then("the DomainBaseModel str_strip_whitespace should be True") def step_domain_base_model_str_strip(context: object) -> None: """Verify str_strip_whitespace on DomainBaseModel.""" assert context.inspected_config.get("str_strip_whitespace") is True @then("the DomainBaseModel validate_assignment should be True") def step_domain_base_model_validate_assignment(context: object) -> None: """Verify validate_assignment on DomainBaseModel.""" assert context.inspected_config.get("validate_assignment") is True @then("the DomainBaseModel arbitrary_types_allowed should be False") def step_domain_base_model_arbitrary_types(context: object) -> None: """Verify arbitrary_types_allowed on DomainBaseModel.""" assert context.inspected_config.get("arbitrary_types_allowed") is False @then("the DomainBaseModel populate_by_name should be True") def step_domain_base_model_populate_by_name(context: object) -> None: """Verify populate_by_name on DomainBaseModel.""" assert context.inspected_config.get("populate_by_name") is True @then("the DomainBaseModel use_enum_values should be True") def step_domain_base_model_use_enum_values(context: object) -> None: """Verify use_enum_values on DomainBaseModel.""" assert context.inspected_config.get("use_enum_values") is True # --------------------------------------------------------------------------- # Then — subclass assertions (generic, reused for all domain models) # --------------------------------------------------------------------------- @then("{class_name} should be a subclass of DomainBaseModel") def step_is_subclass_of_domain_base_model(context: object, class_name: str) -> None: """Verify the imported class is a subclass of DomainBaseModel.""" assert issubclass(context.imported_class, DomainBaseModel), ( f"{class_name} is not a subclass of DomainBaseModel" ) @then("the {class_name} model_config should match DomainBaseModel") def step_config_matches_domain_base_model(context: object, class_name: str) -> None: """Verify the imported class inherits the expected model_config values.""" cfg = context.imported_class.model_config for key, expected in _EXPECTED_CONFIG.items(): actual = cfg.get(key) assert actual == expected, ( f"{class_name}.model_config[{key!r}] = {actual!r}, expected {expected!r}" ) # --------------------------------------------------------------------------- # Then — no inline model_config duplication assertions # --------------------------------------------------------------------------- @then("{class_name} should not define its own model_config") def step_no_own_model_config(context: object, class_name: str) -> None: """Verify the class source does not contain an inline model_config assignment. Pydantic's metaclass copies model_config into every subclass __dict__ automatically, so we inspect the source code instead of __dict__ to confirm no *explicit* duplication exists. """ import inspect source = inspect.getsource(context.inspected_class) # Remove the class header line so we only look at the class body body_lines = source.splitlines()[1:] body = "\n".join(body_lines) assert "model_config" not in body, ( f"{class_name} has an explicit model_config in its source — " "should inherit from DomainBaseModel without redefinition" )