From 27076be4a97e3a27ec9c8f616916dca3a52b2b9e Mon Sep 17 00:00:00 2001 From: Zayd Simjee Date: Thu, 7 Mar 2024 17:15:53 -0800 Subject: [PATCH 1/5] write `use`-ed validators to output_schema root node --- guardrails/guard.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/guardrails/guard.py b/guardrails/guard.py index 77f044518..70b937ae5 100644 --- a/guardrails/guard.py +++ b/guardrails/guard.py @@ -988,7 +988,10 @@ def use( self, validator: Union[Validator, Type[Validator]], *args, **kwargs ) -> "Guard": if validator: - self._validators.append(get_validator(validator, *args, **kwargs)) + hydrated_validator = get_validator(validator, *args, **kwargs) + self._validators.append(hydrated_validator) + + self.rail.output_schema.root_datatype.validators.append(hydrated_validator) return self @@ -1019,7 +1022,10 @@ def use_many( ], ) -> "Guard": for v in validators: - self._validators.append(get_validator(v)) + hydrated_validator = get_validator(v) + self._validators.append(hydrated_validator) + self.rail.output_schema.root_datatype.validators.append(hydrated_validator) + return self From 1f394b5a0dafded27259c88bdc32c9c0661b0d66 Mon Sep 17 00:00:00 2001 From: Zayd Simjee Date: Thu, 7 Mar 2024 23:23:10 -0800 Subject: [PATCH 2/5] lint --- guardrails/guard.py | 1 - 1 file changed, 1 deletion(-) diff --git a/guardrails/guard.py b/guardrails/guard.py index 70b937ae5..2d0fcb53e 100644 --- a/guardrails/guard.py +++ b/guardrails/guard.py @@ -1026,7 +1026,6 @@ def use_many( self._validators.append(hydrated_validator) self.rail.output_schema.root_datatype.validators.append(hydrated_validator) - return self def validate(self, llm_output: str, *args, **kwargs) -> ValidationOutcome[str]: From 965f366dd4bb9fc23f0df98483866b99288ed304 Mon Sep 17 00:00:00 2001 From: Zayd Simjee Date: Thu, 7 Mar 2024 23:25:41 -0800 Subject: [PATCH 3/5] fix unit test --- tests/unit_tests/test_guard.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/unit_tests/test_guard.py b/tests/unit_tests/test_guard.py index 40798cf45..3f225a484 100644 --- a/tests/unit_tests/test_guard.py +++ b/tests/unit_tests/test_guard.py @@ -278,14 +278,13 @@ def test_use_many_tuple(): def test_validate(): guard: Guard = ( Guard() - .use(EndsWith("a")) .use(OneLine) .use(LowerCase(on_fail="fix")) .use(TwoWords) .use(ValidLength, 0, 12, on_fail="refrain") ) - llm_output = "Oh Canada" # bc it meets our criteria + llm_output: str = "Oh Canada" # bc it meets our criteria response = guard.validate(llm_output) From 167b1f8a1d0e4c0857330fea7b4a90d4161bd801 Mon Sep 17 00:00:00 2001 From: Zayd Simjee Date: Mon, 11 Mar 2024 17:04:06 -0700 Subject: [PATCH 4/5] ban `use` and `use_many` on non-string outputs --- guardrails/guard.py | 22 ++++++++++++++++++++++ tests/unit_tests/test_guard.py | 14 ++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/guardrails/guard.py b/guardrails/guard.py index 2d0fcb53e..9b0a286cd 100644 --- a/guardrails/guard.py +++ b/guardrails/guard.py @@ -987,6 +987,17 @@ def use(self, validator: Type[Validator], *args, **kwargs) -> "Guard": def use( self, validator: Union[Validator, Type[Validator]], *args, **kwargs ) -> "Guard": + """ + Use a validator to validate results of an LLM request. + + *Note*: `use` is only available for string output types. + """ + + if (self.rail.output_type != "str"): + raise RuntimeError( + "The `use` method is only available for string output types." + ) + if validator: hydrated_validator = get_validator(validator, *args, **kwargs) self._validators.append(hydrated_validator) @@ -1021,6 +1032,17 @@ def use_many( ], ], ) -> "Guard": + """ + Use a validator to validate results of an LLM request. + + *Note*: `use_many` is only available for string output types. + """ + + if self.rail.output_type != "str": + raise RuntimeError( + "The `use_many` method is only available for string output types." + ) + for v in validators: hydrated_validator = get_validator(v) self._validators.append(hydrated_validator) diff --git a/tests/unit_tests/test_guard.py b/tests/unit_tests/test_guard.py index 3f225a484..1d2a87b90 100644 --- a/tests/unit_tests/test_guard.py +++ b/tests/unit_tests/test_guard.py @@ -214,6 +214,13 @@ def test_use(): assert guard._validators[4]._kwargs["max"] == 12 assert guard._validators[4].on_fail_descriptor == "refrain" # bc we set it + # Raises error when trying to `use` a validator on a non-string + with pytest.raises(RuntimeError): + class TestClass(BaseModel): + another_field: str + py_guard = Guard.from_pydantic(output_class=TestClass) + py_guard.use(EndsWith("a"), OneLine(), LowerCase(), TwoWords(on_fail="reask")) + def test_use_many_instances(): guard: Guard = Guard().use_many( @@ -237,6 +244,13 @@ def test_use_many_instances(): assert isinstance(guard._validators[3], TwoWords) assert guard._validators[3].on_fail_descriptor == "reask" # bc we set it + # Raises error when trying to `use_many` a validator on a non-string + with pytest.raises(RuntimeError): + class TestClass(BaseModel): + another_field: str + py_guard = Guard.from_pydantic(output_class=TestClass) + py_guard.use_many([EndsWith("a"), OneLine(), LowerCase(), TwoWords(on_fail="reask")]) + def test_use_many_tuple(): guard: Guard = Guard().use_many( From 37fc60203cf34994599f6dc1ae9d7bb22a7d73ad Mon Sep 17 00:00:00 2001 From: Zayd Simjee Date: Tue, 12 Mar 2024 10:15:14 -0700 Subject: [PATCH 5/5] lint --- guardrails/guard.py | 12 +++++------- tests/unit_tests/test_guard.py | 8 +++++++- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/guardrails/guard.py b/guardrails/guard.py index 9b0a286cd..c707f8a21 100644 --- a/guardrails/guard.py +++ b/guardrails/guard.py @@ -987,13 +987,12 @@ def use(self, validator: Type[Validator], *args, **kwargs) -> "Guard": def use( self, validator: Union[Validator, Type[Validator]], *args, **kwargs ) -> "Guard": - """ - Use a validator to validate results of an LLM request. - + """Use a validator to validate results of an LLM request. + *Note*: `use` is only available for string output types. """ - if (self.rail.output_type != "str"): + if self.rail.output_type != "str": raise RuntimeError( "The `use` method is only available for string output types." ) @@ -1032,9 +1031,8 @@ def use_many( ], ], ) -> "Guard": - """ - Use a validator to validate results of an LLM request. - + """Use a validator to validate results of an LLM request. + *Note*: `use_many` is only available for string output types. """ diff --git a/tests/unit_tests/test_guard.py b/tests/unit_tests/test_guard.py index 1d2a87b90..729593e1a 100644 --- a/tests/unit_tests/test_guard.py +++ b/tests/unit_tests/test_guard.py @@ -216,8 +216,10 @@ def test_use(): # Raises error when trying to `use` a validator on a non-string with pytest.raises(RuntimeError): + class TestClass(BaseModel): another_field: str + py_guard = Guard.from_pydantic(output_class=TestClass) py_guard.use(EndsWith("a"), OneLine(), LowerCase(), TwoWords(on_fail="reask")) @@ -246,10 +248,14 @@ def test_use_many_instances(): # Raises error when trying to `use_many` a validator on a non-string with pytest.raises(RuntimeError): + class TestClass(BaseModel): another_field: str + py_guard = Guard.from_pydantic(output_class=TestClass) - py_guard.use_many([EndsWith("a"), OneLine(), LowerCase(), TwoWords(on_fail="reask")]) + py_guard.use_many( + [EndsWith("a"), OneLine(), LowerCase(), TwoWords(on_fail="reask")] + ) def test_use_many_tuple():