Skip to content

Commit 9d14d44

Browse files
committed
Rail XML: Rename "format" attr to "validators"
1 parent 0504873 commit 9d14d44

14 files changed

+101
-70
lines changed

guardrails/datatypes.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from guardrails.validator_base import Validator
1717

1818
if TYPE_CHECKING:
19-
from guardrails.schema import FormatAttr
19+
from guardrails.schema import ValidatorsAttr
2020

2121
logger = logging.getLogger(__name__)
2222

@@ -64,20 +64,20 @@ class DataType:
6464
def __init__(
6565
self,
6666
children: Dict[str, Any],
67-
format_attr: "FormatAttr",
67+
validators_attr: "ValidatorsAttr",
6868
optional: bool,
6969
name: Optional[str],
7070
description: Optional[str],
7171
) -> None:
7272
self._children = children
73-
self.format_attr = format_attr
73+
self.validators_attr = validators_attr
7474
self.name = name
7575
self.description = description
7676
self.optional = optional
7777

7878
@property
7979
def validators(self) -> TypedList:
80-
return self.format_attr.validators
80+
return self.validators_attr.validators
8181

8282
def __repr__(self) -> str:
8383
return f"{self.__class__.__name__}({self._children})"
@@ -120,12 +120,12 @@ def set_children_from_xml(self, element: ET._Element):
120120

121121
@classmethod
122122
def from_xml(cls, element: ET._Element, strict: bool = False, **kwargs) -> Self:
123-
from guardrails.schema import FormatAttr
123+
from guardrails.schema import ValidatorsAttr
124124

125125
# TODO: don't want to pass strict through to DataType,
126-
# but need to pass it to FormatAttr.from_element
126+
# but need to pass it to ValidatorsAttr.from_element
127127
# how to handle this?
128-
format_attr = FormatAttr.from_element(element, cls.tag, strict)
128+
validators_attr = ValidatorsAttr.from_element(element, cls.tag, strict)
129129

130130
is_optional = element.attrib.get("required", "true") == "false"
131131

@@ -137,7 +137,7 @@ def from_xml(cls, element: ET._Element, strict: bool = False, **kwargs) -> Self:
137137
if description is not None:
138138
description = cast_xml_to_string(description)
139139

140-
data_type = cls({}, format_attr, is_optional, name, description, **kwargs)
140+
data_type = cls({}, validators_attr, is_optional, name, description, **kwargs)
141141
data_type.set_children_from_xml(element)
142142
return data_type
143143

@@ -255,12 +255,12 @@ class Date(ScalarType):
255255
def __init__(
256256
self,
257257
children: Dict[str, Any],
258-
format_attr: "FormatAttr",
258+
validators_attr: "ValidatorsAttr",
259259
optional: bool,
260260
name: Optional[str],
261261
description: Optional[str],
262262
) -> None:
263-
super().__init__(children, format_attr, optional, name, description)
263+
super().__init__(children, validators_attr, optional, name, description)
264264
self.date_format = None
265265

266266
def from_str(self, s: str) -> Optional[datetime.date]:
@@ -294,13 +294,13 @@ class Time(ScalarType):
294294
def __init__(
295295
self,
296296
children: Dict[str, Any],
297-
format_attr: "FormatAttr",
297+
validators_attr: "ValidatorsAttr",
298298
optional: bool,
299299
name: Optional[str],
300300
description: Optional[str],
301301
) -> None:
302302
self.time_format = "%H:%M:%S"
303-
super().__init__(children, format_attr, optional, name, description)
303+
super().__init__(children, validators_attr, optional, name, description)
304304

305305
def from_str(self, s: str) -> Optional[datetime.time]:
306306
"""Create a Time from a string."""
@@ -458,13 +458,13 @@ class Choice(NonScalarType):
458458
def __init__(
459459
self,
460460
children: Dict[str, Any],
461-
format_attr: "FormatAttr",
461+
validators_attr: "ValidatorsAttr",
462462
optional: bool,
463463
name: Optional[str],
464464
description: Optional[str],
465465
discriminator_key: str,
466466
) -> None:
467-
super().__init__(children, format_attr, optional, name, description)
467+
super().__init__(children, validators_attr, optional, name, description)
468468
self.discriminator_key = discriminator_key
469469

470470
@classmethod
@@ -520,12 +520,12 @@ class Case(NonScalarType):
520520
def __init__(
521521
self,
522522
children: Dict[str, Any],
523-
format_attr: "FormatAttr",
523+
validators_attr: "ValidatorsAttr",
524524
optional: bool,
525525
name: Optional[str],
526526
description: Optional[str],
527527
) -> None:
528-
super().__init__(children, format_attr, optional, name, description)
528+
super().__init__(children, validators_attr, optional, name, description)
529529

530530
def collect_validation(
531531
self,

guardrails/schema.py

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,11 @@
4949
logger = logging.getLogger(__name__)
5050

5151

52-
class FormatAttr(pydantic.BaseModel):
53-
"""Class for parsing and manipulating the `format` attribute of an element.
52+
class ValidatorsAttr(pydantic.BaseModel):
53+
"""Class for parsing and manipulating the `validators` attribute of an
54+
element.
5455
55-
The format attribute is a string that contains semi-colon separated
56+
The validators attribute is a string that contains semi-colon separated
5657
validators e.g. "valid-url; is-reachable". Each validator is itself either:
5758
- the name of an parameter-less validator, e.g. "valid-url"
5859
- the name of a validator with parameters, separated by a colon with a
@@ -68,8 +69,8 @@ class FormatAttr(pydantic.BaseModel):
6869
class Config:
6970
arbitrary_types_allowed = True
7071

71-
# The format attribute string.
72-
format: Optional[str]
72+
# The validators attribute string.
73+
validators_spec: Optional[str]
7374

7475
# The on-fail handlers.
7576
on_fail_handlers: Dict[str, str]
@@ -85,32 +86,40 @@ class Config:
8586

8687
@property
8788
def empty(self) -> bool:
88-
"""Return True if the format attribute is empty, False otherwise."""
89-
return self.format is None
89+
"""Return True if the validators attribute is empty, False
90+
otherwise."""
91+
return self.validators_spec is None
9092

9193
@classmethod
9294
def from_element(
9395
cls, element: ET._Element, tag: str, strict: bool = False
94-
) -> "FormatAttr":
95-
"""Create a FormatAttr object from an XML element.
96+
) -> "ValidatorsAttr":
97+
"""Create a ValidatorsAttr object from an XML element.
9698
9799
Args:
98100
element (ET._Element): The XML element.
99101
100102
Returns:
101-
A FormatAttr object.
103+
A ValidatorsAttr object.
102104
"""
105+
validators_str = element.get("validators")
103106
format_str = element.get("format")
104-
if format_str is None:
107+
if format_str is not None:
108+
warnings.warn(
109+
"Attribute `format` is deprecated. Use `validators` instead.",
110+
DeprecationWarning,
111+
)
112+
validators_str = format_str
113+
if validators_str is None:
105114
return cls(
106-
format=None,
115+
validators_spec=None,
107116
on_fail_handlers={},
108117
validator_args={},
109118
validators=[],
110119
unregistered_validators=[],
111120
)
112121

113-
validator_args = cls.parse(format_str)
122+
validator_args = cls.parse(validators_str)
114123

115124
on_fail_handlers = {}
116125
for key, value in element.attrib.items():
@@ -128,7 +137,7 @@ def from_element(
128137
)
129138

130139
return cls(
131-
format=format_str,
140+
validators_spec=validators_str,
132141
on_fail_handlers=on_fail_handlers,
133142
validator_args=validator_args,
134143
validators=validators,
@@ -196,7 +205,7 @@ def parse(format_string: str) -> Dict[str, List[Any]]:
196205
validators = {}
197206
for token in tokens:
198207
# Parse the token into a validator name and a list of parameters.
199-
validator_name, args = FormatAttr.parse_token(token)
208+
validator_name, args = ValidatorsAttr.parse_token(token)
200209
validators[validator_name] = args
201210

202211
return validators
@@ -268,7 +277,7 @@ def to_prompt(self, with_keywords: bool = True) -> str:
268277
{1 + 2}" will be converted to "valid-url other-validator:
269278
arg1=1.0 arg2=3".
270279
"""
271-
if self.format is None:
280+
if self.validators_spec is None:
272281
return ""
273282
# Use the validators' to_prompt method to convert the format string to
274283
# another string representation.
@@ -953,11 +962,11 @@ def transpile(self, method: str = "default") -> str:
953962
"Here's a description of what I want you to generate: "
954963
f"{obj.description}"
955964
)
956-
if not obj.format_attr.empty:
965+
if not obj.validators_attr.empty:
957966
schema += (
958967
"\n\nYour generated response should satisfy the following properties:"
959968
)
960-
for validator in obj.format_attr.validators:
969+
for validator in obj.validators_attr.validators:
961970
schema += f"\n- {validator.to_prompt()}"
962971

963972
schema += "\n\nDon't talk; just go."
@@ -991,8 +1000,8 @@ def datatypes_to_xml(
9911000
if dt.description:
9921001
el.attrib["description"] = dt.description
9931002

994-
if dt.format_attr:
995-
format_prompt = dt.format_attr.to_prompt()
1003+
if dt.validators_attr:
1004+
format_prompt = dt.validators_attr.to_prompt()
9961005
if format_prompt:
9971006
el.attrib["format"] = format_prompt
9981007

guardrails/utils/pydantic_utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ def add_validators_to_xml_element(
195195
# construct a valid-choices validator for Literal types
196196
if typing.get_origin(field_info.annotation) is typing.Literal:
197197
valid_choices = typing.get_args(field_info.annotation)
198-
element.set("format", "valid-choices")
198+
element.set("validators", "valid-choices")
199199
element.set("valid-choices", ",".join(valid_choices))
200200

201201
return element
@@ -249,7 +249,7 @@ def attach_validators_to_element(
249249

250250
if len(format_prompt) > 0:
251251
format_prompt = "; ".join(format_prompt)
252-
element.set("format", format_prompt)
252+
element.set("validators", format_prompt)
253253
for rail_alias, on_fail in on_fails.items():
254254
element.set("on-fail-" + rail_alias, on_fail)
255255

tests/integration_tests/test_async.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ def string_rail_spec():
231231
<rail version="0.1">
232232
<output
233233
type="string"
234-
format="two-words"
234+
validators="two-words"
235235
on-fail-two-words="fix"
236236
/>
237237
<prompt>

tests/integration_tests/test_cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<output>
1212
<object name="patient_info">
1313
<string name="gender" description="Patient's gender" />
14-
<integer name="age" format="valid-range: 0 100" />
14+
<integer name="age" validators="valid-range: 0 100" />
1515
<string name="symptoms" description="Symptoms that the patient is currently experiencing" />
1616
</object>
1717
</output>

tests/integration_tests/test_data_validation.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ def test_choice_validation(llm_output, raises):
3333
<output>
3434
<choice name="choice" on-fail-choice="exception" discriminator="action">
3535
<case name="fight">
36-
<string name="fight_move" format="valid-choices: {['punch','kick','headbutt']}" on-fail-valid-choices="exception" />
36+
<string name="fight_move" validators="valid-choices: {['punch','kick','headbutt']}" on-fail-valid-choices="exception" />
3737
</case>
3838
<case name="flight">
39-
<string name="flight_direction" format="valid-choices: {['north','south','east','west']}" on-fail-valid-choices="exception" />
40-
<integer name="flight_speed" format="valid-choices: {[1,2,3,4]}" on-fail-valid-choices="exception" />
39+
<string name="flight_direction" validators="valid-choices: {['north','south','east','west']}" on-fail-valid-choices="exception" />
40+
<integer name="flight_speed" validators="valid-choices: {[1,2,3,4]}" on-fail-valid-choices="exception" />
4141
</case>
4242
</choice>
4343
</output>

tests/integration_tests/test_schema_to_prompt.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,20 @@ def test_choice_schema():
1313
<case name="fight">
1414
<string
1515
name="fight_move"
16-
format="valid-choices: {['punch','kick','headbutt']}"
16+
validators="valid-choices: {['punch','kick','headbutt']}"
1717
on-fail-valid-choices="exception"
1818
/>
1919
</case>
2020
<case name="flight">
2121
<object name="flight">
2222
<string
2323
name="flight_direction"
24-
format="valid-choices: {['north','south','east','west']}"
24+
validators="valid-choices: {['north','south','east','west']}"
2525
on-fail-valid-choices="exception"
2626
/>
2727
<integer
2828
name="flight_speed"
29-
format="valid-choices: {[1,2,3,4]}"
29+
validators="valid-choices: {[1,2,3,4]}"
3030
on-fail-valid-choices="exception"
3131
/>
3232
</object>

tests/integration_tests/test_validators.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def embed_function(text: str):
4242
# Check types remain intact
4343
output_schema: StringSchema = guard.rail.output_schema
4444
data_type: DataType = output_schema.root_datatype
45-
validators = data_type.format_attr.validators
45+
validators = data_type.validators_attr.validators
4646
validator: SimilarToList = validators[0]
4747

4848
assert isinstance(validator._standard_deviations, int)

tests/unit_tests/test_datatypes.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from lxml.builder import E
33

44
import guardrails.datatypes as datatypes
5-
from guardrails.schema import FormatAttr
5+
from guardrails.schema import ValidatorsAttr
66

77

88
@pytest.mark.parametrize(
@@ -26,7 +26,7 @@
2626
],
2727
)
2828
def test_get_args(input_string, expected):
29-
_, args = FormatAttr.parse_token(input_string)
29+
_, args = ValidatorsAttr.parse_token(input_string)
3030
assert args == expected
3131

3232

tests/unit_tests/test_guard.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def validate(self, value, metadata):
3131
"""
3232
<rail version="0.1">
3333
<output>
34-
<string name="string_name" format="myrequiringvalidator" />
34+
<string name="string_name" validators="myrequiringvalidator" />
3535
</output>
3636
</rail>
3737
""",
@@ -42,10 +42,10 @@ def validate(self, value, metadata):
4242
<rail version="0.1">
4343
<output>
4444
<object name="temp_name">
45-
<string name="string_name" format="myrequiringvalidator" />
45+
<string name="string_name" validators="myrequiringvalidator" />
4646
</object>
4747
<list name="list_name">
48-
<string name="string_name" format="myrequiringvalidator2" />
48+
<string name="string_name" validators="myrequiringvalidator2" />
4949
</list>
5050
</output>
5151
</rail>
@@ -63,7 +63,7 @@ def validate(self, value, metadata):
6363
<string name="string_name" />
6464
</case>
6565
<case name="hiya">
66-
<string name="string_name" format="myrequiringvalidator" />
66+
<string name="string_name" validators="myrequiringvalidator" />
6767
</case>
6868
</choice>
6969
</list>

0 commit comments

Comments
 (0)