proxyml 0.2.0__tar.gz → 0.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {proxyml-0.2.0 → proxyml-0.2.2}/PKG-INFO +1 -1
- {proxyml-0.2.0 → proxyml-0.2.2}/pyproject.toml +1 -1
- {proxyml-0.2.0 → proxyml-0.2.2}/src/proxyml/__init__.py +2 -0
- {proxyml-0.2.0 → proxyml-0.2.2}/src/proxyml/client.py +97 -49
- {proxyml-0.2.0 → proxyml-0.2.2}/src/proxyml/schema.py +7 -2
- {proxyml-0.2.0 → proxyml-0.2.2}/src/proxyml.egg-info/PKG-INFO +1 -1
- {proxyml-0.2.0 → proxyml-0.2.2}/tests/test_client.py +41 -14
- {proxyml-0.2.0 → proxyml-0.2.2}/LICENSE +0 -0
- {proxyml-0.2.0 → proxyml-0.2.2}/README.md +0 -0
- {proxyml-0.2.0 → proxyml-0.2.2}/setup.cfg +0 -0
- {proxyml-0.2.0 → proxyml-0.2.2}/src/proxyml.egg-info/SOURCES.txt +0 -0
- {proxyml-0.2.0 → proxyml-0.2.2}/src/proxyml.egg-info/dependency_links.txt +0 -0
- {proxyml-0.2.0 → proxyml-0.2.2}/src/proxyml.egg-info/requires.txt +0 -0
- {proxyml-0.2.0 → proxyml-0.2.2}/src/proxyml.egg-info/top_level.txt +0 -0
- {proxyml-0.2.0 → proxyml-0.2.2}/tests/test_schema.py +0 -0
|
@@ -1,16 +1,26 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
|
|
2
|
+
import os
|
|
3
3
|
from typing import Any
|
|
4
4
|
|
|
5
5
|
import orjson
|
|
6
|
-
import requests
|
|
7
|
-
import os
|
|
8
6
|
import numpy as np
|
|
9
7
|
import pandas as pd
|
|
8
|
+
import requests
|
|
10
9
|
from pandas.api.types import is_float_dtype, is_integer_dtype
|
|
11
10
|
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
12
|
|
|
13
13
|
_BOOL_STRINGS = {"true", "false"}
|
|
14
|
+
_TIMEOUT = 120
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class _ErrorResponse:
|
|
18
|
+
"""Returned by HTTP helpers when a network-level error occurs."""
|
|
19
|
+
status_code = 0
|
|
20
|
+
text = ""
|
|
21
|
+
|
|
22
|
+
def json(self) -> dict:
|
|
23
|
+
return {}
|
|
14
24
|
|
|
15
25
|
|
|
16
26
|
def _base_url() -> str:
|
|
@@ -33,7 +43,7 @@ def _headers() -> dict:
|
|
|
33
43
|
}
|
|
34
44
|
|
|
35
45
|
|
|
36
|
-
def post(endpoint: str, payload: dict) -> requests.models.Response:
|
|
46
|
+
def post(endpoint: str, payload: dict) -> requests.models.Response | _ErrorResponse:
|
|
37
47
|
"""
|
|
38
48
|
POSTs a request to a ProxyML API endpoint.
|
|
39
49
|
|
|
@@ -44,53 +54,65 @@ def post(endpoint: str, payload: dict) -> requests.models.Response:
|
|
|
44
54
|
Returns:
|
|
45
55
|
requests Response object.
|
|
46
56
|
"""
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
57
|
+
try:
|
|
58
|
+
return requests.post(
|
|
59
|
+
url=f'{_base_url()}{endpoint}',
|
|
60
|
+
data=orjson.dumps(payload, option=orjson.OPT_SERIALIZE_NUMPY),
|
|
61
|
+
headers=_headers(),
|
|
62
|
+
timeout=_TIMEOUT,
|
|
63
|
+
)
|
|
64
|
+
except requests.exceptions.RequestException as exc:
|
|
65
|
+
logger.error("Network error POSTing to %s: %s", endpoint, exc)
|
|
66
|
+
return _ErrorResponse()
|
|
53
67
|
|
|
54
68
|
|
|
55
|
-
def put(endpoint: str, payload: dict) -> requests.models.Response:
|
|
69
|
+
def put(endpoint: str, payload: dict) -> requests.models.Response | _ErrorResponse:
|
|
56
70
|
"""
|
|
57
71
|
PUTs a request to a ProxyML API endpoint.
|
|
58
72
|
|
|
59
73
|
Args:
|
|
60
74
|
endpoint (str): ProxyML API endpoint. PROXYML_BASE_URL is prepended e.g. use endpoint='/schemas' not 'https://api.proxyml.ai/api/v1/schemas'.
|
|
61
|
-
payload (dict): JSON payload to
|
|
75
|
+
payload (dict): JSON payload to PUT.
|
|
62
76
|
|
|
63
77
|
Returns:
|
|
64
78
|
requests Response object.
|
|
65
|
-
"""
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
79
|
+
"""
|
|
80
|
+
try:
|
|
81
|
+
return requests.put(
|
|
82
|
+
url=f'{_base_url()}{endpoint}',
|
|
83
|
+
data=orjson.dumps(payload, option=orjson.OPT_SERIALIZE_NUMPY),
|
|
84
|
+
headers=_headers(),
|
|
85
|
+
timeout=_TIMEOUT,
|
|
86
|
+
)
|
|
87
|
+
except requests.exceptions.RequestException as exc:
|
|
88
|
+
logger.error("Network error PUTting to %s: %s", endpoint, exc)
|
|
89
|
+
return _ErrorResponse()
|
|
72
90
|
|
|
73
91
|
|
|
74
|
-
def get(endpoint: str, params: dict) -> requests.models.Response:
|
|
92
|
+
def get(endpoint: str, params: dict | None = None) -> requests.models.Response | _ErrorResponse:
|
|
75
93
|
"""
|
|
76
94
|
GETs a request to a ProxyML API endpoint.
|
|
77
95
|
|
|
78
96
|
Args:
|
|
79
97
|
endpoint (str): ProxyML API endpoint. PROXYML_BASE_URL is prepended e.g. use endpoint='/schemas' not 'https://api.proxyml.ai/api/v1/schemas'.
|
|
80
|
-
params (dict):
|
|
98
|
+
params (dict): query parameters.
|
|
81
99
|
|
|
82
100
|
Returns:
|
|
83
101
|
requests Response object.
|
|
84
102
|
"""
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
103
|
+
try:
|
|
104
|
+
return requests.get(
|
|
105
|
+
url=f'{_base_url()}{endpoint}',
|
|
106
|
+
headers=_headers(),
|
|
107
|
+
params=params,
|
|
108
|
+
timeout=_TIMEOUT,
|
|
109
|
+
)
|
|
110
|
+
except requests.exceptions.RequestException as exc:
|
|
111
|
+
logger.error("Network error GETting %s: %s", endpoint, exc)
|
|
112
|
+
return _ErrorResponse()
|
|
91
113
|
|
|
92
114
|
|
|
93
|
-
def patch(endpoint: str, payload: dict) -> requests.models.Response:
|
|
115
|
+
def patch(endpoint: str, payload: dict) -> requests.models.Response | _ErrorResponse:
|
|
94
116
|
"""
|
|
95
117
|
PATCHes a request to a ProxyML API endpoint.
|
|
96
118
|
|
|
@@ -101,15 +123,19 @@ def patch(endpoint: str, payload: dict) -> requests.models.Response:
|
|
|
101
123
|
Returns:
|
|
102
124
|
requests Response object.
|
|
103
125
|
"""
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
126
|
+
try:
|
|
127
|
+
return requests.patch(
|
|
128
|
+
url=f'{_base_url()}{endpoint}',
|
|
129
|
+
data=orjson.dumps(payload, option=orjson.OPT_SERIALIZE_NUMPY),
|
|
130
|
+
headers=_headers(),
|
|
131
|
+
timeout=_TIMEOUT,
|
|
132
|
+
)
|
|
133
|
+
except requests.exceptions.RequestException as exc:
|
|
134
|
+
logger.error("Network error PATCHing %s: %s", endpoint, exc)
|
|
135
|
+
return _ErrorResponse()
|
|
110
136
|
|
|
111
137
|
|
|
112
|
-
def delete(endpoint: str) -> requests.models.Response:
|
|
138
|
+
def delete(endpoint: str) -> requests.models.Response | _ErrorResponse:
|
|
113
139
|
"""
|
|
114
140
|
DELETE request to a ProxyML API endpoint.
|
|
115
141
|
|
|
@@ -119,20 +145,24 @@ def delete(endpoint: str) -> requests.models.Response:
|
|
|
119
145
|
Returns:
|
|
120
146
|
requests Response object.
|
|
121
147
|
"""
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
148
|
+
try:
|
|
149
|
+
return requests.delete(
|
|
150
|
+
url=f'{_base_url()}{endpoint}',
|
|
151
|
+
headers=_headers(),
|
|
152
|
+
timeout=_TIMEOUT,
|
|
153
|
+
)
|
|
154
|
+
except requests.exceptions.RequestException as exc:
|
|
155
|
+
logger.error("Network error DELETEing %s: %s", endpoint, exc)
|
|
156
|
+
return _ErrorResponse()
|
|
127
157
|
|
|
128
158
|
|
|
129
|
-
def put_schema(schema: dict, name: str
|
|
159
|
+
def put_schema(schema: dict, name: str) -> Any:
|
|
130
160
|
"""
|
|
131
161
|
Uploads a data schema.
|
|
132
162
|
|
|
133
163
|
Args:
|
|
134
164
|
schema (dict): data schema object
|
|
135
|
-
name (str):
|
|
165
|
+
name (str): name for the schema.
|
|
136
166
|
Returns:
|
|
137
167
|
API response JSON object, or None if the return code was not 200.
|
|
138
168
|
"""
|
|
@@ -148,7 +178,7 @@ def put_schema(schema: dict, name: str = "default") -> Any:
|
|
|
148
178
|
return None
|
|
149
179
|
|
|
150
180
|
|
|
151
|
-
def fetch_schema(name: str
|
|
181
|
+
def fetch_schema(name: str) -> dict | None:
|
|
152
182
|
"""Retrieve a stored feature schema by name."""
|
|
153
183
|
r = get(endpoint=f'/schema/{name}', params={})
|
|
154
184
|
if r.status_code == 200:
|
|
@@ -212,7 +242,7 @@ def _cast_column(series: pd.Series, ftype: str) -> pd.Series:
|
|
|
212
242
|
return series
|
|
213
243
|
|
|
214
244
|
|
|
215
|
-
def synthesize_data(num_points: int = 100, sample: list | None = None, as_df: bool = True, schema_name: str
|
|
245
|
+
def synthesize_data(num_points: int = 100, sample: list | None = None, as_df: bool = True, *, schema_name: str) -> Any:
|
|
216
246
|
"""
|
|
217
247
|
Synthesizes data based on a data schema.
|
|
218
248
|
|
|
@@ -220,7 +250,7 @@ def synthesize_data(num_points: int = 100, sample: list | None = None, as_df: bo
|
|
|
220
250
|
num_points (int): number of samples to synthesize, defaults to 100.
|
|
221
251
|
sample (list): if specified, synthesized data will be a blend of samples generated from the schema and a number of perturbations around this sample. If not specified (default), all synthesized data is generated by sampling from the data schema.
|
|
222
252
|
as_df (bool): if True (default), data are returned as a pandas DataFrame.
|
|
223
|
-
schema_name (str): name of the data schema to use to generate the data
|
|
253
|
+
schema_name (str): name of the data schema to use to generate the data.
|
|
224
254
|
Returns:
|
|
225
255
|
JSON object representing the synthesized data if as_df=False, a pandas DataFrame if as_df=True, or None if an error occurred.
|
|
226
256
|
"""
|
|
@@ -250,7 +280,8 @@ def train_surrogate(
|
|
|
250
280
|
feature_names: list[str] | None,
|
|
251
281
|
task: str = 'auto',
|
|
252
282
|
test_size: float = 0.2,
|
|
253
|
-
|
|
283
|
+
*,
|
|
284
|
+
schema_name: str,
|
|
254
285
|
name: str | None = None,
|
|
255
286
|
comments: str | None = None,
|
|
256
287
|
) -> Any:
|
|
@@ -263,7 +294,7 @@ def train_surrogate(
|
|
|
263
294
|
feature_names (list): names of the features (columns) in the data.
|
|
264
295
|
task (str): specifies the modeling task, one of "classification," "regression," or "auto" in which case ProxyML will attempt to automatically determine the modeling task.
|
|
265
296
|
test_size (float): fraction of the data to set aside for test data, defaults to 0.2.
|
|
266
|
-
schema_name (str): name of the data schema to use
|
|
297
|
+
schema_name (str): name of the data schema to use.
|
|
267
298
|
name (str): an optional name for the surrogate.
|
|
268
299
|
comments (str): an optional comment string for the surrogate.
|
|
269
300
|
Returns:
|
|
@@ -345,7 +376,7 @@ def find_counterfactual(sample, target, n_neighbors: int = 10000, perturbation_s
|
|
|
345
376
|
sample (list): point around which neighbors will be found.
|
|
346
377
|
target (Any): the desired prediction outcome, can be a string or number for classification or a target predicted value for regression.
|
|
347
378
|
n_neighbors (int): the number of neighbors to search, defaults to 10000.
|
|
348
|
-
|
|
379
|
+
perturbation_scale (float): controls the "wiggle" in the features around the provided sample. Defaults to 0.1.
|
|
349
380
|
version (str): name of the surrogate model to run, defaults to "default."
|
|
350
381
|
as_df (bool): if True, return the counterfactual as a dataframe. If False, returns JSON object.
|
|
351
382
|
Returns:
|
|
@@ -467,7 +498,7 @@ def find_counterfactuals(
|
|
|
467
498
|
samples (list): list of points around which neighbors will be found.
|
|
468
499
|
target (Any): the desired prediction outcome, can be a string or number for classification or a target predicted value for regression.
|
|
469
500
|
n_neighbors (int): the number of neighbors to search, defaults to 10000.
|
|
470
|
-
|
|
501
|
+
perturbation_scale (float): controls the "wiggle" in the features around the provided sample. Defaults to 0.1.
|
|
471
502
|
version (str): name of the surrogate model to run, defaults to "default."
|
|
472
503
|
as_df (bool): if True, return the counterfactual as a dataframe. If False, returns JSON object.
|
|
473
504
|
Returns:
|
|
@@ -592,6 +623,23 @@ def get_feature_importances(version: str | None = None) -> Any:
|
|
|
592
623
|
return None
|
|
593
624
|
|
|
594
625
|
|
|
626
|
+
def health_check() -> dict | None:
|
|
627
|
+
"""Check API connectivity and version. Does not require authentication and does not count against usage quota.
|
|
628
|
+
|
|
629
|
+
Returns:
|
|
630
|
+
Dict with ``status``, ``model_loaded``, and ``version``, or None on failure.
|
|
631
|
+
"""
|
|
632
|
+
try:
|
|
633
|
+
r = requests.get(url=f'{_base_url()}/health', timeout=_TIMEOUT)
|
|
634
|
+
except requests.exceptions.RequestException as exc:
|
|
635
|
+
logger.error("Network error calling /health: %s", exc)
|
|
636
|
+
return None
|
|
637
|
+
if r.status_code == 200:
|
|
638
|
+
return r.json()
|
|
639
|
+
logger.error("Health check failed with status %s: %s", r.status_code, r.text)
|
|
640
|
+
return None
|
|
641
|
+
|
|
642
|
+
|
|
595
643
|
def get_usage() -> dict | None:
|
|
596
644
|
"""Return current tier, usage counts, and quota for the authenticated user."""
|
|
597
645
|
r = get(endpoint='/account/usage', params={})
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
logger = logging.getLogger(__name__)
|
|
3
2
|
|
|
4
|
-
import os
|
|
5
3
|
import numpy as np
|
|
6
4
|
import pandas as pd
|
|
7
5
|
from pandas.api.types import is_float_dtype, is_integer_dtype
|
|
8
6
|
|
|
7
|
+
logger = logging.getLogger(__name__)
|
|
8
|
+
|
|
9
9
|
|
|
10
10
|
def gen_continuous_schema(s: pd.Series, name: str | None = None) -> dict:
|
|
11
11
|
"""
|
|
@@ -73,6 +73,11 @@ def get_schema(df: pd.DataFrame, immutable_cols: list[str] | None) -> dict:
|
|
|
73
73
|
Returns:
|
|
74
74
|
data schema as dict. Review and adjust as needed.
|
|
75
75
|
"""
|
|
76
|
+
if immutable_cols:
|
|
77
|
+
unknown = set(immutable_cols) - set(df.columns)
|
|
78
|
+
if unknown:
|
|
79
|
+
logger.warning("immutable_cols not found in DataFrame and will be ignored: %s", sorted(unknown))
|
|
80
|
+
|
|
76
81
|
schema = {
|
|
77
82
|
'features': list(),
|
|
78
83
|
'_note': (
|
|
@@ -3,11 +3,13 @@ from unittest.mock import MagicMock, patch
|
|
|
3
3
|
|
|
4
4
|
import pandas as pd
|
|
5
5
|
import pytest
|
|
6
|
+
import requests
|
|
6
7
|
|
|
7
8
|
from proxyml.client import (
|
|
8
9
|
_cast_column,
|
|
9
10
|
_base_url,
|
|
10
11
|
_headers,
|
|
12
|
+
health_check,
|
|
11
13
|
delete_model,
|
|
12
14
|
delete_schema,
|
|
13
15
|
diff_models,
|
|
@@ -34,6 +36,31 @@ from proxyml.client import (
|
|
|
34
36
|
)
|
|
35
37
|
|
|
36
38
|
|
|
39
|
+
# ---------------------------------------------------------------------------
|
|
40
|
+
# health_check
|
|
41
|
+
# ---------------------------------------------------------------------------
|
|
42
|
+
|
|
43
|
+
@patch("proxyml.client.requests.get")
|
|
44
|
+
def test_health_check_success(mock_get):
|
|
45
|
+
mock_get.return_value = _mock_response(200, {"status": "ok", "model_loaded": True, "version": "0.1.0"})
|
|
46
|
+
result = health_check()
|
|
47
|
+
assert result == {"status": "ok", "model_loaded": True, "version": "0.1.0"}
|
|
48
|
+
mock_get.assert_called_once()
|
|
49
|
+
assert mock_get.call_args.kwargs["url"].endswith("/health")
|
|
50
|
+
assert "headers" not in mock_get.call_args.kwargs # no auth header
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@patch("proxyml.client.requests.get")
|
|
54
|
+
def test_health_check_failure_returns_none(mock_get):
|
|
55
|
+
mock_get.return_value = _mock_response(503, {"detail": "unavailable"})
|
|
56
|
+
assert health_check() is None
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@patch("proxyml.client.requests.get", side_effect=requests.exceptions.ConnectionError("connection refused"))
|
|
60
|
+
def test_health_check_network_error_returns_none(mock_get):
|
|
61
|
+
assert health_check() is None
|
|
62
|
+
|
|
63
|
+
|
|
37
64
|
# ---------------------------------------------------------------------------
|
|
38
65
|
# _headers
|
|
39
66
|
# ---------------------------------------------------------------------------
|
|
@@ -174,11 +201,11 @@ def _mock_response(status_code, json_body):
|
|
|
174
201
|
|
|
175
202
|
|
|
176
203
|
@patch("proxyml.client.put")
|
|
177
|
-
def
|
|
204
|
+
def test_put_schema_success(mock_put):
|
|
178
205
|
mock_put.return_value = _mock_response(200, {"features": []})
|
|
179
|
-
result = put_schema({"features": []})
|
|
206
|
+
result = put_schema({"features": []}, name="myschema")
|
|
180
207
|
assert result == {"features": []}
|
|
181
|
-
mock_put.assert_called_once_with(endpoint="/schema/
|
|
208
|
+
mock_put.assert_called_once_with(endpoint="/schema/myschema", payload={"features": []})
|
|
182
209
|
|
|
183
210
|
|
|
184
211
|
@patch("proxyml.client.put")
|
|
@@ -191,7 +218,7 @@ def test_put_schema_named(mock_put):
|
|
|
191
218
|
@patch("proxyml.client.put")
|
|
192
219
|
def test_put_schema_failure(mock_put):
|
|
193
220
|
mock_put.return_value = _mock_response(422, {"detail": "invalid"})
|
|
194
|
-
result = put_schema({"features": []})
|
|
221
|
+
result = put_schema({"features": []}, name="myschema")
|
|
195
222
|
assert result is None
|
|
196
223
|
|
|
197
224
|
|
|
@@ -200,11 +227,11 @@ def test_put_schema_failure(mock_put):
|
|
|
200
227
|
# ---------------------------------------------------------------------------
|
|
201
228
|
|
|
202
229
|
@patch("proxyml.client.get")
|
|
203
|
-
def
|
|
230
|
+
def test_fetch_schema_success(mock_get):
|
|
204
231
|
mock_get.return_value = _mock_response(200, {"features": [{"type": "continuous", "name": "age"}]})
|
|
205
|
-
result = fetch_schema()
|
|
232
|
+
result = fetch_schema(name="myschema")
|
|
206
233
|
assert result["features"][0]["name"] == "age"
|
|
207
|
-
mock_get.assert_called_once_with(endpoint="/schema/
|
|
234
|
+
mock_get.assert_called_once_with(endpoint="/schema/myschema", params={})
|
|
208
235
|
|
|
209
236
|
|
|
210
237
|
@patch("proxyml.client.get")
|
|
@@ -282,12 +309,12 @@ def test_synthesize_data_no_sample(mock_post):
|
|
|
282
309
|
"feature_names": ["f_cont", "f_cat"],
|
|
283
310
|
"feature_types": ["continuous", "categorical"],
|
|
284
311
|
})
|
|
285
|
-
df = synthesize_data(num_points=2, sample=None)
|
|
312
|
+
df = synthesize_data(num_points=2, sample=None, schema_name="myschema")
|
|
286
313
|
assert isinstance(df, pd.DataFrame)
|
|
287
314
|
assert list(df.columns) == ["f_cont", "f_cat"]
|
|
288
315
|
payload = mock_post.call_args.kwargs["payload"]
|
|
289
316
|
assert payload["n"] == 2
|
|
290
|
-
assert payload["schema_name"] == "
|
|
317
|
+
assert payload["schema_name"] == "myschema"
|
|
291
318
|
|
|
292
319
|
|
|
293
320
|
@patch("proxyml.client.post")
|
|
@@ -303,7 +330,7 @@ def test_synthesize_data_named_schema(mock_post):
|
|
|
303
330
|
@patch("proxyml.client.post")
|
|
304
331
|
def test_synthesize_data_failure_returns_none(mock_post):
|
|
305
332
|
mock_post.return_value = _mock_response(500, {})
|
|
306
|
-
result = synthesize_data(num_points=10, sample=None)
|
|
333
|
+
result = synthesize_data(num_points=10, sample=None, schema_name="myschema")
|
|
307
334
|
assert result is None
|
|
308
335
|
|
|
309
336
|
|
|
@@ -312,16 +339,16 @@ def test_train_surrogate_with_metadata(mock_post):
|
|
|
312
339
|
mock_post.return_value = _mock_response(200, {
|
|
313
340
|
"version": "abc-123", "trained_at": "2026-04-19T12:00:00",
|
|
314
341
|
"task": "regression", "name": "v1", "comments": "test run",
|
|
315
|
-
"feature_names": None, "metrics": {"r2": 0.95}, "
|
|
342
|
+
"feature_names": None, "metrics": {"r2": 0.95}, "warnings": [],
|
|
316
343
|
})
|
|
317
344
|
result = train_surrogate(
|
|
318
345
|
samples=[[1.0, 2.0]], predictions=[3.0],
|
|
319
|
-
feature_names=None, name="v1", comments="test run",
|
|
346
|
+
feature_names=None, schema_name="myschema", name="v1", comments="test run",
|
|
320
347
|
)
|
|
321
348
|
payload = mock_post.call_args.kwargs["payload"]
|
|
322
349
|
assert payload["name"] == "v1"
|
|
323
350
|
assert payload["comments"] == "test run"
|
|
324
|
-
assert payload["schema_name"] == "
|
|
351
|
+
assert payload["schema_name"] == "myschema"
|
|
325
352
|
assert result["version"] == "abc-123"
|
|
326
353
|
assert result["trained_at"] == "2026-04-19T12:00:00"
|
|
327
354
|
|
|
@@ -337,7 +364,7 @@ def test_train_surrogate_named_schema(mock_post):
|
|
|
337
364
|
@patch("proxyml.client.post")
|
|
338
365
|
def test_train_surrogate_omits_none_metadata(mock_post):
|
|
339
366
|
mock_post.return_value = _mock_response(200, {"version": "abc-123"})
|
|
340
|
-
train_surrogate(samples=[[1.0]], predictions=[1.0], feature_names=None)
|
|
367
|
+
train_surrogate(samples=[[1.0]], predictions=[1.0], feature_names=None, schema_name="myschema")
|
|
341
368
|
payload = mock_post.call_args.kwargs["payload"]
|
|
342
369
|
assert "name" not in payload
|
|
343
370
|
assert "comments" not in payload
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|