diff --git a/dataforge/type_check.py b/dataforge/type_check.py index bf4a940..e3f5a59 100644 --- a/dataforge/type_check.py +++ b/dataforge/type_check.py @@ -37,17 +37,19 @@ def parse_type_spec(type_spec: TypeSpec) -> Tuple[str, Optional[Dict[str, Any]]] return "unknown", None -def check_type(value: Any, expected_type: TypeSpec) -> Tuple[bool, Optional[str]]: +def check_type( + value: Any, expected_type: TypeSpec +) -> Tuple[bool, Optional[str]]: """Check if a value matches the expected type specification.""" actual_type = infer_type(value) type_name, type_info = parse_type_spec(expected_type) - + if type_name == "any": return True, None - + if actual_type != type_name: return False, f"Expected {type_name}, got {actual_type}" - + if type_name == "object" and isinstance(type_info, dict): properties = type_info.get("properties", {}) required = type_info.get("required", []) @@ -56,12 +58,12 @@ def check_type(value: Any, expected_type: TypeSpec) -> Tuple[bool, Optional[str] prop_valid, error = check_type(value[prop_name], prop_type) if not prop_valid: return False, f"Property '{prop_name}': {error}" - + if isinstance(required, list): for req_prop in required: if req_prop not in value: return False, f"Missing required property: '{req_prop}'" - + if type_name == "array" and isinstance(type_info, dict): items = type_info.get("items") if items is not None: @@ -69,11 +71,13 @@ def check_type(value: Any, expected_type: TypeSpec) -> Tuple[bool, Optional[str] item_valid, error = check_type(item, items) if not item_valid: return False, f"Array item {i}: {error}" - + return True, None -def validate_types(data: Any, type_spec: TypeSpec, path: str = "root") -> List[str]: +def validate_types( + data: Any, type_spec: TypeSpec, path: str = "root" +) -> List[str]: """Validate data against a type specification and return all errors.""" errors = [] valid, error = check_type(data, type_spec) @@ -102,11 +106,11 @@ def validate_types(data: Any, type_spec: TypeSpec, path: str = "root") -> List[s def infer_schema_from_data(data: Any) -> Dict[str, Any]: """Infer a JSON Schema from data.""" schema: Dict[str, Any] = {} - + def build_schema(value: Any, schema_obj: Dict[str, Any]) -> None: type_name = infer_type(value) schema_obj["type"] = type_name - + if type_name == "object" and isinstance(value, dict): schema_obj["properties"] = {} required = [] @@ -118,10 +122,10 @@ def infer_schema_from_data(data: Any) -> Dict[str, Any]: required.append(key) if required: schema_obj["required"] = required - + elif type_name == "array" and isinstance(value, list) and value: schema_obj["items"] = {} build_schema(value[0], schema_obj["items"]) - + build_schema(data, schema) return schema