Skip to content

Commit 0842110

Browse files
authored
fix: ChoicesFromFiles snake_case to camelCase (#393)
* Expand Makefile with help and install-editable commands * 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 222ebd1 commit 0842110

3 files changed

Lines changed: 29 additions & 15 deletions

File tree

Makefile

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1-
l lint:
1+
.DEFAULT_GOAL := help
2+
3+
.PHONY: help l lint install-editable
4+
5+
help: ## Show this help message
6+
@echo "Available commands:"
7+
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-20s\033[0m %s\n", $$1, $$2}'
8+
9+
lint: ## Run linting (pre-commit) on all files
210
@echo "Executing lint in backend code (pre-commit)"
311
pre-commit run --show-diff-on-failure --color=always --all-files
12+
13+
l: lint
14+
15+
install-editable: ## Install the SDK in editable mode with dev dependencies
16+
@echo "Installing the SDK in editable mode"
17+
pip install -e ".[dev]"

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: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ def test_ast_string_shorthand_csv(self):
168168
p = get_pipeline(tmpdir)
169169
param_dict = p.to_dict()["parameters"][0]
170170
assert param_dict["choices"] is None
171-
assert param_dict["choices_from_file"] == {"format": None, "path": "districts.csv", "column": None}
171+
assert param_dict["choicesFromFile"] == {"format": None, "path": "districts.csv", "column": None}
172172

173173
def test_ast_string_shorthand_json(self):
174174
with tempfile.TemporaryDirectory() as tmpdir:
@@ -177,7 +177,7 @@ def test_ast_string_shorthand_json(self):
177177
"@parameter('district', type=str, choices='regions.json')",
178178
)
179179
p = get_pipeline(tmpdir)
180-
assert p.to_dict()["parameters"][0]["choices_from_file"]["format"] is None
180+
assert p.to_dict()["parameters"][0]["choicesFromFile"]["format"] is None
181181

182182
def test_ast_string_shorthand_any_extension(self):
183183
with tempfile.TemporaryDirectory() as tmpdir:
@@ -186,7 +186,7 @@ def test_ast_string_shorthand_any_extension(self):
186186
"@parameter('district', type=str, choices='list.yml')",
187187
)
188188
p = get_pipeline(tmpdir)
189-
assert p.to_dict()["parameters"][0]["choices_from_file"]["format"] is None
189+
assert p.to_dict()["parameters"][0]["choicesFromFile"]["format"] is None
190190

191191
def test_ast_string_shorthand_same_output_as_explicit(self):
192192
with tempfile.TemporaryDirectory() as tmpdir:
@@ -229,7 +229,7 @@ def test_ast_static_list_unaffected(self):
229229
p = get_pipeline(tmpdir)
230230
param_dict = p.to_dict()["parameters"][0]
231231
assert param_dict["choices"] == ["UG", "KE"]
232-
assert "choices_from_file" not in param_dict
232+
assert "choicesFromFile" not in param_dict
233233

234234
def test_ast_string_no_extension_accepted(self):
235235
with tempfile.TemporaryDirectory() as tmpdir:
@@ -238,7 +238,7 @@ def test_ast_string_no_extension_accepted(self):
238238
"@parameter('district', type=str, choices='nodot')",
239239
)
240240
p = get_pipeline(tmpdir)
241-
assert p.to_dict()["parameters"][0]["choices_from_file"]["format"] is None
241+
assert p.to_dict()["parameters"][0]["choicesFromFile"]["format"] is None
242242

243243
def test_ast_string_any_extension_accepted(self):
244244
with tempfile.TemporaryDirectory() as tmpdir:
@@ -247,7 +247,7 @@ def test_ast_string_any_extension_accepted(self):
247247
"@parameter('district', type=str, choices='file.xlsx')",
248248
)
249249
p = get_pipeline(tmpdir)
250-
assert p.to_dict()["parameters"][0]["choices_from_file"]["format"] is None
250+
assert p.to_dict()["parameters"][0]["choicesFromFile"]["format"] is None
251251

252252

253253
# ---------------------------------------------------------------------------
@@ -264,13 +264,13 @@ def test_to_dict_emits_file_choices_key(self):
264264
p = Parameter(code="district", type=str, choices=ChoicesFromFile("districts.csv", column="code", format="csv"))
265265
d = p.to_dict()
266266
assert d["choices"] is None
267-
assert d["choices_from_file"] == {"format": "csv", "path": "districts.csv", "column": "code"}
267+
assert d["choicesFromFile"] == {"format": "csv", "path": "districts.csv", "column": "code"}
268268

269269
def test_to_dict_no_file_choices_key_for_static_choices(self):
270270
p = Parameter(code="country", type=str, choices=["UG", "KE"])
271271
d = p.to_dict()
272272
assert d["choices"] == ["UG", "KE"]
273-
assert "choices_from_file" not in d
273+
assert "choicesFromFile" not in d
274274

275275
def test_rejects_file_choices_on_bool_type(self):
276276
with pytest.raises(InvalidParameterError, match="don't accept choices"):
@@ -331,7 +331,7 @@ def test_file_choices_positional_path(self):
331331
p = get_pipeline(tmpdir)
332332
param_dict = p.to_dict()["parameters"][0]
333333
assert param_dict["choices"] is None
334-
assert param_dict["choices_from_file"] == {"format": None, "path": "districts.csv", "column": None}
334+
assert param_dict["choicesFromFile"] == {"format": None, "path": "districts.csv", "column": None}
335335

336336
def test_file_choices_with_column(self):
337337
with tempfile.TemporaryDirectory() as tmpdir:
@@ -341,7 +341,7 @@ def test_file_choices_with_column(self):
341341
)
342342
p = get_pipeline(tmpdir)
343343
param_dict = p.to_dict()["parameters"][0]
344-
assert param_dict["choices_from_file"] == {"format": None, "path": "data/districts.csv", "column": "code"}
344+
assert param_dict["choicesFromFile"] == {"format": None, "path": "data/districts.csv", "column": "code"}
345345

346346
def test_file_choices_with_column_positional(self):
347347
with tempfile.TemporaryDirectory() as tmpdir:
@@ -351,7 +351,7 @@ def test_file_choices_with_column_positional(self):
351351
)
352352
p = get_pipeline(tmpdir)
353353
param_dict = p.to_dict()["parameters"][0]
354-
assert param_dict["choices_from_file"] == {"format": None, "path": "data/districts.csv", "column": "code"}
354+
assert param_dict["choicesFromFile"] == {"format": None, "path": "data/districts.csv", "column": "code"}
355355

356356
def test_file_choices_explicit_format(self):
357357
with tempfile.TemporaryDirectory() as tmpdir:
@@ -361,7 +361,7 @@ def test_file_choices_explicit_format(self):
361361
)
362362
p = get_pipeline(tmpdir)
363363
param_dict = p.to_dict()["parameters"][0]
364-
assert param_dict["choices_from_file"]["format"] == "json"
364+
assert param_dict["choicesFromFile"]["format"] == "json"
365365

366366
def test_file_choices_format_none_by_default(self):
367367
with tempfile.TemporaryDirectory() as tmpdir:
@@ -371,7 +371,7 @@ def test_file_choices_format_none_by_default(self):
371371
)
372372
p = get_pipeline(tmpdir)
373373
param_dict = p.to_dict()["parameters"][0]
374-
assert param_dict["choices_from_file"]["format"] is None
374+
assert param_dict["choicesFromFile"]["format"] is None
375375

376376
def test_unsupported_call_in_choices_raises(self):
377377
with tempfile.TemporaryDirectory() as tmpdir:

0 commit comments

Comments
 (0)