"""Data step definitions for behave — generic variables and environment."""
from __future__ import annotations
from typing import Any
from steplib.core.decorators import step
from steplib.core.registry import StepRegistry
from steplib.modules.data.actions import (
data_assert_env_equals,
data_assert_env_exists,
data_assert_env_not_equals,
data_assert_env_not_exists,
data_assert_variable_contains,
data_assert_variable_ends_with,
data_assert_variable_equals,
data_assert_variable_exists,
data_assert_variable_greater_than,
data_assert_variable_has_length,
data_assert_variable_is_empty,
data_assert_variable_is_not_empty,
data_assert_variable_less_than,
data_assert_variable_matches,
data_assert_variable_not_equals,
data_assert_variable_not_exists,
data_assert_variable_starts_with,
data_clear_variables,
data_copy_variable,
data_delete_env_var,
data_delete_variable,
data_extract_key_path,
data_increment_variable,
data_load_env_file,
data_load_json_file,
data_load_yaml_file,
data_set_env_from_variable,
data_set_env_var,
data_set_variable,
data_set_variable_json,
data_store_env_var,
data_wait,
)
from steplib.modules.data.context import DataContext
def _get_data(context: Any) -> DataContext:
"""Get the DataContext from context.steplib, creating it if needed."""
steplib = getattr(context, "steplib", None)
if steplib is None:
raise RuntimeError(
"context.steplib is not initialized. "
"Call autoload(context) or load(context, ...) in before_all."
)
data = getattr(steplib, "data", None)
if data is None:
data = DataContext()
steplib.data = data
return data
# --- Variable steps ---
[docs]
@step(
"I set the variable {name} to {value}",
category="data",
description="Set a generic variable in the data context.",
example='Given I set the variable "user_id" to "42"',
i18n={
"es": "establezco la variable {name} a {value}",
"pt": "defino a variável {name} como {value}",
},
)
def step_set_variable(context: Any, name: str, value: str) -> None:
"""Set a generic variable."""
data_set_variable(_get_data(context), name.strip('"'), value.strip('"'))
[docs]
@step(
"the variable {name} equals {value}",
category="data",
description="Assert that a variable equals an expected value.",
example='Then the variable "user_id" equals "42"',
i18n={
"es": "la variable {name} es igual a {value}",
"pt": "a variável {name} é igual a {value}",
},
)
def step_variable_equals(context: Any, name: str, value: str) -> None:
"""Assert variable equals."""
data_assert_variable_equals(_get_data(context), name.strip('"'), value.strip('"'))
[docs]
@step(
"the variable {name} exists",
category="data",
description="Assert that a variable exists in the data context.",
example='Then the variable "user_id" exists',
i18n={
"es": "la variable {name} existe",
"pt": "a variável {name} existe",
},
)
def step_variable_exists(context: Any, name: str) -> None:
"""Assert variable exists."""
data_assert_variable_exists(_get_data(context), name.strip('"'))
[docs]
@step(
"the variable {name} does not exist",
category="data",
description="Assert that a variable does not exist in the data context.",
example='Then the variable "old_key" does not exist',
i18n={
"es": "la variable {name} no existe",
"pt": "a variável {name} não existe",
},
)
def step_variable_not_exists(context: Any, name: str) -> None:
"""Assert variable does not exist."""
data_assert_variable_not_exists(_get_data(context), name.strip('"'))
[docs]
@step(
"I delete the variable {name}",
category="data",
description="Delete a variable from the data context.",
example='When I delete the variable "temp"',
i18n={
"es": "elimino la variable {name}",
"pt": "excluo a variável {name}",
},
)
def step_delete_variable(context: Any, name: str) -> None:
"""Delete a variable."""
data_delete_variable(_get_data(context), name.strip('"'))
[docs]
@step(
"I load the YAML file {path} into the variable {name}",
category="data",
description="Load a YAML file and store the parsed content as a variable.",
example='Given I load the YAML file "config.yaml" into the variable "config"',
i18n={
"es": "cargo el archivo YAML {path} en la variable {name}",
"pt": "carrego o arquivo YAML {path} na variável {name}",
},
)
def step_load_yaml(context: Any, path: str, name: str) -> None:
"""Load YAML file into variable."""
data_load_yaml_file(_get_data(context), path.strip('"'), name.strip('"'))
[docs]
@step(
"I load the JSON file {path} into the variable {name}",
category="data",
description="Load a JSON file and store the parsed content as a variable.",
example='Given I load the JSON file "data.json" into the variable "payload"',
i18n={
"es": "cargo el archivo JSON {path} en la variable {name}",
"pt": "carrego o arquivo JSON {path} na variável {name}",
},
)
def step_load_json_file(context: Any, path: str, name: str) -> None:
"""Load JSON file into variable."""
data_load_json_file(_get_data(context), path.strip('"'), name.strip('"'))
# --- Environment variable steps ---
[docs]
@step(
"I set the environment variable {key} to {value}",
category="data",
description="Set an environment variable (restored after the scenario).",
example='Given I set the environment variable "API_KEY" to "secret123"',
i18n={
"es": "establezco la variable de entorno {key} a {value}",
"pt": "defino a variável de ambiente {key} como {value}",
},
)
def step_set_env_var(context: Any, key: str, value: str) -> None:
"""Set an environment variable."""
data_set_env_var(_get_data(context), key.strip('"'), value.strip('"'))
[docs]
@step(
"I delete the environment variable {key}",
category="data",
description="Delete an environment variable (restored after the scenario).",
example='When I delete the environment variable "TEMP_KEY"',
i18n={
"es": "elimino la variable de entorno {key}",
"pt": "excluo a variável de ambiente {key}",
},
)
def step_delete_env_var(context: Any, key: str) -> None:
"""Delete an environment variable."""
data_delete_env_var(_get_data(context), key.strip('"'))
[docs]
@step(
"the environment variable {key} equals {value}",
category="data",
description="Assert that an environment variable equals an expected value.",
example='Then the environment variable "API_KEY" equals "secret123"',
i18n={
"es": "la variable de entorno {key} es igual a {value}",
"pt": "a variável de ambiente {key} é igual a {value}",
},
)
def step_env_equals(context: Any, key: str, value: str) -> None:
"""Assert env var equals."""
data_assert_env_equals(key.strip('"'), value.strip('"'))
[docs]
@step(
"the environment variable {key} exists",
category="data",
description="Assert that an environment variable exists.",
example='Then the environment variable "API_KEY" exists',
i18n={
"es": "la variable de entorno {key} existe",
"pt": "a variável de ambiente {key} existe",
},
)
def step_env_exists(context: Any, key: str) -> None:
"""Assert env var exists."""
data_assert_env_exists(key.strip('"'))
[docs]
@step(
"I store the environment variable {key} as {variable}",
category="data",
description="Store an environment variable's value into a data variable.",
example='Then I store the environment variable "HOME" as "home_dir"',
i18n={
"es": "guardo la variable de entorno {key} como {variable}",
"pt": "armazeno a variável de ambiente {key} como {variable}",
},
)
def step_store_env_var(context: Any, key: str, variable: str) -> None:
"""Store env var into a data variable."""
data_store_env_var(_get_data(context), key.strip('"'), variable.strip('"'))
[docs]
@step(
"I load environment variables from file {path}",
category="data",
description="Load environment variables from a .env-style file.",
example='Given I load environment variables from file ".env"',
i18n={
"es": "cargo variables de entorno desde el archivo {path}",
"pt": "carrego variáveis de ambiente do arquivo {path}",
},
)
def step_load_env_file(context: Any, path: str) -> None:
"""Load env vars from a .env file."""
data_load_env_file(_get_data(context), path.strip('"'))
# --- Extended variable assertions ---
[docs]
@step(
"the variable {name} does not equal {value}",
category="data",
description="Assert that a variable does not equal a value.",
example='Then the variable "status" does not equal "error"',
i18n={
"es": "la variable {name} no es igual a {value}",
"pt": "a variável {name} não é igual a {value}",
},
)
def step_variable_not_equals(context: Any, name: str, value: str) -> None:
"""Assert variable does not equal."""
data_assert_variable_not_equals(_get_data(context), name.strip('"'), value.strip('"'))
[docs]
@step(
"the variable {name} contains {text}",
category="data",
description="Assert that a variable's string value contains a substring.",
example='Then the variable "message" contains "success"',
i18n={
"es": "la variable {name} contiene {text}",
"pt": "a variável {name} contém {text}",
},
)
def step_variable_contains(context: Any, name: str, text: str) -> None:
"""Assert variable contains substring."""
data_assert_variable_contains(_get_data(context), name.strip('"'), text.strip('"'))
[docs]
@step(
"the variable {name} is empty",
category="data",
description="Assert that a variable is empty.",
example='Then the variable "errors" is empty',
i18n={
"es": "la variable {name} está vacía",
"pt": "a variável {name} está vazia",
},
)
def step_variable_is_empty(context: Any, name: str) -> None:
"""Assert variable is empty."""
data_assert_variable_is_empty(_get_data(context), name.strip('"'))
[docs]
@step(
"the variable {name} is not empty",
category="data",
description="Assert that a variable is not empty.",
example='Then the variable "results" is not empty',
i18n={
"es": "la variable {name} no está vacía",
"pt": "a variável {name} não está vazia",
},
)
def step_variable_is_not_empty(context: Any, name: str) -> None:
"""Assert variable is not empty."""
data_assert_variable_is_not_empty(_get_data(context), name.strip('"'))
[docs]
@step(
"the variable {name} has length {count:d}",
category="data",
description="Assert that a variable has a specific length.",
example='Then the variable "items" has length 5',
i18n={
"es": "la variable {name} tiene longitud {count:d}",
"pt": "a variável {name} tem comprimento {count:d}",
},
)
def step_variable_has_length(context: Any, name: str, count: int) -> None:
"""Assert variable has length."""
data_assert_variable_has_length(_get_data(context), name.strip('"'), count)
# --- Extended env assertions ---
[docs]
@step(
"the environment variable {key} does not equal {value}",
category="data",
description="Assert that an environment variable does not equal a value.",
example='Then the environment variable "MODE" does not equal "production"',
i18n={
"es": "la variable de entorno {key} no es igual a {value}",
"pt": "a variável de ambiente {key} não é igual a {value}",
},
)
def step_env_not_equals(context: Any, key: str, value: str) -> None:
"""Assert env var does not equal."""
data_assert_env_not_equals(key.strip('"'), value.strip('"'))
[docs]
@step(
"the environment variable {key} does not exist",
category="data",
description="Assert that an environment variable does not exist.",
example='Then the environment variable "DEBUG" does not exist',
i18n={
"es": "la variable de entorno {key} no existe",
"pt": "a variável de ambiente {key} não existe",
},
)
def step_env_not_exists(context: Any, key: str) -> None:
"""Assert env var does not exist."""
data_assert_env_not_exists(key.strip('"'))
# --- Variable manipulation ---
[docs]
@step(
"I copy the variable {source} to {target}",
category="data",
description="Copy a variable to a new name.",
example='When I copy the variable "original" to "backup"',
i18n={
"es": "copio la variable {source} a {target}",
"pt": "copio a variável {source} para {target}",
},
)
def step_copy_variable(context: Any, source: str, target: str) -> None:
"""Copy a variable."""
data_copy_variable(_get_data(context), source.strip('"'), target.strip('"'))
[docs]
@step(
"I clear all variables",
category="data",
description="Remove all variables from the data context.",
example="When I clear all variables",
i18n={
"es": "limpio todas las variables",
"pt": "limpo todas as variáveis",
},
)
def step_clear_variables(context: Any) -> None:
"""Clear all variables."""
data_clear_variables(_get_data(context))
[docs]
@step(
"I set the variable {name} to the JSON {json}",
category="data",
description="Set a variable to a parsed JSON value.",
example='Given I set the variable "config" to the JSON \'{"debug": true}\'',
i18n={
"es": "establezco la variable {name} al JSON {json}",
"pt": "defino a variável {name} como o JSON {json}",
},
)
def step_set_variable_json(context: Any, name: str, json_str: str) -> None:
"""Set a variable from a JSON string."""
import json as _json
cleaned = json_str.strip("'").strip('"')
try:
_json.loads(cleaned)
except _json.JSONDecodeError as exc:
raise AssertionError(f"Invalid JSON value: {exc}") from exc
data_set_variable_json(_get_data(context), name.strip('"'), cleaned)
[docs]
@step(
"I set the environment variable {key} from the variable {variable}",
category="data",
description="Set an environment variable from a data variable's value.",
example='When I set the environment variable "TOKEN" from the variable "api_token"',
i18n={
"es": "establezco la variable de entorno {key} desde la variable {variable}",
"pt": "defino a variável de ambiente {key} da variável {variable}",
},
)
def step_set_env_from_variable(context: Any, key: str, variable: str) -> None:
"""Set env var from a data variable."""
data_set_env_from_variable(_get_data(context), variable.strip('"'), key.strip('"'))
# --- Extended variable assertions ---
[docs]
@step(
"the variable {name} matches the pattern {pattern}",
category="data",
description="Assert that a variable's value matches a regex pattern.",
example='Then the variable "email" matches the pattern ".*@.*\\..*"',
i18n={
"es": "la variable {name} coincide con el patrón {pattern}",
"pt": "a variável {name} corresponde ao padrão {pattern}",
},
)
def step_variable_matches(context: Any, name: str, pattern: str) -> None:
"""Assert variable matches regex pattern."""
data_assert_variable_matches(
_get_data(context), name.strip('"'), pattern.strip('"')
)
[docs]
@step(
"the variable {name} starts with {text}",
category="data",
description="Assert that a variable's value starts with the given text.",
example='Then the variable "greeting" starts with "Hello"',
i18n={
"es": "la variable {name} comienza con {text}",
"pt": "a variável {name} começa com {text}",
},
)
def step_variable_starts_with(context: Any, name: str, text: str) -> None:
"""Assert variable starts with text."""
data_assert_variable_starts_with(
_get_data(context), name.strip('"'), text.strip('"')
)
[docs]
@step(
"the variable {name} ends with {text}",
category="data",
description="Assert that a variable's value ends with the given text.",
example='Then the variable "filename" ends with ".csv"',
i18n={
"es": "la variable {name} termina con {text}",
"pt": "a variável {name} termina com {text}",
},
)
def step_variable_ends_with(context: Any, name: str, text: str) -> None:
"""Assert variable ends with text."""
data_assert_variable_ends_with(
_get_data(context), name.strip('"'), text.strip('"')
)
[docs]
@step(
"I increment the variable {name} by {amount:d}",
category="data",
description="Increment a numeric variable by a given amount.",
example='When I increment the variable "counter" by 1',
i18n={
"es": "incremento la variable {name} en {amount:d}",
"pt": "incremento a variável {name} em {amount:d}",
},
)
def step_increment_variable(context: Any, name: str, amount: int) -> None:
"""Increment a numeric variable."""
data_increment_variable(_get_data(context), name.strip('"'), amount)
[docs]
@step(
"the variable {name} is greater than {value}",
category="data",
description="Assert that a variable's numeric value is greater than a threshold.",
example='Then the variable "count" is greater than 10',
i18n={
"es": "la variable {name} es mayor que {value}",
"pt": "a variável {name} é maior que {value}",
},
)
def step_variable_greater_than(context: Any, name: str, value: str) -> None:
"""Assert variable is greater than value."""
data_assert_variable_greater_than(
_get_data(context), name.strip('"'), value.strip('"')
)
[docs]
@step(
"the variable {name} is less than {value}",
category="data",
description="Assert that a variable's numeric value is less than a threshold.",
example='Then the variable "count" is less than 100',
i18n={
"es": "la variable {name} es menor que {value}",
"pt": "a variável {name} é menor que {value}",
},
)
def step_variable_less_than(context: Any, name: str, value: str) -> None:
"""Assert variable is less than value."""
data_assert_variable_less_than(
_get_data(context), name.strip('"'), value.strip('"')
)
# --- Utility steps ---
[docs]
@step(
"I wait for {seconds:f} seconds",
category="data",
description="Sleep for a given number of seconds.",
example="When I wait for 2.5 seconds",
i18n={
"es": "espero {seconds:f} segundos",
"pt": "eu espero {seconds:f} segundos",
},
)
def step_wait(context: Any, seconds: float) -> None:
"""Wait for a number of seconds."""
data_wait(seconds)
_ALL_STEPS = [
step_set_variable,
step_variable_equals,
step_variable_exists,
step_variable_not_exists,
step_delete_variable,
step_load_yaml,
step_load_json_file,
step_extract_key_path,
# Extended variable assertions
step_variable_not_equals,
step_variable_contains,
step_variable_is_empty,
step_variable_is_not_empty,
step_variable_has_length,
# Regex + string assertions
step_variable_matches,
step_variable_starts_with,
step_variable_ends_with,
# Numeric assertions
step_variable_greater_than,
step_variable_less_than,
# Variable manipulation
step_copy_variable,
step_clear_variables,
step_set_variable_json,
step_increment_variable,
# Env
step_set_env_var,
step_delete_env_var,
step_env_equals,
step_env_exists,
step_store_env_var,
step_load_env_file,
# Extended env assertions
step_env_not_equals,
step_env_not_exists,
# Env from variable
step_set_env_from_variable,
# Utility
step_wait,
]
[docs]
def register(registry: StepRegistry) -> None:
"""Register all data steps into the given registry."""
for step_fn in _ALL_STEPS:
registry.add(step_fn)