feat: improve internal typings in manifest#278
Conversation
There was a problem hiding this comment.
Code Review
This pull request improves type safety in manifest.py by introducing strict type definitions (ManifestParamBase, SpecValue, etc.) and refactoring helper functions to use them. Two critical issues were identified in the review: first, using a generic alias (list[ManifestParamBase]) as a default_factory in ManifestStack will raise a runtime TypeError; second, the new strict type checking in _object_to_spec will raise a TypeError for previously supported types like tuple and custom mappings, which should be explicitly handled.
| elif data is None: | ||
| return None | ||
| elif isinstance(data, _util.Sentinel): | ||
| return data | ||
| elif isinstance(data, (str, int, float, bool)): | ||
| return data | ||
| else: | ||
| raise TypeError(f"Unsupported manifest spec value: {type(data)!r}") |
There was a problem hiding this comment.
With the introduction of the strict TypeError check for unsupported types, common types like tuple or custom mappings (which were previously returned as-is) will now raise a TypeError. Since _Mapping is already imported in this file, we should explicitly handle tuple (converting it to a list) and _Mapping (converting it to a spec dict) to maintain compatibility and robustness.
| elif data is None: | |
| return None | |
| elif isinstance(data, _util.Sentinel): | |
| return data | |
| elif isinstance(data, (str, int, float, bool)): | |
| return data | |
| else: | |
| raise TypeError(f"Unsupported manifest spec value: {type(data)!r}") | |
| elif isinstance(data, tuple): | |
| return list(map(_object_to_spec, data)) | |
| elif isinstance(data, _Mapping): | |
| return _dict_to_spec(data) | |
| elif data is None: | |
| return None | |
| elif isinstance(data, _util.Sentinel): | |
| return data | |
| elif isinstance(data, (str, int, float, bool)): | |
| return data | |
| else: | |
| raise TypeError(f"Unsupported manifest spec value: {type(data)!r}") |
Summary
_typing.Any.Problem/Root Cause
Issue #31 called out that the manifest internals still relied on
_typing.Any, which left the manifest serialization path loosely typed even though it operates on a constrained set of values. The previous implementation useddict[str, _typing.Any], untyped helper inputs, and a narrowlistcheck in_object_to_spec, so type information was lost across manifest parameter conversion and dataclass serialization.Solution/Changes
This change introduces explicit aliases for supported manifest parameter types and manifest spec values, then threads those types through the manifest conversion helpers. The serialization path now distinguishes dataclass instances, mappings, and non-string sequences, which preserves support for inputs such as tuples while keeping the output normalized to manifest-compatible lists and dicts. It also updates the shared
_paramsregistry type so stored params are typed asParamorSecretParaminstead of a genericExpression.Testing
format,lint,docs,Analyze,CodeQL, andtest (3.10)/test (3.12).