Merge pull request #42 from HideyoshiNakazone/improvement/better-string-validations

(improvement): Adds More Type Formats to String Parser
This commit was merged in pull request #42.
This commit is contained in:
2025-08-20 00:31:46 -03:00
committed by GitHub
3 changed files with 54 additions and 12 deletions

View File

@@ -1,10 +1,12 @@
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 EmailStr, HttpUrl, IPvAnyAddress from pydantic import AnyUrl, EmailStr
from typing_extensions import 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 uuid import UUID
class StringTypeParser(GenericTypeParser): class StringTypeParser(GenericTypeParser):
@@ -20,15 +22,22 @@ class StringTypeParser(GenericTypeParser):
} }
format_type_mapping = { format_type_mapping = {
"email": EmailStr, # 7.3.1. Dates, Times, and Duration
"uri": HttpUrl,
"ipv4": IPvAnyAddress,
"ipv6": IPvAnyAddress,
"hostname": str,
"date": date, "date": date,
"time": time, "time": time,
"date-time": datetime, "date-time": datetime,
"duration": timedelta, "duration": timedelta,
# 7.3.2. Email Addresses
"email": EmailStr,
# 7.3.3. Hostnames
"hostname": str,
# 7.3.4. IP Addresses
"ipv4": IPv4Address,
"ipv6": IPv6Address,
# 7.3.5. Resource Identifiers
"uri": AnyUrl,
# "iri" # Not supported by pydantic and currently not supported by jambo
"uuid": UUID,
} }
format_pattern_mapping = { format_pattern_mapping = {

View File

@@ -1,9 +1,11 @@
from jambo.parser import StringTypeParser from jambo.parser import StringTypeParser
from pydantic import EmailStr, HttpUrl, IPvAnyAddress from pydantic import AnyUrl, EmailStr
from datetime import date, datetime, time, timedelta from datetime import date, datetime, time, timedelta
from ipaddress import IPv4Address, IPv6Address
from unittest import TestCase from unittest import TestCase
from uuid import UUID
class TestStringTypeParser(TestCase): class TestStringTypeParser(TestCase):
@@ -111,12 +113,14 @@ 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, HttpUrl) self.assertEqual(type_parsing, AnyUrl)
def test_string_parser_with_ip_formats(self): def test_string_parser_with_ip_formats(self):
parser = StringTypeParser() parser = StringTypeParser()
for ip_format in ["ipv4", "ipv6"]: formats = {"ipv4": IPv4Address, "ipv6": IPv6Address}
for ip_format, expected_type in formats.items():
properties = { properties = {
"type": "string", "type": "string",
"format": ip_format, "format": ip_format,
@@ -126,7 +130,19 @@ class TestStringTypeParser(TestCase):
"placeholder", properties "placeholder", properties
) )
self.assertEqual(type_parsing, IPvAnyAddress) self.assertEqual(type_parsing, expected_type)
def test_string_parser_with_uuid_format(self):
parser = StringTypeParser()
properties = {
"type": "string",
"format": "uuid",
}
type_parsing, type_validator = parser.from_properties("placeholder", properties)
self.assertEqual(type_parsing, UUID)
def test_string_parser_with_time_format(self): def test_string_parser_with_time_format(self):
parser = StringTypeParser() parser = StringTypeParser()

View File

@@ -1,9 +1,10 @@
from jambo import SchemaConverter from jambo import SchemaConverter
from pydantic import BaseModel, HttpUrl from pydantic import AnyUrl, BaseModel
from ipaddress import IPv4Address, IPv6Address from ipaddress import IPv4Address, IPv6Address
from unittest import TestCase from unittest import TestCase
from uuid import UUID
def is_pydantic_model(cls): def is_pydantic_model(cls):
@@ -463,7 +464,7 @@ class TestSchemaConverter(TestCase):
} }
model = SchemaConverter.build(schema) model = SchemaConverter.build(schema)
self.assertEqual( self.assertEqual(
model(website="https://example.com").website, HttpUrl("https://example.com") model(website="https://example.com").website, AnyUrl("https://example.com")
) )
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
model(website="invalid-uri") model(website="invalid-uri")
@@ -493,6 +494,22 @@ class TestSchemaConverter(TestCase):
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
model(ip="invalid-ipv6") model(ip="invalid-ipv6")
def test_string_format_uuid(self):
schema = {
"title": "UUIDTest",
"type": "object",
"properties": {"id": {"type": "string", "format": "uuid"}},
}
model = SchemaConverter.build(schema)
self.assertEqual(
model(id="123e4567-e89b-12d3-a456-426614174000").id,
UUID("123e4567-e89b-12d3-a456-426614174000"),
)
with self.assertRaises(ValueError):
model(id="invalid-uuid")
def test_string_format_hostname(self): def test_string_format_hostname(self):
schema = { schema = {
"title": "HostnameTest", "title": "HostnameTest",