SIENTIAPDE-1579: Fix SientiaMlException propagation in ModelServing.search_runs_by_name to correctly raise the exception with its message, resolving a TypeError. Enhance training test script to support scenario-specific CSV files for different test cases. Update search_runs_by_name return type hint and apply minor code formatting.

This commit is contained in:
Bruno Domingues
2026-02-19 21:13:41 -03:00
parent f952647cf6
commit 41c4490cad
5 changed files with 56 additions and 33 deletions

View File

@@ -56,7 +56,7 @@ class ModelServing:
# Function to list runs for a given experiment
def search_runs_by_name(
self, experiment_names: list[str], order_by: None | list[str] = None
) -> pd.DataFrame:
) -> pd.DataFrame | list:
"""
List runs for a specified MLflow experiment.
@@ -64,7 +64,7 @@ class ModelServing:
experiment_names (list[str]): List with experiment_names to retrieve runs from.
Returns:
pandas.DataFrame: A DataFrame containing run information.
Union[pd.DataFrame, list]: A DataFrame or list containing run information.
Raises:
SientiaMlException: If unable to search runs.
@@ -73,7 +73,7 @@ class ModelServing:
runs = mlflow.search_runs(experiment_names=experiment_names, order_by=order_by)
except SientiaMlException as e:
logging.error(e)
raise SientiaMlException from e
raise SientiaMlException(str(e)) from e
return runs
def set_experiment(self, experiment_identifier: str) -> None:

View File

@@ -35,9 +35,7 @@ def validate_frontend_date_format(fmt: str | None) -> None:
return
if fmt not in ALLOWED_FRONTEND_DATE_FORMATS:
allowed = ', '.join(sorted(ALLOWED_FRONTEND_DATE_FORMATS))
raise ValueError(
f'Invalid date_format "{fmt}". Allowed formats: {allowed}'
)
raise ValueError(f'Invalid date_format "{fmt}". Allowed formats: {allowed}')
def _frontend_date_format_to_strftime(fmt: str | None) -> str | None:

View File

@@ -51,6 +51,12 @@ TEST_SCENARIOS_DIR = PROJECT_ROOT / 'docs' / 'test-scenarios'
MINIO_ALIAS = 'suse'
MINIO_BUCKET = 'model-training'
# Mapeamento de CSV específico por cenário
SCENARIO_CSV_MAPPING = {
'12-angular-test-date-format': Path('docs/DB_CV022_WIT230.csv'),
'13-angular-test-double-date-column': Path('docs/DB_CV022_WIT230 _double_date_column.csv'),
}
POSTGRES_CONFIG = {
'host': os.getenv('POSTGRES_HOST'),
'port': os.getenv('POSTGRES_PORT'),
@@ -306,6 +312,10 @@ def run_local_pipeline(
result['error'] = str(exc)
return result
# Use scenario-specific CSV if mapped, otherwise use provided csv_path
if scenario_name in SCENARIO_CSV_MAPPING:
csv_path = SCENARIO_CSV_MAPPING[scenario_name]
csv_path = _resolve_csv_path(csv_path)
_ensure_source_file(csv_path)
payload = _build_local_payload(request_data, csv_path)
@@ -450,6 +460,11 @@ def run_single_scenario(scenario_name: str, csv_path: Path) -> dict:
result['error'] = str(exc)
return result
# Use scenario-specific CSV if mapped, otherwise use provided csv_path
if scenario_name in SCENARIO_CSV_MAPPING:
csv_path = SCENARIO_CSV_MAPPING[scenario_name]
print(f' Using scenario-specific CSV: {csv_path}')
csv_path = _resolve_csv_path(csv_path)
# Upload CSV to MinIO

View File

@@ -112,18 +112,16 @@ def test_search_runs_by_name_with_order_by(mock_search_runs, mock_set_tracking_u
def test_search_runs_by_name_raises_exception(
mock_logging_error, mock_search_runs, mock_set_tracking_uri
):
"""Test search_runs_by_name raises TypeError due to bug in line 80 of model_serving.py."""
"""Test search_runs_by_name properly propagates SientiaMlException."""
model_serving = ModelServing(tracking_uri='http://mlflow.example.com')
exception = SientiaMlException(message='Search failed')
mock_search_runs.side_effect = exception
# The code has a bug on line 80: "raise SientiaMlException from e"
# This raises TypeError because SientiaMlException requires 'message' argument
with raises(TypeError, match="missing 1 required positional argument: 'message'"):
with raises(SientiaMlException, match='Search failed'):
model_serving.search_runs_by_name(['experiment1'])
mock_logging_error.assert_called_once()
mock_logging_error.assert_called_once_with(exception)
@patch('model_manager.sientia.model_serving.mlflow.set_tracking_uri')

View File

@@ -993,7 +993,9 @@ class TestConfigureDatetimeIndex:
assert 'var2' in result.columns
@pytest.mark.filterwarnings('ignore::UserWarning')
def test_configure_datetime_index_invalid_timestamp_column(self, training_repo, datetime_params):
def test_configure_datetime_index_invalid_timestamp_column(
self, training_repo, datetime_params
):
"""Test _configure_datetime_index with invalid timestamp values."""
data = pd.DataFrame(
{
@@ -1199,10 +1201,12 @@ class TestEnsureDateColumnParsed:
def test_parses_column_with_format(self, date_params):
"""When date_column and date_format set, column is parsed as datetime."""
data = pd.DataFrame({
'ts': ['2023-01-01 10:00:00', '2023-06-15 14:30:00'],
'x': [1, 2],
})
data = pd.DataFrame(
{
'ts': ['2023-01-01 10:00:00', '2023-06-15 14:30:00'],
'x': [1, 2],
}
)
result = _ensure_date_column_parsed(data, date_params)
assert result['ts'].dtype == 'datetime64[ns]'
assert result['ts'].iloc[0].year == 2023
@@ -1212,10 +1216,12 @@ class TestEnsureDateColumnParsed:
def test_invalid_values_coerced_to_nat(self, date_params):
"""Invalid date strings are coerced to NaT when format is set."""
date_params.date_format = 'yyyy-MM-dd HH:mm:ss'
data = pd.DataFrame({
'ts': ['2023-01-01 00:00:00', 'not-a-date', '2023-12-31 00:00:00'],
'x': [1, 2, 3],
})
data = pd.DataFrame(
{
'ts': ['2023-01-01 00:00:00', 'not-a-date', '2023-12-31 00:00:00'],
'x': [1, 2, 3],
}
)
result = _ensure_date_column_parsed(data, date_params)
assert pd.isna(result['ts'].iloc[1])
assert result['ts'].iloc[0].year == 2023
@@ -1256,10 +1262,12 @@ class TestApplySupportFilters:
def test_snake_case_upper_lower_line(self):
"""Support filters with upper_line/lower_line (snake_case) filter rows."""
data = pd.DataFrame({
'x': [1.0, 2.0, 3.0, 4.0],
'target': [2.0, 4.0, 6.0, 8.0],
})
data = pd.DataFrame(
{
'x': [1.0, 2.0, 3.0, 4.0],
'target': [2.0, 4.0, 6.0, 8.0],
}
)
support_filters = {
'x': {
'upper_line': {'intercept': 1.0, 'angle': 50},
@@ -1272,10 +1280,12 @@ class TestApplySupportFilters:
def test_camel_case_upper_lower_line(self):
"""Support filters with upperLine/lowerLine (camelCase) are accepted."""
data = pd.DataFrame({
'x': [1.0, 2.0, 3.0],
'target': [1.0, 2.0, 3.0],
})
data = pd.DataFrame(
{
'x': [1.0, 2.0, 3.0],
'target': [1.0, 2.0, 3.0],
}
)
support_filters = {
'x': {
'upperLine': {'intercept': 2, 'angle': 5},
@@ -1288,11 +1298,13 @@ class TestApplySupportFilters:
def test_two_variables_ands_masks(self):
"""Two variables apply AND of both masks."""
data = pd.DataFrame({
'a': [1.0, 2.0, 3.0],
'b': [1.0, 2.0, 3.0],
'target': [2.0, 2.0, 2.0],
})
data = pd.DataFrame(
{
'a': [1.0, 2.0, 3.0],
'b': [1.0, 2.0, 3.0],
'target': [2.0, 2.0, 2.0],
}
)
support_filters = {
'a': {
'upper_line': {'intercept': 10, 'angle': 45},