@@ -68,7 +68,17 @@ class _Resolution(NamedTuple):
6868 is_explicit_schema_path : bool = False
6969
7070
71- class URN (UserString ):
71+ class URN (str ):
72+ """URN string type with validation.
73+
74+ Inherits from str directly so it can be used anywhere a str is expected,
75+ including as argument to str.startswith(), dict keys, etc.
76+ """
77+
78+ def __new__ (cls , urn : str ) -> "URN" :
79+ cls .check_syntax (urn )
80+ return super ().__new__ (cls , urn )
81+
7282 @classmethod
7383 def __get_pydantic_core_schema__ (
7484 cls ,
@@ -83,10 +93,6 @@ def __get_pydantic_core_schema__(
8393 ),
8494 )
8595
86- def __init__ (self , urn : str ):
87- self .check_syntax (urn )
88- self .data = urn
89-
9096 @classmethod
9197 def check_syntax (cls , path : str ) -> None :
9298 """Validate URN-based path format.
@@ -330,7 +336,7 @@ def urn(self) -> str | None:
330336
331337 schema = self .schema
332338 if not schema and issubclass (self .__scim_model__ , Resource ):
333- schema = self .__scim_model__ .model_fields [ "schemas" ]. default [ 0 ]
339+ schema = self .__scim_model__ .__schema__
334340
335341 if not self .attr :
336342 return schema if schema else None
@@ -348,12 +354,12 @@ def _resolve_model(self) -> tuple[type[BaseModel], str | None] | None:
348354 attr_path = self .attr
349355
350356 if ":" in self and isclass (model ) and issubclass (model , Resource | Extension ):
351- model_schema = model .model_fields [ "schemas" ]. default [ 0 ]
357+ model_schema = model .__schema__
352358 path_lower = str (self ).lower ()
353359
354- if path_lower == model_schema .lower ():
360+ if model_schema and path_lower == model_schema .lower ():
355361 return model , None
356- elif path_lower .startswith (model_schema .lower ()):
362+ elif model_schema and path_lower .startswith (model_schema .lower ()):
357363 attr_path = str (self )[len (model_schema ) :].lstrip (":" )
358364 elif issubclass (model , Resource ):
359365 for (
@@ -414,7 +420,7 @@ def _resolve_instance(
414420 if ":" not in path_str :
415421 return _Resolution (resource , path_str )
416422
417- model_schema = type (resource ). model_fields [ "schemas" ]. default [ 0 ]
423+ model_schema = str ( getattr ( type (resource ), "__schema__" , "" ))
418424 path_lower = path_str .lower ()
419425
420426 if isinstance (resource , Resource | Extension ) and path_lower .startswith (
@@ -708,10 +714,11 @@ def iter_model_paths(
708714
709715 field_type = target_model .get_field_root_type (field_name )
710716
717+ urn : str
711718 if isclass (field_type ) and issubclass (field_type , Extension ):
712719 if not include_extensions :
713720 continue
714- urn = field_type .model_fields [ "schemas" ]. default [ 0 ]
721+ urn = field_type .__schema__ or ""
715722 elif isclass (target_model ) and issubclass (target_model , Extension ):
716723 urn = target_model ().get_attribute_urn (field_name )
717724 else :
0 commit comments