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:
- 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

View File

@@ -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
from typing_extensions import Unpack
from datetime import date, datetime, time, timedelta
from ipaddress import IPv4Address, IPv6Address
@@ -64,7 +64,7 @@ class StringTypeParser(GenericTypeParser):
if "examples" in mapped_properties:
mapped_properties["examples"] = [
self._parse_example(example, format_type, mapped_type)
TypeAdapter(mapped_type).validate_python(example)
for example in mapped_properties["examples"]
]
@@ -73,26 +73,3 @@ class StringTypeParser(GenericTypeParser):
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

View File

@@ -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

View File

@@ -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),
],
)

View File

@@ -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)