diff --git a/.githooks/pre-commit-config.yaml b/.githooks/pre-commit-config.yaml index 08560b3..9aa9bb0 100644 --- a/.githooks/pre-commit-config.yaml +++ b/.githooks/pre-commit-config.yaml @@ -1,7 +1,7 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.11.4 + rev: v0.14.7 hooks: # Run the linter. - id: ruff diff --git a/jambo/parser/string_type_parser.py b/jambo/parser/string_type_parser.py index 4c18761..b09cf20 100644 --- a/jambo/parser/string_type_parser.py +++ b/jambo/parser/string_type_parser.py @@ -2,8 +2,8 @@ from jambo.exceptions import InvalidSchemaException from jambo.parser._type_parser import GenericTypeParser from jambo.types.type_parser_options import TypeParserOptions -from pydantic import AnyUrl, EmailStr -from typing_extensions import Any, Unpack +from pydantic import AnyUrl, EmailStr, TypeAdapter, ValidationError +from typing_extensions import Unpack from datetime import date, datetime, time, timedelta from ipaddress import IPv4Address, IPv6Address @@ -62,37 +62,19 @@ class StringTypeParser(GenericTypeParser): if format_type in self.format_pattern_mapping: mapped_properties["pattern"] = self.format_pattern_mapping[format_type] - if "examples" in mapped_properties: - mapped_properties["examples"] = [ - self._parse_example(example, format_type, mapped_type) - for example in mapped_properties["examples"] - ] + try: + if "examples" in mapped_properties: + mapped_properties["examples"] = [ + TypeAdapter(mapped_type).validate_python(example) + for example in mapped_properties["examples"] + ] + except ValidationError as err: + raise InvalidSchemaException( + f"Invalid example type for field {name}." + ) from err if "json_schema_extra" not in mapped_properties: mapped_properties["json_schema_extra"] = {} mapped_properties["json_schema_extra"]["format"] = format_type return mapped_type, mapped_properties - - def _parse_example( - self, example: Any, format_type: str, mapped_type: type[Any] - ) -> Any: - """ - Parse example from JSON Schema format to python format - :param example: Example Value - :param format_type: Format Type - :param mapped_type: Type to parse - :return: Example parsed - """ - match format_type: - case "date" | "time" | "date-time": - return mapped_type.fromisoformat(example) - case "duration": - # TODO: Implement duration parser - raise NotImplementedError - case "ipv4" | "ipv6": - return mapped_type(example) - case "uuid": - return mapped_type(example) - case _: - return example diff --git a/jambo/schema_converter.py b/jambo/schema_converter.py index 0e92119..2e46828 100644 --- a/jambo/schema_converter.py +++ b/jambo/schema_converter.py @@ -128,10 +128,8 @@ class SchemaConverter: Gets a cached reference from the reference cache. :param ref_name: The name of the reference to get. :return: The cached reference, or None if not found. - """ - cached_type = self._namespace_registry.get( - namespace, {} - ).get(ref_name) + """ + cached_type = self._namespace_registry.get(namespace, {}).get(ref_name) if isinstance(cached_type, type): return cached_type diff --git a/tests/parser/test_string_type_parser.py b/tests/parser/test_string_type_parser.py index b00b487..56334ec 100644 --- a/tests/parser/test_string_type_parser.py +++ b/tests/parser/test_string_type_parser.py @@ -3,7 +3,6 @@ from jambo.parser import StringTypeParser from pydantic import AnyUrl, EmailStr -import unittest from datetime import date, datetime, time, timedelta, timezone from ipaddress import IPv4Address, IPv6Address, ip_address from unittest import TestCase @@ -121,7 +120,7 @@ class TestStringTypeParser(TestCase): type_parsing, type_validator = parser.from_properties("placeholder", properties) self.assertEqual(type_parsing, AnyUrl) - self.assertEqual(type_validator["examples"], ["test://domain/resource"]) + self.assertEqual(type_validator["examples"], [AnyUrl("test://domain/resource")]) def test_string_parser_with_ip_formats(self): parser = StringTypeParser() @@ -299,7 +298,6 @@ class TestStringTypeParser(TestCase): }, ) - @unittest.skip("Duration parsing not yet implemented") def test_string_parser_with_timedelta_format(self): parser = StringTypeParser() @@ -315,9 +313,9 @@ class TestStringTypeParser(TestCase): self.assertEqual( type_validator["examples"], [ - timedelta(days=7), + timedelta(days=428, hours=4, minutes=5, seconds=6), timedelta(minutes=30), - timedelta(hours=4, minutes=5, seconds=6), + timedelta(days=7), timedelta(seconds=0.5), ], ) diff --git a/tests/test_schema_converter.py b/tests/test_schema_converter.py index dd2b32c..e9bcb5b 100644 --- a/tests/test_schema_converter.py +++ b/tests/test_schema_converter.py @@ -1109,7 +1109,7 @@ class TestSchemaConverter(TestCase): def test_namespace_isolation_via_on_call_config(self): namespace = "namespace1" - + schema: JSONSchema = { "$id": namespace, "title": "Person", @@ -1130,16 +1130,16 @@ class TestSchemaConverter(TestCase): } model = self.converter.build_with_cache(schema) - + invalid_cached_model = self.converter.get_cached_ref("Person") self.assertIsNone(invalid_cached_model) - + cached_model = self.converter.get_cached_ref("Person", namespace=namespace) self.assertIs(model, cached_model) def test_clear_namespace_registry(self): namespace = "namespace_to_clear" - + schema: JSONSchema = { "$id": namespace, "title": "Person", @@ -1160,11 +1160,13 @@ class TestSchemaConverter(TestCase): } model = self.converter.build_with_cache(schema) - + cached_model = self.converter.get_cached_ref("Person", namespace=namespace) self.assertIs(model, cached_model) - + self.converter.clear_ref_cache(namespace=namespace) - - cleared_cached_model = self.converter.get_cached_ref("Person", namespace=namespace) + + cleared_cached_model = self.converter.get_cached_ref( + "Person", namespace=namespace + ) self.assertIsNone(cleared_cached_model)