Skip to content

Commit de7e05f

Browse files
committed
fix: ChoicesFromFiles should be in camelCase
This is a bug in the SDK's CLI upload path. Root cause The server's GraphQL ParameterInput type expects the field name choicesFromFile in camelCase. The SDK was sending choices_from_file in snake_case, so the server rejected it. Exact error was: ``` Field 'choices_from_file' is not defined by type 'ParameterInput'. Did you mean 'choicesFromFile'?" ```
1 parent 06b3d3f commit de7e05f

2 files changed

Lines changed: 16 additions & 15 deletions

File tree

openhexa/sdk/pipelines/parameter/decorator.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ def to_dict(self) -> dict[str, typing.Any]:
119119
"directory": self.directory,
120120
}
121121
if isinstance(self.choices, ChoicesFromFile):
122-
d["choices_from_file"] = self.choices.to_dict()
122+
d["choicesFromFile"] = self.choices.to_dict()
123123
return d
124124

125125
def _validate_single(self, value: typing.Any):

tests/test_choices.py

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
"""Tests for ChoicesFromFile dynamic parameter choices."""
22

33
import tempfile
4-
from unittest import TestCase
4+
from pathlib import Path
5+
from unittest import TestCase, mock
56

67
import pytest
78

@@ -168,7 +169,7 @@ def test_ast_string_shorthand_csv(self):
168169
p = get_pipeline(tmpdir)
169170
param_dict = p.to_dict()["parameters"][0]
170171
assert param_dict["choices"] is None
171-
assert param_dict["choices_from_file"] == {"format": None, "path": "districts.csv", "column": None}
172+
assert param_dict["choicesFromFile"] == {"format": None, "path": "districts.csv", "column": None}
172173

173174
def test_ast_string_shorthand_json(self):
174175
with tempfile.TemporaryDirectory() as tmpdir:
@@ -177,7 +178,7 @@ def test_ast_string_shorthand_json(self):
177178
"@parameter('district', type=str, choices='regions.json')",
178179
)
179180
p = get_pipeline(tmpdir)
180-
assert p.to_dict()["parameters"][0]["choices_from_file"]["format"] is None
181+
assert p.to_dict()["parameters"][0]["choicesFromFile"]["format"] is None
181182

182183
def test_ast_string_shorthand_any_extension(self):
183184
with tempfile.TemporaryDirectory() as tmpdir:
@@ -186,7 +187,7 @@ def test_ast_string_shorthand_any_extension(self):
186187
"@parameter('district', type=str, choices='list.yml')",
187188
)
188189
p = get_pipeline(tmpdir)
189-
assert p.to_dict()["parameters"][0]["choices_from_file"]["format"] is None
190+
assert p.to_dict()["parameters"][0]["choicesFromFile"]["format"] is None
190191

191192
def test_ast_string_shorthand_same_output_as_explicit(self):
192193
with tempfile.TemporaryDirectory() as tmpdir:
@@ -229,7 +230,7 @@ def test_ast_static_list_unaffected(self):
229230
p = get_pipeline(tmpdir)
230231
param_dict = p.to_dict()["parameters"][0]
231232
assert param_dict["choices"] == ["UG", "KE"]
232-
assert "choices_from_file" not in param_dict
233+
assert "choicesFromFile" not in param_dict
233234

234235
def test_ast_string_no_extension_accepted(self):
235236
with tempfile.TemporaryDirectory() as tmpdir:
@@ -238,7 +239,7 @@ def test_ast_string_no_extension_accepted(self):
238239
"@parameter('district', type=str, choices='nodot')",
239240
)
240241
p = get_pipeline(tmpdir)
241-
assert p.to_dict()["parameters"][0]["choices_from_file"]["format"] is None
242+
assert p.to_dict()["parameters"][0]["choicesFromFile"]["format"] is None
242243

243244
def test_ast_string_any_extension_accepted(self):
244245
with tempfile.TemporaryDirectory() as tmpdir:
@@ -247,7 +248,7 @@ def test_ast_string_any_extension_accepted(self):
247248
"@parameter('district', type=str, choices='file.xlsx')",
248249
)
249250
p = get_pipeline(tmpdir)
250-
assert p.to_dict()["parameters"][0]["choices_from_file"]["format"] is None
251+
assert p.to_dict()["parameters"][0]["choicesFromFile"]["format"] is None
251252

252253

253254
# ---------------------------------------------------------------------------
@@ -264,13 +265,13 @@ def test_to_dict_emits_file_choices_key(self):
264265
p = Parameter(code="district", type=str, choices=ChoicesFromFile("districts.csv", column="code", format="csv"))
265266
d = p.to_dict()
266267
assert d["choices"] is None
267-
assert d["choices_from_file"] == {"format": "csv", "path": "districts.csv", "column": "code"}
268+
assert d["choicesFromFile"] == {"format": "csv", "path": "districts.csv", "column": "code"}
268269

269270
def test_to_dict_no_file_choices_key_for_static_choices(self):
270271
p = Parameter(code="country", type=str, choices=["UG", "KE"])
271272
d = p.to_dict()
272273
assert d["choices"] == ["UG", "KE"]
273-
assert "choices_from_file" not in d
274+
assert "choicesFromFile" not in d
274275

275276
def test_rejects_file_choices_on_bool_type(self):
276277
with pytest.raises(InvalidParameterError, match="don't accept choices"):
@@ -331,7 +332,7 @@ def test_file_choices_positional_path(self):
331332
p = get_pipeline(tmpdir)
332333
param_dict = p.to_dict()["parameters"][0]
333334
assert param_dict["choices"] is None
334-
assert param_dict["choices_from_file"] == {"format": None, "path": "districts.csv", "column": None}
335+
assert param_dict["choicesFromFile"] == {"format": None, "path": "districts.csv", "column": None}
335336

336337
def test_file_choices_with_column(self):
337338
with tempfile.TemporaryDirectory() as tmpdir:
@@ -341,7 +342,7 @@ def test_file_choices_with_column(self):
341342
)
342343
p = get_pipeline(tmpdir)
343344
param_dict = p.to_dict()["parameters"][0]
344-
assert param_dict["choices_from_file"] == {"format": None, "path": "data/districts.csv", "column": "code"}
345+
assert param_dict["choicesFromFile"] == {"format": None, "path": "data/districts.csv", "column": "code"}
345346

346347
def test_file_choices_with_column_positional(self):
347348
with tempfile.TemporaryDirectory() as tmpdir:
@@ -351,7 +352,7 @@ def test_file_choices_with_column_positional(self):
351352
)
352353
p = get_pipeline(tmpdir)
353354
param_dict = p.to_dict()["parameters"][0]
354-
assert param_dict["choices_from_file"] == {"format": None, "path": "data/districts.csv", "column": "code"}
355+
assert param_dict["choicesFromFile"] == {"format": None, "path": "data/districts.csv", "column": "code"}
355356

356357
def test_file_choices_explicit_format(self):
357358
with tempfile.TemporaryDirectory() as tmpdir:
@@ -361,7 +362,7 @@ def test_file_choices_explicit_format(self):
361362
)
362363
p = get_pipeline(tmpdir)
363364
param_dict = p.to_dict()["parameters"][0]
364-
assert param_dict["choices_from_file"]["format"] == "json"
365+
assert param_dict["choicesFromFile"]["format"] == "json"
365366

366367
def test_file_choices_format_none_by_default(self):
367368
with tempfile.TemporaryDirectory() as tmpdir:
@@ -371,7 +372,7 @@ def test_file_choices_format_none_by_default(self):
371372
)
372373
p = get_pipeline(tmpdir)
373374
param_dict = p.to_dict()["parameters"][0]
374-
assert param_dict["choices_from_file"]["format"] is None
375+
assert param_dict["choicesFromFile"]["format"] is None
375376

376377
def test_unsupported_call_in_choices_raises(self):
377378
with tempfile.TemporaryDirectory() as tmpdir:

0 commit comments

Comments
 (0)