feat: duration string parser #73

Merged
JCHacking merged 2 commits from string-duration into main 2025-12-06 19:53:27 +00:00
5 changed files with 19 additions and 44 deletions
Showing only changes of commit dd31f62ef2 - Show all commits

View File

@@ -1,7 +1,7 @@
repos: repos:
- repo: https://github.com/astral-sh/ruff-pre-commit - repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version. # Ruff version.
rev: v0.11.4 rev: v0.14.7
hooks: hooks:
# Run the linter. # Run the linter.
- id: ruff - id: ruff

View File

@@ -2,8 +2,8 @@ from jambo.exceptions import InvalidSchemaException
from jambo.parser._type_parser import GenericTypeParser from jambo.parser._type_parser import GenericTypeParser
from jambo.types.type_parser_options import TypeParserOptions from jambo.types.type_parser_options import TypeParserOptions
from pydantic import AnyUrl, EmailStr from pydantic import AnyUrl, EmailStr, TypeAdapter
from typing_extensions import Any, Unpack from typing_extensions import Unpack
from datetime import date, datetime, time, timedelta from datetime import date, datetime, time, timedelta
from ipaddress import IPv4Address, IPv6Address from ipaddress import IPv4Address, IPv6Address
@@ -64,7 +64,7 @@ class StringTypeParser(GenericTypeParser):
if "examples" in mapped_properties: if "examples" in mapped_properties:
mapped_properties["examples"] = [ mapped_properties["examples"] = [
self._parse_example(example, format_type, mapped_type) TypeAdapter(mapped_type).validate_python(example)
for example in mapped_properties["examples"] for example in mapped_properties["examples"]
] ]
@@ -73,26 +73,3 @@ class StringTypeParser(GenericTypeParser):
mapped_properties["json_schema_extra"]["format"] = format_type mapped_properties["json_schema_extra"]["format"] = format_type
return mapped_type, mapped_properties 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

View File

@@ -129,9 +129,7 @@ class SchemaConverter:
:param ref_name: The name of the reference to get. :param ref_name: The name of the reference to get.
:return: The cached reference, or None if not found. :return: The cached reference, or None if not found.
""" """
cached_type = self._namespace_registry.get( cached_type = self._namespace_registry.get(namespace, {}).get(ref_name)
namespace, {}
).get(ref_name)
if isinstance(cached_type, type): if isinstance(cached_type, type):
return cached_type return cached_type

View File

@@ -3,7 +3,6 @@ from jambo.parser import StringTypeParser
from pydantic import AnyUrl, EmailStr from pydantic import AnyUrl, EmailStr
import unittest
from datetime import date, datetime, time, timedelta, timezone from datetime import date, datetime, time, timedelta, timezone
from ipaddress import IPv4Address, IPv6Address, ip_address from ipaddress import IPv4Address, IPv6Address, ip_address
from unittest import TestCase from unittest import TestCase
@@ -121,7 +120,7 @@ class TestStringTypeParser(TestCase):
type_parsing, type_validator = parser.from_properties("placeholder", properties) type_parsing, type_validator = parser.from_properties("placeholder", properties)
self.assertEqual(type_parsing, AnyUrl) 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): def test_string_parser_with_ip_formats(self):
parser = StringTypeParser() parser = StringTypeParser()
@@ -299,7 +298,6 @@ class TestStringTypeParser(TestCase):
}, },
) )
@unittest.skip("Duration parsing not yet implemented")
def test_string_parser_with_timedelta_format(self): def test_string_parser_with_timedelta_format(self):
parser = StringTypeParser() parser = StringTypeParser()
@@ -315,9 +313,9 @@ class TestStringTypeParser(TestCase):
self.assertEqual( self.assertEqual(
type_validator["examples"], type_validator["examples"],
[ [
timedelta(days=7), timedelta(days=428, hours=4, minutes=5, seconds=6),
timedelta(minutes=30), timedelta(minutes=30),
timedelta(hours=4, minutes=5, seconds=6), timedelta(days=7),
timedelta(seconds=0.5), timedelta(seconds=0.5),
], ],
) )

View File

@@ -1166,5 +1166,7 @@ class TestSchemaConverter(TestCase):
self.converter.clear_ref_cache(namespace=namespace) 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) self.assertIsNone(cleared_cached_model)