diff --git a/CHANGELOG.md b/CHANGELOG.md index 68d9429e4..6e667a1b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `GriptapeCloudAssistantDriver` for interacting with Griptape Cloud's Assistant API. - `OpenAiAssistantDriver` for interacting with OpenAI's Assistant API. - `GriptapeCloudToolTool` for running Griptape Cloud hosted Tools. +- `JsonLoader` for loading and parsing JSON files. ### Changed diff --git a/docs/griptape-framework/data/loaders.md b/docs/griptape-framework/data/loaders.md index ce403c9fe..14bc3eed2 100644 --- a/docs/griptape-framework/data/loaders.md +++ b/docs/griptape-framework/data/loaders.md @@ -67,6 +67,15 @@ The Loader will load audio in its native format and populates the resulting Arti --8<-- "docs/griptape-framework/data/src/loaders_10.py" ``` +### JSON + +Loads JSON files into [JsonArtifact](../../griptape-framework/data/artifacts.md#json)s: + +```python + +--8<-- "docs/griptape-framework/data/src/loaders_json.py" +``` + ## Web !!! info diff --git a/docs/griptape-framework/data/src/loaders_json.py b/docs/griptape-framework/data/src/loaders_json.py new file mode 100644 index 000000000..d9b465ac0 --- /dev/null +++ b/docs/griptape-framework/data/src/loaders_json.py @@ -0,0 +1,9 @@ +from pathlib import Path + +from griptape.loaders import JsonLoader + +# Load an image from disk +JsonLoader().load("tests/resources/test.json") + +# You can also pass a Path object +JsonLoader().load(Path("tests/resources/test.json")) diff --git a/griptape/loaders/__init__.py b/griptape/loaders/__init__.py index b86370607..d00c8c6d6 100644 --- a/griptape/loaders/__init__.py +++ b/griptape/loaders/__init__.py @@ -2,6 +2,7 @@ from .base_file_loader import BaseFileLoader from .text_loader import TextLoader +from .json_loader import JsonLoader from .pdf_loader import PdfLoader from .web_loader import WebLoader from .sql_loader import SqlLoader @@ -19,6 +20,7 @@ "BaseLoader", "BaseFileLoader", "TextLoader", + "JsonLoader", "PdfLoader", "WebLoader", "SqlLoader", diff --git a/griptape/loaders/json_loader.py b/griptape/loaders/json_loader.py new file mode 100644 index 000000000..dc387943b --- /dev/null +++ b/griptape/loaders/json_loader.py @@ -0,0 +1,14 @@ +from __future__ import annotations + +import json + +from attrs import define + +from griptape.artifacts import JsonArtifact +from griptape.loaders import BaseFileLoader + + +@define +class JsonLoader(BaseFileLoader[JsonArtifact]): + def parse(self, data: bytes) -> JsonArtifact: + return JsonArtifact(json.loads(data), encoding=self.encoding) diff --git a/tests/resources/test.json b/tests/resources/test.json new file mode 100644 index 000000000..599b99619 --- /dev/null +++ b/tests/resources/test.json @@ -0,0 +1,26 @@ +{ + "name": "John Doe", + "age": 30, + "email": "johndoe@example.com", + "isActive": true, + "roles": [ + "user", + "admin" + ], + "address": { + "street": "123 Main St", + "city": "Anytown", + "state": "CA", + "postalCode": "12345" + }, + "phoneNumbers": [ + { + "type": "home", + "number": "555-555-5555" + }, + { + "type": "work", + "number": "555-555-1234" + } + ] +} diff --git a/tests/unit/loaders/test_json_loader.py b/tests/unit/loaders/test_json_loader.py new file mode 100644 index 000000000..8802783de --- /dev/null +++ b/tests/unit/loaders/test_json_loader.py @@ -0,0 +1,39 @@ +import pytest + +from griptape.loaders import JsonLoader + + +class TestJsonLoader: + @pytest.fixture(params=["ascii", "utf-8", None]) + def loader(self, request): + encoding = request.param + if encoding is None: + return JsonLoader() + else: + return JsonLoader(encoding=encoding) + + @pytest.fixture(params=["path_from_resource_path"]) + def create_source(self, request): + return request.getfixturevalue(request.param) + + def test_load(self, loader, create_source): + source = create_source("test.json") + + artifact = loader.load(source) + + assert artifact.value["name"] == "John Doe" + assert artifact.encoding == loader.encoding + + def test_load_collection(self, loader, create_source): + resource_paths = ["test.json"] + sources = [create_source(resource_path) for resource_path in resource_paths] + + collection = loader.load_collection(sources) + + keys = {loader.to_key(source) for source in sources} + assert collection.keys() == keys + + key = next(iter(keys)) + artifact = collection[key] + + assert artifact.encoding == loader.encoding