fix(dataset): raise a clear error when custom dataset_info is not a list#9751
fix(dataset): raise a clear error when custom dataset_info is not a list#9751he-yufeng wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces a validation check in register_dataset_info to ensure that dataset_info is a list, raising a ValueError with a clear message if it is not. It also adds a corresponding unit test to verify this behavior. The review feedback highlights two important issues: first, a potential crash in the logging logic of register_dataset_info where .keys() might be called on the list, along with an inaccurate type hint; second, a resource leak in the new test because the temporary file created with delete=False is never cleaned up.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| if not isinstance(dataset_info, list): | ||
| raise ValueError( | ||
| f'`dataset_info` should be a JSON list of dataset entries (e.g. `[{{...}}]`), but got ' | ||
| f'type `{type(dataset_info).__name__}`. Please wrap the entry in a list.') |
There was a problem hiding this comment.
Since dataset_info is now strictly validated to be a list, the logging logic on line 117 will crash with an AttributeError: 'list' object has no attribute 'keys' if log_msg is None and len(dataset_info) >= 5. This is because dataset_info.keys() is called on a list.
To fix this, please update line 117 to slice the list instead of calling .keys(). For example:
log_msg = dataset_info if len(dataset_info) < 5 else dataset_info[:5]Additionally, the type hint for dataset_info on line 84 (Union[str, List[str], None]) is misleading because dataset_info is actually a list of dictionaries (dataset entries), not a list of strings. It should be updated to Union[str, List[Dict[str, Any]], None].
There was a problem hiding this comment.
Fixed in 79f3cc5. You're right — once the list validation is in place, list(dataset_info.keys()) (a leftover from when dataset_info was a dict) crashes for 5+ entries whenever log_msg is None (a JSON-list string or a list passed directly). Switched it to dataset_info[:5] and tightened the annotation to Union[str, list, None] since the entries are dicts, not str.
| with tempfile.NamedTemporaryFile('w', suffix='.json', delete=False, encoding='utf-8') as f: | ||
| json.dump({'ms_dataset_id': 'swift/self-cognition'}, f) | ||
| path = f.name | ||
|
|
||
| try: | ||
| register_dataset_info(path) | ||
| except ValueError as e: | ||
| assert 'list' in str(e) | ||
| else: | ||
| raise AssertionError('expected ValueError for a non-list dataset_info') |
There was a problem hiding this comment.
The temporary file created with delete=False is never cleaned up after the test runs. We should wrap the test execution in a try...finally block to ensure the temporary file is deleted, preventing resource leaks in the test environment.
| with tempfile.NamedTemporaryFile('w', suffix='.json', delete=False, encoding='utf-8') as f: | |
| json.dump({'ms_dataset_id': 'swift/self-cognition'}, f) | |
| path = f.name | |
| try: | |
| register_dataset_info(path) | |
| except ValueError as e: | |
| assert 'list' in str(e) | |
| else: | |
| raise AssertionError('expected ValueError for a non-list dataset_info') | |
| import os | |
| with tempfile.NamedTemporaryFile("w", suffix=".json", delete=False, encoding="utf-8") as f: | |
| json.dump({"ms_dataset_id": "swift/self-cognition"}, f) | |
| path = f.name | |
| try: | |
| try: | |
| register_dataset_info(path) | |
| except ValueError as e: | |
| assert "list" in str(e) | |
| else: | |
| raise AssertionError("expected ValueError for a non-list dataset_info") | |
| finally: | |
| if os.path.exists(path): | |
| os.remove(path) |
There was a problem hiding this comment.
Fixed in 79f3cc5 — wrapped the assertion in an inner try/except/else and added an outer finally: os.remove(path) so the delete=False temp file is always cleaned up.
register_dataset_info loads the --custom_dataset_info JSON and then does
`for d_info in dataset_info: _register_d_info(d_info)`. When a user writes a
single entry as a top-level object `{...}` instead of the documented one-element
list `[{...}]`, `for d_info in dataset_info` iterates the dict keys (strings),
and _preprocess_d_info then does `d_info['preprocess_func'] = ...` on a str,
raising a cryptic `TypeError: 'str' object does not support item assignment`.
The built-in dataset_info.json is a list and the docs state it "is a list of
metadata for datasets", so a non-list is a user mistake that deserves a clear
message.
Validate the loaded dataset_info is a list and raise a helpful ValueError
otherwise. Valid list inputs are unaffected.
38d2d21 to
50a99df
Compare
Address review: register_dataset_info now enforces dataset_info is a list, so the tail log_msg branch that called dataset_info.keys() (a leftover from when it was a dict) raised AttributeError for 5+ entries when log_msg is None. Slice the list instead, tighten the type hint to Union[str, list, None], and clean up the delete=False temp file in the new test via try/finally.
What
register_dataset_info(used by--custom_dataset_info xxx.json) loads the JSON and iterates it withfor d_info in dataset_info: _register_d_info(d_info). When a single entry is written as a top-level object{...}instead of the documented one-element list[{...}],for d_info in dataset_infoiterates the dict keys (strings), and_preprocess_d_infothen runsd_info['preprocess_func'] = ...on astr, raising a crypticTypeError: 'str' object does not support item assignmentwith no hint that the JSON shape is wrong.The built-in
dataset_info.jsonis a list and the docs state it "is a list of metadata for datasets", so a top-level non-list is a user mistake. Dropping the outer[]when copying a single-entry example is an easy one to make.Fix
Validate that the loaded
dataset_infois a list and raise a helpfulValueErrorotherwise. Valid list inputs are unaffected.Verification
Reproduced the dispatch logic standalone (no swift deps needed for the type check):
[{...}](documented){...}(top-level object)TypeError: 'str' object does not support item assignmentValueError: dataset_info should be a JSON list ...test_register_dataset_info_rejects_non_listwrites a temp.jsonholding a top-level object and assertsregister_dataset_inforaisesValueError.