From b1426ca93e2020ab2b61aabfe1726c79e39342a1 Mon Sep 17 00:00:00 2001 From: Arthur Bied-Charreton Date: Wed, 23 Jul 2025 15:38:21 +0200 Subject: [PATCH 1/6] Add handling for config dirs ending with .yml/yaml & add tests --- nemoguardrails/rails/llm/config.py | 2 +- tests/test_configs/general.yml/README.md | 8 ++++++++ tests/test_configs/general.yml/general.yml | 19 +++++++++++++++++++ tests/test_rails_config.py | 10 ++++++++++ 4 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 tests/test_configs/general.yml/README.md create mode 100644 tests/test_configs/general.yml/general.yml diff --git a/nemoguardrails/rails/llm/config.py b/nemoguardrails/rails/llm/config.py index 306413155..e18c42299 100644 --- a/nemoguardrails/rails/llm/config.py +++ b/nemoguardrails/rails/llm/config.py @@ -1468,7 +1468,7 @@ def from_path( """ # If the config path is a file, we load the YAML content. # Otherwise, if it's a folder, we iterate through all files. - if config_path.endswith(".yaml") or config_path.endswith(".yml"): + if os.path.isfile(config_path) and config_path.endswith((".yaml", ".yml")): with open(config_path) as f: raw_config = yaml.safe_load(f.read()) diff --git a/tests/test_configs/general.yml/README.md b/tests/test_configs/general.yml/README.md new file mode 100644 index 000000000..5fe9a5cbc --- /dev/null +++ b/tests/test_configs/general.yml/README.md @@ -0,0 +1,8 @@ +# General Config + +This is a sample configuration of rails that only sets a general instruction rail. + +The directory has a `.yml` extension. This is used to verify that directories with this extension +are not treated as `YAML` files. + +Feel free to comment/uncomment the lines in `general.yml` to switch the LLM that is used. diff --git a/tests/test_configs/general.yml/general.yml b/tests/test_configs/general.yml/general.yml new file mode 100644 index 000000000..007393229 --- /dev/null +++ b/tests/test_configs/general.yml/general.yml @@ -0,0 +1,19 @@ +# A sample configuration that only uses a general instruction. + +# General assistant instruction +instructions: + - type: general + content: | + I am a large language model trained by OpenAI. + I am designed to generate human-like text based on the input that I receive. + This can include providing responses to questions, generating summaries of text, or even generating entire documents on a given topic. + I am able to understand and process natural language, so you can interact with me in the same way that you would with another person. + Feel free to ask me any questions that you have, and I will do my best to provide a helpful and accurate response. + You can also provide me with text or a topic, and I can generate text based on that input. + Whether you have a specific question that you need answered, or you need help with a language-related task, please let me know how I can assist you today. + +# Using OpenAI +models: + - type: main + engine: openai + model: gpt-3.5-turbo-instruct diff --git a/tests/test_rails_config.py b/tests/test_rails_config.py index 8ccbb9497..aee7dd1ac 100644 --- a/tests/test_rails_config.py +++ b/tests/test_rails_config.py @@ -117,6 +117,16 @@ def test_rails_config_from_path(): assert config.sample_conversation is not None +def test_rails_config_from_path_yml_extension(): + """Test loading RailsConfig from path.""" + + config_path = os.path.join(os.path.dirname(__file__), "test_configs", "general.yml") + config = RailsConfig.from_path(config_path) + assert config is not None + assert len(config.instructions) > 0 + assert config.sample_conversation is not None + + def test_rails_config_parse_obj(): """Test parsing RailsConfig from object.""" From aba9a6e3c4ef8eb6e1709900dff9b8fe97ada31e Mon Sep 17 00:00:00 2001 From: Pouyan <13303554+Pouyanpi@users.noreply.github.com> Date: Fri, 15 Aug 2025 09:16:33 +0200 Subject: [PATCH 2/6] Delete tests/test_configs/general.yml/general.yml Signed-off-by: Pouyan <13303554+Pouyanpi@users.noreply.github.com> --- tests/test_configs/general.yml/general.yml | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 tests/test_configs/general.yml/general.yml diff --git a/tests/test_configs/general.yml/general.yml b/tests/test_configs/general.yml/general.yml deleted file mode 100644 index 007393229..000000000 --- a/tests/test_configs/general.yml/general.yml +++ /dev/null @@ -1,19 +0,0 @@ -# A sample configuration that only uses a general instruction. - -# General assistant instruction -instructions: - - type: general - content: | - I am a large language model trained by OpenAI. - I am designed to generate human-like text based on the input that I receive. - This can include providing responses to questions, generating summaries of text, or even generating entire documents on a given topic. - I am able to understand and process natural language, so you can interact with me in the same way that you would with another person. - Feel free to ask me any questions that you have, and I will do my best to provide a helpful and accurate response. - You can also provide me with text or a topic, and I can generate text based on that input. - Whether you have a specific question that you need answered, or you need help with a language-related task, please let me know how I can assist you today. - -# Using OpenAI -models: - - type: main - engine: openai - model: gpt-3.5-turbo-instruct From d7090d486fcff41959d8cfbad247d3637973b129 Mon Sep 17 00:00:00 2001 From: Pouyan <13303554+Pouyanpi@users.noreply.github.com> Date: Fri, 15 Aug 2025 09:17:03 +0200 Subject: [PATCH 3/6] Delete tests/test_configs/general.yml/README.md Signed-off-by: Pouyan <13303554+Pouyanpi@users.noreply.github.com> --- tests/test_configs/general.yml/README.md | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 tests/test_configs/general.yml/README.md diff --git a/tests/test_configs/general.yml/README.md b/tests/test_configs/general.yml/README.md deleted file mode 100644 index 5fe9a5cbc..000000000 --- a/tests/test_configs/general.yml/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# General Config - -This is a sample configuration of rails that only sets a general instruction rail. - -The directory has a `.yml` extension. This is used to verify that directories with this extension -are not treated as `YAML` files. - -Feel free to comment/uncomment the lines in `general.yml` to switch the LLM that is used. From c20c360a963db9f37ac9b7cab87401e4bbb8efd2 Mon Sep 17 00:00:00 2001 From: Pouyan <13303554+Pouyanpi@users.noreply.github.com> Date: Fri, 15 Aug 2025 09:17:17 +0200 Subject: [PATCH 4/6] Apply suggestion from @Pouyanpi Signed-off-by: Pouyan <13303554+Pouyanpi@users.noreply.github.com> --- tests/test_rails_config.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/test_rails_config.py b/tests/test_rails_config.py index aee7dd1ac..ff53f3861 100644 --- a/tests/test_rails_config.py +++ b/tests/test_rails_config.py @@ -118,6 +118,32 @@ def test_rails_config_from_path(): def test_rails_config_from_path_yml_extension(): + """Test loading RailsConfig when the config directory ends with a .yml suffix. + + Ensures a directory mistakenly named with a YAML extension is treated as a directory, + not a file, and its internal YAML config is loaded properly. + """ + + with tempfile.TemporaryDirectory(suffix=".yml") as temp_dir: + temp_path = Path(temp_dir) + + minimal_yaml = ( + "models: []\n" + "instructions:\n" + " - type: general\n" + " content: Test instruction\n" + "sample_conversation: Test conversation\n" + ) + + # place a config file inside the directory-with-.yml suffix + (temp_path / "config.yml").write_text(minimal_yaml) + + config = RailsConfig.from_path(str(temp_path)) + assert config is not None + assert len(config.instructions) > 0 + assert config.sample_conversation is not None + + """Test loading RailsConfig from path.""" config_path = os.path.join(os.path.dirname(__file__), "test_configs", "general.yml") From 6f2a22bf9fc17b5be897ebf00b95c1f7ffb911ae Mon Sep 17 00:00:00 2001 From: Pouyan <13303554+Pouyanpi@users.noreply.github.com> Date: Fri, 15 Aug 2025 09:29:30 +0200 Subject: [PATCH 5/6] Update tests/test_rails_config.py Signed-off-by: Pouyan <13303554+Pouyanpi@users.noreply.github.com> --- tests/test_rails_config.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/tests/test_rails_config.py b/tests/test_rails_config.py index ff53f3861..6942b5576 100644 --- a/tests/test_rails_config.py +++ b/tests/test_rails_config.py @@ -144,15 +144,6 @@ def test_rails_config_from_path_yml_extension(): assert config.sample_conversation is not None - """Test loading RailsConfig from path.""" - - config_path = os.path.join(os.path.dirname(__file__), "test_configs", "general.yml") - config = RailsConfig.from_path(config_path) - assert config is not None - assert len(config.instructions) > 0 - assert config.sample_conversation is not None - - def test_rails_config_parse_obj(): """Test parsing RailsConfig from object.""" From 45d1d00b8d31796e46e4fc5f3bdff1b3aacc5fd5 Mon Sep 17 00:00:00 2001 From: winstonallo Date: Fri, 15 Aug 2025 09:42:31 +0200 Subject: [PATCH 6/6] Import tempfile and Path in test_rails_config.py --- tests/test_rails_config.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_rails_config.py b/tests/test_rails_config.py index 6942b5576..6fe54f487 100644 --- a/tests/test_rails_config.py +++ b/tests/test_rails_config.py @@ -15,6 +15,8 @@ import logging import os +import tempfile +from pathlib import Path from unittest import mock import pytest