From cfd0ff5192518253a65bc7f9980d8672648ff270 Mon Sep 17 00:00:00 2001 From: estelle Date: Tue, 7 Jul 2026 15:18:35 +0200 Subject: [PATCH 01/14] Move components out of experimental namespace --- CHANGELOG.md | 12 +- .../chunk_reader/neo4j_chunk_reader.py | 7 +- .../components/custom_component.py | 2 +- .../components/extractors/custom_extractor.py | 4 +- .../llm_entity_relation_extractor.py | 6 +- ...y_relation_extractor_with_custom_prompt.py | 6 +- ...lation_extractor_with_structured_output.py | 6 +- .../lexical_graph_builder.py | 6 +- .../components/loaders/custom_loader.py | 7 +- .../components/loaders/pdf_loader.py | 2 +- .../components/loaders/pdf_loader_from_url.py | 2 +- .../components/pruners/graph_pruner.py | 6 +- .../components/resolvers/custom_resolver.py | 4 +- .../fuzzy_match_entity_resolver_pre_filter.py | 6 +- .../simple_entity_resolver_pre_filter.py | 6 +- .../spacy_entity_resolver_pre_filter.py | 6 +- .../components/schema_builders/schema.py | 2 +- .../schema_from_existing_graph.py | 2 +- .../schema_builders/schema_from_text.py | 2 +- ...schema_from_text_with_structured_output.py | 2 +- .../components/splitters/custom_splitter.py | 7 +- .../splitters/fixed_size_splitter.py | 6 +- .../components/writers/custom_writer.py | 10 +- .../components/writers/neo4j_writer.py | 4 +- .../pipeline/kg_builder_from_pdf.py | 12 +- .../pipeline/kg_builder_from_text.py | 12 +- ...builder_two_documents_entity_resolution.py | 12 +- .../lexical_graph_builder_from_text.py | 12 +- .../pipeline/pipeline_streaming.py | 2 +- .../pipeline/pipeline_with_notifications.py | 8 +- ...l_graph_to_entity_graph_single_pipeline.py | 18 +- ...cal_graph_to_entity_graph_two_pipelines.py | 20 +- .../build_graph/pipeline/visualization.py | 4 +- examples/kg_builder.py | 12 +- pyproject.toml | 1 + .../neo4j_graphrag}/components/__init__.py | 0 .../component.py => components/base.py} | 40 +- .../components/data_loader.py | 4 +- .../{experimental => }/components/embedder.py | 6 +- .../components/entity_relation_extractor.py | 12 +- .../components/filename_collision_handler.py | 0 .../components/graph_pruning.py | 6 +- .../components/graph_schema_extraction.py | 22 +- .../components/kg_writer.py | 24 +- .../components/lexical_graph.py | 4 +- .../components/neo4j_reader.py | 6 +- .../components/parquet_formatter.py | 4 +- .../components/parquet_output.py | 0 .../components/pdf_loader.py | 6 +- .../{experimental => }/components/resolver.py | 9 +- .../{experimental => }/components/schema.py | 22 +- .../components/text_splitters/__init__.py | 0 .../components/text_splitters/base.py | 4 +- .../text_splitters/fixed_size_splitter.py | 6 +- .../components/text_splitters/langchain.py | 6 +- .../components/text_splitters/llamaindex.py | 6 +- .../{experimental => }/components/types.py | 4 +- .../experimental/components/__init__.py | 27 ++ .../experimental/pipeline/__init__.py | 3 - .../pipeline/config/object_config.py | 4 +- .../template_pipeline/simple_kg_builder.py | 20 +- .../experimental/pipeline/kg_builder.py | 16 +- .../experimental/pipeline/pipeline.py | 2 +- .../experimental/pipeline/types/context.py | 30 +- .../pipeline/types/definitions.py | 2 +- .../pipeline/types/orchestration.py | 2 +- .../experimental/utils/schema.py | 2 +- .../test_entity_resolver_component_e2e.py | 2 +- .../test_graph_pruning_component_e2e.py | 6 +- .../test_kg_builder_pipeline_e2e.py | 12 +- .../test_kg_writer_component_e2e.py | 8 +- ...est_lexical_graph_builder_component_e2e.py | 6 +- .../test_neo4j_reader_component_e2e.py | 8 +- .../experimental/test_simplekgpipeline_e2e.py | 4 +- tests/unit/components/__init__.py | 14 + .../components/sample_data/hello.md | 0 .../components/sample_data/lorem_ipsum.pdf | Bin .../components/test_data_loader.py | 15 +- .../components/test_embedder.py | 4 +- .../test_entity_relation_extractor.py | 4 +- .../components/test_graph_pruning.py | 10 +- .../test_graph_schema_extraction.py | 4 +- .../test_graph_schema_extraction_contract.py | 4 +- .../components/test_kg_writer.py | 42 +- .../components/test_lexical_graph_builder.py | 4 +- .../components/test_neo4j_reader.py | 4 +- .../test_property_type_deprecation.py | 2 +- .../components/test_resolver.py | 4 +- .../components/test_schema.py | 20 +- .../components/test_types.py | 14 +- .../components/text_splitters/__init__.py | 0 .../test_fixed_size_splitter.py | 4 +- .../text_splitters/test_langchain.py | 7 +- .../text_splitters/test_llamaindex.py | 7 +- tests/unit/conftest.py | 2 +- .../unit/experimental/pipeline/components.py | 2 +- .../test_simple_kg_builder.py | 25 +- .../pipeline/config/test_pipeline_config.py | 2 +- .../experimental/pipeline/test_component.py | 2 +- .../experimental/pipeline/test_kg_builder.py | 18 +- .../pipeline/test_orchestrator.py | 2 +- .../experimental/pipeline/test_pipeline.py | 3 +- tests/unit/experimental/utils/test_schema.py | 2 +- uv.lock | 374 +++++++++++++++++- 104 files changed, 785 insertions(+), 391 deletions(-) rename {tests/unit/experimental => src/neo4j_graphrag}/components/__init__.py (100%) rename src/neo4j_graphrag/{experimental/pipeline/component.py => components/base.py} (78%) rename src/neo4j_graphrag/{experimental => }/components/data_loader.py (97%) rename src/neo4j_graphrag/{experimental => }/components/embedder.py (94%) rename src/neo4j_graphrag/{experimental => }/components/entity_relation_extractor.py (96%) rename src/neo4j_graphrag/{experimental => }/components/filename_collision_handler.py (100%) rename src/neo4j_graphrag/{experimental => }/components/graph_pruning.py (98%) rename src/neo4j_graphrag/{experimental => }/components/graph_schema_extraction.py (81%) rename src/neo4j_graphrag/{experimental => }/components/kg_writer.py (95%) rename src/neo4j_graphrag/{experimental => }/components/lexical_graph.py (98%) rename src/neo4j_graphrag/{experimental => }/components/neo4j_reader.py (94%) rename src/neo4j_graphrag/{experimental => }/components/parquet_formatter.py (99%) rename src/neo4j_graphrag/{experimental => }/components/parquet_output.py (100%) rename src/neo4j_graphrag/{experimental => }/components/pdf_loader.py (81%) rename src/neo4j_graphrag/{experimental => }/components/resolver.py (97%) rename src/neo4j_graphrag/{experimental => }/components/schema.py (98%) rename src/neo4j_graphrag/{experimental => }/components/text_splitters/__init__.py (100%) rename src/neo4j_graphrag/{experimental => }/components/text_splitters/base.py (88%) rename src/neo4j_graphrag/{experimental => }/components/text_splitters/fixed_size_splitter.py (95%) rename src/neo4j_graphrag/{experimental => }/components/text_splitters/langchain.py (87%) rename src/neo4j_graphrag/{experimental => }/components/text_splitters/llamaindex.py (88%) rename src/neo4j_graphrag/{experimental => }/components/types.py (98%) create mode 100644 tests/unit/components/__init__.py rename tests/unit/{experimental => }/components/sample_data/hello.md (100%) rename tests/unit/{experimental => }/components/sample_data/lorem_ipsum.pdf (100%) rename tests/unit/{experimental => }/components/test_data_loader.py (93%) rename tests/unit/{experimental => }/components/test_embedder.py (91%) rename tests/unit/{experimental => }/components/test_entity_relation_extractor.py (99%) rename tests/unit/{experimental => }/components/test_graph_pruning.py (98%) rename tests/unit/{experimental => }/components/test_graph_schema_extraction.py (98%) rename tests/unit/{experimental => }/components/test_graph_schema_extraction_contract.py (96%) rename tests/unit/{experimental => }/components/test_kg_writer.py (97%) rename tests/unit/{experimental => }/components/test_lexical_graph_builder.py (97%) rename tests/unit/{experimental => }/components/test_neo4j_reader.py (96%) rename tests/unit/{experimental => }/components/test_property_type_deprecation.py (98%) rename tests/unit/{experimental => }/components/test_resolver.py (98%) rename tests/unit/{experimental => }/components/test_schema.py (99%) rename tests/unit/{experimental => }/components/test_types.py (79%) create mode 100644 tests/unit/components/text_splitters/__init__.py rename tests/unit/{experimental => }/components/text_splitters/test_fixed_size_splitter.py (98%) rename tests/unit/{experimental => }/components/text_splitters/test_langchain.py (91%) rename tests/unit/{experimental => }/components/text_splitters/test_llamaindex.py (90%) diff --git a/CHANGELOG.md b/CHANGELOG.md index e54fff1dd..bd4e09f98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,16 @@ - (**breaking**) `AnthropicLLM.supports_structured_output` is now `True`. As a result, `SchemaFromTextExtractor` and `LLMEntityRelationExtractor` (and `SimpleKGPipeline`, which enables structured output automatically when the LLM supports it) now use structured output by default with `AnthropicLLM`. This requires a Claude 4.5+ model (e.g. `claude-sonnet-4-5`); using `AnthropicLLM` with an older Claude model in these components will now raise an error where it previously worked. To keep the previous behavior, use a Claude 4.5+ model, or construct `LLMEntityRelationExtractor` / `SchemaFromTextExtractor` directly with `use_structured_output=False`. +- Preparation for 2.0: + - All `Components` have been moved out of the `experimental` namespace + - Import `from neo4j_graphrag.experimental.components... ` still work but raises a deprecation warning + - Import from the experimental namespace will be removed in 2.0 + - Update to use `from neo4j_graphrag.components... ` instead + - Improperly defined components now raise a `ComponentDefinitionError` instead of `PipelineDefinitionError` + - `TaskProgressNotifier` and `RunContext` have been moved to `neo4j_graphrag.components.base` + - The `Component` base class has been moved to `neo4j_graphrag.components.base` + + ## 1.18.0 ### Changed @@ -17,7 +27,7 @@ - Experimental: `GraphSchema` validation now rejects `KEY` and `EXISTENCE` constraints on the same node or relationship property (including composite KEY members), since KEY already implies mandatory presence. Legacy `PropertyType.required` migration no longer adds redundant EXISTENCE constraints for KEY-covered properties. The schema-from-text extraction prompt includes the same rule. - Experimental: the schema-from-text extraction prompt now instructs the LLM to define each relationship type once and reuse it across patterns, using distinct type names only when patterns genuinely need different properties or constraints. - Experimental: LLM-auto-generated schemas now reconcile duplicate `relationship_types` (entries sharing the same label) by merging them into a single type that carries the union of their properties, emitting a warning log. This reflects that Neo4j relationship types are global per name. -- Experimental (**breaking**): `GraphSchema` now raises `SchemaValidationError` when the same label appears more than once in `relationship_types`. Because Neo4j relationship types are global per name (every relationship of a given type shares the same properties and constraints regardless of its endpoints), a label cannot have two conflicting definitions. +- Experimental (**breaking**): `GraphSchema` now raises `SchemaValidationError` when the same label appears more than once in `relationship_types`. Because Neo4j relationship types are global per name (every relationship of a given type shares the same properties and constraints regardless of its endpoints), a label cannot have two conflicting definitions. ## 1.17.0 diff --git a/examples/customize/build_graph/components/chunk_reader/neo4j_chunk_reader.py b/examples/customize/build_graph/components/chunk_reader/neo4j_chunk_reader.py index f48dc1bd2..97c8bd25e 100644 --- a/examples/customize/build_graph/components/chunk_reader/neo4j_chunk_reader.py +++ b/examples/customize/build_graph/components/chunk_reader/neo4j_chunk_reader.py @@ -1,8 +1,11 @@ import asyncio import neo4j -from neo4j_graphrag.experimental.components.neo4j_reader import Neo4jChunkReader -from neo4j_graphrag.experimental.components.types import LexicalGraphConfig, TextChunks +from neo4j_graphrag.components.neo4j_reader import Neo4jChunkReader +from neo4j_graphrag.components.types import ( + LexicalGraphConfig, + TextChunks, +) async def main(driver: neo4j.Driver) -> TextChunks: diff --git a/examples/customize/build_graph/components/custom_component.py b/examples/customize/build_graph/components/custom_component.py index ea71ce4d3..06f36d5e6 100644 --- a/examples/customize/build_graph/components/custom_component.py +++ b/examples/customize/build_graph/components/custom_component.py @@ -8,7 +8,7 @@ import random -from neo4j_graphrag.experimental.pipeline import Component, DataModel +from neo4j_graphrag.components.base import Component, DataModel from pydantic import BaseModel, validate_call diff --git a/examples/customize/build_graph/components/extractors/custom_extractor.py b/examples/customize/build_graph/components/extractors/custom_extractor.py index dcc73d89d..57f792dd3 100644 --- a/examples/customize/build_graph/components/extractors/custom_extractor.py +++ b/examples/customize/build_graph/components/extractors/custom_extractor.py @@ -1,10 +1,10 @@ from typing import Any, Optional -from neo4j_graphrag.experimental.components.entity_relation_extractor import ( +from neo4j_graphrag.components.entity_relation_extractor import ( EntityRelationExtractor, OnError, ) -from neo4j_graphrag.experimental.components.types import ( +from neo4j_graphrag.components.types import ( DocumentInfo, LexicalGraphConfig, Neo4jGraph, diff --git a/examples/customize/build_graph/components/extractors/llm_entity_relation_extractor.py b/examples/customize/build_graph/components/extractors/llm_entity_relation_extractor.py index 71892f67f..1786695af 100644 --- a/examples/customize/build_graph/components/extractors/llm_entity_relation_extractor.py +++ b/examples/customize/build_graph/components/extractors/llm_entity_relation_extractor.py @@ -1,7 +1,5 @@ -from neo4j_graphrag.experimental.components.entity_relation_extractor import ( - LLMEntityRelationExtractor, -) -from neo4j_graphrag.experimental.components.types import ( +from neo4j_graphrag.components.entity_relation_extractor import LLMEntityRelationExtractor +from neo4j_graphrag.components.types import ( Neo4jGraph, TextChunk, TextChunks, diff --git a/examples/customize/build_graph/components/extractors/llm_entity_relation_extractor_with_custom_prompt.py b/examples/customize/build_graph/components/extractors/llm_entity_relation_extractor_with_custom_prompt.py index 71892f67f..1786695af 100644 --- a/examples/customize/build_graph/components/extractors/llm_entity_relation_extractor_with_custom_prompt.py +++ b/examples/customize/build_graph/components/extractors/llm_entity_relation_extractor_with_custom_prompt.py @@ -1,7 +1,5 @@ -from neo4j_graphrag.experimental.components.entity_relation_extractor import ( - LLMEntityRelationExtractor, -) -from neo4j_graphrag.experimental.components.types import ( +from neo4j_graphrag.components.entity_relation_extractor import LLMEntityRelationExtractor +from neo4j_graphrag.components.types import ( Neo4jGraph, TextChunk, TextChunks, diff --git a/examples/customize/build_graph/components/extractors/llm_entity_relation_extractor_with_structured_output.py b/examples/customize/build_graph/components/extractors/llm_entity_relation_extractor_with_structured_output.py index 808efd93e..835ca7b43 100644 --- a/examples/customize/build_graph/components/extractors/llm_entity_relation_extractor_with_structured_output.py +++ b/examples/customize/build_graph/components/extractors/llm_entity_relation_extractor_with_structured_output.py @@ -16,10 +16,8 @@ import asyncio from dotenv import load_dotenv -from neo4j_graphrag.experimental.components.entity_relation_extractor import ( - LLMEntityRelationExtractor, -) -from neo4j_graphrag.experimental.components.types import ( +from neo4j_graphrag.components.entity_relation_extractor import LLMEntityRelationExtractor +from neo4j_graphrag.components.types import ( Neo4jGraph, TextChunk, TextChunks, diff --git a/examples/customize/build_graph/components/lexical_graph_builder/lexical_graph_builder.py b/examples/customize/build_graph/components/lexical_graph_builder/lexical_graph_builder.py index 63c5846d0..cb55a8b70 100644 --- a/examples/customize/build_graph/components/lexical_graph_builder/lexical_graph_builder.py +++ b/examples/customize/build_graph/components/lexical_graph_builder/lexical_graph_builder.py @@ -1,7 +1,5 @@ -from neo4j_graphrag.experimental.components.lexical_graph import ( - LexicalGraphBuilder, -) -from neo4j_graphrag.experimental.components.types import ( +from neo4j_graphrag.components.lexical_graph import LexicalGraphBuilder +from neo4j_graphrag.components.types import ( GraphResult, LexicalGraphConfig, TextChunk, diff --git a/examples/customize/build_graph/components/loaders/custom_loader.py b/examples/customize/build_graph/components/loaders/custom_loader.py index 1c5d97f54..cdd664914 100644 --- a/examples/customize/build_graph/components/loaders/custom_loader.py +++ b/examples/customize/build_graph/components/loaders/custom_loader.py @@ -5,8 +5,11 @@ from fsspec import AbstractFileSystem -from neo4j_graphrag.experimental.components.data_loader import DataLoader -from neo4j_graphrag.experimental.components.types import DocumentInfo, LoadedDocument +from neo4j_graphrag.components.data_loader import DataLoader +from neo4j_graphrag.components.types import ( + DocumentInfo, + LoadedDocument, +) class MyLoader(DataLoader): diff --git a/examples/customize/build_graph/components/loaders/pdf_loader.py b/examples/customize/build_graph/components/loaders/pdf_loader.py index d43076c76..c2e45f98a 100644 --- a/examples/customize/build_graph/components/loaders/pdf_loader.py +++ b/examples/customize/build_graph/components/loaders/pdf_loader.py @@ -3,7 +3,7 @@ import asyncio from pathlib import Path -from neo4j_graphrag.experimental.components.data_loader import PdfLoader +from neo4j_graphrag.components.pdf_loader import PdfLoader root_dir = Path(__file__).parents[4] file_path = root_dir / "data" / "Harry Potter and the Chamber of Secrets Summary.pdf" diff --git a/examples/customize/build_graph/components/loaders/pdf_loader_from_url.py b/examples/customize/build_graph/components/loaders/pdf_loader_from_url.py index 1d875100b..3c78bfd66 100644 --- a/examples/customize/build_graph/components/loaders/pdf_loader_from_url.py +++ b/examples/customize/build_graph/components/loaders/pdf_loader_from_url.py @@ -2,7 +2,7 @@ import asyncio -from neo4j_graphrag.experimental.components.data_loader import PdfLoader +from neo4j_graphrag.components.data_loader import PdfLoader url = "https://raw.githubusercontent.com/neo4j/neo4j-graphrag-python/c166afc4d5abc56a5686f3da46a97ed7c07da19d/examples/data/Harry%20Potter%20and%20the%20Chamber%20of%20Secrets%20Summary.pdf" diff --git a/examples/customize/build_graph/components/pruners/graph_pruner.py b/examples/customize/build_graph/components/pruners/graph_pruner.py index 6d938a97f..8981cf8d6 100644 --- a/examples/customize/build_graph/components/pruners/graph_pruner.py +++ b/examples/customize/build_graph/components/pruners/graph_pruner.py @@ -2,8 +2,8 @@ import asyncio -from neo4j_graphrag.experimental.components.graph_pruning import GraphPruning -from neo4j_graphrag.experimental.components.schema import ( +from neo4j_graphrag.components.graph_pruning import GraphPruning +from neo4j_graphrag.components.schema import ( ConstraintType, GraphConstraintType, GraphSchema, @@ -12,7 +12,7 @@ PropertyType, RelationshipType, ) -from neo4j_graphrag.experimental.components.types import ( +from neo4j_graphrag.components.types import ( Neo4jGraph, Neo4jNode, Neo4jRelationship, diff --git a/examples/customize/build_graph/components/resolvers/custom_resolver.py b/examples/customize/build_graph/components/resolvers/custom_resolver.py index 26375f183..3feb7b3c3 100644 --- a/examples/customize/build_graph/components/resolvers/custom_resolver.py +++ b/examples/customize/build_graph/components/resolvers/custom_resolver.py @@ -5,8 +5,8 @@ from typing import Any, Optional import neo4j -from neo4j_graphrag.experimental.components.resolver import EntityResolver -from neo4j_graphrag.experimental.components.types import ResolutionStats +from neo4j_graphrag.components.resolver import EntityResolver +from neo4j_graphrag.components.types import ResolutionStats class MyEntityResolver(EntityResolver): diff --git a/examples/customize/build_graph/components/resolvers/fuzzy_match_entity_resolver_pre_filter.py b/examples/customize/build_graph/components/resolvers/fuzzy_match_entity_resolver_pre_filter.py index ef8298cde..a7240b5e9 100644 --- a/examples/customize/build_graph/components/resolvers/fuzzy_match_entity_resolver_pre_filter.py +++ b/examples/customize/build_graph/components/resolvers/fuzzy_match_entity_resolver_pre_filter.py @@ -11,10 +11,8 @@ See apoc.refactor.mergeNodes documentation for more details. """ -from neo4j_graphrag.experimental.components.resolver import ( - FuzzyMatchResolver, -) -from neo4j_graphrag.experimental.components.types import ResolutionStats +from neo4j_graphrag.components.resolver import FuzzyMatchResolver +from neo4j_graphrag.components.types import ResolutionStats import neo4j diff --git a/examples/customize/build_graph/components/resolvers/simple_entity_resolver_pre_filter.py b/examples/customize/build_graph/components/resolvers/simple_entity_resolver_pre_filter.py index d9f8cbabb..4a196ce45 100644 --- a/examples/customize/build_graph/components/resolvers/simple_entity_resolver_pre_filter.py +++ b/examples/customize/build_graph/components/resolvers/simple_entity_resolver_pre_filter.py @@ -11,10 +11,8 @@ """ import neo4j -from neo4j_graphrag.experimental.components.resolver import ( - SinglePropertyExactMatchResolver, -) -from neo4j_graphrag.experimental.components.types import ResolutionStats +from neo4j_graphrag.components.resolver import SinglePropertyExactMatchResolver +from neo4j_graphrag.components.types import ResolutionStats async def main(driver: neo4j.Driver) -> None: diff --git a/examples/customize/build_graph/components/resolvers/spacy_entity_resolver_pre_filter.py b/examples/customize/build_graph/components/resolvers/spacy_entity_resolver_pre_filter.py index 2da7ed062..fe4d6e6c9 100644 --- a/examples/customize/build_graph/components/resolvers/spacy_entity_resolver_pre_filter.py +++ b/examples/customize/build_graph/components/resolvers/spacy_entity_resolver_pre_filter.py @@ -12,10 +12,8 @@ """ import neo4j -from neo4j_graphrag.experimental.components.resolver import ( - SpaCySemanticMatchResolver, -) -from neo4j_graphrag.experimental.components.types import ResolutionStats +from neo4j_graphrag.components.resolver import SpaCySemanticMatchResolver +from neo4j_graphrag.components.types import ResolutionStats async def main(driver: neo4j.Driver) -> None: diff --git a/examples/customize/build_graph/components/schema_builders/schema.py b/examples/customize/build_graph/components/schema_builders/schema.py index 6ca408dee..1a23d223b 100644 --- a/examples/customize/build_graph/components/schema_builders/schema.py +++ b/examples/customize/build_graph/components/schema_builders/schema.py @@ -12,7 +12,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from neo4j_graphrag.experimental.components.schema import ( +from neo4j_graphrag.components.schema import ( SchemaBuilder, NodeType, PropertyType, diff --git a/examples/customize/build_graph/components/schema_builders/schema_from_existing_graph.py b/examples/customize/build_graph/components/schema_builders/schema_from_existing_graph.py index 717c74be6..d97ff2cae 100644 --- a/examples/customize/build_graph/components/schema_builders/schema_from_existing_graph.py +++ b/examples/customize/build_graph/components/schema_builders/schema_from_existing_graph.py @@ -7,7 +7,7 @@ import neo4j -from neo4j_graphrag.experimental.components.schema import ( +from neo4j_graphrag.components.schema import ( SchemaFromExistingGraphExtractor, GraphSchema, ) diff --git a/examples/customize/build_graph/components/schema_builders/schema_from_text.py b/examples/customize/build_graph/components/schema_builders/schema_from_text.py index 71301965a..07142a86b 100644 --- a/examples/customize/build_graph/components/schema_builders/schema_from_text.py +++ b/examples/customize/build_graph/components/schema_builders/schema_from_text.py @@ -12,7 +12,7 @@ from pathlib import Path from dotenv import load_dotenv -from neo4j_graphrag.experimental.components.schema import ( +from neo4j_graphrag.components.schema import ( SchemaFromTextExtractor, GraphSchema, ) diff --git a/examples/customize/build_graph/components/schema_builders/schema_from_text_with_structured_output.py b/examples/customize/build_graph/components/schema_builders/schema_from_text_with_structured_output.py index 9dec3c06c..50fbea848 100644 --- a/examples/customize/build_graph/components/schema_builders/schema_from_text_with_structured_output.py +++ b/examples/customize/build_graph/components/schema_builders/schema_from_text_with_structured_output.py @@ -21,7 +21,7 @@ import asyncio from dotenv import load_dotenv -from neo4j_graphrag.experimental.components.schema import ( +from neo4j_graphrag.components.schema import ( SchemaFromTextExtractor, GraphSchema, ) diff --git a/examples/customize/build_graph/components/splitters/custom_splitter.py b/examples/customize/build_graph/components/splitters/custom_splitter.py index f28edbc1f..3a2ce6613 100644 --- a/examples/customize/build_graph/components/splitters/custom_splitter.py +++ b/examples/customize/build_graph/components/splitters/custom_splitter.py @@ -1,5 +1,8 @@ -from neo4j_graphrag.experimental.components.text_splitters.base import TextSplitter -from neo4j_graphrag.experimental.components.types import TextChunk, TextChunks +from neo4j_graphrag.components.text_splitters.base import TextSplitter +from neo4j_graphrag.components.types import ( + TextChunk, + TextChunks, +) class MySplitter(TextSplitter): diff --git a/examples/customize/build_graph/components/splitters/fixed_size_splitter.py b/examples/customize/build_graph/components/splitters/fixed_size_splitter.py index 0b97f3938..ff1ff033b 100644 --- a/examples/customize/build_graph/components/splitters/fixed_size_splitter.py +++ b/examples/customize/build_graph/components/splitters/fixed_size_splitter.py @@ -1,7 +1,5 @@ -from neo4j_graphrag.experimental.components.text_splitters.fixed_size_splitter import ( - FixedSizeSplitter, -) -from neo4j_graphrag.experimental.components.types import TextChunks +from neo4j_graphrag.components.text_splitters.fixed_size_splitter import FixedSizeSplitter +from neo4j_graphrag.components.types import TextChunks async def main() -> TextChunks: diff --git a/examples/customize/build_graph/components/writers/custom_writer.py b/examples/customize/build_graph/components/writers/custom_writer.py index 4b44a620f..3384c659f 100644 --- a/examples/customize/build_graph/components/writers/custom_writer.py +++ b/examples/customize/build_graph/components/writers/custom_writer.py @@ -3,8 +3,14 @@ """ import neo4j -from neo4j_graphrag.experimental.components.kg_writer import KGWriter, KGWriterModel -from neo4j_graphrag.experimental.components.types import LexicalGraphConfig, Neo4jGraph +from neo4j_graphrag.components.kg_writer import ( + KGWriter, + KGWriterModel, +) +from neo4j_graphrag.components.types import ( + LexicalGraphConfig, + Neo4jGraph, +) from pydantic import validate_call from neo4j_graphrag.utils import driver_config diff --git a/examples/customize/build_graph/components/writers/neo4j_writer.py b/examples/customize/build_graph/components/writers/neo4j_writer.py index 60dbcea97..afc3e85b1 100644 --- a/examples/customize/build_graph/components/writers/neo4j_writer.py +++ b/examples/customize/build_graph/components/writers/neo4j_writer.py @@ -1,9 +1,9 @@ import neo4j -from neo4j_graphrag.experimental.components.kg_writer import ( +from neo4j_graphrag.components.kg_writer import ( KGWriterModel, Neo4jWriter, ) -from neo4j_graphrag.experimental.components.types import Neo4jGraph +from neo4j_graphrag.components.types import Neo4jGraph async def main(driver: neo4j.Driver, graph: Neo4jGraph) -> KGWriterModel: diff --git a/examples/customize/build_graph/pipeline/kg_builder_from_pdf.py b/examples/customize/build_graph/pipeline/kg_builder_from_pdf.py index 0e2ee0f2b..aae29d817 100644 --- a/examples/customize/build_graph/pipeline/kg_builder_from_pdf.py +++ b/examples/customize/build_graph/pipeline/kg_builder_from_pdf.py @@ -17,20 +17,18 @@ import asyncio import logging -from neo4j_graphrag.experimental.components.entity_relation_extractor import ( +from neo4j_graphrag.components.entity_relation_extractor import ( LLMEntityRelationExtractor, OnError, ) -from neo4j_graphrag.experimental.components.kg_writer import Neo4jWriter -from neo4j_graphrag.experimental.components.data_loader import PdfLoader -from neo4j_graphrag.experimental.components.schema import ( +from neo4j_graphrag.components.kg_writer import Neo4jWriter +from neo4j_graphrag.components.data_loader import PdfLoader +from neo4j_graphrag.components.schema import ( SchemaBuilder, NodeType, RelationshipType, ) -from neo4j_graphrag.experimental.components.text_splitters.fixed_size_splitter import ( - FixedSizeSplitter, -) +from neo4j_graphrag.components.text_splitters.fixed_size_splitter import FixedSizeSplitter from neo4j_graphrag.experimental.pipeline.pipeline import PipelineResult from neo4j_graphrag.llm import LLMInterface, OpenAILLM diff --git a/examples/customize/build_graph/pipeline/kg_builder_from_text.py b/examples/customize/build_graph/pipeline/kg_builder_from_text.py index 2057edf6c..fc36d5d0f 100644 --- a/examples/customize/build_graph/pipeline/kg_builder_from_text.py +++ b/examples/customize/build_graph/pipeline/kg_builder_from_text.py @@ -17,21 +17,19 @@ import asyncio from neo4j_graphrag.embeddings.openai import OpenAIEmbeddings -from neo4j_graphrag.experimental.components.embedder import TextChunkEmbedder -from neo4j_graphrag.experimental.components.entity_relation_extractor import ( +from neo4j_graphrag.components.embedder import TextChunkEmbedder +from neo4j_graphrag.components.entity_relation_extractor import ( LLMEntityRelationExtractor, OnError, ) -from neo4j_graphrag.experimental.components.kg_writer import Neo4jWriter -from neo4j_graphrag.experimental.components.schema import ( +from neo4j_graphrag.components.kg_writer import Neo4jWriter +from neo4j_graphrag.components.schema import ( SchemaBuilder, NodeType, PropertyType, RelationshipType, ) -from neo4j_graphrag.experimental.components.text_splitters.fixed_size_splitter import ( - FixedSizeSplitter, -) +from neo4j_graphrag.components.text_splitters.fixed_size_splitter import FixedSizeSplitter from neo4j_graphrag.experimental.pipeline import Pipeline from neo4j_graphrag.experimental.pipeline.pipeline import PipelineResult from neo4j_graphrag.llm import LLMInterface, OpenAILLM diff --git a/examples/customize/build_graph/pipeline/kg_builder_two_documents_entity_resolution.py b/examples/customize/build_graph/pipeline/kg_builder_two_documents_entity_resolution.py index 267cfc454..9374609e5 100644 --- a/examples/customize/build_graph/pipeline/kg_builder_two_documents_entity_resolution.py +++ b/examples/customize/build_graph/pipeline/kg_builder_two_documents_entity_resolution.py @@ -17,22 +17,22 @@ import asyncio import neo4j -from neo4j_graphrag.experimental.components.entity_relation_extractor import ( +from neo4j_graphrag.components.entity_relation_extractor import ( LLMEntityRelationExtractor, OnError, ) -from neo4j_graphrag.experimental.components.kg_writer import Neo4jWriter -from neo4j_graphrag.experimental.components.data_loader import PdfLoader -from neo4j_graphrag.experimental.components.resolver import ( +from neo4j_graphrag.components.kg_writer import Neo4jWriter +from neo4j_graphrag.components.data_loader import PdfLoader +from neo4j_graphrag.components.resolver import ( SinglePropertyExactMatchResolver, ) -from neo4j_graphrag.experimental.components.schema import ( +from neo4j_graphrag.components.schema import ( SchemaBuilder, NodeType, PropertyType, RelationshipType, ) -from neo4j_graphrag.experimental.components.text_splitters.fixed_size_splitter import ( +from neo4j_graphrag.components.text_splitters.fixed_size_splitter import ( FixedSizeSplitter, ) from neo4j_graphrag.experimental.pipeline import Pipeline diff --git a/examples/customize/build_graph/pipeline/lexical_graph_builder_from_text.py b/examples/customize/build_graph/pipeline/lexical_graph_builder_from_text.py index c2fbdec4e..88358ae24 100644 --- a/examples/customize/build_graph/pipeline/lexical_graph_builder_from_text.py +++ b/examples/customize/build_graph/pipeline/lexical_graph_builder_from_text.py @@ -3,13 +3,11 @@ import asyncio from neo4j_graphrag.embeddings.openai import OpenAIEmbeddings -from neo4j_graphrag.experimental.components.embedder import TextChunkEmbedder -from neo4j_graphrag.experimental.components.kg_writer import Neo4jWriter -from neo4j_graphrag.experimental.components.lexical_graph import LexicalGraphBuilder -from neo4j_graphrag.experimental.components.text_splitters.fixed_size_splitter import ( - FixedSizeSplitter, -) -from neo4j_graphrag.experimental.components.types import LexicalGraphConfig +from neo4j_graphrag.components.embedder import TextChunkEmbedder +from neo4j_graphrag.components.kg_writer import Neo4jWriter +from neo4j_graphrag.components.lexical_graph import LexicalGraphBuilder +from neo4j_graphrag.components.text_splitters.fixed_size_splitter import FixedSizeSplitter +from neo4j_graphrag.components.types import LexicalGraphConfig from neo4j_graphrag.experimental.pipeline import Pipeline from neo4j_graphrag.experimental.pipeline.pipeline import PipelineResult diff --git a/examples/customize/build_graph/pipeline/pipeline_streaming.py b/examples/customize/build_graph/pipeline/pipeline_streaming.py index 088901fe2..3d688fe09 100644 --- a/examples/customize/build_graph/pipeline/pipeline_streaming.py +++ b/examples/customize/build_graph/pipeline/pipeline_streaming.py @@ -1,6 +1,6 @@ import asyncio -from neo4j_graphrag.experimental.pipeline.component import Component, DataModel +from neo4j_graphrag.components.base import Component, DataModel from neo4j_graphrag.experimental.pipeline.pipeline import Pipeline from neo4j_graphrag.experimental.pipeline.notification import EventType, Event from neo4j_graphrag.experimental.pipeline.types.context import RunContext diff --git a/examples/customize/build_graph/pipeline/pipeline_with_notifications.py b/examples/customize/build_graph/pipeline/pipeline_with_notifications.py index 88939d2ab..ad537ef07 100644 --- a/examples/customize/build_graph/pipeline/pipeline_with_notifications.py +++ b/examples/customize/build_graph/pipeline/pipeline_with_notifications.py @@ -8,11 +8,9 @@ import logging import neo4j -from neo4j_graphrag.experimental.components.kg_writer import Neo4jWriter -from neo4j_graphrag.experimental.components.lexical_graph import LexicalGraphBuilder -from neo4j_graphrag.experimental.components.text_splitters.fixed_size_splitter import ( - FixedSizeSplitter, -) +from neo4j_graphrag.components.kg_writer import Neo4jWriter +from neo4j_graphrag.components.lexical_graph import LexicalGraphBuilder +from neo4j_graphrag.components.text_splitters.fixed_size_splitter import FixedSizeSplitter from neo4j_graphrag.experimental.pipeline import Pipeline from neo4j_graphrag.experimental.pipeline.pipeline import PipelineResult from neo4j_graphrag.experimental.pipeline.notification import Event diff --git a/examples/customize/build_graph/pipeline/text_to_lexical_graph_to_entity_graph_single_pipeline.py b/examples/customize/build_graph/pipeline/text_to_lexical_graph_to_entity_graph_single_pipeline.py index 7c01ccadc..aa1e26077 100644 --- a/examples/customize/build_graph/pipeline/text_to_lexical_graph_to_entity_graph_single_pipeline.py +++ b/examples/customize/build_graph/pipeline/text_to_lexical_graph_to_entity_graph_single_pipeline.py @@ -8,22 +8,18 @@ import asyncio from neo4j_graphrag.embeddings.openai import OpenAIEmbeddings -from neo4j_graphrag.experimental.components.embedder import TextChunkEmbedder -from neo4j_graphrag.experimental.components.entity_relation_extractor import ( - LLMEntityRelationExtractor, -) -from neo4j_graphrag.experimental.components.kg_writer import Neo4jWriter -from neo4j_graphrag.experimental.components.lexical_graph import LexicalGraphBuilder -from neo4j_graphrag.experimental.components.schema import ( +from neo4j_graphrag.components.embedder import TextChunkEmbedder +from neo4j_graphrag.components.entity_relation_extractor import LLMEntityRelationExtractor +from neo4j_graphrag.components.kg_writer import Neo4jWriter +from neo4j_graphrag.components.lexical_graph import LexicalGraphBuilder +from neo4j_graphrag.components.schema import ( SchemaBuilder, NodeType, PropertyType, RelationshipType, ) -from neo4j_graphrag.experimental.components.text_splitters.fixed_size_splitter import ( - FixedSizeSplitter, -) -from neo4j_graphrag.experimental.components.types import LexicalGraphConfig +from neo4j_graphrag.components.text_splitters.fixed_size_splitter import FixedSizeSplitter +from neo4j_graphrag.components.types import LexicalGraphConfig from neo4j_graphrag.experimental.pipeline import Pipeline from neo4j_graphrag.experimental.pipeline.pipeline import PipelineResult from neo4j_graphrag.llm import LLMInterface, OpenAILLM diff --git a/examples/customize/build_graph/pipeline/text_to_lexical_graph_to_entity_graph_two_pipelines.py b/examples/customize/build_graph/pipeline/text_to_lexical_graph_to_entity_graph_two_pipelines.py index fe7a53625..abf674825 100644 --- a/examples/customize/build_graph/pipeline/text_to_lexical_graph_to_entity_graph_two_pipelines.py +++ b/examples/customize/build_graph/pipeline/text_to_lexical_graph_to_entity_graph_two_pipelines.py @@ -9,23 +9,19 @@ import asyncio from neo4j_graphrag.embeddings.openai import OpenAIEmbeddings -from neo4j_graphrag.experimental.components.embedder import TextChunkEmbedder -from neo4j_graphrag.experimental.components.entity_relation_extractor import ( - LLMEntityRelationExtractor, -) -from neo4j_graphrag.experimental.components.kg_writer import Neo4jWriter -from neo4j_graphrag.experimental.components.lexical_graph import LexicalGraphBuilder -from neo4j_graphrag.experimental.components.neo4j_reader import Neo4jChunkReader -from neo4j_graphrag.experimental.components.schema import ( +from neo4j_graphrag.components.embedder import TextChunkEmbedder +from neo4j_graphrag.components.entity_relation_extractor import LLMEntityRelationExtractor +from neo4j_graphrag.components.kg_writer import Neo4jWriter +from neo4j_graphrag.components.lexical_graph import LexicalGraphBuilder +from neo4j_graphrag.components.neo4j_reader import Neo4jChunkReader +from neo4j_graphrag.components.schema import ( SchemaBuilder, NodeType, PropertyType, RelationshipType, ) -from neo4j_graphrag.experimental.components.text_splitters.fixed_size_splitter import ( - FixedSizeSplitter, -) -from neo4j_graphrag.experimental.components.types import LexicalGraphConfig +from neo4j_graphrag.components.text_splitters.fixed_size_splitter import FixedSizeSplitter +from neo4j_graphrag.components.types import LexicalGraphConfig from neo4j_graphrag.experimental.pipeline import Pipeline from neo4j_graphrag.experimental.pipeline.pipeline import PipelineResult from neo4j_graphrag.llm import LLMInterface, OpenAILLM diff --git a/examples/customize/build_graph/pipeline/visualization.py b/examples/customize/build_graph/pipeline/visualization.py index b0add6c15..38c90fff1 100644 --- a/examples/customize/build_graph/pipeline/visualization.py +++ b/examples/customize/build_graph/pipeline/visualization.py @@ -14,8 +14,8 @@ # limitations under the License. """This example illustrates how to visualize a Pipeline""" -from neo4j_graphrag.experimental.pipeline import Component, Pipeline -from neo4j_graphrag.experimental.pipeline.component import DataModel +from neo4j_graphrag.experimental.pipeline import Pipeline +from neo4j_graphrag.components.base import Component, DataModel from pydantic import validate_call diff --git a/examples/kg_builder.py b/examples/kg_builder.py index 213d4eae5..95575055e 100644 --- a/examples/kg_builder.py +++ b/examples/kg_builder.py @@ -24,20 +24,18 @@ import logging import neo4j -from neo4j_graphrag.experimental.components.entity_relation_extractor import ( +from neo4j_graphrag.components.entity_relation_extractor import ( LLMEntityRelationExtractor, OnError, ) -from neo4j_graphrag.experimental.components.kg_writer import Neo4jWriter -from neo4j_graphrag.experimental.components.data_loader import PdfLoader -from neo4j_graphrag.experimental.components.schema import ( +from neo4j_graphrag.components.kg_writer import Neo4jWriter +from neo4j_graphrag.components.data_loader import PdfLoader +from neo4j_graphrag.components.schema import ( SchemaBuilder, NodeType, RelationshipType, ) -from neo4j_graphrag.experimental.components.text_splitters.fixed_size_splitter import ( - FixedSizeSplitter, -) +from neo4j_graphrag.components.text_splitters.fixed_size_splitter import FixedSizeSplitter from neo4j_graphrag.experimental.pipeline.pipeline import PipelineResult from neo4j_graphrag.llm import LLMInterface, OpenAILLM diff --git a/pyproject.toml b/pyproject.toml index b4927a5be..fc8d5dbfb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -53,6 +53,7 @@ bedrock = ["boto3>=1.35.0,<2.0.0"] ollama = ["ollama>=0.4.4,<0.5.0"] openai = ["openai>=1.51.1,<2.0.0"] mistralai = ["mistralai>=1.0.3,<2.0.0"] +litellm = ["litellm>=1.0.0,<2.0.0"] qdrant = ["qdrant-client>=1.11.3,<2.0.0"] kg_creation_tools = ["neo4j-viz>=0.4.2,<0.5.0"] sentence-transformers = ["sentence-transformers>=3.0.0,<4.0.0"] diff --git a/tests/unit/experimental/components/__init__.py b/src/neo4j_graphrag/components/__init__.py similarity index 100% rename from tests/unit/experimental/components/__init__.py rename to src/neo4j_graphrag/components/__init__.py diff --git a/src/neo4j_graphrag/experimental/pipeline/component.py b/src/neo4j_graphrag/components/base.py similarity index 78% rename from src/neo4j_graphrag/experimental/pipeline/component.py rename to src/neo4j_graphrag/components/base.py index ebbf7e36c..6bb768a5f 100644 --- a/src/neo4j_graphrag/experimental/pipeline/component.py +++ b/src/neo4j_graphrag/components/base.py @@ -15,21 +15,49 @@ from __future__ import annotations import inspect -from typing import Any, Union, get_type_hints +from collections.abc import Awaitable +from typing import Any, Optional, Protocol, Union, get_type_hints, runtime_checkable -from pydantic import BaseModel +from pydantic import BaseModel, ConfigDict -from neo4j_graphrag.experimental.pipeline.exceptions import PipelineDefinitionError -from neo4j_graphrag.experimental.pipeline.types.context import RunContext from neo4j_graphrag.utils.validation import issubclass_safe +@runtime_checkable +class TaskProgressNotifierProtocol(Protocol): + """This protocol is used to send events from the component to the + Pipeline callback protocol. + The event sent to the callback will be of type :ref:`TaskEvent`, + with `event_type=TASK_PROGRESS`. + """ + + def __call__(self, message: str, data: dict[str, Any]) -> Awaitable[None]: ... + + +class RunContext(BaseModel): + """Context passed to the component""" + + run_id: str + task_name: str + notifier: Optional[TaskProgressNotifierProtocol] = None + + model_config = ConfigDict(arbitrary_types_allowed=True) + + async def notify(self, message: str, data: dict[str, Any]) -> None: + if self.notifier: + await self.notifier(message=message, data=data) + + class DataModel(BaseModel): """Input or Output data model for Components""" pass +class ComponentDefinitionError(Exception): + pass + + class ComponentMeta(type): def __new__( meta, name: str, bases: tuple[type, ...], attrs: dict[str, Any] @@ -54,12 +82,12 @@ def __new__( # extract returned fields from the run method return type hint return_model = get_type_hints(run).get("return") if return_model is None: - raise PipelineDefinitionError( + raise ComponentDefinitionError( f"The run method return type must be annotated in {name}" ) # the type hint must be a subclass of DataModel if not issubclass_safe(return_model, DataModel): - raise PipelineDefinitionError( + raise ComponentDefinitionError( f"The run method must return a subclass of DataModel in {name}" ) attrs["component_outputs"] = { diff --git a/src/neo4j_graphrag/experimental/components/data_loader.py b/src/neo4j_graphrag/components/data_loader.py similarity index 97% rename from src/neo4j_graphrag/experimental/components/data_loader.py rename to src/neo4j_graphrag/components/data_loader.py index bcc5960bc..9361c3b89 100644 --- a/src/neo4j_graphrag/experimental/components/data_loader.py +++ b/src/neo4j_graphrag/components/data_loader.py @@ -27,12 +27,12 @@ from fsspec.implementations.local import LocalFileSystem from neo4j_graphrag.exceptions import MarkdownLoadError, PdfLoaderError -from neo4j_graphrag.experimental.components.types import ( +from neo4j_graphrag.components.types import ( DocumentInfo, DocumentType, LoadedDocument, ) -from neo4j_graphrag.experimental.pipeline.component import Component +from neo4j_graphrag.components.base import Component def is_default_fs(fs: fsspec.AbstractFileSystem) -> bool: diff --git a/src/neo4j_graphrag/experimental/components/embedder.py b/src/neo4j_graphrag/components/embedder.py similarity index 94% rename from src/neo4j_graphrag/experimental/components/embedder.py rename to src/neo4j_graphrag/components/embedder.py index a0f1c2cb5..5fbb0d877 100644 --- a/src/neo4j_graphrag/experimental/components/embedder.py +++ b/src/neo4j_graphrag/components/embedder.py @@ -16,8 +16,8 @@ import asyncio from neo4j_graphrag.embeddings.base import Embedder -from neo4j_graphrag.experimental.components.types import TextChunk, TextChunks -from neo4j_graphrag.experimental.pipeline.component import Component +from neo4j_graphrag.components.types import TextChunk, TextChunks +from neo4j_graphrag.components.base import Component class TextChunkEmbedder(Component): @@ -31,7 +31,7 @@ class TextChunkEmbedder(Component): .. code-block:: python - from neo4j_graphrag.experimental.components.embedder import TextChunkEmbedder + from neo4j_graphrag.components.embedder import TextChunkEmbedder from neo4j_graphrag.embeddings.openai import OpenAIEmbeddings from neo4j_graphrag.experimental.pipeline import Pipeline diff --git a/src/neo4j_graphrag/experimental/components/entity_relation_extractor.py b/src/neo4j_graphrag/components/entity_relation_extractor.py similarity index 96% rename from src/neo4j_graphrag/experimental/components/entity_relation_extractor.py rename to src/neo4j_graphrag/components/entity_relation_extractor.py index d71553451..24500ff6b 100644 --- a/src/neo4j_graphrag/experimental/components/entity_relation_extractor.py +++ b/src/neo4j_graphrag/components/entity_relation_extractor.py @@ -24,16 +24,16 @@ from pydantic import ValidationError, validate_call from neo4j_graphrag.exceptions import LLMGenerationError -from neo4j_graphrag.experimental.components.lexical_graph import LexicalGraphBuilder -from neo4j_graphrag.experimental.components.schema import GraphSchema -from neo4j_graphrag.experimental.components.types import ( +from neo4j_graphrag.components.lexical_graph import LexicalGraphBuilder +from neo4j_graphrag.components.schema import GraphSchema +from neo4j_graphrag.components.types import ( DocumentInfo, LexicalGraphConfig, Neo4jGraph, TextChunk, TextChunks, ) -from neo4j_graphrag.experimental.pipeline.component import Component +from neo4j_graphrag.components.base import Component from neo4j_graphrag.experimental.pipeline.exceptions import InvalidJSONError from neo4j_graphrag.generation.prompts import ERExtractionTemplate, PromptTemplate from neo4j_graphrag.llm import LLMInterface @@ -175,7 +175,7 @@ class LLMEntityRelationExtractor(EntityRelationExtractor): .. code-block:: python - from neo4j_graphrag.experimental.components.entity_relation_extractor import LLMEntityRelationExtractor + from neo4j_graphrag.components.entity_relation_extractor import LLMEntityRelationExtractor from neo4j_graphrag.llm import OpenAILLM from neo4j_graphrag.experimental.pipeline import Pipeline @@ -189,7 +189,7 @@ class LLMEntityRelationExtractor(EntityRelationExtractor): .. code-block:: python - from neo4j_graphrag.experimental.components.entity_relation_extractor import LLMEntityRelationExtractor + from neo4j_graphrag.components.entity_relation_extractor import LLMEntityRelationExtractor from neo4j_graphrag.llm import OpenAILLM from neo4j_graphrag.experimental.pipeline import Pipeline diff --git a/src/neo4j_graphrag/experimental/components/filename_collision_handler.py b/src/neo4j_graphrag/components/filename_collision_handler.py similarity index 100% rename from src/neo4j_graphrag/experimental/components/filename_collision_handler.py rename to src/neo4j_graphrag/components/filename_collision_handler.py diff --git a/src/neo4j_graphrag/experimental/components/graph_pruning.py b/src/neo4j_graphrag/components/graph_pruning.py similarity index 98% rename from src/neo4j_graphrag/experimental/components/graph_pruning.py rename to src/neo4j_graphrag/components/graph_pruning.py index 8903c14e7..c3f97422d 100644 --- a/src/neo4j_graphrag/experimental/components/graph_pruning.py +++ b/src/neo4j_graphrag/components/graph_pruning.py @@ -19,20 +19,20 @@ from pydantic import validate_call, BaseModel -from neo4j_graphrag.experimental.components.schema import ( +from neo4j_graphrag.components.schema import ( GraphSchema, Pattern, PropertyType, NodeType, RelationshipType, ) -from neo4j_graphrag.experimental.components.types import ( +from neo4j_graphrag.components.types import ( Neo4jGraph, Neo4jNode, Neo4jRelationship, LexicalGraphConfig, ) -from neo4j_graphrag.experimental.pipeline import Component, DataModel +from neo4j_graphrag.components.base import Component, DataModel logger = logging.getLogger(__name__) diff --git a/src/neo4j_graphrag/experimental/components/graph_schema_extraction.py b/src/neo4j_graphrag/components/graph_schema_extraction.py similarity index 81% rename from src/neo4j_graphrag/experimental/components/graph_schema_extraction.py rename to src/neo4j_graphrag/components/graph_schema_extraction.py index 1f3c95c16..2105fa3ec 100644 --- a/src/neo4j_graphrag/experimental/components/graph_schema_extraction.py +++ b/src/neo4j_graphrag/components/graph_schema_extraction.py @@ -16,13 +16,13 @@ """Pydantic models for schema-from-text **structured output** only. These types are a lean wire format for ``response_format`` with supported LLMs. -Pipeline code uses :class:`~neo4j_graphrag.experimental.components.schema.GraphSchema` -exclusively; convert via :meth:`~neo4j_graphrag.experimental.components.schema.GraphSchema.from_extraction_output`. +Pipeline code uses :class:`~neo4j_graphrag.components.schema.GraphSchema` +exclusively; convert via :meth:`~neo4j_graphrag.components.schema.GraphSchema.from_extraction_output`. Vertex AI builds JSON Schema from Pydantic and parses it with protobuf; it rejects ``anyOf`` branches that use JSON Schema ``type: "null"`` (e.g. ``Optional[str]``). Extraction-specific models therefore avoid nullable fields (e.g. use empty string -sentinels where runtime :class:`~neo4j_graphrag.experimental.components.schema.ConstraintType` +sentinels where runtime :class:`~neo4j_graphrag.components.schema.ConstraintType` uses ``None``). """ @@ -32,7 +32,7 @@ from pydantic import BaseModel, ConfigDict, Field -from neo4j_graphrag.experimental.components.schema import ( +from neo4j_graphrag.components.schema import ( Neo4jPropertyTypeName, Pattern, ) @@ -42,7 +42,7 @@ class ExtractedPropertyType(BaseModel): - """Property definition aligned with :class:`~neo4j_graphrag.experimental.components.schema.PropertyType` for extraction.""" + """Property definition aligned with :class:`~neo4j_graphrag.components.schema.PropertyType` for extraction.""" name: str type: Neo4jPropertyTypeName @@ -73,8 +73,8 @@ class ExtractedConstraintType(BaseModel): This is a **wire DTO** only: shapes the JSON Schema (e.g. no nullable ``relationship_type``, which Vertex's protobuf parser rejects). Semantic rules match - :class:`~neo4j_graphrag.experimental.components.schema.ConstraintType`; those are enforced - when building :class:`~neo4j_graphrag.experimental.components.schema.GraphSchema`, not here. + :class:`~neo4j_graphrag.components.schema.ConstraintType`; those are enforced + when building :class:`~neo4j_graphrag.components.schema.GraphSchema`, not here. """ type: Literal["UNIQUENESS", "EXISTENCE", "KEY"] @@ -88,10 +88,10 @@ class ExtractedConstraintType(BaseModel): def wire_extraction_constraints_for_graph_schema( constraints: list[dict[str, Any]], ) -> list[dict[str, Any]]: - """Map extraction constraint dicts to values compatible with :class:`~neo4j_graphrag.experimental.components.schema.ConstraintType`. + """Map extraction constraint dicts to values compatible with :class:`~neo4j_graphrag.components.schema.ConstraintType`. The empty-string ``relationship_type`` wire sentinel (and any missing or ``None`` value) is removed, - so that :class:`~neo4j_graphrag.experimental.components.schema.ConstraintType` falls back to its + so that :class:`~neo4j_graphrag.components.schema.ConstraintType` falls back to its default. All three constraint types (UNIQUENESS, EXISTENCE, KEY) support both node and relationship scope; relationship_type is only removed when it is empty or None. """ @@ -110,8 +110,8 @@ def wire_extraction_constraints_for_graph_schema( class GraphSchemaExtractionOutput(BaseModel): """JSON shape for LLM schema-from-text structured output (V2). - Convert to :class:`~neo4j_graphrag.experimental.components.schema.GraphSchema` with - :meth:`~neo4j_graphrag.experimental.components.schema.GraphSchema.from_extraction_output`. + Convert to :class:`~neo4j_graphrag.components.schema.GraphSchema` with + :meth:`~neo4j_graphrag.components.schema.GraphSchema.from_extraction_output`. """ node_types: list[ExtractedNodeType] = Field(default_factory=list) diff --git a/src/neo4j_graphrag/experimental/components/kg_writer.py b/src/neo4j_graphrag/components/kg_writer.py similarity index 95% rename from src/neo4j_graphrag/experimental/components/kg_writer.py rename to src/neo4j_graphrag/components/kg_writer.py index c9c73c2f5..c1a4dcf22 100644 --- a/src/neo4j_graphrag/experimental/components/kg_writer.py +++ b/src/neo4j_graphrag/components/kg_writer.py @@ -22,24 +22,22 @@ import neo4j from pydantic import validate_call -from neo4j_graphrag.experimental.components.filename_collision_handler import ( - FilenameCollisionHandler, -) -from neo4j_graphrag.experimental.components.parquet_formatter import ( +from neo4j_graphrag.components.filename_collision_handler import FilenameCollisionHandler +from neo4j_graphrag.components.parquet_formatter import ( INTERNAL_ID_PROPERTY, Neo4jGraphParquetFormatter, ) -from neo4j_graphrag.experimental.components.parquet_output import ( +from neo4j_graphrag.components.parquet_output import ( ParquetOutputDestination, ) -from neo4j_graphrag.experimental.components.types import ( +from neo4j_graphrag.components.types import ( LexicalGraphConfig, Neo4jGraph, Neo4jNode, Neo4jRelationship, ) -from neo4j_graphrag.experimental.components.schema import GraphSchema -from neo4j_graphrag.experimental.pipeline.component import Component, DataModel +from neo4j_graphrag.components.schema import GraphSchema +from neo4j_graphrag.components.base import Component, DataModel from neo4j_graphrag.neo4j_queries import ( upsert_node_query, upsert_relationship_query, @@ -130,7 +128,7 @@ class KGWriterModel(DataModel): - "files": list of file descriptors with file_path, etc. (ParquetWriter). Each file entry includes ``columns``: a list of dicts with ``name``, ``type``, ``is_primary_key``, and ``is_unique`` (KEY / synthetic ``__id__`` / ``from``/``to`` - vs UNIQUENESS constraints per :class:`~neo4j_graphrag.experimental.components.schema.GraphSchema`). + vs UNIQUENESS constraints per :class:`~neo4j_graphrag.components.schema.GraphSchema`). Node files include a ``constraints`` list with ``KEY``, ``UNIQUENESS``, and node-scoped ``EXISTENCE`` entries (grouped ``properties`` lists), plus at least one single-property ``KEY`` (``__id__`` is injected when the schema has none). Node files whose @@ -184,7 +182,7 @@ class Neo4jWriter(KGWriter): .. code-block:: python from neo4j import GraphDatabase - from neo4j_graphrag.experimental.components.kg_writer import Neo4jWriter + from neo4j_graphrag.components.kg_writer import Neo4jWriter from neo4j_graphrag.experimental.pipeline import Pipeline URI = "neo4j://localhost:7687" @@ -335,9 +333,9 @@ class ParquetWriter(KGWriter): .. code-block:: python - from neo4j_graphrag.experimental.components.filename_collision_handler import FilenameCollisionHandler - from neo4j_graphrag.experimental.components.kg_writer import ParquetWriter - from neo4j_graphrag.experimental.components.parquet_output import ParquetOutputDestination + from neo4j_graphrag.components.filename_collision_handler import FilenameCollisionHandler + from neo4j_graphrag.components.kg_writer import ParquetWriter + from neo4j_graphrag.components.parquet_output import ParquetOutputDestination from neo4j_graphrag.experimental.pipeline import Pipeline # Provide your own implementation of ParquetOutputDestination (local, GCS, S3, etc.) diff --git a/src/neo4j_graphrag/experimental/components/lexical_graph.py b/src/neo4j_graphrag/components/lexical_graph.py similarity index 98% rename from src/neo4j_graphrag/experimental/components/lexical_graph.py rename to src/neo4j_graphrag/components/lexical_graph.py index 4a700fda9..cff965bdf 100644 --- a/src/neo4j_graphrag/experimental/components/lexical_graph.py +++ b/src/neo4j_graphrag/components/lexical_graph.py @@ -20,7 +20,7 @@ from pydantic import validate_call -from neo4j_graphrag.experimental.components.types import ( +from neo4j_graphrag.components.types import ( DocumentInfo, GraphResult, LexicalGraphConfig, @@ -31,7 +31,7 @@ TextChunk, TextChunks, ) -from neo4j_graphrag.experimental.pipeline import Component +from neo4j_graphrag.components.base import Component logger = logging.getLogger(__name__) diff --git a/src/neo4j_graphrag/experimental/components/neo4j_reader.py b/src/neo4j_graphrag/components/neo4j_reader.py similarity index 94% rename from src/neo4j_graphrag/experimental/components/neo4j_reader.py rename to src/neo4j_graphrag/components/neo4j_reader.py index f54539bc2..a6fb6851f 100644 --- a/src/neo4j_graphrag/experimental/components/neo4j_reader.py +++ b/src/neo4j_graphrag/components/neo4j_reader.py @@ -19,12 +19,12 @@ import neo4j from pydantic import validate_call -from neo4j_graphrag.experimental.components.types import ( +from neo4j_graphrag.components.types import ( LexicalGraphConfig, TextChunk, TextChunks, ) -from neo4j_graphrag.experimental.pipeline import Component +from neo4j_graphrag.components.base import Component from neo4j_graphrag.utils import driver_config @@ -41,7 +41,7 @@ class Neo4jChunkReader(Component): .. code-block:: python from neo4j import GraphDatabase - from neo4j_graphrag.experimental.components.neo4j_reader import Neo4jChunkReader + from neo4j_graphrag.components.neo4j_reader import Neo4jChunkReader URI = "neo4j://localhost:7687" AUTH = ("neo4j", "password") diff --git a/src/neo4j_graphrag/experimental/components/parquet_formatter.py b/src/neo4j_graphrag/components/parquet_formatter.py similarity index 99% rename from src/neo4j_graphrag/experimental/components/parquet_formatter.py rename to src/neo4j_graphrag/components/parquet_formatter.py index 7bfda4742..47c299728 100644 --- a/src/neo4j_graphrag/experimental/components/parquet_formatter.py +++ b/src/neo4j_graphrag/components/parquet_formatter.py @@ -29,12 +29,12 @@ from io import BytesIO from typing import Any, DefaultDict, Optional -from neo4j_graphrag.experimental.components.schema import ( +from neo4j_graphrag.components.schema import ( ConstraintType, GraphConstraintType, GraphSchema, ) -from neo4j_graphrag.experimental.components.types import ( +from neo4j_graphrag.components.types import ( LexicalGraphConfig, Neo4jGraph, Neo4jNode, diff --git a/src/neo4j_graphrag/experimental/components/parquet_output.py b/src/neo4j_graphrag/components/parquet_output.py similarity index 100% rename from src/neo4j_graphrag/experimental/components/parquet_output.py rename to src/neo4j_graphrag/components/parquet_output.py diff --git a/src/neo4j_graphrag/experimental/components/pdf_loader.py b/src/neo4j_graphrag/components/pdf_loader.py similarity index 81% rename from src/neo4j_graphrag/experimental/components/pdf_loader.py rename to src/neo4j_graphrag/components/pdf_loader.py index 2613bff98..d4dbf0404 100644 --- a/src/neo4j_graphrag/experimental/components/pdf_loader.py +++ b/src/neo4j_graphrag/components/pdf_loader.py @@ -14,7 +14,7 @@ # limitations under the License. """Backward compatibility: :class:`PdfLoader` is defined in :mod:`data_loader`. -Import from ``neo4j_graphrag.experimental.components.data_loader`` in new code. +Import from ``neo4j_graphrag.components.data_loader`` in new code. """ import warnings @@ -22,10 +22,10 @@ from .data_loader import PdfLoader, DataLoader warnings.warn( - "Importing from `neo4j_graphrag.experimental.components.pdf_loader` is " + "Importing from `neo4j_graphrag.components.pdf_loader` is " "deprecated and will be removed in a version 2.0. " "Import `PdfLoader` and `DataLoader` from " - "`neo4j_graphrag.experimental.components.data_loader` instead.", + "`neo4j_graphrag.components.data_loader` instead.", DeprecationWarning, stacklevel=2, ) diff --git a/src/neo4j_graphrag/experimental/components/resolver.py b/src/neo4j_graphrag/components/resolver.py similarity index 97% rename from src/neo4j_graphrag/experimental/components/resolver.py rename to src/neo4j_graphrag/components/resolver.py index f0aaae7a5..9c7cc3cae 100644 --- a/src/neo4j_graphrag/experimental/components/resolver.py +++ b/src/neo4j_graphrag/components/resolver.py @@ -43,9 +43,8 @@ import neo4j -from neo4j_graphrag.experimental.components.types import ResolutionStats -from neo4j_graphrag.experimental.pipeline import Component -from neo4j_graphrag.experimental.pipeline.component import ComponentMeta +from neo4j_graphrag.components.types import ResolutionStats +from neo4j_graphrag.components.base import Component, ComponentMeta from neo4j_graphrag.utils import driver_config logger = logging.getLogger(__name__) @@ -85,7 +84,7 @@ class SinglePropertyExactMatchResolver(EntityResolver): .. code-block:: python from neo4j import GraphDatabase - from neo4j_graphrag.experimental.components.resolver import SinglePropertyExactMatchResolver + from neo4j_graphrag.components.resolver import SinglePropertyExactMatchResolver URI = "neo4j://localhost:7687" AUTH = ("neo4j", "password") @@ -330,7 +329,7 @@ class SpaCySemanticMatchResolver(BasePropertySimilarityResolver): .. code-block:: python from neo4j import GraphDatabase - from neo4j_graphrag.experimental.components.resolver import SpaCySemanticMatchResolver + from neo4j_graphrag.components.resolver import SpaCySemanticMatchResolver URI = "neo4j://localhost:7687" AUTH = ("neo4j", "password") diff --git a/src/neo4j_graphrag/experimental/components/schema.py b/src/neo4j_graphrag/components/schema.py similarity index 98% rename from src/neo4j_graphrag/experimental/components/schema.py rename to src/neo4j_graphrag/components/schema.py index 7366aebcb..dae9af2ab 100644 --- a/src/neo4j_graphrag/experimental/components/schema.py +++ b/src/neo4j_graphrag/components/schema.py @@ -54,7 +54,7 @@ SchemaExtractionError, SchemaValidationError, ) -from neo4j_graphrag.experimental.pipeline.component import Component, DataModel +from neo4j_graphrag.components.base import Component, DataModel from neo4j_graphrag.experimental.pipeline.types.schema import ( EntityInputType, RelationInputType, @@ -69,7 +69,7 @@ ) if TYPE_CHECKING: - from neo4j_graphrag.experimental.components.graph_schema_extraction import ( + from neo4j_graphrag.components.graph_schema_extraction import ( GraphSchemaExtractionOutput, ) @@ -988,7 +988,7 @@ def model_json_schema(cls, **kwargs: Any) -> dict[str, Any]: # type: ignore[ove VertexAI requires: - No 'const' keyword (convert to enum with single value) - Prefer :class:`~neo4j_graphrag.experimental.components.graph_schema_extraction.GraphSchemaExtractionOutput` + Prefer :class:`~neo4j_graphrag.components.graph_schema_extraction.GraphSchemaExtractionOutput` for schema-from-text structured output (leaner schema). """ schema = super().model_json_schema(**kwargs) @@ -1002,7 +1002,7 @@ def from_extraction_output(cls, dto: GraphSchemaExtractionOutput) -> Self: Applies the same cross-reference filtering and validation as :class:`SchemaFromTextExtractor`. """ - from neo4j_graphrag.experimental.components.graph_schema_extraction import ( + from neo4j_graphrag.components.graph_schema_extraction import ( GraphSchemaExtractionOutput, wire_extraction_constraints_for_graph_schema, ) @@ -1101,7 +1101,7 @@ class SchemaBuilder(BaseSchemaBuilder): .. code-block:: python - from neo4j_graphrag.experimental.components.schema import ( + from neo4j_graphrag.components.schema import ( SchemaBuilder, NodeType, PropertyType, @@ -1573,14 +1573,14 @@ class SchemaFromTextExtractor(BaseSchemaBuilder): prompt_template (Optional[PromptTemplate]): A custom prompt template to use for extraction. llm_params (Optional[Dict[str, Any]]): Additional parameters passed to the LLM. use_structured_output (bool): Whether to use structured output (LLMInterfaceV2) with - :class:`~neo4j_graphrag.experimental.components.graph_schema_extraction.GraphSchemaExtractionOutput`. + :class:`~neo4j_graphrag.components.graph_schema_extraction.GraphSchemaExtractionOutput`. Only supported for OpenAILLM and VertexAILLM. Defaults to False (uses V1 prompt-based JSON extraction). Example with V1 (default, prompt-based JSON): .. code-block:: python - from neo4j_graphrag.experimental.components.schema import SchemaFromTextExtractor + from neo4j_graphrag.components.schema import SchemaFromTextExtractor from neo4j_graphrag.llm import OpenAILLM llm = OpenAILLM(model_name="gpt-5", model_params={"temperature": 0}) @@ -1590,7 +1590,7 @@ class SchemaFromTextExtractor(BaseSchemaBuilder): .. code-block:: python - from neo4j_graphrag.experimental.components.schema import SchemaFromTextExtractor + from neo4j_graphrag.components.schema import SchemaFromTextExtractor from neo4j_graphrag.llm import OpenAILLM llm = OpenAILLM(model_name="gpt-5") @@ -1771,7 +1771,7 @@ async def _run_with_structured_output(self, prompt: str) -> GraphSchema: """Extract schema using structured output (V2). V2 uses LLMInterfaceV2 with - :class:`~neo4j_graphrag.experimental.components.graph_schema_extraction.GraphSchemaExtractionOutput` + :class:`~neo4j_graphrag.components.graph_schema_extraction.GraphSchemaExtractionOutput` as ``response_format``, then converts to :class:`GraphSchema`. Requires OpenAI or VertexAI. Args: @@ -1784,9 +1784,7 @@ async def _run_with_structured_output(self, prompt: str) -> GraphSchema: RuntimeError: If LLM is not OpenAILLM or VertexAILLM SchemaExtractionError: If LLM generation or validation fails """ - from neo4j_graphrag.experimental.components.graph_schema_extraction import ( - GraphSchemaExtractionOutput, - ) + from neo4j_graphrag.components.graph_schema_extraction import GraphSchemaExtractionOutput # Capability check # This should never happen due to __init__ validation diff --git a/src/neo4j_graphrag/experimental/components/text_splitters/__init__.py b/src/neo4j_graphrag/components/text_splitters/__init__.py similarity index 100% rename from src/neo4j_graphrag/experimental/components/text_splitters/__init__.py rename to src/neo4j_graphrag/components/text_splitters/__init__.py diff --git a/src/neo4j_graphrag/experimental/components/text_splitters/base.py b/src/neo4j_graphrag/components/text_splitters/base.py similarity index 88% rename from src/neo4j_graphrag/experimental/components/text_splitters/base.py rename to src/neo4j_graphrag/components/text_splitters/base.py index 3061712b9..6c6b9be3b 100644 --- a/src/neo4j_graphrag/experimental/components/text_splitters/base.py +++ b/src/neo4j_graphrag/components/text_splitters/base.py @@ -16,8 +16,8 @@ from abc import abstractmethod -from neo4j_graphrag.experimental.components.types import TextChunks -from neo4j_graphrag.experimental.pipeline.component import Component +from neo4j_graphrag.components.types import TextChunks +from neo4j_graphrag.components.base import Component class TextSplitter(Component): diff --git a/src/neo4j_graphrag/experimental/components/text_splitters/fixed_size_splitter.py b/src/neo4j_graphrag/components/text_splitters/fixed_size_splitter.py similarity index 95% rename from src/neo4j_graphrag/experimental/components/text_splitters/fixed_size_splitter.py rename to src/neo4j_graphrag/components/text_splitters/fixed_size_splitter.py index 029744d4c..0b973f044 100644 --- a/src/neo4j_graphrag/experimental/components/text_splitters/fixed_size_splitter.py +++ b/src/neo4j_graphrag/components/text_splitters/fixed_size_splitter.py @@ -14,8 +14,8 @@ # limitations under the License. from pydantic import validate_call -from neo4j_graphrag.experimental.components.text_splitters.base import TextSplitter -from neo4j_graphrag.experimental.components.types import TextChunk, TextChunks +from neo4j_graphrag.components.text_splitters.base import TextSplitter +from neo4j_graphrag.components.types import TextChunk, TextChunks def _adjust_chunk_start(text: str, approximate_start: int) -> int: @@ -83,7 +83,7 @@ class FixedSizeSplitter(TextSplitter): .. code-block:: python - from neo4j_graphrag.experimental.components.text_splitters.fixed_size_splitter import FixedSizeSplitter + from neo4j_graphrag.components.text_splitters.fixed_size_splitter import FixedSizeSplitter from neo4j_graphrag.experimental.pipeline import Pipeline pipeline = Pipeline() diff --git a/src/neo4j_graphrag/experimental/components/text_splitters/langchain.py b/src/neo4j_graphrag/components/text_splitters/langchain.py similarity index 87% rename from src/neo4j_graphrag/experimental/components/text_splitters/langchain.py rename to src/neo4j_graphrag/components/text_splitters/langchain.py index f44f1b46d..215b3a4f8 100644 --- a/src/neo4j_graphrag/experimental/components/text_splitters/langchain.py +++ b/src/neo4j_graphrag/components/text_splitters/langchain.py @@ -16,8 +16,8 @@ from langchain_text_splitters import TextSplitter as LangChainTextSplitter -from neo4j_graphrag.experimental.components.text_splitters.base import TextSplitter -from neo4j_graphrag.experimental.components.types import TextChunk, TextChunks +from neo4j_graphrag.components.text_splitters.base import TextSplitter +from neo4j_graphrag.components.types import TextChunk, TextChunks class LangChainTextSplitterAdapter(TextSplitter): @@ -32,7 +32,7 @@ class LangChainTextSplitterAdapter(TextSplitter): .. code-block:: python from langchain_text_splitters import RecursiveCharacterTextSplitter - from neo4j_graphrag.experimental.components.text_splitters.langchain import LangChainTextSplitterAdapter + from neo4j_graphrag.components.text_splitters.langchain import LangChainTextSplitterAdapter from neo4j_graphrag.experimental.pipeline import Pipeline pipeline = Pipeline() diff --git a/src/neo4j_graphrag/experimental/components/text_splitters/llamaindex.py b/src/neo4j_graphrag/components/text_splitters/llamaindex.py similarity index 88% rename from src/neo4j_graphrag/experimental/components/text_splitters/llamaindex.py rename to src/neo4j_graphrag/components/text_splitters/llamaindex.py index b9e51c912..f87dbfe3c 100644 --- a/src/neo4j_graphrag/experimental/components/text_splitters/llamaindex.py +++ b/src/neo4j_graphrag/components/text_splitters/llamaindex.py @@ -16,8 +16,8 @@ from llama_index.core.node_parser import TextSplitter as LlamaIndexTextSplitter -from neo4j_graphrag.experimental.components.text_splitters.base import TextSplitter -from neo4j_graphrag.experimental.components.types import TextChunk, TextChunks +from neo4j_graphrag.components.text_splitters.base import TextSplitter +from neo4j_graphrag.components.types import TextChunk, TextChunks class LlamaIndexTextSplitterAdapter(TextSplitter): @@ -32,7 +32,7 @@ class LlamaIndexTextSplitterAdapter(TextSplitter): .. code-block:: python from llama_index.core.node_parser.text.sentence import SentenceSplitter - from neo4j_graphrag.experimental.components.text_splitters.llamaindex import ( + from neo4j_graphrag.components.text_splitters.llamaindex import ( LlamaIndexTextSplitterAdapter, ) from neo4j_graphrag.experimental.pipeline import Pipeline diff --git a/src/neo4j_graphrag/experimental/components/types.py b/src/neo4j_graphrag/components/types.py similarity index 98% rename from src/neo4j_graphrag/experimental/components/types.py rename to src/neo4j_graphrag/components/types.py index 0a2751064..1901dd7d0 100644 --- a/src/neo4j_graphrag/experimental/components/types.py +++ b/src/neo4j_graphrag/components/types.py @@ -23,7 +23,7 @@ from pydantic import BaseModel, ConfigDict, Field -from neo4j_graphrag.experimental.pipeline.component import DataModel +from neo4j_graphrag.components.base import DataModel logger = logging.getLogger(__name__) @@ -93,7 +93,7 @@ def document_id(self) -> str: class LoadedDocument(DataModel): - """Extracted text and metadata for a file loaded by a :class:`~neo4j_graphrag.experimental.components.data_loader.DataLoader`.""" + """Extracted text and metadata for a file loaded by a :class:`~neo4j_graphrag.components.data_loader.DataLoader`.""" text: str document_info: DocumentInfo diff --git a/src/neo4j_graphrag/experimental/components/__init__.py b/src/neo4j_graphrag/experimental/components/__init__.py index c0199c144..505ccd332 100644 --- a/src/neo4j_graphrag/experimental/components/__init__.py +++ b/src/neo4j_graphrag/experimental/components/__init__.py @@ -12,3 +12,30 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +import warnings +import importlib +from typing import Any + + +def __getattr__(name: str) -> Any: + warnings.warn( + f"Importing component {name} from the experimental namespace is deprecated and will be removed in version `2.0`. Use `from neo4j_graphrag.components... import ...` instead.", + DeprecationWarning, + stacklevel=2, + ) + try: + print(name) + module_split = name.rsplit(".", 1) + module_name = "neo4j_graphrag.components" + if len(module_split) == 1: + klass_name = module_split[0] + else: + module_name = module_name + "." + module_split[0] + klass_name = module_split[1] + print(module_split, module_name, klass_name) + module = importlib.import_module(module_name) + klass = getattr(module, klass_name) + return klass + except (ImportError, AttributeError) as e: + print(e) + raise diff --git a/src/neo4j_graphrag/experimental/pipeline/__init__.py b/src/neo4j_graphrag/experimental/pipeline/__init__.py index 4cb0c9411..1b8e4a373 100644 --- a/src/neo4j_graphrag/experimental/pipeline/__init__.py +++ b/src/neo4j_graphrag/experimental/pipeline/__init__.py @@ -12,14 +12,11 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from .component import Component, DataModel from .pipeline import Pipeline from .stores import InMemoryStore, Store __all__ = [ "Store", "InMemoryStore", - "Component", - "DataModel", "Pipeline", ] diff --git a/src/neo4j_graphrag/experimental/pipeline/config/object_config.py b/src/neo4j_graphrag/experimental/pipeline/config/object_config.py index 295a9c443..5fddb11ae 100644 --- a/src/neo4j_graphrag/experimental/pipeline/config/object_config.py +++ b/src/neo4j_graphrag/experimental/pipeline/config/object_config.py @@ -42,7 +42,7 @@ ) from neo4j_graphrag.embeddings import Embedder -from neo4j_graphrag.experimental.pipeline import Component +from neo4j_graphrag.components.base import Component from neo4j_graphrag.experimental.pipeline.config.base import AbstractConfig from neo4j_graphrag.experimental.pipeline.config.param_resolver import ( ParamConfig, @@ -244,7 +244,7 @@ class ComponentConfig(ObjectConfig[Component]): run_params_: dict[str, ParamConfig] = {} - DEFAULT_MODULE = "neo4j_graphrag.experimental.components" + DEFAULT_MODULE = "neo4j_graphrag.components" INTERFACE = Component def get_run_params(self, resolved_data: dict[str, Any]) -> dict[str, Any]: diff --git a/src/neo4j_graphrag/experimental/pipeline/config/template_pipeline/simple_kg_builder.py b/src/neo4j_graphrag/experimental/pipeline/config/template_pipeline/simple_kg_builder.py index ec6a1ffb1..27fb73d01 100644 --- a/src/neo4j_graphrag/experimental/pipeline/config/template_pipeline/simple_kg_builder.py +++ b/src/neo4j_graphrag/experimental/pipeline/config/template_pipeline/simple_kg_builder.py @@ -30,35 +30,35 @@ from pydantic import ConfigDict, Field, field_validator, model_validator from typing_extensions import Self -from neo4j_graphrag.experimental.components.embedder import TextChunkEmbedder -from neo4j_graphrag.experimental.components.entity_relation_extractor import ( +from neo4j_graphrag.components.embedder import TextChunkEmbedder +from neo4j_graphrag.components.entity_relation_extractor import ( EntityRelationExtractor, LLMEntityRelationExtractor, OnError, ) -from neo4j_graphrag.experimental.components.graph_pruning import GraphPruning -from neo4j_graphrag.experimental.components.kg_writer import KGWriter, Neo4jWriter +from neo4j_graphrag.components.graph_pruning import GraphPruning +from neo4j_graphrag.components.kg_writer import KGWriter, Neo4jWriter from neo4j_graphrag.exceptions import UnsupportedDocumentFormatError -from neo4j_graphrag.experimental.components.data_loader import ( +from neo4j_graphrag.components.data_loader import ( DataLoader, MarkdownLoader, PdfLoader, ) -from neo4j_graphrag.experimental.components.resolver import ( +from neo4j_graphrag.components.resolver import ( EntityResolver, SinglePropertyExactMatchResolver, ) -from neo4j_graphrag.experimental.components.schema import ( +from neo4j_graphrag.components.schema import ( SchemaBuilder, GraphSchema, SchemaFromTextExtractor, BaseSchemaBuilder, ) -from neo4j_graphrag.experimental.components.text_splitters.base import TextSplitter -from neo4j_graphrag.experimental.components.text_splitters.fixed_size_splitter import ( +from neo4j_graphrag.components.text_splitters.base import TextSplitter +from neo4j_graphrag.components.text_splitters.fixed_size_splitter import ( FixedSizeSplitter, ) -from neo4j_graphrag.experimental.components.types import ( +from neo4j_graphrag.components.types import ( DocumentType, LexicalGraphConfig, LoadedDocument, diff --git a/src/neo4j_graphrag/experimental/pipeline/kg_builder.py b/src/neo4j_graphrag/experimental/pipeline/kg_builder.py index 3b7666ec2..b64eee6b9 100644 --- a/src/neo4j_graphrag/experimental/pipeline/kg_builder.py +++ b/src/neo4j_graphrag/experimental/pipeline/kg_builder.py @@ -23,13 +23,11 @@ from pydantic import ValidationError from neo4j_graphrag.embeddings import Embedder -from neo4j_graphrag.experimental.components.entity_relation_extractor import OnError -from neo4j_graphrag.experimental.components.kg_writer import KGWriter -from neo4j_graphrag.experimental.components.data_loader import DataLoader -from neo4j_graphrag.experimental.components.text_splitters.base import TextSplitter -from neo4j_graphrag.experimental.components.types import ( - LexicalGraphConfig, -) +from neo4j_graphrag.components.entity_relation_extractor import OnError +from neo4j_graphrag.components.types import LexicalGraphConfig +from neo4j_graphrag.components.kg_writer import KGWriter +from neo4j_graphrag.components.data_loader import DataLoader +from neo4j_graphrag.components.text_splitters.base import TextSplitter from neo4j_graphrag.experimental.pipeline.config.object_config import ComponentType from neo4j_graphrag.experimental.pipeline.config.runner import PipelineRunner from neo4j_graphrag.experimental.pipeline.config.template_pipeline import ( @@ -43,7 +41,7 @@ ) from neo4j_graphrag.generation.prompts import ERExtractionTemplate from neo4j_graphrag.llm.base import LLMInterface -from neo4j_graphrag.experimental.components.schema import GraphSchema +from neo4j_graphrag.components.schema import GraphSchema logger = logging.getLogger(__name__) @@ -88,7 +86,7 @@ class SimpleKGPipeline: text_splitter (Optional[TextSplitter]): A text splitter component. Defaults to FixedSizeSplitter(). file_loader (Optional[DataLoader]): A document loader component. Defaults to an internal extension-based loader that supports ``.pdf``, ``.md``, and ``.markdown``. - Use :class:`~neo4j_graphrag.experimental.components.data_loader.PdfLoader` for PDF-only paths. + Use :class:`~neo4j_graphrag.components.data_loader.PdfLoader` for PDF-only paths. pdf_loader (Optional[DataLoader]): Deprecated. If set, it is used as ``file_loader`` and emits a warning. Do not pass both ``file_loader`` and ``pdf_loader``. Prefer ``file_loader``. kg_writer (Optional[KGWriter]): A knowledge graph writer component. Defaults to Neo4jWriter(). diff --git a/src/neo4j_graphrag/experimental/pipeline/pipeline.py b/src/neo4j_graphrag/experimental/pipeline/pipeline.py index e0687c613..698975384 100644 --- a/src/neo4j_graphrag/experimental/pipeline/pipeline.py +++ b/src/neo4j_graphrag/experimental/pipeline/pipeline.py @@ -34,7 +34,7 @@ from pydantic import BaseModel -from neo4j_graphrag.experimental.pipeline.component import Component +from neo4j_graphrag.components.base import Component from neo4j_graphrag.experimental.pipeline.exceptions import ( PipelineDefinitionError, ) diff --git a/src/neo4j_graphrag/experimental/pipeline/types/context.py b/src/neo4j_graphrag/experimental/pipeline/types/context.py index d641aae38..f86e699e0 100644 --- a/src/neo4j_graphrag/experimental/pipeline/types/context.py +++ b/src/neo4j_graphrag/experimental/pipeline/types/context.py @@ -12,32 +12,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from pydantic import BaseModel, ConfigDict -from collections.abc import Awaitable +from neo4j_graphrag.components.base import RunContext, TaskProgressNotifierProtocol -from typing import Any, Optional, Protocol, runtime_checkable - - -@runtime_checkable -class TaskProgressNotifierProtocol(Protocol): - """This protocol is used to send events from the component to the - Pipeline callback protocol. - The event sent to the callback will be of type :ref:`TaskEvent`, - with `event_type=TASK_PROGRESS`. - """ - - def __call__(self, message: str, data: dict[str, Any]) -> Awaitable[None]: ... - - -class RunContext(BaseModel): - """Context passed to the component""" - - run_id: str - task_name: str - notifier: Optional[TaskProgressNotifierProtocol] = None - - model_config = ConfigDict(arbitrary_types_allowed=True) - - async def notify(self, message: str, data: dict[str, Any]) -> None: - if self.notifier: - await self.notifier(message=message, data=data) +__all__ = ["RunContext", "TaskProgressNotifierProtocol"] diff --git a/src/neo4j_graphrag/experimental/pipeline/types/definitions.py b/src/neo4j_graphrag/experimental/pipeline/types/definitions.py index 68ae403b4..2cbe9e9d6 100644 --- a/src/neo4j_graphrag/experimental/pipeline/types/definitions.py +++ b/src/neo4j_graphrag/experimental/pipeline/types/definitions.py @@ -19,7 +19,7 @@ from pydantic import BaseModel, ConfigDict -from neo4j_graphrag.experimental.pipeline.component import Component +from neo4j_graphrag.components.base import Component class ComponentDefinition(BaseModel): diff --git a/src/neo4j_graphrag/experimental/pipeline/types/orchestration.py b/src/neo4j_graphrag/experimental/pipeline/types/orchestration.py index ba6f99636..af026bdf6 100644 --- a/src/neo4j_graphrag/experimental/pipeline/types/orchestration.py +++ b/src/neo4j_graphrag/experimental/pipeline/types/orchestration.py @@ -20,7 +20,7 @@ from pydantic import BaseModel, Field, SerializeAsAny -from neo4j_graphrag.experimental.pipeline.component import DataModel +from neo4j_graphrag.components.base import DataModel class RunStatus(enum.Enum): diff --git a/src/neo4j_graphrag/experimental/utils/schema.py b/src/neo4j_graphrag/experimental/utils/schema.py index 80d162977..85e909d28 100644 --- a/src/neo4j_graphrag/experimental/utils/schema.py +++ b/src/neo4j_graphrag/experimental/utils/schema.py @@ -19,7 +19,7 @@ except ImportError: VisualizationGraph = Node = Relationship = None # type: ignore[misc,assignment] -from neo4j_graphrag.experimental.components.schema import ( +from neo4j_graphrag.components.schema import ( GraphSchema, NodeType, PropertyType, diff --git a/tests/e2e/experimental/test_entity_resolver_component_e2e.py b/tests/e2e/experimental/test_entity_resolver_component_e2e.py index 9e1f1a7bb..adedc48e4 100644 --- a/tests/e2e/experimental/test_entity_resolver_component_e2e.py +++ b/tests/e2e/experimental/test_entity_resolver_component_e2e.py @@ -14,7 +14,7 @@ # limitations under the License. import neo4j import pytest -from neo4j_graphrag.experimental.components.resolver import ( +from neo4j_graphrag.components.resolver import ( SinglePropertyExactMatchResolver, ) diff --git a/tests/e2e/experimental/test_graph_pruning_component_e2e.py b/tests/e2e/experimental/test_graph_pruning_component_e2e.py index f5471631a..94bfba479 100644 --- a/tests/e2e/experimental/test_graph_pruning_component_e2e.py +++ b/tests/e2e/experimental/test_graph_pruning_component_e2e.py @@ -16,12 +16,12 @@ import pytest -from neo4j_graphrag.experimental.components.graph_pruning import ( +from neo4j_graphrag.components.graph_pruning import ( GraphPruning, PruningReason, ) -from neo4j_graphrag.experimental.components.schema import GraphSchema -from neo4j_graphrag.experimental.components.types import ( +from neo4j_graphrag.components.schema import GraphSchema +from neo4j_graphrag.components.types import ( Neo4jGraph, Neo4jNode, Neo4jRelationship, diff --git a/tests/e2e/experimental/test_kg_builder_pipeline_e2e.py b/tests/e2e/experimental/test_kg_builder_pipeline_e2e.py index 3ba4ba7cc..cb639ac26 100644 --- a/tests/e2e/experimental/test_kg_builder_pipeline_e2e.py +++ b/tests/e2e/experimental/test_kg_builder_pipeline_e2e.py @@ -22,22 +22,22 @@ import pytest from neo4j_graphrag.embeddings.base import Embedder from neo4j_graphrag.exceptions import LLMGenerationError -from neo4j_graphrag.experimental.components.embedder import TextChunkEmbedder -from neo4j_graphrag.experimental.components.entity_relation_extractor import ( +from neo4j_graphrag.components.embedder import TextChunkEmbedder +from neo4j_graphrag.components.entity_relation_extractor import ( LLMEntityRelationExtractor, OnError, ) -from neo4j_graphrag.experimental.components.kg_writer import Neo4jWriter -from neo4j_graphrag.experimental.components.resolver import ( +from neo4j_graphrag.components.kg_writer import Neo4jWriter +from neo4j_graphrag.components.resolver import ( SinglePropertyExactMatchResolver, ) -from neo4j_graphrag.experimental.components.schema import ( +from neo4j_graphrag.components.schema import ( SchemaBuilder, NodeType, PropertyType, RelationshipType, ) -from neo4j_graphrag.experimental.components.text_splitters.fixed_size_splitter import ( +from neo4j_graphrag.components.text_splitters.fixed_size_splitter import ( FixedSizeSplitter, ) from neo4j_graphrag.experimental.pipeline import Pipeline diff --git a/tests/e2e/experimental/test_kg_writer_component_e2e.py b/tests/e2e/experimental/test_kg_writer_component_e2e.py index 8f4c60142..ba8b3ce2d 100644 --- a/tests/e2e/experimental/test_kg_writer_component_e2e.py +++ b/tests/e2e/experimental/test_kg_writer_component_e2e.py @@ -19,14 +19,14 @@ import neo4j import pytest -from neo4j_graphrag.experimental.components.filename_collision_handler import ( +from neo4j_graphrag.components.filename_collision_handler import ( FilenameCollisionHandler, ) -from neo4j_graphrag.experimental.components.kg_writer import Neo4jWriter, ParquetWriter -from neo4j_graphrag.experimental.components.parquet_formatter import ( +from neo4j_graphrag.components.kg_writer import Neo4jWriter, ParquetWriter +from neo4j_graphrag.components.parquet_formatter import ( INTERNAL_ID_PROPERTY, ) -from neo4j_graphrag.experimental.components.types import ( +from neo4j_graphrag.components.types import ( LexicalGraphConfig, Neo4jGraph, Neo4jNode, diff --git a/tests/e2e/experimental/test_lexical_graph_builder_component_e2e.py b/tests/e2e/experimental/test_lexical_graph_builder_component_e2e.py index edd46b73a..33bb35b18 100644 --- a/tests/e2e/experimental/test_lexical_graph_builder_component_e2e.py +++ b/tests/e2e/experimental/test_lexical_graph_builder_component_e2e.py @@ -14,9 +14,9 @@ # limitations under the License. import neo4j import pytest -from neo4j_graphrag.experimental.components.kg_writer import Neo4jWriter -from neo4j_graphrag.experimental.components.lexical_graph import LexicalGraphBuilder -from neo4j_graphrag.experimental.components.types import ( +from neo4j_graphrag.components.kg_writer import Neo4jWriter +from neo4j_graphrag.components.lexical_graph import LexicalGraphBuilder +from neo4j_graphrag.components.types import ( LexicalGraphConfig, TextChunk, TextChunks, diff --git a/tests/e2e/experimental/test_neo4j_reader_component_e2e.py b/tests/e2e/experimental/test_neo4j_reader_component_e2e.py index e33a5c0e0..cb2d0405c 100644 --- a/tests/e2e/experimental/test_neo4j_reader_component_e2e.py +++ b/tests/e2e/experimental/test_neo4j_reader_component_e2e.py @@ -16,11 +16,9 @@ import neo4j import pytest -from neo4j_graphrag.experimental.components.entity_relation_extractor import ( - LLMEntityRelationExtractor, -) -from neo4j_graphrag.experimental.components.neo4j_reader import Neo4jChunkReader -from neo4j_graphrag.experimental.components.types import LexicalGraphConfig, TextChunk +from neo4j_graphrag.components.entity_relation_extractor import LLMEntityRelationExtractor +from neo4j_graphrag.components.neo4j_reader import Neo4jChunkReader +from neo4j_graphrag.components.types import LexicalGraphConfig, TextChunk from neo4j_graphrag.experimental.pipeline import Pipeline from neo4j_graphrag.llm import LLMResponse diff --git a/tests/e2e/experimental/test_simplekgpipeline_e2e.py b/tests/e2e/experimental/test_simplekgpipeline_e2e.py index 40e7e9dca..ea5353906 100644 --- a/tests/e2e/experimental/test_simplekgpipeline_e2e.py +++ b/tests/e2e/experimental/test_simplekgpipeline_e2e.py @@ -20,10 +20,10 @@ import neo4j import pytest from neo4j import Driver -from neo4j_graphrag.experimental.components.text_splitters.fixed_size_splitter import ( +from neo4j_graphrag.components.text_splitters.fixed_size_splitter import ( FixedSizeSplitter, ) -from neo4j_graphrag.experimental.components.types import LexicalGraphConfig +from neo4j_graphrag.components.types import LexicalGraphConfig from neo4j_graphrag.experimental.pipeline.kg_builder import SimpleKGPipeline from neo4j_graphrag.llm import LLMResponse diff --git a/tests/unit/components/__init__.py b/tests/unit/components/__init__.py new file mode 100644 index 000000000..c0199c144 --- /dev/null +++ b/tests/unit/components/__init__.py @@ -0,0 +1,14 @@ +# Copyright (c) "Neo4j" +# Neo4j Sweden AB [https://neo4j.com] +# # +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# # +# https://www.apache.org/licenses/LICENSE-2.0 +# # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/tests/unit/experimental/components/sample_data/hello.md b/tests/unit/components/sample_data/hello.md similarity index 100% rename from tests/unit/experimental/components/sample_data/hello.md rename to tests/unit/components/sample_data/hello.md diff --git a/tests/unit/experimental/components/sample_data/lorem_ipsum.pdf b/tests/unit/components/sample_data/lorem_ipsum.pdf similarity index 100% rename from tests/unit/experimental/components/sample_data/lorem_ipsum.pdf rename to tests/unit/components/sample_data/lorem_ipsum.pdf diff --git a/tests/unit/experimental/components/test_data_loader.py b/tests/unit/components/test_data_loader.py similarity index 93% rename from tests/unit/experimental/components/test_data_loader.py rename to tests/unit/components/test_data_loader.py index 3d7f71dff..356a17e3f 100644 --- a/tests/unit/experimental/components/test_data_loader.py +++ b/tests/unit/components/test_data_loader.py @@ -23,11 +23,14 @@ from fsspec import AbstractFileSystem from fsspec.implementations.local import LocalFileSystem from neo4j_graphrag.exceptions import MarkdownLoadError, PdfLoaderError -from neo4j_graphrag.experimental.components.data_loader import ( +from neo4j_graphrag.components.data_loader import ( MarkdownLoader, PdfLoader, ) -from neo4j_graphrag.experimental.components.types import DocumentType, LoadedDocument +from neo4j_graphrag.components.types import ( + DocumentType, + LoadedDocument, +) BASE_DIR = Path(__file__).parent @@ -162,7 +165,7 @@ def test_pdf_loader_non_local_filesystem_branch_uses_bytesio( dummy_pdf_path: str, ) -> None: """Non-\"default\" local FS (``auto_mkdir=True``) reads into BytesIO for pypdf.""" - from neo4j_graphrag.experimental.components.data_loader import is_default_fs + from neo4j_graphrag.components.data_loader import is_default_fs fs = LocalFileSystem(auto_mkdir=True) assert is_default_fs(fs) is False @@ -172,13 +175,13 @@ def test_pdf_loader_non_local_filesystem_branch_uses_bytesio( def test_pdf_loader_backward_compat_reexport_module() -> None: """``pdf_loader`` submodule re-exports the same classes as ``data_loader``.""" - from neo4j_graphrag.experimental.components.data_loader import ( + from neo4j_graphrag.components.data_loader import ( DataLoader as DataLoaderDirect, PdfLoader as PdfLoaderDirect, ) with pytest.warns(DeprecationWarning, match="pdf_loader"): - from neo4j_graphrag.experimental.components.pdf_loader import ( + from neo4j_graphrag.components.pdf_loader import ( DataLoader as DataLoaderReexport, PdfLoader as PdfLoaderReexport, ) @@ -188,7 +191,7 @@ def test_pdf_loader_backward_compat_reexport_module() -> None: def test_pdf_loader_module_emits_import_time_deprecation_warning() -> None: - module_name = "neo4j_graphrag.experimental.components.pdf_loader" + module_name = "neo4j_graphrag.components.pdf_loader" sys.modules.pop(module_name, None) with pytest.warns(DeprecationWarning, match="Importing from .*pdf_loader"): importlib.import_module(module_name) diff --git a/tests/unit/experimental/components/test_embedder.py b/tests/unit/components/test_embedder.py similarity index 91% rename from tests/unit/experimental/components/test_embedder.py rename to tests/unit/components/test_embedder.py index 7dfd10ab9..030b93e7b 100644 --- a/tests/unit/experimental/components/test_embedder.py +++ b/tests/unit/components/test_embedder.py @@ -15,8 +15,8 @@ from unittest.mock import MagicMock import pytest -from neo4j_graphrag.experimental.components.embedder import TextChunkEmbedder -from neo4j_graphrag.experimental.components.types import ( +from neo4j_graphrag.components.embedder import TextChunkEmbedder +from neo4j_graphrag.components.types import ( TextChunk, TextChunks, ) diff --git a/tests/unit/experimental/components/test_entity_relation_extractor.py b/tests/unit/components/test_entity_relation_extractor.py similarity index 99% rename from tests/unit/experimental/components/test_entity_relation_extractor.py rename to tests/unit/components/test_entity_relation_extractor.py index cf69d5f78..3c3ae4234 100644 --- a/tests/unit/experimental/components/test_entity_relation_extractor.py +++ b/tests/unit/components/test_entity_relation_extractor.py @@ -19,13 +19,13 @@ import pytest from neo4j_graphrag.exceptions import LLMGenerationError -from neo4j_graphrag.experimental.components.entity_relation_extractor import ( +from neo4j_graphrag.components.entity_relation_extractor import ( LLMEntityRelationExtractor, OnError, balance_curly_braces, fix_invalid_json, ) -from neo4j_graphrag.experimental.components.types import ( +from neo4j_graphrag.components.types import ( DocumentInfo, Neo4jGraph, TextChunk, diff --git a/tests/unit/experimental/components/test_graph_pruning.py b/tests/unit/components/test_graph_pruning.py similarity index 98% rename from tests/unit/experimental/components/test_graph_pruning.py rename to tests/unit/components/test_graph_pruning.py index ac3254fb4..064d7c94f 100644 --- a/tests/unit/experimental/components/test_graph_pruning.py +++ b/tests/unit/components/test_graph_pruning.py @@ -19,13 +19,13 @@ from unittest.mock import ANY, Mock, patch import pytest -from neo4j_graphrag.experimental.components.graph_pruning import ( +from neo4j_graphrag.components.graph_pruning import ( GraphPruning, GraphPruningResult, PruningReason, PruningStats, ) -from neo4j_graphrag.experimental.components.schema import ( +from neo4j_graphrag.components.schema import ( GraphConstraintType, GraphSchema, NodeType, @@ -33,7 +33,7 @@ PropertyType, RelationshipType, ) -from neo4j_graphrag.experimental.components.types import ( +from neo4j_graphrag.components.types import ( LexicalGraphConfig, Neo4jGraph, Neo4jNode, @@ -756,7 +756,7 @@ def test_graph_pruning_validate_relationship( ) -@patch("neo4j_graphrag.experimental.components.graph_pruning.GraphPruning._clean_graph") +@patch("neo4j_graphrag.components.graph_pruning.GraphPruning._clean_graph") @pytest.mark.asyncio async def test_graph_pruning_run_happy_path( mock_clean_graph: Mock, @@ -795,7 +795,7 @@ async def test_graph_pruning_run_no_schema() -> None: @patch( - "neo4j_graphrag.experimental.components.graph_pruning.GraphPruning._enforce_nodes" + "neo4j_graphrag.components.graph_pruning.GraphPruning._enforce_nodes" ) def test_graph_pruning_clean_graph( mock_enforce_nodes: Mock, diff --git a/tests/unit/experimental/components/test_graph_schema_extraction.py b/tests/unit/components/test_graph_schema_extraction.py similarity index 98% rename from tests/unit/experimental/components/test_graph_schema_extraction.py rename to tests/unit/components/test_graph_schema_extraction.py index 04ad4f298..3ffdfe5fc 100644 --- a/tests/unit/experimental/components/test_graph_schema_extraction.py +++ b/tests/unit/components/test_graph_schema_extraction.py @@ -17,7 +17,7 @@ from __future__ import annotations -from neo4j_graphrag.experimental.components.graph_schema_extraction import ( +from neo4j_graphrag.components.graph_schema_extraction import ( ExtractedConstraintType, ExtractedNodeType, ExtractedPropertyType, @@ -25,7 +25,7 @@ GraphSchemaExtractionOutput, wire_extraction_constraints_for_graph_schema, ) -from neo4j_graphrag.experimental.components.schema import GraphSchema, Pattern +from neo4j_graphrag.components.schema import GraphSchema, Pattern def test_wire_extraction_constraints_keeps_relationship_type_for_uniqueness() -> None: diff --git a/tests/unit/experimental/components/test_graph_schema_extraction_contract.py b/tests/unit/components/test_graph_schema_extraction_contract.py similarity index 96% rename from tests/unit/experimental/components/test_graph_schema_extraction_contract.py rename to tests/unit/components/test_graph_schema_extraction_contract.py index daa829872..69915ea7a 100644 --- a/tests/unit/experimental/components/test_graph_schema_extraction_contract.py +++ b/tests/unit/components/test_graph_schema_extraction_contract.py @@ -20,14 +20,14 @@ from __future__ import annotations -from neo4j_graphrag.experimental.components.graph_schema_extraction import ( +from neo4j_graphrag.components.graph_schema_extraction import ( ExtractedConstraintType, ExtractedNodeType, ExtractedPropertyType, ExtractedRelationshipType, GraphSchemaExtractionOutput, ) -from neo4j_graphrag.experimental.components.schema import ( +from neo4j_graphrag.components.schema import ( ConstraintType, GraphSchema, NodeType, diff --git a/tests/unit/experimental/components/test_kg_writer.py b/tests/unit/components/test_kg_writer.py similarity index 97% rename from tests/unit/experimental/components/test_kg_writer.py rename to tests/unit/components/test_kg_writer.py index 1f13bdf4e..a6e84e66e 100644 --- a/tests/unit/experimental/components/test_kg_writer.py +++ b/tests/unit/components/test_kg_writer.py @@ -22,22 +22,20 @@ from unittest.mock import MagicMock, Mock import pytest -from neo4j_graphrag.experimental.components.filename_collision_handler import ( - FilenameCollisionHandler, -) -from neo4j_graphrag.experimental.components.parquet_formatter import ( +from neo4j_graphrag.components.filename_collision_handler import FilenameCollisionHandler +from neo4j_graphrag.components.parquet_formatter import ( INTERNAL_ID_PROPERTY, Neo4jGraphParquetFormatter, get_unique_properties_for_node_type, sanitize_parquet_filestem, ) -from neo4j_graphrag.experimental.components.kg_writer import ( +from neo4j_graphrag.components.kg_writer import batched +from neo4j_graphrag.components.kg_writer import ( Neo4jWriter, ParquetWriter, - batched, ) -from neo4j_graphrag.experimental.components.schema import GraphSchema -from neo4j_graphrag.experimental.components.types import ( +from neo4j_graphrag.components.schema import GraphSchema +from neo4j_graphrag.components.types import ( LexicalGraphConfig, Neo4jGraph, Neo4jNode, @@ -141,11 +139,11 @@ def test_filename_collision_handler_reset_clears_state() -> None: @mock.patch( - "neo4j_graphrag.experimental.components.kg_writer.get_version", + "neo4j_graphrag.components.kg_writer.get_version", return_value=((5, 22, 0), False, False), ) @mock.patch( - "neo4j_graphrag.experimental.components.kg_writer.Neo4jWriter._db_setup", + "neo4j_graphrag.components.kg_writer.Neo4jWriter._db_setup", return_value=None, ) def test_upsert_nodes(_: Mock, driver: MagicMock) -> None: @@ -175,11 +173,11 @@ def test_upsert_nodes(_: Mock, driver: MagicMock) -> None: @mock.patch( - "neo4j_graphrag.experimental.components.kg_writer.get_version", + "neo4j_graphrag.components.kg_writer.get_version", return_value=((5, 22, 0), False, False), ) @mock.patch( - "neo4j_graphrag.experimental.components.kg_writer.Neo4jWriter._db_setup", + "neo4j_graphrag.components.kg_writer.Neo4jWriter._db_setup", return_value=None, ) def test_upsert_nodes_with_embedding( @@ -217,11 +215,11 @@ def test_upsert_nodes_with_embedding( @mock.patch( - "neo4j_graphrag.experimental.components.kg_writer.get_version", + "neo4j_graphrag.components.kg_writer.get_version", return_value=((5, 22, 0), False, False), ) @mock.patch( - "neo4j_graphrag.experimental.components.kg_writer.Neo4jWriter._db_setup", + "neo4j_graphrag.components.kg_writer.Neo4jWriter._db_setup", return_value=None, ) def test_upsert_relationship(_: Mock, driver: MagicMock) -> None: @@ -254,11 +252,11 @@ def test_upsert_relationship(_: Mock, driver: MagicMock) -> None: @mock.patch( - "neo4j_graphrag.experimental.components.kg_writer.get_version", + "neo4j_graphrag.components.kg_writer.get_version", return_value=((5, 22, 0), False, False), ) @mock.patch( - "neo4j_graphrag.experimental.components.kg_writer.Neo4jWriter._db_setup", + "neo4j_graphrag.components.kg_writer.Neo4jWriter._db_setup", return_value=None, ) def test_upsert_relationship_with_embedding(_: Mock, driver: MagicMock) -> None: @@ -293,12 +291,12 @@ def test_upsert_relationship_with_embedding(_: Mock, driver: MagicMock) -> None: @mock.patch( - "neo4j_graphrag.experimental.components.kg_writer.get_version", + "neo4j_graphrag.components.kg_writer.get_version", return_value=((5, 22, 0), False, False), ) @pytest.mark.asyncio @mock.patch( - "neo4j_graphrag.experimental.components.kg_writer.Neo4jWriter._db_setup", + "neo4j_graphrag.components.kg_writer.Neo4jWriter._db_setup", return_value=None, ) async def test_run(_: Mock, driver: MagicMock) -> None: @@ -350,7 +348,7 @@ async def test_run(_: Mock, driver: MagicMock) -> None: @pytest.mark.asyncio @mock.patch( - "neo4j_graphrag.experimental.components.kg_writer.Neo4jWriter._db_setup", + "neo4j_graphrag.components.kg_writer.Neo4jWriter._db_setup", return_value=None, ) async def test_run_is_version_below_5_23(_: Mock) -> None: @@ -408,7 +406,7 @@ async def test_run_is_version_below_5_23(_: Mock) -> None: @pytest.mark.asyncio @mock.patch( - "neo4j_graphrag.experimental.components.kg_writer.Neo4jWriter._db_setup", + "neo4j_graphrag.components.kg_writer.Neo4jWriter._db_setup", return_value=None, ) async def test_run_is_version_5_23_or_above(_: Mock) -> None: @@ -467,7 +465,7 @@ async def test_run_is_version_5_23_or_above(_: Mock) -> None: @pytest.mark.asyncio @mock.patch( - "neo4j_graphrag.experimental.components.kg_writer.Neo4jWriter._db_setup", + "neo4j_graphrag.components.kg_writer.Neo4jWriter._db_setup", return_value=None, ) async def test_run_is_version_5_24_or_above(_: Mock) -> None: @@ -536,7 +534,7 @@ async def test_run_is_version_5_24_or_above(_: Mock) -> None: ], ) @mock.patch( - "neo4j_graphrag.experimental.components.kg_writer.Neo4jWriter._db_setup", + "neo4j_graphrag.components.kg_writer.Neo4jWriter._db_setup", return_value=None, ) def test_get_version( diff --git a/tests/unit/experimental/components/test_lexical_graph_builder.py b/tests/unit/components/test_lexical_graph_builder.py similarity index 97% rename from tests/unit/experimental/components/test_lexical_graph_builder.py rename to tests/unit/components/test_lexical_graph_builder.py index e75c9214a..960163503 100644 --- a/tests/unit/experimental/components/test_lexical_graph_builder.py +++ b/tests/unit/components/test_lexical_graph_builder.py @@ -17,8 +17,8 @@ import uuid import pytest -from neo4j_graphrag.experimental.components.lexical_graph import LexicalGraphBuilder -from neo4j_graphrag.experimental.components.types import ( +from neo4j_graphrag.components.lexical_graph import LexicalGraphBuilder +from neo4j_graphrag.components.types import ( DEFAULT_CHUNK_NODE_LABEL, DEFAULT_CHUNK_TO_DOCUMENT_RELATIONSHIP_TYPE, DEFAULT_DOCUMENT_NODE_LABEL, diff --git a/tests/unit/experimental/components/test_neo4j_reader.py b/tests/unit/components/test_neo4j_reader.py similarity index 96% rename from tests/unit/experimental/components/test_neo4j_reader.py rename to tests/unit/components/test_neo4j_reader.py index 331d80739..ad2aec1a0 100644 --- a/tests/unit/experimental/components/test_neo4j_reader.py +++ b/tests/unit/components/test_neo4j_reader.py @@ -16,10 +16,10 @@ import neo4j import pytest -from neo4j_graphrag.experimental.components.neo4j_reader import ( +from neo4j_graphrag.components.neo4j_reader import ( Neo4jChunkReader, ) -from neo4j_graphrag.experimental.components.types import LexicalGraphConfig, TextChunks +from neo4j_graphrag.components.types import LexicalGraphConfig, TextChunks @pytest.mark.asyncio diff --git a/tests/unit/experimental/components/test_property_type_deprecation.py b/tests/unit/components/test_property_type_deprecation.py similarity index 98% rename from tests/unit/experimental/components/test_property_type_deprecation.py rename to tests/unit/components/test_property_type_deprecation.py index 6f43e60ea..d5f6c8189 100644 --- a/tests/unit/experimental/components/test_property_type_deprecation.py +++ b/tests/unit/components/test_property_type_deprecation.py @@ -19,7 +19,7 @@ import pytest -from neo4j_graphrag.experimental.components.schema import ( +from neo4j_graphrag.components.schema import ( ConstraintType, GraphConstraintType, GraphSchema, diff --git a/tests/unit/experimental/components/test_resolver.py b/tests/unit/components/test_resolver.py similarity index 98% rename from tests/unit/experimental/components/test_resolver.py rename to tests/unit/components/test_resolver.py index 1949f608f..e20b598c5 100644 --- a/tests/unit/experimental/components/test_resolver.py +++ b/tests/unit/components/test_resolver.py @@ -18,12 +18,12 @@ import neo4j import numpy as np import pytest -from neo4j_graphrag.experimental.components.resolver import ( +from neo4j_graphrag.components.resolver import ( FuzzyMatchResolver, SinglePropertyExactMatchResolver, SpaCySemanticMatchResolver, ) -from neo4j_graphrag.experimental.components.types import ResolutionStats +from neo4j_graphrag.components.types import ResolutionStats class FakeNLPModel: diff --git a/tests/unit/experimental/components/test_schema.py b/tests/unit/components/test_schema.py similarity index 99% rename from tests/unit/experimental/components/test_schema.py rename to tests/unit/components/test_schema.py index 3f8ae1376..c17df2ff4 100644 --- a/tests/unit/experimental/components/test_schema.py +++ b/tests/unit/components/test_schema.py @@ -23,7 +23,7 @@ from pydantic import ValidationError from neo4j_graphrag.exceptions import SchemaValidationError, SchemaExtractionError -from neo4j_graphrag.experimental.components.schema import ( +from neo4j_graphrag.components.schema import ( SchemaBuilder, NodeType, PropertyType, @@ -936,7 +936,7 @@ def test_composite_uniqueness_and_key_different_properties_allowed() -> None: def test_extract_graph_constraints_from_metadata_composite_key() -> None: - from neo4j_graphrag.experimental.components.schema import ( + from neo4j_graphrag.components.schema import ( SchemaFromExistingGraphExtractor, ) @@ -2215,7 +2215,7 @@ async def test_schema_from_text_uniqueness_does_not_force_required_property( @pytest.mark.asyncio -@patch("neo4j_graphrag.experimental.components.schema.get_structured_schema") +@patch("neo4j_graphrag.components.schema.get_structured_schema") async def test_schema_from_existing_graph(mock_get_structured_schema: Mock) -> None: mock_get_structured_schema.return_value = { "node_props": { @@ -2296,7 +2296,7 @@ async def test_schema_from_existing_graph(mock_get_structured_schema: Mock) -> N @pytest.mark.asyncio -@patch("neo4j_graphrag.experimental.components.schema.get_structured_schema") +@patch("neo4j_graphrag.components.schema.get_structured_schema") async def test_schema_from_existing_graph_additional_params( mock_get_structured_schema: Mock, ) -> None: @@ -2455,9 +2455,7 @@ def test_extract_graph_constraints_from_metadata_relationship_uniqueness_maps_to def test_graph_schema_extraction_output_json_schema_lean_root() -> None: """Structured-output schema must not include pipeline-only GraphSchema flags.""" - from neo4j_graphrag.experimental.components.graph_schema_extraction import ( - GraphSchemaExtractionOutput, - ) + from neo4j_graphrag.components.graph_schema_extraction import GraphSchemaExtractionOutput raw = GraphSchemaExtractionOutput.model_json_schema() dumped = json.dumps(raw) @@ -2470,9 +2468,7 @@ def test_graph_schema_extraction_constraint_schema_avoids_null_type_for_vertex() None ): """Vertex AI maps JSON Schema to protobuf and rejects ``type: \"null\"`` (e.g. ``Optional``).""" - from neo4j_graphrag.experimental.components.graph_schema_extraction import ( - GraphSchemaExtractionOutput, - ) + from neo4j_graphrag.components.graph_schema_extraction import GraphSchemaExtractionOutput raw = GraphSchemaExtractionOutput.model_json_schema() ect = (raw.get("$defs") or {}).get("ExtractedConstraintType") @@ -2483,7 +2479,7 @@ def test_graph_schema_extraction_constraint_schema_avoids_null_type_for_vertex() def test_graph_schema_from_extraction_output() -> None: - from neo4j_graphrag.experimental.components.graph_schema_extraction import ( + from neo4j_graphrag.components.graph_schema_extraction import ( ExtractedConstraintType, ExtractedNodeType, ExtractedPropertyType, @@ -2712,7 +2708,7 @@ def test_validate_extraction_dict_unique_relationship_labels_unchanged( def test_from_extraction_output_merges_duplicate_relationship_types() -> None: """The V2 structured-output path also merges duplicate relationship types.""" - from neo4j_graphrag.experimental.components.graph_schema_extraction import ( + from neo4j_graphrag.components.graph_schema_extraction import ( ExtractedNodeType, ExtractedPropertyType, ExtractedRelationshipType, diff --git a/tests/unit/experimental/components/test_types.py b/tests/unit/components/test_types.py similarity index 79% rename from tests/unit/experimental/components/test_types.py rename to tests/unit/components/test_types.py index 41b5c6090..e4f8c93fa 100644 --- a/tests/unit/experimental/components/test_types.py +++ b/tests/unit/components/test_types.py @@ -20,12 +20,12 @@ def test_pdf_document_alias_is_loaded_document_and_warns() -> None: """Accessing PdfDocument emits DeprecationWarning and returns LoadedDocument.""" - import neo4j_graphrag.experimental.components.types as types_mod + import neo4j_graphrag.components.types as types_mod with pytest.warns(DeprecationWarning, match="PdfDocument is deprecated"): PdfDocument = types_mod.PdfDocument - from neo4j_graphrag.experimental.components.types import LoadedDocument + from neo4j_graphrag.components.types import LoadedDocument assert PdfDocument is LoadedDocument @@ -33,23 +33,21 @@ def test_pdf_document_alias_is_loaded_document_and_warns() -> None: def test_pdf_document_from_import_backward_compat_warns() -> None: """``from ...types import PdfDocument`` still works and emits DeprecationWarning.""" with pytest.warns(DeprecationWarning, match="PdfDocument is deprecated"): - from neo4j_graphrag.experimental.components.types import ( - LoadedDocument, - PdfDocument, - ) + from neo4j_graphrag.components.types import PdfDocument + from neo4j_graphrag.components.types import LoadedDocument assert PdfDocument is LoadedDocument def test_types_dir_includes_pdf_document() -> None: - import neo4j_graphrag.experimental.components.types as types_mod + import neo4j_graphrag.components.types as types_mod assert "PdfDocument" in dir(types_mod) assert "LoadedDocument" in dir(types_mod) def test_getattr_unknown_raises() -> None: - import neo4j_graphrag.experimental.components.types as types_mod + import neo4j_graphrag.components.types as types_mod with pytest.raises(AttributeError, match="no attribute 'not_a_real_export'"): _ = types_mod.not_a_real_export diff --git a/tests/unit/components/text_splitters/__init__.py b/tests/unit/components/text_splitters/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/unit/experimental/components/text_splitters/test_fixed_size_splitter.py b/tests/unit/components/text_splitters/test_fixed_size_splitter.py similarity index 98% rename from tests/unit/experimental/components/text_splitters/test_fixed_size_splitter.py rename to tests/unit/components/text_splitters/test_fixed_size_splitter.py index f18770415..49a000c99 100644 --- a/tests/unit/experimental/components/text_splitters/test_fixed_size_splitter.py +++ b/tests/unit/components/text_splitters/test_fixed_size_splitter.py @@ -16,12 +16,12 @@ from itertools import zip_longest import pytest -from neo4j_graphrag.experimental.components.text_splitters.fixed_size_splitter import ( +from neo4j_graphrag.components.text_splitters.fixed_size_splitter import ( FixedSizeSplitter, _adjust_chunk_end, _adjust_chunk_start, ) -from neo4j_graphrag.experimental.components.types import TextChunk +from neo4j_graphrag.components.types import TextChunk @pytest.mark.asyncio diff --git a/tests/unit/experimental/components/text_splitters/test_langchain.py b/tests/unit/components/text_splitters/test_langchain.py similarity index 91% rename from tests/unit/experimental/components/text_splitters/test_langchain.py rename to tests/unit/components/text_splitters/test_langchain.py index 3fbde4df7..320ed9599 100644 --- a/tests/unit/experimental/components/text_splitters/test_langchain.py +++ b/tests/unit/components/text_splitters/test_langchain.py @@ -14,10 +14,13 @@ # limitations under the License. import pytest from langchain_text_splitters import RecursiveCharacterTextSplitter -from neo4j_graphrag.experimental.components.text_splitters.langchain import ( +from neo4j_graphrag.components.text_splitters.langchain import ( LangChainTextSplitterAdapter, ) -from neo4j_graphrag.experimental.components.types import TextChunk, TextChunks +from neo4j_graphrag.components.types import ( + TextChunk, + TextChunks, +) text = """ Lorem ipsum dolor sit amet, consectetur adipiscing elit. diff --git a/tests/unit/experimental/components/text_splitters/test_llamaindex.py b/tests/unit/components/text_splitters/test_llamaindex.py similarity index 90% rename from tests/unit/experimental/components/text_splitters/test_llamaindex.py rename to tests/unit/components/text_splitters/test_llamaindex.py index 15908148e..8d7df28f6 100644 --- a/tests/unit/experimental/components/text_splitters/test_llamaindex.py +++ b/tests/unit/components/text_splitters/test_llamaindex.py @@ -14,10 +14,11 @@ # limitations under the License. import pytest from llama_index.core.node_parser.text.sentence import SentenceSplitter -from neo4j_graphrag.experimental.components.text_splitters.llamaindex import ( - LlamaIndexTextSplitterAdapter, +from neo4j_graphrag.components.text_splitters.llamaindex import LlamaIndexTextSplitterAdapter +from neo4j_graphrag.components.types import ( + TextChunk, + TextChunks, ) -from neo4j_graphrag.experimental.components.types import TextChunk, TextChunks text = """ Lorem ipsum dolor sit amet, consectetur adipiscing elit. diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py index b93623481..1526bd355 100644 --- a/tests/unit/conftest.py +++ b/tests/unit/conftest.py @@ -19,7 +19,7 @@ import neo4j import pytest from neo4j_graphrag.embeddings.base import Embedder -from neo4j_graphrag.experimental.pipeline import Component +from neo4j_graphrag.components.base import Component from neo4j_graphrag.llm import LLMInterface from neo4j_graphrag.retrievers import ( HybridRetriever, diff --git a/tests/unit/experimental/pipeline/components.py b/tests/unit/experimental/pipeline/components.py index e1b2e1845..2ab568aea 100644 --- a/tests/unit/experimental/pipeline/components.py +++ b/tests/unit/experimental/pipeline/components.py @@ -14,7 +14,7 @@ # limitations under the License. import asyncio -from neo4j_graphrag.experimental.pipeline import Component, DataModel +from neo4j_graphrag.components.base import Component, DataModel from neo4j_graphrag.experimental.pipeline.types.context import RunContext diff --git a/tests/unit/experimental/pipeline/config/template_pipeline/test_simple_kg_builder.py b/tests/unit/experimental/pipeline/config/template_pipeline/test_simple_kg_builder.py index 57f76552f..3a4dbc551 100644 --- a/tests/unit/experimental/pipeline/config/template_pipeline/test_simple_kg_builder.py +++ b/tests/unit/experimental/pipeline/config/template_pipeline/test_simple_kg_builder.py @@ -18,21 +18,22 @@ import neo4j import pytest from neo4j_graphrag.embeddings import Embedder -from neo4j_graphrag.experimental.components.embedder import TextChunkEmbedder -from neo4j_graphrag.experimental.components.entity_relation_extractor import ( +from neo4j_graphrag.components.embedder import TextChunkEmbedder +from neo4j_graphrag.components.entity_relation_extractor import ( LLMEntityRelationExtractor, OnError, ) -from neo4j_graphrag.experimental.components.kg_writer import Neo4jWriter -from neo4j_graphrag.experimental.components.data_loader import MarkdownLoader, PdfLoader -from neo4j_graphrag.experimental.components.schema import ( +from neo4j_graphrag.components.kg_writer import Neo4jWriter +from neo4j_graphrag.components.data_loader import ( + MarkdownLoader, + PdfLoader, +) +from neo4j_graphrag.components.schema import ( SchemaBuilder, SchemaFromTextExtractor, GraphSchema, ) -from neo4j_graphrag.experimental.components.text_splitters.fixed_size_splitter import ( - FixedSizeSplitter, -) +from neo4j_graphrag.components.text_splitters.fixed_size_splitter import FixedSizeSplitter from neo4j_graphrag.experimental.pipeline.config.object_config import ( ComponentConfig, ComponentType, @@ -45,7 +46,7 @@ EntityInputType, RelationInputType, ) -from neo4j_graphrag.experimental.components.types import DocumentType +from neo4j_graphrag.components.types import DocumentType from neo4j_graphrag.generation.prompts import ERExtractionTemplate from neo4j_graphrag.llm import LLMInterface @@ -68,7 +69,7 @@ async def test_simple_kg_pipeline_config_default_file_loader_supports_markdown() loader = config._get_file_loader() assert loader is not None doc = await loader.run( - filepath="tests/unit/experimental/components/sample_data/hello.md" + filepath="tests/unit/components/sample_data/hello.md" ) assert doc.document_info.document_type == DocumentType.MARKDOWN @@ -258,7 +259,7 @@ def test_simple_kg_pipeline_config_extractor_structured_output( @patch( - "neo4j_graphrag.experimental.components.kg_writer.get_version", + "neo4j_graphrag.components.kg_writer.get_version", return_value=((5, 23, 0), False, False), ) @patch( @@ -280,7 +281,7 @@ def test_simple_kg_pipeline_config_writer( @patch( - "neo4j_graphrag.experimental.components.kg_writer.get_version", + "neo4j_graphrag.components.kg_writer.get_version", return_value=((5, 23, 0), False, False), ) @patch("neo4j_graphrag.experimental.pipeline.config.object_config.ComponentType.parse") diff --git a/tests/unit/experimental/pipeline/config/test_pipeline_config.py b/tests/unit/experimental/pipeline/config/test_pipeline_config.py index 3d3ee72d4..9bddea85c 100644 --- a/tests/unit/experimental/pipeline/config/test_pipeline_config.py +++ b/tests/unit/experimental/pipeline/config/test_pipeline_config.py @@ -16,7 +16,7 @@ import neo4j from neo4j_graphrag.embeddings import Embedder -from neo4j_graphrag.experimental.pipeline import Component +from neo4j_graphrag.components.base import Component from neo4j_graphrag.experimental.pipeline.config.object_config import ( ComponentConfig, ComponentType, diff --git a/tests/unit/experimental/pipeline/test_component.py b/tests/unit/experimental/pipeline/test_component.py index ba39aebaf..dfb801399 100644 --- a/tests/unit/experimental/pipeline/test_component.py +++ b/tests/unit/experimental/pipeline/test_component.py @@ -16,7 +16,7 @@ import pytest -from neo4j_graphrag.experimental.pipeline import Component +from neo4j_graphrag.components.base import Component from neo4j_graphrag.experimental.pipeline.types.context import RunContext from .components import ComponentMultiply, ComponentMultiplyWithContext, IntResultModel diff --git a/tests/unit/experimental/pipeline/test_kg_builder.py b/tests/unit/experimental/pipeline/test_kg_builder.py index 36cbe6adc..3e9be536c 100644 --- a/tests/unit/experimental/pipeline/test_kg_builder.py +++ b/tests/unit/experimental/pipeline/test_kg_builder.py @@ -18,10 +18,8 @@ import neo4j import pytest from neo4j_graphrag.embeddings import Embedder -from neo4j_graphrag.experimental.components.data_loader import PdfLoader -from neo4j_graphrag.experimental.components.types import ( - LexicalGraphConfig, -) +from neo4j_graphrag.components.data_loader import PdfLoader +from neo4j_graphrag.components.types import LexicalGraphConfig from neo4j_graphrag.experimental.pipeline.exceptions import PipelineDefinitionError from neo4j_graphrag.experimental.pipeline.kg_builder import SimpleKGPipeline from neo4j_graphrag.experimental.pipeline.pipeline import PipelineResult @@ -29,7 +27,7 @@ @mock.patch( - "neo4j_graphrag.experimental.components.kg_writer.get_version", + "neo4j_graphrag.components.kg_writer.get_version", return_value=((5, 23, 0), False, False), ) @pytest.mark.asyncio @@ -59,7 +57,7 @@ async def test_knowledge_graph_builder_from_pdf_deprecated_kwarg(_: Mock) -> Non @mock.patch( - "neo4j_graphrag.experimental.components.kg_writer.get_version", + "neo4j_graphrag.components.kg_writer.get_version", return_value=((5, 23, 0), False, False), ) @pytest.mark.asyncio @@ -90,7 +88,7 @@ async def test_knowledge_graph_builder_pdf_loader_deprecated_kwarg(_: Mock) -> N @mock.patch( - "neo4j_graphrag.experimental.components.kg_writer.get_version", + "neo4j_graphrag.components.kg_writer.get_version", return_value=((5, 23, 0), False, False), ) @pytest.mark.asyncio @@ -127,7 +125,7 @@ async def test_knowledge_graph_builder_document_info_with_file(_: Mock) -> None: @mock.patch( - "neo4j_graphrag.experimental.components.kg_writer.get_version", + "neo4j_graphrag.components.kg_writer.get_version", return_value=((5, 23, 0), False, False), ) @pytest.mark.asyncio @@ -166,7 +164,7 @@ async def test_knowledge_graph_builder_document_info_with_text(_: Mock) -> None: @mock.patch( - "neo4j_graphrag.experimental.components.kg_writer.get_version", + "neo4j_graphrag.components.kg_writer.get_version", return_value=((5, 23, 0), False, False), ) @pytest.mark.asyncio @@ -233,7 +231,7 @@ def test_knowledge_graph_builder_pdf_loader_and_file_loader_conflict() -> None: @mock.patch( - "neo4j_graphrag.experimental.components.kg_writer.get_version", + "neo4j_graphrag.components.kg_writer.get_version", return_value=((5, 23, 0), False, False), ) @pytest.mark.asyncio diff --git a/tests/unit/experimental/pipeline/test_orchestrator.py b/tests/unit/experimental/pipeline/test_orchestrator.py index bb611da96..8c3d31b39 100644 --- a/tests/unit/experimental/pipeline/test_orchestrator.py +++ b/tests/unit/experimental/pipeline/test_orchestrator.py @@ -15,8 +15,8 @@ from unittest.mock import Mock, patch import pytest +from neo4j_graphrag.components.base import Component from neo4j_graphrag.experimental.pipeline import ( - Component, Pipeline, ) from neo4j_graphrag.experimental.pipeline.exceptions import ( diff --git a/tests/unit/experimental/pipeline/test_pipeline.py b/tests/unit/experimental/pipeline/test_pipeline.py index 16e23cd27..fc407621d 100644 --- a/tests/unit/experimental/pipeline/test_pipeline.py +++ b/tests/unit/experimental/pipeline/test_pipeline.py @@ -22,7 +22,8 @@ from unittest.mock import AsyncMock, call, patch import pytest -from neo4j_graphrag.experimental.pipeline import Component, Pipeline +from neo4j_graphrag.components.base import Component +from neo4j_graphrag.experimental.pipeline import Pipeline from neo4j_graphrag.experimental.pipeline.exceptions import PipelineDefinitionError from neo4j_graphrag.experimental.pipeline.notification import ( EventCallbackProtocol, diff --git a/tests/unit/experimental/utils/test_schema.py b/tests/unit/experimental/utils/test_schema.py index 09055da0b..d88c6389d 100644 --- a/tests/unit/experimental/utils/test_schema.py +++ b/tests/unit/experimental/utils/test_schema.py @@ -19,7 +19,7 @@ from pydantic import ValidationError from neo4j_viz import VisualizationGraph -from neo4j_graphrag.experimental.components.schema import GraphSchema +from neo4j_graphrag.components.schema import GraphSchema from neo4j_graphrag.experimental.utils.schema import schema_visualization diff --git a/uv.lock b/uv.lock index 76f4db8b5..5c6071806 100644 --- a/uv.lock +++ b/uv.lock @@ -1147,6 +1147,69 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fa/93/b44f67589e4d439913dab6720f7e3507b0fa8b8e56d06f6fc875ced26afb/fastavro-1.12.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:43ded16b3f4a9f1a42f5970c2aa618acb23ea59c4fcaa06680bdf470b255e5a8", size = 3386636, upload-time = "2025-10-10T15:42:18.974Z" }, ] +[[package]] +name = "fastuuid" +version = "0.14.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/7d/d9daedf0f2ebcacd20d599928f8913e9d2aea1d56d2d355a93bfa2b611d7/fastuuid-0.14.0.tar.gz", hash = "sha256:178947fc2f995b38497a74172adee64fdeb8b7ec18f2a5934d037641ba265d26", size = 18232, upload-time = "2025-10-19T22:19:22.402Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ad/b2/731a6696e37cd20eed353f69a09f37a984a43c9713764ee3f7ad5f57f7f9/fastuuid-0.14.0-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:6e6243d40f6c793c3e2ee14c13769e341b90be5ef0c23c82fa6515a96145181a", size = 516760, upload-time = "2025-10-19T22:25:21.509Z" }, + { url = "https://files.pythonhosted.org/packages/c5/79/c73c47be2a3b8734d16e628982653517f80bbe0570e27185d91af6096507/fastuuid-0.14.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:13ec4f2c3b04271f62be2e1ce7e95ad2dd1cf97e94503a3760db739afbd48f00", size = 264748, upload-time = "2025-10-19T22:41:52.873Z" }, + { url = "https://files.pythonhosted.org/packages/24/c5/84c1eea05977c8ba5173555b0133e3558dc628bcf868d6bf1689ff14aedc/fastuuid-0.14.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b2fdd48b5e4236df145a149d7125badb28e0a383372add3fbaac9a6b7a394470", size = 254537, upload-time = "2025-10-19T22:33:55.603Z" }, + { url = "https://files.pythonhosted.org/packages/0e/23/4e362367b7fa17dbed646922f216b9921efb486e7abe02147e4b917359f8/fastuuid-0.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f74631b8322d2780ebcf2d2d75d58045c3e9378625ec51865fe0b5620800c39d", size = 278994, upload-time = "2025-10-19T22:26:17.631Z" }, + { url = "https://files.pythonhosted.org/packages/b2/72/3985be633b5a428e9eaec4287ed4b873b7c4c53a9639a8b416637223c4cd/fastuuid-0.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83cffc144dc93eb604b87b179837f2ce2af44871a7b323f2bfed40e8acb40ba8", size = 280003, upload-time = "2025-10-19T22:23:45.415Z" }, + { url = "https://files.pythonhosted.org/packages/b3/6d/6ef192a6df34e2266d5c9deb39cd3eea986df650cbcfeaf171aa52a059c3/fastuuid-0.14.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a771f135ab4523eb786e95493803942a5d1fc1610915f131b363f55af53b219", size = 303583, upload-time = "2025-10-19T22:26:00.756Z" }, + { url = "https://files.pythonhosted.org/packages/9d/11/8a2ea753c68d4fece29d5d7c6f3f903948cc6e82d1823bc9f7f7c0355db3/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4edc56b877d960b4eda2c4232f953a61490c3134da94f3c28af129fb9c62a4f6", size = 460955, upload-time = "2025-10-19T22:36:25.196Z" }, + { url = "https://files.pythonhosted.org/packages/23/42/7a32c93b6ce12642d9a152ee4753a078f372c9ebb893bc489d838dd4afd5/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bcc96ee819c282e7c09b2eed2b9bd13084e3b749fdb2faf58c318d498df2efbe", size = 480763, upload-time = "2025-10-19T22:24:28.451Z" }, + { url = "https://files.pythonhosted.org/packages/b9/e9/a5f6f686b46e3ed4ed3b93770111c233baac87dd6586a411b4988018ef1d/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7a3c0bca61eacc1843ea97b288d6789fbad7400d16db24e36a66c28c268cfe3d", size = 452613, upload-time = "2025-10-19T22:25:06.827Z" }, + { url = "https://files.pythonhosted.org/packages/b4/c9/18abc73c9c5b7fc0e476c1733b678783b2e8a35b0be9babd423571d44e98/fastuuid-0.14.0-cp310-cp310-win32.whl", hash = "sha256:7f2f3efade4937fae4e77efae1af571902263de7b78a0aee1a1653795a093b2a", size = 155045, upload-time = "2025-10-19T22:28:32.732Z" }, + { url = "https://files.pythonhosted.org/packages/5e/8a/d9e33f4eb4d4f6d9f2c5c7d7e96b5cdbb535c93f3b1ad6acce97ee9d4bf8/fastuuid-0.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:ae64ba730d179f439b0736208b4c279b8bc9c089b102aec23f86512ea458c8a4", size = 156122, upload-time = "2025-10-19T22:23:15.59Z" }, + { url = "https://files.pythonhosted.org/packages/98/f3/12481bda4e5b6d3e698fbf525df4443cc7dce746f246b86b6fcb2fba1844/fastuuid-0.14.0-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:73946cb950c8caf65127d4e9a325e2b6be0442a224fd51ba3b6ac44e1912ce34", size = 516386, upload-time = "2025-10-19T22:42:40.176Z" }, + { url = "https://files.pythonhosted.org/packages/59/19/2fc58a1446e4d72b655648eb0879b04e88ed6fa70d474efcf550f640f6ec/fastuuid-0.14.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:12ac85024637586a5b69645e7ed986f7535106ed3013640a393a03e461740cb7", size = 264569, upload-time = "2025-10-19T22:25:50.977Z" }, + { url = "https://files.pythonhosted.org/packages/78/29/3c74756e5b02c40cfcc8b1d8b5bac4edbd532b55917a6bcc9113550e99d1/fastuuid-0.14.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:05a8dde1f395e0c9b4be515b7a521403d1e8349443e7641761af07c7ad1624b1", size = 254366, upload-time = "2025-10-19T22:29:49.166Z" }, + { url = "https://files.pythonhosted.org/packages/52/96/d761da3fccfa84f0f353ce6e3eb8b7f76b3aa21fd25e1b00a19f9c80a063/fastuuid-0.14.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09378a05020e3e4883dfdab438926f31fea15fd17604908f3d39cbeb22a0b4dc", size = 278978, upload-time = "2025-10-19T22:35:41.306Z" }, + { url = "https://files.pythonhosted.org/packages/fc/c2/f84c90167cc7765cb82b3ff7808057608b21c14a38531845d933a4637307/fastuuid-0.14.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbb0c4b15d66b435d2538f3827f05e44e2baafcc003dd7d8472dc67807ab8fd8", size = 279692, upload-time = "2025-10-19T22:25:36.997Z" }, + { url = "https://files.pythonhosted.org/packages/af/7b/4bacd03897b88c12348e7bd77943bac32ccf80ff98100598fcff74f75f2e/fastuuid-0.14.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cd5a7f648d4365b41dbf0e38fe8da4884e57bed4e77c83598e076ac0c93995e7", size = 303384, upload-time = "2025-10-19T22:29:46.578Z" }, + { url = "https://files.pythonhosted.org/packages/c0/a2/584f2c29641df8bd810d00c1f21d408c12e9ad0c0dafdb8b7b29e5ddf787/fastuuid-0.14.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c0a94245afae4d7af8c43b3159d5e3934c53f47140be0be624b96acd672ceb73", size = 460921, upload-time = "2025-10-19T22:36:42.006Z" }, + { url = "https://files.pythonhosted.org/packages/24/68/c6b77443bb7764c760e211002c8638c0c7cce11cb584927e723215ba1398/fastuuid-0.14.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:2b29e23c97e77c3a9514d70ce343571e469098ac7f5a269320a0f0b3e193ab36", size = 480575, upload-time = "2025-10-19T22:28:18.975Z" }, + { url = "https://files.pythonhosted.org/packages/5a/87/93f553111b33f9bb83145be12868c3c475bf8ea87c107063d01377cc0e8e/fastuuid-0.14.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1e690d48f923c253f28151b3a6b4e335f2b06bf669c68a02665bc150b7839e94", size = 452317, upload-time = "2025-10-19T22:25:32.75Z" }, + { url = "https://files.pythonhosted.org/packages/9e/8c/a04d486ca55b5abb7eaa65b39df8d891b7b1635b22db2163734dc273579a/fastuuid-0.14.0-cp311-cp311-win32.whl", hash = "sha256:a6f46790d59ab38c6aa0e35c681c0484b50dc0acf9e2679c005d61e019313c24", size = 154804, upload-time = "2025-10-19T22:24:15.615Z" }, + { url = "https://files.pythonhosted.org/packages/9c/b2/2d40bf00820de94b9280366a122cbaa60090c8cf59e89ac3938cf5d75895/fastuuid-0.14.0-cp311-cp311-win_amd64.whl", hash = "sha256:e150eab56c95dc9e3fefc234a0eedb342fac433dacc273cd4d150a5b0871e1fa", size = 156099, upload-time = "2025-10-19T22:24:31.646Z" }, + { url = "https://files.pythonhosted.org/packages/02/a2/e78fcc5df65467f0d207661b7ef86c5b7ac62eea337c0c0fcedbeee6fb13/fastuuid-0.14.0-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:77e94728324b63660ebf8adb27055e92d2e4611645bf12ed9d88d30486471d0a", size = 510164, upload-time = "2025-10-19T22:31:45.635Z" }, + { url = "https://files.pythonhosted.org/packages/2b/b3/c846f933f22f581f558ee63f81f29fa924acd971ce903dab1a9b6701816e/fastuuid-0.14.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:caa1f14d2102cb8d353096bc6ef6c13b2c81f347e6ab9d6fbd48b9dea41c153d", size = 261837, upload-time = "2025-10-19T22:38:38.53Z" }, + { url = "https://files.pythonhosted.org/packages/54/ea/682551030f8c4fa9a769d9825570ad28c0c71e30cf34020b85c1f7ee7382/fastuuid-0.14.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d23ef06f9e67163be38cece704170486715b177f6baae338110983f99a72c070", size = 251370, upload-time = "2025-10-19T22:40:26.07Z" }, + { url = "https://files.pythonhosted.org/packages/14/dd/5927f0a523d8e6a76b70968e6004966ee7df30322f5fc9b6cdfb0276646a/fastuuid-0.14.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c9ec605ace243b6dbe3bd27ebdd5d33b00d8d1d3f580b39fdd15cd96fd71796", size = 277766, upload-time = "2025-10-19T22:37:23.779Z" }, + { url = "https://files.pythonhosted.org/packages/16/6e/c0fb547eef61293153348f12e0f75a06abb322664b34a1573a7760501336/fastuuid-0.14.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:808527f2407f58a76c916d6aa15d58692a4a019fdf8d4c32ac7ff303b7d7af09", size = 278105, upload-time = "2025-10-19T22:26:56.821Z" }, + { url = "https://files.pythonhosted.org/packages/2d/b1/b9c75e03b768f61cf2e84ee193dc18601aeaf89a4684b20f2f0e9f52b62c/fastuuid-0.14.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2fb3c0d7fef6674bbeacdd6dbd386924a7b60b26de849266d1ff6602937675c8", size = 301564, upload-time = "2025-10-19T22:30:31.604Z" }, + { url = "https://files.pythonhosted.org/packages/fc/fa/f7395fdac07c7a54f18f801744573707321ca0cee082e638e36452355a9d/fastuuid-0.14.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab3f5d36e4393e628a4df337c2c039069344db5f4b9d2a3c9cea48284f1dd741", size = 459659, upload-time = "2025-10-19T22:31:32.341Z" }, + { url = "https://files.pythonhosted.org/packages/66/49/c9fd06a4a0b1f0f048aacb6599e7d96e5d6bc6fa680ed0d46bf111929d1b/fastuuid-0.14.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:b9a0ca4f03b7e0b01425281ffd44e99d360e15c895f1907ca105854ed85e2057", size = 478430, upload-time = "2025-10-19T22:26:22.962Z" }, + { url = "https://files.pythonhosted.org/packages/be/9c/909e8c95b494e8e140e8be6165d5fc3f61fdc46198c1554df7b3e1764471/fastuuid-0.14.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3acdf655684cc09e60fb7e4cf524e8f42ea760031945aa8086c7eae2eeeabeb8", size = 450894, upload-time = "2025-10-19T22:27:01.647Z" }, + { url = "https://files.pythonhosted.org/packages/90/eb/d29d17521976e673c55ef7f210d4cdd72091a9ec6755d0fd4710d9b3c871/fastuuid-0.14.0-cp312-cp312-win32.whl", hash = "sha256:9579618be6280700ae36ac42c3efd157049fe4dd40ca49b021280481c78c3176", size = 154374, upload-time = "2025-10-19T22:29:19.879Z" }, + { url = "https://files.pythonhosted.org/packages/cc/fc/f5c799a6ea6d877faec0472d0b27c079b47c86b1cdc577720a5386483b36/fastuuid-0.14.0-cp312-cp312-win_amd64.whl", hash = "sha256:d9e4332dc4ba054434a9594cbfaf7823b57993d7d8e7267831c3e059857cf397", size = 156550, upload-time = "2025-10-19T22:27:49.658Z" }, + { url = "https://files.pythonhosted.org/packages/a5/83/ae12dd39b9a39b55d7f90abb8971f1a5f3c321fd72d5aa83f90dc67fe9ed/fastuuid-0.14.0-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:77a09cb7427e7af74c594e409f7731a0cf887221de2f698e1ca0ebf0f3139021", size = 510720, upload-time = "2025-10-19T22:42:34.633Z" }, + { url = "https://files.pythonhosted.org/packages/53/b0/a4b03ff5d00f563cc7546b933c28cb3f2a07344b2aec5834e874f7d44143/fastuuid-0.14.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:9bd57289daf7b153bfa3e8013446aa144ce5e8c825e9e366d455155ede5ea2dc", size = 262024, upload-time = "2025-10-19T22:30:25.482Z" }, + { url = "https://files.pythonhosted.org/packages/9c/6d/64aee0a0f6a58eeabadd582e55d0d7d70258ffdd01d093b30c53d668303b/fastuuid-0.14.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ac60fc860cdf3c3f327374db87ab8e064c86566ca8c49d2e30df15eda1b0c2d5", size = 251679, upload-time = "2025-10-19T22:36:14.096Z" }, + { url = "https://files.pythonhosted.org/packages/60/f5/a7e9cda8369e4f7919d36552db9b2ae21db7915083bc6336f1b0082c8b2e/fastuuid-0.14.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab32f74bd56565b186f036e33129da77db8be09178cd2f5206a5d4035fb2a23f", size = 277862, upload-time = "2025-10-19T22:36:23.302Z" }, + { url = "https://files.pythonhosted.org/packages/f0/d3/8ce11827c783affffd5bd4d6378b28eb6cc6d2ddf41474006b8d62e7448e/fastuuid-0.14.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33e678459cf4addaedd9936bbb038e35b3f6b2061330fd8f2f6a1d80414c0f87", size = 278278, upload-time = "2025-10-19T22:29:43.809Z" }, + { url = "https://files.pythonhosted.org/packages/a2/51/680fb6352d0bbade04036da46264a8001f74b7484e2fd1f4da9e3db1c666/fastuuid-0.14.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1e3cc56742f76cd25ecb98e4b82a25f978ccffba02e4bdce8aba857b6d85d87b", size = 301788, upload-time = "2025-10-19T22:36:06.825Z" }, + { url = "https://files.pythonhosted.org/packages/fa/7c/2014b5785bd8ebdab04ec857635ebd84d5ee4950186a577db9eff0fb8ff6/fastuuid-0.14.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:cb9a030f609194b679e1660f7e32733b7a0f332d519c5d5a6a0a580991290022", size = 459819, upload-time = "2025-10-19T22:35:31.623Z" }, + { url = "https://files.pythonhosted.org/packages/01/d2/524d4ceeba9160e7a9bc2ea3e8f4ccf1ad78f3bde34090ca0c51f09a5e91/fastuuid-0.14.0-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:09098762aad4f8da3a888eb9ae01c84430c907a297b97166b8abc07b640f2995", size = 478546, upload-time = "2025-10-19T22:26:03.023Z" }, + { url = "https://files.pythonhosted.org/packages/bc/17/354d04951ce114bf4afc78e27a18cfbd6ee319ab1829c2d5fb5e94063ac6/fastuuid-0.14.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:1383fff584fa249b16329a059c68ad45d030d5a4b70fb7c73a08d98fd53bcdab", size = 450921, upload-time = "2025-10-19T22:31:02.151Z" }, + { url = "https://files.pythonhosted.org/packages/fb/be/d7be8670151d16d88f15bb121c5b66cdb5ea6a0c2a362d0dcf30276ade53/fastuuid-0.14.0-cp313-cp313-win32.whl", hash = "sha256:a0809f8cc5731c066c909047f9a314d5f536c871a7a22e815cc4967c110ac9ad", size = 154559, upload-time = "2025-10-19T22:36:36.011Z" }, + { url = "https://files.pythonhosted.org/packages/22/1d/5573ef3624ceb7abf4a46073d3554e37191c868abc3aecd5289a72f9810a/fastuuid-0.14.0-cp313-cp313-win_amd64.whl", hash = "sha256:0df14e92e7ad3276327631c9e7cec09e32572ce82089c55cb1bb8df71cf394ed", size = 156539, upload-time = "2025-10-19T22:33:35.898Z" }, + { url = "https://files.pythonhosted.org/packages/16/c9/8c7660d1fe3862e3f8acabd9be7fc9ad71eb270f1c65cce9a2b7a31329ab/fastuuid-0.14.0-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:b852a870a61cfc26c884af205d502881a2e59cc07076b60ab4a951cc0c94d1ad", size = 510600, upload-time = "2025-10-19T22:43:44.17Z" }, + { url = "https://files.pythonhosted.org/packages/4c/f4/a989c82f9a90d0ad995aa957b3e572ebef163c5299823b4027986f133dfb/fastuuid-0.14.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:c7502d6f54cd08024c3ea9b3514e2d6f190feb2f46e6dbcd3747882264bb5f7b", size = 262069, upload-time = "2025-10-19T22:43:38.38Z" }, + { url = "https://files.pythonhosted.org/packages/da/6c/a1a24f73574ac995482b1326cf7ab41301af0fabaa3e37eeb6b3df00e6e2/fastuuid-0.14.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1ca61b592120cf314cfd66e662a5b54a578c5a15b26305e1b8b618a6f22df714", size = 251543, upload-time = "2025-10-19T22:32:22.537Z" }, + { url = "https://files.pythonhosted.org/packages/1a/20/2a9b59185ba7a6c7b37808431477c2d739fcbdabbf63e00243e37bd6bf49/fastuuid-0.14.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa75b6657ec129d0abded3bec745e6f7ab642e6dba3a5272a68247e85f5f316f", size = 277798, upload-time = "2025-10-19T22:33:53.821Z" }, + { url = "https://files.pythonhosted.org/packages/ef/33/4105ca574f6ded0af6a797d39add041bcfb468a1255fbbe82fcb6f592da2/fastuuid-0.14.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8a0dfea3972200f72d4c7df02c8ac70bad1bb4c58d7e0ec1e6f341679073a7f", size = 278283, upload-time = "2025-10-19T22:29:02.812Z" }, + { url = "https://files.pythonhosted.org/packages/fe/8c/fca59f8e21c4deb013f574eae05723737ddb1d2937ce87cb2a5d20992dc3/fastuuid-0.14.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1bf539a7a95f35b419f9ad105d5a8a35036df35fdafae48fb2fd2e5f318f0d75", size = 301627, upload-time = "2025-10-19T22:35:54.985Z" }, + { url = "https://files.pythonhosted.org/packages/cb/e2/f78c271b909c034d429218f2798ca4e89eeda7983f4257d7865976ddbb6c/fastuuid-0.14.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:9a133bf9cc78fdbd1179cb58a59ad0100aa32d8675508150f3658814aeefeaa4", size = 459778, upload-time = "2025-10-19T22:28:00.999Z" }, + { url = "https://files.pythonhosted.org/packages/1e/f0/5ff209d865897667a2ff3e7a572267a9ced8f7313919f6d6043aed8b1caa/fastuuid-0.14.0-cp314-cp314-musllinux_1_1_i686.whl", hash = "sha256:f54d5b36c56a2d5e1a31e73b950b28a0d83eb0c37b91d10408875a5a29494bad", size = 478605, upload-time = "2025-10-19T22:36:21.764Z" }, + { url = "https://files.pythonhosted.org/packages/e0/c8/2ce1c78f983a2c4987ea865d9516dbdfb141a120fd3abb977ae6f02ba7ca/fastuuid-0.14.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:ec27778c6ca3393ef662e2762dba8af13f4ec1aaa32d08d77f71f2a70ae9feb8", size = 450837, upload-time = "2025-10-19T22:34:37.178Z" }, + { url = "https://files.pythonhosted.org/packages/df/60/dad662ec9a33b4a5fe44f60699258da64172c39bd041da2994422cdc40fe/fastuuid-0.14.0-cp314-cp314-win32.whl", hash = "sha256:e23fc6a83f112de4be0cc1990e5b127c27663ae43f866353166f87df58e73d06", size = 154532, upload-time = "2025-10-19T22:35:18.217Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f6/da4db31001e854025ffd26bc9ba0740a9cbba2c3259695f7c5834908b336/fastuuid-0.14.0-cp314-cp314-win_amd64.whl", hash = "sha256:df61342889d0f5e7a32f7284e55ef95103f2110fee433c2ae7c2c0956d76ac8a", size = 156457, upload-time = "2025-10-19T22:33:44.579Z" }, +] + [[package]] name = "filelock" version = "3.20.2" @@ -2090,6 +2153,34 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595, upload-time = "2024-06-10T19:24:40.698Z" }, ] +[[package]] +name = "jsonschema" +version = "4.26.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "jsonschema-specifications" }, + { name = "referencing" }, + { name = "rpds-py", version = "0.30.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "rpds-py", version = "2026.5.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b3/fc/e067678238fa451312d4c62bf6e6cf5ec56375422aee02f9cb5f909b3047/jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326", size = 366583, upload-time = "2026-01-07T13:41:07.246Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl", hash = "sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce", size = 90630, upload-time = "2026-01-07T13:41:05.306Z" }, +] + +[[package]] +name = "jsonschema-specifications" +version = "2025.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "referencing" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" }, +] + [[package]] name = "langchain-core" version = "0.3.81" @@ -2251,6 +2342,29 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/51/0e/b756c7708143a63fca65a51ca07990fa647db2cc8fcd65177b9e96680255/librt-0.7.7-cp314-cp314t-win_arm64.whl", hash = "sha256:142c2cd91794b79fd0ce113bd658993b7ede0fe93057668c2f98a45ca00b7e91", size = 39724, upload-time = "2026-01-01T23:52:09.745Z" }, ] +[[package]] +name = "litellm" +version = "1.80.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp" }, + { name = "click" }, + { name = "fastuuid" }, + { name = "httpx" }, + { name = "importlib-metadata" }, + { name = "jinja2" }, + { name = "jsonschema" }, + { name = "openai" }, + { name = "pydantic" }, + { name = "python-dotenv" }, + { name = "tiktoken" }, + { name = "tokenizers" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bd/8c/48d533affdbc6d485b7ad4221cd3b40b8c12f9f5568edfe0be0b11e7b945/litellm-1.80.0.tar.gz", hash = "sha256:eeac733eb6b226f9e5fb020f72fe13a32b3354b001dc62bcf1bc4d9b526d6231", size = 11591976, upload-time = "2025-11-16T00:03:51.812Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ea/53/aa31e4d057b3746b3c323ca993003d6cf15ef987e7fe7ceb53681695ae87/litellm-1.80.0-py3-none-any.whl", hash = "sha256:fd0009758f4772257048d74bf79bb64318859adb4ea49a8b66fdbc718cd80b6e", size = 10492975, upload-time = "2025-11-16T00:03:49.182Z" }, +] + [[package]] name = "llama-cloud" version = "0.1.35" @@ -3024,6 +3138,9 @@ google-genai = [ kg-creation-tools = [ { name = "neo4j-viz" }, ] +litellm = [ + { name = "litellm" }, +] mistralai = [ { name = "mistralai" }, ] @@ -3074,6 +3191,7 @@ requires-dist = [ { name = "langchain-huggingface", marker = "extra == 'examples'", specifier = ">=0.1.0,<2.0.0" }, { name = "langchain-openai", marker = "extra == 'examples'", specifier = ">=0.2.2,<2.0.0" }, { name = "langchain-text-splitters", marker = "extra == 'experimental'", specifier = ">=0.3.0,<2.0.0" }, + { name = "litellm", marker = "extra == 'litellm'", specifier = ">=1.0.0,<2.0.0" }, { name = "llama-index", marker = "extra == 'experimental'", specifier = ">=0.13.0,<0.14.0" }, { name = "mistralai", marker = "extra == 'mistralai'", specifier = ">=1.0.3,<2.0.0" }, { name = "neo4j", specifier = ">=5.17.0,<7.0.0" }, @@ -3098,7 +3216,7 @@ requires-dist = [ { name = "types-pyyaml", specifier = ">=6.0.12.20240917,<7.0.0" }, { name = "weaviate-client", marker = "extra == 'weaviate'", specifier = ">=4.6.1,<5.0.0" }, ] -provides-extras = ["weaviate", "pinecone", "google", "google-genai", "cohere", "anthropic", "bedrock", "ollama", "openai", "mistralai", "qdrant", "kg-creation-tools", "sentence-transformers", "experimental", "examples", "nlp", "fuzzy-matching"] +provides-extras = ["weaviate", "pinecone", "google", "google-genai", "cohere", "anthropic", "bedrock", "ollama", "openai", "mistralai", "litellm", "qdrant", "kg-creation-tools", "sentence-transformers", "experimental", "examples", "nlp", "fuzzy-matching"] [package.metadata.requires-dev] dev = [ @@ -4678,6 +4796,21 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b1/ad/fa2d3e5c29a04ead7eaa731c7cd1f30f9ec3c77b3a578fdf90280797cbcb/rapidfuzz-3.14.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56fefb4382bb12250f164250240b9dd7772e41c5c8ae976fd598a32292449cc5", size = 1511361, upload-time = "2025-11-01T11:54:49.057Z" }, ] +[[package]] +name = "referencing" +version = "0.37.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "rpds-py", version = "0.30.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "rpds-py", version = "2026.5.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/22/f5/df4e9027acead3ecc63e50fe1e36aca1523e1719559c499951bb4b53188f/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8", size = 78036, upload-time = "2025-10-13T15:30:48.871Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766, upload-time = "2025-10-13T15:30:47.625Z" }, +] + [[package]] name = "regex" version = "2025.11.3" @@ -4834,6 +4967,245 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/10/14/ea3cdd7276fcd731a9003fe4abeb6b395a38110ddff6a6a509f4ee00f741/roman-5.2-py3-none-any.whl", hash = "sha256:89d3b47400388806d06ff77ea77c79ab080bc127820dea6bf34e1f1c1b8e676e", size = 6041, upload-time = "2025-11-11T08:03:56.051Z" }, ] +[[package]] +name = "rpds-py" +version = "0.30.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.11'", +] +sdist = { url = "https://files.pythonhosted.org/packages/20/af/3f2f423103f1113b36230496629986e0ef7e199d2aa8392452b484b38ced/rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84", size = 69469, upload-time = "2025-11-30T20:24:38.837Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/06/0c/0c411a0ec64ccb6d104dcabe0e713e05e153a9a2c3c2bd2b32ce412166fe/rpds_py-0.30.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:679ae98e00c0e8d68a7fda324e16b90fd5260945b45d3b824c892cec9eea3288", size = 370490, upload-time = "2025-11-30T20:21:33.256Z" }, + { url = "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4cc2206b76b4f576934f0ed374b10d7ca5f457858b157ca52064bdfc26b9fc00", size = 359751, upload-time = "2025-11-30T20:21:34.591Z" }, + { url = "https://files.pythonhosted.org/packages/cd/7c/e4933565ef7f7a0818985d87c15d9d273f1a649afa6a52ea35ad011195ea/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:389a2d49eded1896c3d48b0136ead37c48e221b391c052fba3f4055c367f60a6", size = 389696, upload-time = "2025-11-30T20:21:36.122Z" }, + { url = "https://files.pythonhosted.org/packages/5e/01/6271a2511ad0815f00f7ed4390cf2567bec1d4b1da39e2c27a41e6e3b4de/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:32c8528634e1bf7121f3de08fa85b138f4e0dc47657866630611b03967f041d7", size = 403136, upload-time = "2025-11-30T20:21:37.728Z" }, + { url = "https://files.pythonhosted.org/packages/55/64/c857eb7cd7541e9b4eee9d49c196e833128a55b89a9850a9c9ac33ccf897/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f207f69853edd6f6700b86efb84999651baf3789e78a466431df1331608e5324", size = 524699, upload-time = "2025-11-30T20:21:38.92Z" }, + { url = "https://files.pythonhosted.org/packages/9c/ed/94816543404078af9ab26159c44f9e98e20fe47e2126d5d32c9d9948d10a/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:67b02ec25ba7a9e8fa74c63b6ca44cf5707f2fbfadae3ee8e7494297d56aa9df", size = 412022, upload-time = "2025-11-30T20:21:40.407Z" }, + { url = "https://files.pythonhosted.org/packages/61/b5/707f6cf0066a6412aacc11d17920ea2e19e5b2f04081c64526eb35b5c6e7/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0e95f6819a19965ff420f65578bacb0b00f251fefe2c8b23347c37174271f3", size = 390522, upload-time = "2025-11-30T20:21:42.17Z" }, + { url = "https://files.pythonhosted.org/packages/13/4e/57a85fda37a229ff4226f8cbcf09f2a455d1ed20e802ce5b2b4a7f5ed053/rpds_py-0.30.0-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:a452763cc5198f2f98898eb98f7569649fe5da666c2dc6b5ddb10fde5a574221", size = 404579, upload-time = "2025-11-30T20:21:43.769Z" }, + { url = "https://files.pythonhosted.org/packages/f9/da/c9339293513ec680a721e0e16bf2bac3db6e5d7e922488de471308349bba/rpds_py-0.30.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e0b65193a413ccc930671c55153a03ee57cecb49e6227204b04fae512eb657a7", size = 421305, upload-time = "2025-11-30T20:21:44.994Z" }, + { url = "https://files.pythonhosted.org/packages/f9/be/522cb84751114f4ad9d822ff5a1aa3c98006341895d5f084779b99596e5c/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:858738e9c32147f78b3ac24dc0edb6610000e56dc0f700fd5f651d0a0f0eb9ff", size = 572503, upload-time = "2025-11-30T20:21:46.91Z" }, + { url = "https://files.pythonhosted.org/packages/a2/9b/de879f7e7ceddc973ea6e4629e9b380213a6938a249e94b0cdbcc325bb66/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:da279aa314f00acbb803da1e76fa18666778e8a8f83484fba94526da5de2cba7", size = 598322, upload-time = "2025-11-30T20:21:48.709Z" }, + { url = "https://files.pythonhosted.org/packages/48/ac/f01fc22efec3f37d8a914fc1b2fb9bcafd56a299edbe96406f3053edea5a/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7c64d38fb49b6cdeda16ab49e35fe0da2e1e9b34bc38bd78386530f218b37139", size = 560792, upload-time = "2025-11-30T20:21:50.024Z" }, + { url = "https://files.pythonhosted.org/packages/e2/da/4e2b19d0f131f35b6146425f846563d0ce036763e38913d917187307a671/rpds_py-0.30.0-cp310-cp310-win32.whl", hash = "sha256:6de2a32a1665b93233cde140ff8b3467bdb9e2af2b91079f0333a0974d12d464", size = 221901, upload-time = "2025-11-30T20:21:51.32Z" }, + { url = "https://files.pythonhosted.org/packages/96/cb/156d7a5cf4f78a7cc571465d8aec7a3c447c94f6749c5123f08438bcf7bc/rpds_py-0.30.0-cp310-cp310-win_amd64.whl", hash = "sha256:1726859cd0de969f88dc8673bdd954185b9104e05806be64bcd87badbe313169", size = 235823, upload-time = "2025-11-30T20:21:52.505Z" }, + { url = "https://files.pythonhosted.org/packages/4d/6e/f964e88b3d2abee2a82c1ac8366da848fce1c6d834dc2132c3fda3970290/rpds_py-0.30.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a2bffea6a4ca9f01b3f8e548302470306689684e61602aa3d141e34da06cf425", size = 370157, upload-time = "2025-11-30T20:21:53.789Z" }, + { url = "https://files.pythonhosted.org/packages/94/ba/24e5ebb7c1c82e74c4e4f33b2112a5573ddc703915b13a073737b59b86e0/rpds_py-0.30.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dc4f992dfe1e2bc3ebc7444f6c7051b4bc13cd8e33e43511e8ffd13bf407010d", size = 359676, upload-time = "2025-11-30T20:21:55.475Z" }, + { url = "https://files.pythonhosted.org/packages/84/86/04dbba1b087227747d64d80c3b74df946b986c57af0a9f0c98726d4d7a3b/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:422c3cb9856d80b09d30d2eb255d0754b23e090034e1deb4083f8004bd0761e4", size = 389938, upload-time = "2025-11-30T20:21:57.079Z" }, + { url = "https://files.pythonhosted.org/packages/42/bb/1463f0b1722b7f45431bdd468301991d1328b16cffe0b1c2918eba2c4eee/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07ae8a593e1c3c6b82ca3292efbe73c30b61332fd612e05abee07c79359f292f", size = 402932, upload-time = "2025-11-30T20:21:58.47Z" }, + { url = "https://files.pythonhosted.org/packages/99/ee/2520700a5c1f2d76631f948b0736cdf9b0acb25abd0ca8e889b5c62ac2e3/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12f90dd7557b6bd57f40abe7747e81e0c0b119bef015ea7726e69fe550e394a4", size = 525830, upload-time = "2025-11-30T20:21:59.699Z" }, + { url = "https://files.pythonhosted.org/packages/e0/ad/bd0331f740f5705cc555a5e17fdf334671262160270962e69a2bdef3bf76/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:99b47d6ad9a6da00bec6aabe5a6279ecd3c06a329d4aa4771034a21e335c3a97", size = 412033, upload-time = "2025-11-30T20:22:00.991Z" }, + { url = "https://files.pythonhosted.org/packages/f8/1e/372195d326549bb51f0ba0f2ecb9874579906b97e08880e7a65c3bef1a99/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33f559f3104504506a44bb666b93a33f5d33133765b0c216a5bf2f1e1503af89", size = 390828, upload-time = "2025-11-30T20:22:02.723Z" }, + { url = "https://files.pythonhosted.org/packages/ab/2b/d88bb33294e3e0c76bc8f351a3721212713629ffca1700fa94979cb3eae8/rpds_py-0.30.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:946fe926af6e44f3697abbc305ea168c2c31d3e3ef1058cf68f379bf0335a78d", size = 404683, upload-time = "2025-11-30T20:22:04.367Z" }, + { url = "https://files.pythonhosted.org/packages/50/32/c759a8d42bcb5289c1fac697cd92f6fe01a018dd937e62ae77e0e7f15702/rpds_py-0.30.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:495aeca4b93d465efde585977365187149e75383ad2684f81519f504f5c13038", size = 421583, upload-time = "2025-11-30T20:22:05.814Z" }, + { url = "https://files.pythonhosted.org/packages/2b/81/e729761dbd55ddf5d84ec4ff1f47857f4374b0f19bdabfcf929164da3e24/rpds_py-0.30.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9a0ca5da0386dee0655b4ccdf46119df60e0f10da268d04fe7cc87886872ba7", size = 572496, upload-time = "2025-11-30T20:22:07.713Z" }, + { url = "https://files.pythonhosted.org/packages/14/f6/69066a924c3557c9c30baa6ec3a0aa07526305684c6f86c696b08860726c/rpds_py-0.30.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8d6d1cc13664ec13c1b84241204ff3b12f9bb82464b8ad6e7a5d3486975c2eed", size = 598669, upload-time = "2025-11-30T20:22:09.312Z" }, + { url = "https://files.pythonhosted.org/packages/5f/48/905896b1eb8a05630d20333d1d8ffd162394127b74ce0b0784ae04498d32/rpds_py-0.30.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3896fa1be39912cf0757753826bc8bdc8ca331a28a7c4ae46b7a21280b06bb85", size = 561011, upload-time = "2025-11-30T20:22:11.309Z" }, + { url = "https://files.pythonhosted.org/packages/22/16/cd3027c7e279d22e5eb431dd3c0fbc677bed58797fe7581e148f3f68818b/rpds_py-0.30.0-cp311-cp311-win32.whl", hash = "sha256:55f66022632205940f1827effeff17c4fa7ae1953d2b74a8581baaefb7d16f8c", size = 221406, upload-time = "2025-11-30T20:22:13.101Z" }, + { url = "https://files.pythonhosted.org/packages/fa/5b/e7b7aa136f28462b344e652ee010d4de26ee9fd16f1bfd5811f5153ccf89/rpds_py-0.30.0-cp311-cp311-win_amd64.whl", hash = "sha256:a51033ff701fca756439d641c0ad09a41d9242fa69121c7d8769604a0a629825", size = 236024, upload-time = "2025-11-30T20:22:14.853Z" }, + { url = "https://files.pythonhosted.org/packages/14/a6/364bba985e4c13658edb156640608f2c9e1d3ea3c81b27aa9d889fff0e31/rpds_py-0.30.0-cp311-cp311-win_arm64.whl", hash = "sha256:47b0ef6231c58f506ef0b74d44e330405caa8428e770fec25329ed2cb971a229", size = 229069, upload-time = "2025-11-30T20:22:16.577Z" }, + { url = "https://files.pythonhosted.org/packages/03/e7/98a2f4ac921d82f33e03f3835f5bf3a4a40aa1bfdc57975e74a97b2b4bdd/rpds_py-0.30.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a161f20d9a43006833cd7068375a94d035714d73a172b681d8881820600abfad", size = 375086, upload-time = "2025-11-30T20:22:17.93Z" }, + { url = "https://files.pythonhosted.org/packages/4d/a1/bca7fd3d452b272e13335db8d6b0b3ecde0f90ad6f16f3328c6fb150c889/rpds_py-0.30.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6abc8880d9d036ecaafe709079969f56e876fcf107f7a8e9920ba6d5a3878d05", size = 359053, upload-time = "2025-11-30T20:22:19.297Z" }, + { url = "https://files.pythonhosted.org/packages/65/1c/ae157e83a6357eceff62ba7e52113e3ec4834a84cfe07fa4b0757a7d105f/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca28829ae5f5d569bb62a79512c842a03a12576375d5ece7d2cadf8abe96ec28", size = 390763, upload-time = "2025-11-30T20:22:21.661Z" }, + { url = "https://files.pythonhosted.org/packages/d4/36/eb2eb8515e2ad24c0bd43c3ee9cd74c33f7ca6430755ccdb240fd3144c44/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a1010ed9524c73b94d15919ca4d41d8780980e1765babf85f9a2f90d247153dd", size = 408951, upload-time = "2025-11-30T20:22:23.408Z" }, + { url = "https://files.pythonhosted.org/packages/d6/65/ad8dc1784a331fabbd740ef6f71ce2198c7ed0890dab595adb9ea2d775a1/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8d1736cfb49381ba528cd5baa46f82fdc65c06e843dab24dd70b63d09121b3f", size = 514622, upload-time = "2025-11-30T20:22:25.16Z" }, + { url = "https://files.pythonhosted.org/packages/63/8e/0cfa7ae158e15e143fe03993b5bcd743a59f541f5952e1546b1ac1b5fd45/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d948b135c4693daff7bc2dcfc4ec57237a29bd37e60c2fabf5aff2bbacf3e2f1", size = 414492, upload-time = "2025-11-30T20:22:26.505Z" }, + { url = "https://files.pythonhosted.org/packages/60/1b/6f8f29f3f995c7ffdde46a626ddccd7c63aefc0efae881dc13b6e5d5bb16/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47f236970bccb2233267d89173d3ad2703cd36a0e2a6e92d0560d333871a3d23", size = 394080, upload-time = "2025-11-30T20:22:27.934Z" }, + { url = "https://files.pythonhosted.org/packages/6d/d5/a266341051a7a3ca2f4b750a3aa4abc986378431fc2da508c5034d081b70/rpds_py-0.30.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:2e6ecb5a5bcacf59c3f912155044479af1d0b6681280048b338b28e364aca1f6", size = 408680, upload-time = "2025-11-30T20:22:29.341Z" }, + { url = "https://files.pythonhosted.org/packages/10/3b/71b725851df9ab7a7a4e33cf36d241933da66040d195a84781f49c50490c/rpds_py-0.30.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a8fa71a2e078c527c3e9dc9fc5a98c9db40bcc8a92b4e8858e36d329f8684b51", size = 423589, upload-time = "2025-11-30T20:22:31.469Z" }, + { url = "https://files.pythonhosted.org/packages/00/2b/e59e58c544dc9bd8bd8384ecdb8ea91f6727f0e37a7131baeff8d6f51661/rpds_py-0.30.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:73c67f2db7bc334e518d097c6d1e6fed021bbc9b7d678d6cc433478365d1d5f5", size = 573289, upload-time = "2025-11-30T20:22:32.997Z" }, + { url = "https://files.pythonhosted.org/packages/da/3e/a18e6f5b460893172a7d6a680e86d3b6bc87a54c1f0b03446a3c8c7b588f/rpds_py-0.30.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5ba103fb455be00f3b1c2076c9d4264bfcb037c976167a6047ed82f23153f02e", size = 599737, upload-time = "2025-11-30T20:22:34.419Z" }, + { url = "https://files.pythonhosted.org/packages/5c/e2/714694e4b87b85a18e2c243614974413c60aa107fd815b8cbc42b873d1d7/rpds_py-0.30.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7cee9c752c0364588353e627da8a7e808a66873672bcb5f52890c33fd965b394", size = 563120, upload-time = "2025-11-30T20:22:35.903Z" }, + { url = "https://files.pythonhosted.org/packages/6f/ab/d5d5e3bcedb0a77f4f613706b750e50a5a3ba1c15ccd3665ecc636c968fd/rpds_py-0.30.0-cp312-cp312-win32.whl", hash = "sha256:1ab5b83dbcf55acc8b08fc62b796ef672c457b17dbd7820a11d6c52c06839bdf", size = 223782, upload-time = "2025-11-30T20:22:37.271Z" }, + { url = "https://files.pythonhosted.org/packages/39/3b/f786af9957306fdc38a74cef405b7b93180f481fb48453a114bb6465744a/rpds_py-0.30.0-cp312-cp312-win_amd64.whl", hash = "sha256:a090322ca841abd453d43456ac34db46e8b05fd9b3b4ac0c78bcde8b089f959b", size = 240463, upload-time = "2025-11-30T20:22:39.021Z" }, + { url = "https://files.pythonhosted.org/packages/f3/d2/b91dc748126c1559042cfe41990deb92c4ee3e2b415f6b5234969ffaf0cc/rpds_py-0.30.0-cp312-cp312-win_arm64.whl", hash = "sha256:669b1805bd639dd2989b281be2cfd951c6121b65e729d9b843e9639ef1fd555e", size = 230868, upload-time = "2025-11-30T20:22:40.493Z" }, + { url = "https://files.pythonhosted.org/packages/ed/dc/d61221eb88ff410de3c49143407f6f3147acf2538c86f2ab7ce65ae7d5f9/rpds_py-0.30.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f83424d738204d9770830d35290ff3273fbb02b41f919870479fab14b9d303b2", size = 374887, upload-time = "2025-11-30T20:22:41.812Z" }, + { url = "https://files.pythonhosted.org/packages/fd/32/55fb50ae104061dbc564ef15cc43c013dc4a9f4527a1f4d99baddf56fe5f/rpds_py-0.30.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e7536cd91353c5273434b4e003cbda89034d67e7710eab8761fd918ec6c69cf8", size = 358904, upload-time = "2025-11-30T20:22:43.479Z" }, + { url = "https://files.pythonhosted.org/packages/58/70/faed8186300e3b9bdd138d0273109784eea2396c68458ed580f885dfe7ad/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2771c6c15973347f50fece41fc447c054b7ac2ae0502388ce3b6738cd366e3d4", size = 389945, upload-time = "2025-11-30T20:22:44.819Z" }, + { url = "https://files.pythonhosted.org/packages/bd/a8/073cac3ed2c6387df38f71296d002ab43496a96b92c823e76f46b8af0543/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0a59119fc6e3f460315fe9d08149f8102aa322299deaa5cab5b40092345c2136", size = 407783, upload-time = "2025-11-30T20:22:46.103Z" }, + { url = "https://files.pythonhosted.org/packages/77/57/5999eb8c58671f1c11eba084115e77a8899d6e694d2a18f69f0ba471ec8b/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:76fec018282b4ead0364022e3c54b60bf368b9d926877957a8624b58419169b7", size = 515021, upload-time = "2025-11-30T20:22:47.458Z" }, + { url = "https://files.pythonhosted.org/packages/e0/af/5ab4833eadc36c0a8ed2bc5c0de0493c04f6c06de223170bd0798ff98ced/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:692bef75a5525db97318e8cd061542b5a79812d711ea03dbc1f6f8dbb0c5f0d2", size = 414589, upload-time = "2025-11-30T20:22:48.872Z" }, + { url = "https://files.pythonhosted.org/packages/b7/de/f7192e12b21b9e9a68a6d0f249b4af3fdcdff8418be0767a627564afa1f1/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9027da1ce107104c50c81383cae773ef5c24d296dd11c99e2629dbd7967a20c6", size = 394025, upload-time = "2025-11-30T20:22:50.196Z" }, + { url = "https://files.pythonhosted.org/packages/91/c4/fc70cd0249496493500e7cc2de87504f5aa6509de1e88623431fec76d4b6/rpds_py-0.30.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:9cf69cdda1f5968a30a359aba2f7f9aa648a9ce4b580d6826437f2b291cfc86e", size = 408895, upload-time = "2025-11-30T20:22:51.87Z" }, + { url = "https://files.pythonhosted.org/packages/58/95/d9275b05ab96556fefff73a385813eb66032e4c99f411d0795372d9abcea/rpds_py-0.30.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a4796a717bf12b9da9d3ad002519a86063dcac8988b030e405704ef7d74d2d9d", size = 422799, upload-time = "2025-11-30T20:22:53.341Z" }, + { url = "https://files.pythonhosted.org/packages/06/c1/3088fc04b6624eb12a57eb814f0d4997a44b0d208d6cace713033ff1a6ba/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5d4c2aa7c50ad4728a094ebd5eb46c452e9cb7edbfdb18f9e1221f597a73e1e7", size = 572731, upload-time = "2025-11-30T20:22:54.778Z" }, + { url = "https://files.pythonhosted.org/packages/d8/42/c612a833183b39774e8ac8fecae81263a68b9583ee343db33ab571a7ce55/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ba81a9203d07805435eb06f536d95a266c21e5b2dfbf6517748ca40c98d19e31", size = 599027, upload-time = "2025-11-30T20:22:56.212Z" }, + { url = "https://files.pythonhosted.org/packages/5f/60/525a50f45b01d70005403ae0e25f43c0384369ad24ffe46e8d9068b50086/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:945dccface01af02675628334f7cf49c2af4c1c904748efc5cf7bbdf0b579f95", size = 563020, upload-time = "2025-11-30T20:22:58.2Z" }, + { url = "https://files.pythonhosted.org/packages/0b/5d/47c4655e9bcd5ca907148535c10e7d489044243cc9941c16ed7cd53be91d/rpds_py-0.30.0-cp313-cp313-win32.whl", hash = "sha256:b40fb160a2db369a194cb27943582b38f79fc4887291417685f3ad693c5a1d5d", size = 223139, upload-time = "2025-11-30T20:23:00.209Z" }, + { url = "https://files.pythonhosted.org/packages/f2/e1/485132437d20aa4d3e1d8b3fb5a5e65aa8139f1e097080c2a8443201742c/rpds_py-0.30.0-cp313-cp313-win_amd64.whl", hash = "sha256:806f36b1b605e2d6a72716f321f20036b9489d29c51c91f4dd29a3e3afb73b15", size = 240224, upload-time = "2025-11-30T20:23:02.008Z" }, + { url = "https://files.pythonhosted.org/packages/24/95/ffd128ed1146a153d928617b0ef673960130be0009c77d8fbf0abe306713/rpds_py-0.30.0-cp313-cp313-win_arm64.whl", hash = "sha256:d96c2086587c7c30d44f31f42eae4eac89b60dabbac18c7669be3700f13c3ce1", size = 230645, upload-time = "2025-11-30T20:23:03.43Z" }, + { url = "https://files.pythonhosted.org/packages/ff/1b/b10de890a0def2a319a2626334a7f0ae388215eb60914dbac8a3bae54435/rpds_py-0.30.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:eb0b93f2e5c2189ee831ee43f156ed34e2a89a78a66b98cadad955972548be5a", size = 364443, upload-time = "2025-11-30T20:23:04.878Z" }, + { url = "https://files.pythonhosted.org/packages/0d/bf/27e39f5971dc4f305a4fb9c672ca06f290f7c4e261c568f3dea16a410d47/rpds_py-0.30.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:922e10f31f303c7c920da8981051ff6d8c1a56207dbdf330d9047f6d30b70e5e", size = 353375, upload-time = "2025-11-30T20:23:06.342Z" }, + { url = "https://files.pythonhosted.org/packages/40/58/442ada3bba6e8e6615fc00483135c14a7538d2ffac30e2d933ccf6852232/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdc62c8286ba9bf7f47befdcea13ea0e26bf294bda99758fd90535cbaf408000", size = 383850, upload-time = "2025-11-30T20:23:07.825Z" }, + { url = "https://files.pythonhosted.org/packages/14/14/f59b0127409a33c6ef6f5c1ebd5ad8e32d7861c9c7adfa9a624fc3889f6c/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:47f9a91efc418b54fb8190a6b4aa7813a23fb79c51f4bb84e418f5476c38b8db", size = 392812, upload-time = "2025-11-30T20:23:09.228Z" }, + { url = "https://files.pythonhosted.org/packages/b3/66/e0be3e162ac299b3a22527e8913767d869e6cc75c46bd844aa43fb81ab62/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f3587eb9b17f3789ad50824084fa6f81921bbf9a795826570bda82cb3ed91f2", size = 517841, upload-time = "2025-11-30T20:23:11.186Z" }, + { url = "https://files.pythonhosted.org/packages/3d/55/fa3b9cf31d0c963ecf1ba777f7cf4b2a2c976795ac430d24a1f43d25a6ba/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39c02563fc592411c2c61d26b6c5fe1e51eaa44a75aa2c8735ca88b0d9599daa", size = 408149, upload-time = "2025-11-30T20:23:12.864Z" }, + { url = "https://files.pythonhosted.org/packages/60/ca/780cf3b1a32b18c0f05c441958d3758f02544f1d613abf9488cd78876378/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51a1234d8febafdfd33a42d97da7a43f5dcb120c1060e352a3fbc0c6d36e2083", size = 383843, upload-time = "2025-11-30T20:23:14.638Z" }, + { url = "https://files.pythonhosted.org/packages/82/86/d5f2e04f2aa6247c613da0c1dd87fcd08fa17107e858193566048a1e2f0a/rpds_py-0.30.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:eb2c4071ab598733724c08221091e8d80e89064cd472819285a9ab0f24bcedb9", size = 396507, upload-time = "2025-11-30T20:23:16.105Z" }, + { url = "https://files.pythonhosted.org/packages/4b/9a/453255d2f769fe44e07ea9785c8347edaf867f7026872e76c1ad9f7bed92/rpds_py-0.30.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6bdfdb946967d816e6adf9a3d8201bfad269c67efe6cefd7093ef959683c8de0", size = 414949, upload-time = "2025-11-30T20:23:17.539Z" }, + { url = "https://files.pythonhosted.org/packages/a3/31/622a86cdc0c45d6df0e9ccb6becdba5074735e7033c20e401a6d9d0e2ca0/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c77afbd5f5250bf27bf516c7c4a016813eb2d3e116139aed0096940c5982da94", size = 565790, upload-time = "2025-11-30T20:23:19.029Z" }, + { url = "https://files.pythonhosted.org/packages/1c/5d/15bbf0fb4a3f58a3b1c67855ec1efcc4ceaef4e86644665fff03e1b66d8d/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:61046904275472a76c8c90c9ccee9013d70a6d0f73eecefd38c1ae7c39045a08", size = 590217, upload-time = "2025-11-30T20:23:20.885Z" }, + { url = "https://files.pythonhosted.org/packages/6d/61/21b8c41f68e60c8cc3b2e25644f0e3681926020f11d06ab0b78e3c6bbff1/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4c5f36a861bc4b7da6516dbdf302c55313afa09b81931e8280361a4f6c9a2d27", size = 555806, upload-time = "2025-11-30T20:23:22.488Z" }, + { url = "https://files.pythonhosted.org/packages/f9/39/7e067bb06c31de48de3eb200f9fc7c58982a4d3db44b07e73963e10d3be9/rpds_py-0.30.0-cp313-cp313t-win32.whl", hash = "sha256:3d4a69de7a3e50ffc214ae16d79d8fbb0922972da0356dcf4d0fdca2878559c6", size = 211341, upload-time = "2025-11-30T20:23:24.449Z" }, + { url = "https://files.pythonhosted.org/packages/0a/4d/222ef0b46443cf4cf46764d9c630f3fe4abaa7245be9417e56e9f52b8f65/rpds_py-0.30.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f14fc5df50a716f7ece6a80b6c78bb35ea2ca47c499e422aa4463455dd96d56d", size = 225768, upload-time = "2025-11-30T20:23:25.908Z" }, + { url = "https://files.pythonhosted.org/packages/86/81/dad16382ebbd3d0e0328776d8fd7ca94220e4fa0798d1dc5e7da48cb3201/rpds_py-0.30.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:68f19c879420aa08f61203801423f6cd5ac5f0ac4ac82a2368a9fcd6a9a075e0", size = 362099, upload-time = "2025-11-30T20:23:27.316Z" }, + { url = "https://files.pythonhosted.org/packages/2b/60/19f7884db5d5603edf3c6bce35408f45ad3e97e10007df0e17dd57af18f8/rpds_py-0.30.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ec7c4490c672c1a0389d319b3a9cfcd098dcdc4783991553c332a15acf7249be", size = 353192, upload-time = "2025-11-30T20:23:29.151Z" }, + { url = "https://files.pythonhosted.org/packages/bf/c4/76eb0e1e72d1a9c4703c69607cec123c29028bff28ce41588792417098ac/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f251c812357a3fed308d684a5079ddfb9d933860fc6de89f2b7ab00da481e65f", size = 384080, upload-time = "2025-11-30T20:23:30.785Z" }, + { url = "https://files.pythonhosted.org/packages/72/87/87ea665e92f3298d1b26d78814721dc39ed8d2c74b86e83348d6b48a6f31/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac98b175585ecf4c0348fd7b29c3864bda53b805c773cbf7bfdaffc8070c976f", size = 394841, upload-time = "2025-11-30T20:23:32.209Z" }, + { url = "https://files.pythonhosted.org/packages/77/ad/7783a89ca0587c15dcbf139b4a8364a872a25f861bdb88ed99f9b0dec985/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3e62880792319dbeb7eb866547f2e35973289e7d5696c6e295476448f5b63c87", size = 516670, upload-time = "2025-11-30T20:23:33.742Z" }, + { url = "https://files.pythonhosted.org/packages/5b/3c/2882bdac942bd2172f3da574eab16f309ae10a3925644e969536553cb4ee/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e7fc54e0900ab35d041b0601431b0a0eb495f0851a0639b6ef90f7741b39a18", size = 408005, upload-time = "2025-11-30T20:23:35.253Z" }, + { url = "https://files.pythonhosted.org/packages/ce/81/9a91c0111ce1758c92516a3e44776920b579d9a7c09b2b06b642d4de3f0f/rpds_py-0.30.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47e77dc9822d3ad616c3d5759ea5631a75e5809d5a28707744ef79d7a1bcfcad", size = 382112, upload-time = "2025-11-30T20:23:36.842Z" }, + { url = "https://files.pythonhosted.org/packages/cf/8e/1da49d4a107027e5fbc64daeab96a0706361a2918da10cb41769244b805d/rpds_py-0.30.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:b4dc1a6ff022ff85ecafef7979a2c6eb423430e05f1165d6688234e62ba99a07", size = 399049, upload-time = "2025-11-30T20:23:38.343Z" }, + { url = "https://files.pythonhosted.org/packages/df/5a/7ee239b1aa48a127570ec03becbb29c9d5a9eb092febbd1699d567cae859/rpds_py-0.30.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4559c972db3a360808309e06a74628b95eaccbf961c335c8fe0d590cf587456f", size = 415661, upload-time = "2025-11-30T20:23:40.263Z" }, + { url = "https://files.pythonhosted.org/packages/70/ea/caa143cf6b772f823bc7929a45da1fa83569ee49b11d18d0ada7f5ee6fd6/rpds_py-0.30.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:0ed177ed9bded28f8deb6ab40c183cd1192aa0de40c12f38be4d59cd33cb5c65", size = 565606, upload-time = "2025-11-30T20:23:42.186Z" }, + { url = "https://files.pythonhosted.org/packages/64/91/ac20ba2d69303f961ad8cf55bf7dbdb4763f627291ba3d0d7d67333cced9/rpds_py-0.30.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ad1fa8db769b76ea911cb4e10f049d80bf518c104f15b3edb2371cc65375c46f", size = 591126, upload-time = "2025-11-30T20:23:44.086Z" }, + { url = "https://files.pythonhosted.org/packages/21/20/7ff5f3c8b00c8a95f75985128c26ba44503fb35b8e0259d812766ea966c7/rpds_py-0.30.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:46e83c697b1f1c72b50e5ee5adb4353eef7406fb3f2043d64c33f20ad1c2fc53", size = 553371, upload-time = "2025-11-30T20:23:46.004Z" }, + { url = "https://files.pythonhosted.org/packages/72/c7/81dadd7b27c8ee391c132a6b192111ca58d866577ce2d9b0ca157552cce0/rpds_py-0.30.0-cp314-cp314-win32.whl", hash = "sha256:ee454b2a007d57363c2dfd5b6ca4a5d7e2c518938f8ed3b706e37e5d470801ed", size = 215298, upload-time = "2025-11-30T20:23:47.696Z" }, + { url = "https://files.pythonhosted.org/packages/3e/d2/1aaac33287e8cfb07aab2e6b8ac1deca62f6f65411344f1433c55e6f3eb8/rpds_py-0.30.0-cp314-cp314-win_amd64.whl", hash = "sha256:95f0802447ac2d10bcc69f6dc28fe95fdf17940367b21d34e34c737870758950", size = 228604, upload-time = "2025-11-30T20:23:49.501Z" }, + { url = "https://files.pythonhosted.org/packages/e8/95/ab005315818cc519ad074cb7784dae60d939163108bd2b394e60dc7b5461/rpds_py-0.30.0-cp314-cp314-win_arm64.whl", hash = "sha256:613aa4771c99f03346e54c3f038e4cc574ac09a3ddfb0e8878487335e96dead6", size = 222391, upload-time = "2025-11-30T20:23:50.96Z" }, + { url = "https://files.pythonhosted.org/packages/9e/68/154fe0194d83b973cdedcdcc88947a2752411165930182ae41d983dcefa6/rpds_py-0.30.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:7e6ecfcb62edfd632e56983964e6884851786443739dbfe3582947e87274f7cb", size = 364868, upload-time = "2025-11-30T20:23:52.494Z" }, + { url = "https://files.pythonhosted.org/packages/83/69/8bbc8b07ec854d92a8b75668c24d2abcb1719ebf890f5604c61c9369a16f/rpds_py-0.30.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a1d0bc22a7cdc173fedebb73ef81e07faef93692b8c1ad3733b67e31e1b6e1b8", size = 353747, upload-time = "2025-11-30T20:23:54.036Z" }, + { url = "https://files.pythonhosted.org/packages/ab/00/ba2e50183dbd9abcce9497fa5149c62b4ff3e22d338a30d690f9af970561/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d08f00679177226c4cb8c5265012eea897c8ca3b93f429e546600c971bcbae7", size = 383795, upload-time = "2025-11-30T20:23:55.556Z" }, + { url = "https://files.pythonhosted.org/packages/05/6f/86f0272b84926bcb0e4c972262f54223e8ecc556b3224d281e6598fc9268/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5965af57d5848192c13534f90f9dd16464f3c37aaf166cc1da1cae1fd5a34898", size = 393330, upload-time = "2025-11-30T20:23:57.033Z" }, + { url = "https://files.pythonhosted.org/packages/cb/e9/0e02bb2e6dc63d212641da45df2b0bf29699d01715913e0d0f017ee29438/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a4e86e34e9ab6b667c27f3211ca48f73dba7cd3d90f8d5b11be56e5dbc3fb4e", size = 518194, upload-time = "2025-11-30T20:23:58.637Z" }, + { url = "https://files.pythonhosted.org/packages/ee/ca/be7bca14cf21513bdf9c0606aba17d1f389ea2b6987035eb4f62bd923f25/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5d3e6b26f2c785d65cc25ef1e5267ccbe1b069c5c21b8cc724efee290554419", size = 408340, upload-time = "2025-11-30T20:24:00.2Z" }, + { url = "https://files.pythonhosted.org/packages/c2/c7/736e00ebf39ed81d75544c0da6ef7b0998f8201b369acf842f9a90dc8fce/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:626a7433c34566535b6e56a1b39a7b17ba961e97ce3b80ec62e6f1312c025551", size = 383765, upload-time = "2025-11-30T20:24:01.759Z" }, + { url = "https://files.pythonhosted.org/packages/4a/3f/da50dfde9956aaf365c4adc9533b100008ed31aea635f2b8d7b627e25b49/rpds_py-0.30.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:acd7eb3f4471577b9b5a41baf02a978e8bdeb08b4b355273994f8b87032000a8", size = 396834, upload-time = "2025-11-30T20:24:03.687Z" }, + { url = "https://files.pythonhosted.org/packages/4e/00/34bcc2565b6020eab2623349efbdec810676ad571995911f1abdae62a3a0/rpds_py-0.30.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fe5fa731a1fa8a0a56b0977413f8cacac1768dad38d16b3a296712709476fbd5", size = 415470, upload-time = "2025-11-30T20:24:05.232Z" }, + { url = "https://files.pythonhosted.org/packages/8c/28/882e72b5b3e6f718d5453bd4d0d9cf8df36fddeb4ddbbab17869d5868616/rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:74a3243a411126362712ee1524dfc90c650a503502f135d54d1b352bd01f2404", size = 565630, upload-time = "2025-11-30T20:24:06.878Z" }, + { url = "https://files.pythonhosted.org/packages/3b/97/04a65539c17692de5b85c6e293520fd01317fd878ea1995f0367d4532fb1/rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:3e8eeb0544f2eb0d2581774be4c3410356eba189529a6b3e36bbbf9696175856", size = 591148, upload-time = "2025-11-30T20:24:08.445Z" }, + { url = "https://files.pythonhosted.org/packages/85/70/92482ccffb96f5441aab93e26c4d66489eb599efdcf96fad90c14bbfb976/rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:dbd936cde57abfee19ab3213cf9c26be06d60750e60a8e4dd85d1ab12c8b1f40", size = 556030, upload-time = "2025-11-30T20:24:10.956Z" }, + { url = "https://files.pythonhosted.org/packages/20/53/7c7e784abfa500a2b6b583b147ee4bb5a2b3747a9166bab52fec4b5b5e7d/rpds_py-0.30.0-cp314-cp314t-win32.whl", hash = "sha256:dc824125c72246d924f7f796b4f63c1e9dc810c7d9e2355864b3c3a73d59ade0", size = 211570, upload-time = "2025-11-30T20:24:12.735Z" }, + { url = "https://files.pythonhosted.org/packages/d0/02/fa464cdfbe6b26e0600b62c528b72d8608f5cc49f96b8d6e38c95d60c676/rpds_py-0.30.0-cp314-cp314t-win_amd64.whl", hash = "sha256:27f4b0e92de5bfbc6f86e43959e6edd1425c33b5e69aab0984a72047f2bcf1e3", size = 226532, upload-time = "2025-11-30T20:24:14.634Z" }, + { url = "https://files.pythonhosted.org/packages/69/71/3f34339ee70521864411f8b6992e7ab13ac30d8e4e3309e07c7361767d91/rpds_py-0.30.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c2262bdba0ad4fc6fb5545660673925c2d2a5d9e2e0fb603aad545427be0fc58", size = 372292, upload-time = "2025-11-30T20:24:16.537Z" }, + { url = "https://files.pythonhosted.org/packages/57/09/f183df9b8f2d66720d2ef71075c59f7e1b336bec7ee4c48f0a2b06857653/rpds_py-0.30.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:ee6af14263f25eedc3bb918a3c04245106a42dfd4f5c2285ea6f997b1fc3f89a", size = 362128, upload-time = "2025-11-30T20:24:18.086Z" }, + { url = "https://files.pythonhosted.org/packages/7a/68/5c2594e937253457342e078f0cc1ded3dd7b2ad59afdbf2d354869110a02/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3adbb8179ce342d235c31ab8ec511e66c73faa27a47e076ccc92421add53e2bb", size = 391542, upload-time = "2025-11-30T20:24:20.092Z" }, + { url = "https://files.pythonhosted.org/packages/49/5c/31ef1afd70b4b4fbdb2800249f34c57c64beb687495b10aec0365f53dfc4/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:250fa00e9543ac9b97ac258bd37367ff5256666122c2d0f2bc97577c60a1818c", size = 404004, upload-time = "2025-11-30T20:24:22.231Z" }, + { url = "https://files.pythonhosted.org/packages/e3/63/0cfbea38d05756f3440ce6534d51a491d26176ac045e2707adc99bb6e60a/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9854cf4f488b3d57b9aaeb105f06d78e5529d3145b1e4a41750167e8c213c6d3", size = 527063, upload-time = "2025-11-30T20:24:24.302Z" }, + { url = "https://files.pythonhosted.org/packages/42/e6/01e1f72a2456678b0f618fc9a1a13f882061690893c192fcad9f2926553a/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:993914b8e560023bc0a8bf742c5f303551992dcb85e247b1e5c7f4a7d145bda5", size = 413099, upload-time = "2025-11-30T20:24:25.916Z" }, + { url = "https://files.pythonhosted.org/packages/b8/25/8df56677f209003dcbb180765520c544525e3ef21ea72279c98b9aa7c7fb/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58edca431fb9b29950807e301826586e5bbf24163677732429770a697ffe6738", size = 392177, upload-time = "2025-11-30T20:24:27.834Z" }, + { url = "https://files.pythonhosted.org/packages/4a/b4/0a771378c5f16f8115f796d1f437950158679bcd2a7c68cf251cfb00ed5b/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:dea5b552272a944763b34394d04577cf0f9bd013207bc32323b5a89a53cf9c2f", size = 406015, upload-time = "2025-11-30T20:24:29.457Z" }, + { url = "https://files.pythonhosted.org/packages/36/d8/456dbba0af75049dc6f63ff295a2f92766b9d521fa00de67a2bd6427d57a/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ba3af48635eb83d03f6c9735dfb21785303e73d22ad03d489e88adae6eab8877", size = 423736, upload-time = "2025-11-30T20:24:31.22Z" }, + { url = "https://files.pythonhosted.org/packages/13/64/b4d76f227d5c45a7e0b796c674fd81b0a6c4fbd48dc29271857d8219571c/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:dff13836529b921e22f15cb099751209a60009731a68519630a24d61f0b1b30a", size = 573981, upload-time = "2025-11-30T20:24:32.934Z" }, + { url = "https://files.pythonhosted.org/packages/20/91/092bacadeda3edf92bf743cc96a7be133e13a39cdbfd7b5082e7ab638406/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:1b151685b23929ab7beec71080a8889d4d6d9fa9a983d213f07121205d48e2c4", size = 599782, upload-time = "2025-11-30T20:24:35.169Z" }, + { url = "https://files.pythonhosted.org/packages/d1/b7/b95708304cd49b7b6f82fdd039f1748b66ec2b21d6a45180910802f1abf1/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:ac37f9f516c51e5753f27dfdef11a88330f04de2d564be3991384b2f3535d02e", size = 562191, upload-time = "2025-11-30T20:24:36.853Z" }, +] + +[[package]] +name = "rpds-py" +version = "2026.5.1" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.14'", + "python_full_version == '3.13.*'", + "python_full_version == '3.12.*'", + "python_full_version == '3.11.*'", +] +sdist = { url = "https://files.pythonhosted.org/packages/2e/43/25a8dcd3feedd735039a8f0b5b7e3b118232b5eae288c4fd9ab200d41094/rpds_py-2026.5.1.tar.gz", hash = "sha256:07b24fea40541e28570e5b795a4a38fbdcd12550c06bd0748005ecc8116ca256", size = 64459, upload-time = "2026-05-28T12:02:13.232Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4f/a0/acf8b6fc20bfdcd3a45bd3f57680fb198e157b7e997b9123b10763798bd2/rpds_py-2026.5.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:3397a5ed7174dc2786bb214030232fc36fe8e5584fec43a9952cc542b1a12036", size = 355609, upload-time = "2026-05-28T11:58:50.78Z" }, + { url = "https://files.pythonhosted.org/packages/b6/95/f8203fd997484b1690a6869cd0e503b6c3c6be55b0ecc36d1a491fe742f0/rpds_py-2026.5.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:99ab6ba7bfa2cb0f96a04e3652355bf04e3f51aceb1e943b8541dab7ba4828cc", size = 348460, upload-time = "2026-05-28T11:58:52.374Z" }, + { url = "https://files.pythonhosted.org/packages/33/8c/b47326ad2f0be545a5e5c1a55937a12afaea7d392ba2837bb9680f57e6c9/rpds_py-2026.5.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0efbe45632665e53e3db8fe1e5692db58fc5cb9bab4459d570b83efefe11164", size = 381031, upload-time = "2026-05-28T11:58:53.775Z" }, + { url = "https://files.pythonhosted.org/packages/22/0b/e83bbd97ffac6f6389b605cd4e1c8ac5761dc7e977769c9255d8c5adb7bd/rpds_py-2026.5.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:01d17b29c0c23d82b1f4751147ec49cf451f1fc2554eb9ef5f957e55d2656ead", size = 387121, upload-time = "2026-05-28T11:58:55.243Z" }, + { url = "https://files.pythonhosted.org/packages/fd/0e/d285d1bc8864245919c61e1ca82263e4a66d337759c3a4cef72766ff9afc/rpds_py-2026.5.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7559f72b94ae52659086c595dfa017cde03155f7832071d30959049052cb3ece", size = 501026, upload-time = "2026-05-28T11:58:56.788Z" }, + { url = "https://files.pythonhosted.org/packages/86/06/ccb2109a1e543437b5e43816f2b43b9554cc6783145528a4e3711e05c011/rpds_py-2026.5.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9e25b7088f9ccbfc0dfcaa52bf969300ca229e10ecf758974ebcbb080a4b37bb", size = 391865, upload-time = "2026-05-28T11:58:58.298Z" }, + { url = "https://files.pythonhosted.org/packages/3d/33/237173db1cfef10105b3839a24de00eb8d2a523711add4632447cdf0aedd/rpds_py-2026.5.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:613fc4ee9eaef26dc5840666214dd6fbcebcf32f46e76f4abc473059f4e13dda", size = 378012, upload-time = "2026-05-28T11:58:59.589Z" }, + { url = "https://files.pythonhosted.org/packages/97/64/1eae54e34d5161f9969295e80bd6b62a55f2b6ac5f2a5b60d02c2140e758/rpds_py-2026.5.1-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:85264a90ff4c05c1568dd65f5921c837614b67c60358fb4c17df3b7f2e90690a", size = 391111, upload-time = "2026-05-28T11:59:01.104Z" }, + { url = "https://files.pythonhosted.org/packages/d8/34/5bb334a5a0f65d77869217c4654f34c78a7d11b93938a3c076a2edeafc52/rpds_py-2026.5.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fe71bca7d547acb17027c7fd1624ff8aae623499c498d3e7011182c4de5c25e0", size = 409225, upload-time = "2026-05-28T11:59:02.433Z" }, + { url = "https://files.pythonhosted.org/packages/16/0f/007ec21283b5b040b4ec3bd95e0402591e22bfa7d5c93dfe01c465c2d2d7/rpds_py-2026.5.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05fa4f41f37ec97c9c260441a940450a192f78d774d2b097eee1379f1e1246a", size = 556487, upload-time = "2026-05-28T11:59:04.012Z" }, + { url = "https://files.pythonhosted.org/packages/ff/10/5437c94508169b6b22d8418fef7a66e9ffb5f3b9e9c94460f2eedafe06ff/rpds_py-2026.5.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:df1d2a1996755b24b9ecee92cb4d36c28f86f464a6a173349c26bab41e94b8c2", size = 620798, upload-time = "2026-05-28T11:59:05.485Z" }, + { url = "https://files.pythonhosted.org/packages/e0/d5/9937dce4d6bda74157b954e7d1460db05a22f5929dccfeeba1ed27a93df0/rpds_py-2026.5.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8895840ac4809e5f60c88fd07617cd71326e73d6e5a8aa783c5c0f7c24985de2", size = 584053, upload-time = "2026-05-28T11:59:06.837Z" }, + { url = "https://files.pythonhosted.org/packages/6c/31/750617dd0ae1752471bf43f9e41d263398fae7cde7849d23b8574a70e617/rpds_py-2026.5.1-cp311-cp311-win32.whl", hash = "sha256:3684a59b158a7683aaeb8e25352e9a9dd2122cec78f2d8530266e4f91b4c7b3f", size = 214390, upload-time = "2026-05-28T11:59:08.402Z" }, + { url = "https://files.pythonhosted.org/packages/3c/bb/3dcab0e1d9516303f2eb672a5d6f62eca5a69e2886301e9c8c54b520c39b/rpds_py-2026.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:7bd530e6a530bb3ea892f194fafa455f3516ac25ecf7143fd33c09be62b0470a", size = 231097, upload-time = "2026-05-28T11:59:09.786Z" }, + { url = "https://files.pythonhosted.org/packages/49/d6/c6bbf5cb1cf12b9732df8074b57f6ef8341ba884c95d40632ae8bddb44e4/rpds_py-2026.5.1-cp311-cp311-win_arm64.whl", hash = "sha256:0a5ae4dbe43c1076983b72616496919872ae7bbe7a1e21cc48336bc3154d130b", size = 226361, upload-time = "2026-05-28T11:59:11.079Z" }, + { url = "https://files.pythonhosted.org/packages/d4/e7/a78582dc57caa592dcc7d4fb69b61390561e908eb3d2f5df5928a8e354c0/rpds_py-2026.5.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3abe24a66e57adcfa645d718063a5fa5103ecc71ddbf26d78af8f9368018ff1d", size = 353040, upload-time = "2026-05-28T11:59:12.531Z" }, + { url = "https://files.pythonhosted.org/packages/a3/43/35e3f136343aef451e545ce8c38d36c2f93c0ed88703db8b64ba2b205c68/rpds_py-2026.5.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:58b1d94308ddf0b1982f61f2eb54bf92997c9ece8a8093ef014250f4a517906c", size = 345775, upload-time = "2026-05-28T11:59:13.827Z" }, + { url = "https://files.pythonhosted.org/packages/20/e1/0f2160c5982d3157734d5cb3ed63d8b2d583a73c9864f77b666449f32cf8/rpds_py-2026.5.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fa92420128dadce7f54bd73ba1825a273e9268fe9e35dbf7e6362890efa4e08", size = 376329, upload-time = "2026-05-28T11:59:15.271Z" }, + { url = "https://files.pythonhosted.org/packages/d0/11/ee0ba42aff83bf4effdbc576673c6be64c5e173978c3f6d537e94482f77d/rpds_py-2026.5.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ca653c6546386227cd9800d1bef6a348099acf8db4250341da6d90f663d6dfcb", size = 383539, upload-time = "2026-05-28T11:59:16.665Z" }, + { url = "https://files.pythonhosted.org/packages/11/df/d94aa6a499d4ac40afe2d7620f2c597fd3c0f182e854ad7cf3f596a81cb6/rpds_py-2026.5.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66c93681c4729e4e3ecba31b8179fae083ff3118841672835140338b4b9867c1", size = 494674, upload-time = "2026-05-28T11:59:17.991Z" }, + { url = "https://files.pythonhosted.org/packages/1f/75/33d30f43bb2f458de11979486a591b1bf6e5651765ed1704c6197c2dc773/rpds_py-2026.5.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40ff257542e04796880e011e15cd4dc21c2599975df2aaa8f2c8495ca574e1a5", size = 389268, upload-time = "2026-05-28T11:59:19.434Z" }, + { url = "https://files.pythonhosted.org/packages/f4/1e/2c9096fc19d5fd084b0184ca2b651e659aa0a37e6fdbecf6ece47f147fe1/rpds_py-2026.5.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6825cc329b290e93c5f6a9be2393118a763f6ccf6abd83704e0c102ca583644", size = 376280, upload-time = "2026-05-28T11:59:21Z" }, + { url = "https://files.pythonhosted.org/packages/b9/e5/61ec9f8be8211ea7f48448195549e4aaf02004083475493b0e137702ecb2/rpds_py-2026.5.1-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:de42116e69cb53b911cc34aee5ab98f36c597b822545045d49e938818b99e5e4", size = 387233, upload-time = "2026-05-28T11:59:22.454Z" }, + { url = "https://files.pythonhosted.org/packages/0d/ca/bcec1005c4f4a234f92a29078631fee49206c7265ccae966f18fd332e80e/rpds_py-2026.5.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c0f920015df2a504bebaba6d4c31ccf3fcf942f92655c086da30b671aad19aa6", size = 405009, upload-time = "2026-05-28T11:59:23.845Z" }, + { url = "https://files.pythonhosted.org/packages/72/e6/4d5718c5cf26c522dc7c9999e238da1e77380b81d0c5d1df11e271ddfeb1/rpds_py-2026.5.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0408a24e44feb919423dc6d9da677cb5cddb894d2ca9e763967d156d9c60fab4", size = 553113, upload-time = "2026-05-28T11:59:25.184Z" }, + { url = "https://files.pythonhosted.org/packages/d4/25/2ee807bdb3e1f0b7eddf7782acd5665a8b5205a331a7d7244a52c4812fd9/rpds_py-2026.5.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:cea68bcd53467561ae2f96a6bdad1544299ba97b5b0ddcd5ac3d376e5c781c24", size = 618838, upload-time = "2026-05-28T11:59:26.749Z" }, + { url = "https://files.pythonhosted.org/packages/6a/c1/7d4c26f167f8c41501cc073d30ee22082b16ce358cf5b00ec97cbc7804ea/rpds_py-2026.5.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4be8b1d2a705cc37d08256004e1d07de143fa0075c8e85a3df020b776f62b732", size = 582436, upload-time = "2026-05-28T11:59:28.11Z" }, + { url = "https://files.pythonhosted.org/packages/04/1d/9d12b0a337bab46f4769f8857f4007e3b2d639e14f9a44a0efe157696e64/rpds_py-2026.5.1-cp312-cp312-win32.whl", hash = "sha256:6736718bd4fc49cbcb538ba30516fdbef161522acefb739657d48b97bd864fed", size = 212734, upload-time = "2026-05-28T11:59:29.689Z" }, + { url = "https://files.pythonhosted.org/packages/c5/93/e4116f2de7f56bc7406a76033dc501811ddeb22b7f056b92d632871ebb0c/rpds_py-2026.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:0a7d1eec967df0e9b22614a5e177622e0c89611d03727fa0cb48e45028907870", size = 229045, upload-time = "2026-05-28T11:59:31.033Z" }, + { url = "https://files.pythonhosted.org/packages/cb/53/6c3419d85eb2ec5938a37627c585b42d76a63bb731d6e42ed4b079ebf486/rpds_py-2026.5.1-cp312-cp312-win_arm64.whl", hash = "sha256:1841d067089e117142d79b98aa0df2f08b52f2ecc1819dd2700636c0db74a473", size = 223967, upload-time = "2026-05-28T11:59:32.318Z" }, + { url = "https://files.pythonhosted.org/packages/6c/32/14c961ad295f490eb0849ada8b79683e93a59b9de3afdd983eaf55fa6867/rpds_py-2026.5.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:efef4ac29c6ff495531eb17ee705b62841ecaa291b7c7077e848ea03e237164d", size = 352787, upload-time = "2026-05-28T11:59:33.655Z" }, + { url = "https://files.pythonhosted.org/packages/ca/bb/d1b85117967c11191441a7274ae616c65d93901d082c588f89a50a8da5ae/rpds_py-2026.5.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c39f5b67a8a2e67179ada2a954227d670fe65fa9098457f698f56ddf248709b3", size = 345179, upload-time = "2026-05-28T11:59:35Z" }, + { url = "https://files.pythonhosted.org/packages/7c/46/d84105f062e626a1b233f863907288a4708c2d833b8b4c6fb2764bc080c0/rpds_py-2026.5.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5c30f3f04eef4fbd362226a6f31d7c8895ca4fbb6e0b790f6890a98d8da8559", size = 376173, upload-time = "2026-05-28T11:59:36.43Z" }, + { url = "https://files.pythonhosted.org/packages/e2/ae/469d7959ce5b1201e1de135dc735b86db3b35dd0d1734f6a44246d5f061c/rpds_py-2026.5.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:277f6c82f0580848796c7ecc8a7173aa3bfb928e4ff831261c2f60a81dc270db", size = 383162, upload-time = "2026-05-28T11:59:37.995Z" }, + { url = "https://files.pythonhosted.org/packages/dc/a2/57853d31a1116a561aa072794602ad3f6341e18d70a8523f1bd5b9fc1e5a/rpds_py-2026.5.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:63c2c4c213f1a4e3f3de28ecab029dbdee976324e729c0d7a55211be72576b02", size = 495093, upload-time = "2026-05-28T11:59:39.453Z" }, + { url = "https://files.pythonhosted.org/packages/99/63/3a8eabcad9314b7daf5c65f451d2c33d989235cd8a5762186cf2c3f5a4f8/rpds_py-2026.5.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3350ec808fb538fe71a1f94dfaa0e29c598dfad805ce49f0caec5ae3183c652b", size = 389829, upload-time = "2026-05-28T11:59:40.896Z" }, + { url = "https://files.pythonhosted.org/packages/4b/25/05678d97fc25e2622df14dc530fb82023174ecfff6733991ed0d78f167bd/rpds_py-2026.5.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1b964e3ab599e718dc46c018d104b1ebc007cbc6567d827c94a687fca56d77e", size = 374786, upload-time = "2026-05-28T11:59:42.626Z" }, + { url = "https://files.pythonhosted.org/packages/88/d1/8c90b6431e80a3b91b284a5c7c8c0c4f9c006444d90477a740d6e0f9c694/rpds_py-2026.5.1-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:19cb09fab7b7fc96b2a6e28f2e34b72a3705ff27b37edb77455316e5d3f3dc9b", size = 386920, upload-time = "2026-05-28T11:59:44.124Z" }, + { url = "https://files.pythonhosted.org/packages/ff/99/4638f672ab356682d633ee0da9255f5b67ce6efd0b85eb94ad3e255e65a5/rpds_py-2026.5.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:abe76bcdba31e576cb83eeb8797aa0d882b738fef6dc65d0601fc753806a5b46", size = 405059, upload-time = "2026-05-28T11:59:47.177Z" }, + { url = "https://files.pythonhosted.org/packages/66/3f/3546524b6eb4cc2e1f363a3d638fa52f6c24faae3500c25fb488b02f1740/rpds_py-2026.5.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8bff7073db3899158fff55ebf57b113a67030af26f80a18978f9f0aa60250ddf", size = 553030, upload-time = "2026-05-28T11:59:48.603Z" }, + { url = "https://files.pythonhosted.org/packages/c6/c3/7b3388c796fcf471bd17194242d4dc1a7608567c0fa422bcc1c5e79f9c1e/rpds_py-2026.5.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8ba264fa49be666cd9cc56bf34ec7002fb3d27a4aee5bcb4d43d0d18feb1bb6f", size = 618975, upload-time = "2026-05-28T11:59:50.314Z" }, + { url = "https://files.pythonhosted.org/packages/61/1e/a3cb07f2795075d1d88efddae2f541359fde5f08c81ee114c29c2949c90a/rpds_py-2026.5.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4860b603ddda0475a8885499b3729e90229d480105b42651962a5397d995fa89", size = 581178, upload-time = "2026-05-28T11:59:51.673Z" }, + { url = "https://files.pythonhosted.org/packages/a1/74/e758c03a5ef46f04c37f2651a2893db846d569ba8a7bca469d4b58939bcd/rpds_py-2026.5.1-cp313-cp313-win32.whl", hash = "sha256:7944270ae71383f6e2657dd7d5ce4eeb4ac2d0059a6738f0510583d462ab4842", size = 212481, upload-time = "2026-05-28T11:59:53.148Z" }, + { url = "https://files.pythonhosted.org/packages/70/ec/a2aca432db9c7359b40fa393eeeaa0d166c2f70175be956e75fa24197c44/rpds_py-2026.5.1-cp313-cp313-win_amd64.whl", hash = "sha256:88647f43a73c4e01be19b04ceef0c8d3a1958153604d13c773becd8016f2a0cf", size = 228519, upload-time = "2026-05-28T11:59:54.505Z" }, + { url = "https://files.pythonhosted.org/packages/29/60/a73bfdd45b096574556acf303bbd9fa9eed36ca8a818b514e2a5d5fe2b9d/rpds_py-2026.5.1-cp313-cp313-win_arm64.whl", hash = "sha256:453895624ecf7db7063b1004e44037522bbaef9ff6a945e59bc71662d7a03abd", size = 223446, upload-time = "2026-05-28T11:59:56.081Z" }, + { url = "https://files.pythonhosted.org/packages/18/e2/408105fd611823f00882aea810f3989a30d26b1bab8b6beb20f98c724e0e/rpds_py-2026.5.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:b4e4bc98639ec915f512fde3aa7a95e0041d95d9c3cc86eea841fa63cb1e8600", size = 355287, upload-time = "2026-05-28T11:59:57.448Z" }, + { url = "https://files.pythonhosted.org/packages/8d/58/5c4a43436843c90d0f6d19f82c200c80e3843ca9fa07b237623327f6d384/rpds_py-2026.5.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:cacedb7a6e167680acba45ad5716e89067d225dc80da0d7040cae8c81d4572fa", size = 347033, upload-time = "2026-05-28T11:59:58.881Z" }, + { url = "https://files.pythonhosted.org/packages/fb/c2/1a71acdacaf4e259b10278fb87b039ded3cf80041bcd89dd8a3ea702ded6/rpds_py-2026.5.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68700371c5d7ae1412862ddfa719090925c93ecf351c566d66f09d04b136ea00", size = 376891, upload-time = "2026-05-28T12:00:00.516Z" }, + { url = "https://files.pythonhosted.org/packages/c2/c8/535f3d9b65addd8e28aa87b83c6e526799c3717a88273db8ea795beeef7a/rpds_py-2026.5.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:296c799becfa849c779c8725494fe9ed94959ed886787df4364b058465bad7f0", size = 385646, upload-time = "2026-05-28T12:00:02.394Z" }, + { url = "https://files.pythonhosted.org/packages/1c/91/dc033f313345c354ade914dbe73cdb90b615a4409ea02430d5356794f3d8/rpds_py-2026.5.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d3858b908218ee108d0bbfb2095ccc237648053c9bf98affad7cb079acaf1d97", size = 498830, upload-time = "2026-05-28T12:00:04.189Z" }, + { url = "https://files.pythonhosted.org/packages/27/fc/90fcbea459dbb8ddc18a2e0fd1de9412b48bc84ffff2db771cf714bacfd6/rpds_py-2026.5.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4fb8d2e7cb2f850b169806d61d1b991738acec96500a75c30f49caf064ce7cef", size = 392830, upload-time = "2026-05-28T12:00:05.797Z" }, + { url = "https://files.pythonhosted.org/packages/b2/1d/46cd11a228c9750684a798d98f878be6f614aa762438da7378f035e79e35/rpds_py-2026.5.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27b74c10ed6a8f190f4287f53bcfea348b92a84a9c9f70d30183d1e6172d580d", size = 379613, upload-time = "2026-05-28T12:00:07.433Z" }, + { url = "https://files.pythonhosted.org/packages/24/4a/d9b0c6af3a1de03eb93741bbe8be2bdce84d8fda8224f3005451d86df389/rpds_py-2026.5.1-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:b9a6528956191c48c52294a592dbd4a8386d7048bdb25c0efcb6b966466c6d83", size = 388183, upload-time = "2026-05-28T12:00:09.227Z" }, + { url = "https://files.pythonhosted.org/packages/c5/b4/db7aaabdda6d020afc87d981bcc2f57a434c7dec60ecfc2ab3dd50b20351/rpds_py-2026.5.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:af03e34e860047bc7a352b842856fcf78798fbb81132cc98bd2f907ab4eb9cd2", size = 408578, upload-time = "2026-05-28T12:00:10.779Z" }, + { url = "https://files.pythonhosted.org/packages/08/d6/070f6a41cbb343e2ac4171859bf3f3623e0ab002f72619d6d505313ec2de/rpds_py-2026.5.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:fea6e836d10abbe191d557d33bd58bd5987725fe63aa1eefe557d230209855bd", size = 553573, upload-time = "2026-05-28T12:00:12.443Z" }, + { url = "https://files.pythonhosted.org/packages/75/ab/1a71ea3589c4345dac0a0518f0e6a031cb42689277851b683c46d27463a5/rpds_py-2026.5.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:fc0c0f878ea770a0a8a462456c5ad36fc9fe6358e6b76fdadc7f17575e0b8bf1", size = 620861, upload-time = "2026-05-28T12:00:14.09Z" }, + { url = "https://files.pythonhosted.org/packages/8a/22/9bf80a56069c0c443fcfefac639a86a744550a2898817a6dfd3e26654924/rpds_py-2026.5.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e0b360f316d966b048b085857630b3cc51f3db2f07b06f440eac8f695374d1e3", size = 585633, upload-time = "2026-05-28T12:00:15.66Z" }, + { url = "https://files.pythonhosted.org/packages/da/68/3b2c0a75c9e04125696f84ebdbbf304acf5a40b58ba4481cdb98a922c3ba/rpds_py-2026.5.1-cp313-cp313t-win32.whl", hash = "sha256:a2999883eedf72fdfb7520b92c7d4ec2572a71ff40239377aa604cc529eecafc", size = 210074, upload-time = "2026-05-28T12:00:17.291Z" }, + { url = "https://files.pythonhosted.org/packages/e7/8b/609157d5a25d37d4f29f92840ba531f416907c34ae5c5739dd21fc2bef98/rpds_py-2026.5.1-cp313-cp313t-win_amd64.whl", hash = "sha256:e07be2a9d7122bd6e82dea89814ef8dc893feb1aae97fec1630f3263bbb30e55", size = 228635, upload-time = "2026-05-28T12:00:18.73Z" }, + { url = "https://files.pythonhosted.org/packages/d4/6f/19c1918a4b590d8de87e712e4abe4b3875771eff60216fb6153cf6665c68/rpds_py-2026.5.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:1f2c391c3059798093b65df23aca2cac150460ae9c630d99dec83d703d9485b9", size = 349756, upload-time = "2026-05-28T12:00:20.217Z" }, + { url = "https://files.pythonhosted.org/packages/e5/60/a06fe7da34eca79dacbf958a2ba0c6eea85bc2b29de20080bf40f72f66fa/rpds_py-2026.5.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:413b424f7c4ee65ab5e5be91f5731be0f8b41a1ee2b12dfe810d716312e95a78", size = 343831, upload-time = "2026-05-28T12:00:21.711Z" }, + { url = "https://files.pythonhosted.org/packages/bf/ec/b2333b97b90e2a6ef6ca8ad386ee284968e74bcfe113b3f1a8d9036429a9/rpds_py-2026.5.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c595a1d9255dce0599e13130d1440ab2506654f2b50294226ee06402f8fef63", size = 375127, upload-time = "2026-05-28T12:00:23.326Z" }, + { url = "https://files.pythonhosted.org/packages/14/7f/e00aae54067f2b488c4637961d5f58204d470795fc791085fa3f15060d2e/rpds_py-2026.5.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1c27c5f6102eac8c03e7595a00827a53b271ba40a53b59ff8709170e0855ea4a", size = 379034, upload-time = "2026-05-28T12:00:24.89Z" }, + { url = "https://files.pythonhosted.org/packages/be/cc/423999bbb8ae8dc93c77fc1d5e984ade5eb89d237d3bb884ccfa72ae2890/rpds_py-2026.5.1-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6c7fcf61d44cacecaf3aea542b0e053db77972a4573e7ceda16fb2b399161195", size = 490823, upload-time = "2026-05-28T12:00:26.676Z" }, + { url = "https://files.pythonhosted.org/packages/0f/aa/c671bf660f12e68d3c52ff86c7066ed1372df5a0f4f2ff584e419b8207e7/rpds_py-2026.5.1-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2c817a189d4ee14290420e5ff051e4dd6baa13f3edf84685071dee07a6d538ee", size = 388144, upload-time = "2026-05-28T12:00:28.577Z" }, + { url = "https://files.pythonhosted.org/packages/19/c8/d63bb75b68afe77b229e3021c6031bcaf01da5db5b0e69d0d10f9ba679a7/rpds_py-2026.5.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21846aac0ed2e0589f38c12dc44e77bb64e494b771eadbcf169cba00566ba7ba", size = 371959, upload-time = "2026-05-28T12:00:30.304Z" }, + { url = "https://files.pythonhosted.org/packages/82/35/c51122014d8274ff37dc606d60049c3db7d83da02b5b282511e5a906a9a6/rpds_py-2026.5.1-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:b317c87a13f769a4e787819bd508aaa5d69aa09b0880de9af6d3a8a54571cdec", size = 383558, upload-time = "2026-05-28T12:00:31.764Z" }, + { url = "https://files.pythonhosted.org/packages/e3/f9/2790cb99c136a5363acdeacf5c27c56f3de0d4118a1f48fca83404c99c89/rpds_py-2026.5.1-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ce87129d9f2c14fa6c4a8601fb80eb4488c80d38a20cd13758ef11123e14995d", size = 402789, upload-time = "2026-05-28T12:00:33.247Z" }, + { url = "https://files.pythonhosted.org/packages/e5/1b/e4fb584f8c75d35c38150ff6a332cda949e6f97acba1f4fd123b14ab56fe/rpds_py-2026.5.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9cdddb6c1207d284d94fd1530adf57fbd797fe7c4b8704ba85f49414f2557e7d", size = 551405, upload-time = "2026-05-28T12:00:34.819Z" }, + { url = "https://files.pythonhosted.org/packages/d8/f7/a6731b4216cb3793ea1af5391da240f5683dacc0d13e034fe5fc3503f240/rpds_py-2026.5.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:4e237e139f94d3c036fd28eb9f564c99055476ff4ff05cd42be55ce349b5aa02", size = 616975, upload-time = "2026-05-28T12:00:36.268Z" }, + { url = "https://files.pythonhosted.org/packages/2c/ea/2e051a81d95d8e63f4b35a1c463a87e8766bc3d083c067c5dfb6bf220747/rpds_py-2026.5.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ed0954b524873214369184a9c82b0eaa45a3fbb9a798cd95b17e0d98499e7ea0", size = 578701, upload-time = "2026-05-28T12:00:37.82Z" }, + { url = "https://files.pythonhosted.org/packages/65/56/b5f6fdb2083e32bca8a8993d89e70db114b4756c9e2c38421328126689d2/rpds_py-2026.5.1-cp314-cp314-win32.whl", hash = "sha256:2d88621d6a7d4dfa633d21abe90f280bb205274e16b1d1e61c6ad4640b2453b7", size = 209806, upload-time = "2026-05-28T12:00:39.492Z" }, + { url = "https://files.pythonhosted.org/packages/fb/80/65a5aa96c155e611d1ed844e4e1f57f3e36b021f396d9f8585d756e6b90d/rpds_py-2026.5.1-cp314-cp314-win_amd64.whl", hash = "sha256:cef8ac28d26f4dda3533060c20fbf80a325458fa9fd23ea72a73cdfa8e978838", size = 225985, upload-time = "2026-05-28T12:00:40.94Z" }, + { url = "https://files.pythonhosted.org/packages/27/7c/ad185212e87b05f196daef92bc5f3caf07298eb47c295b5585c3dd3093ac/rpds_py-2026.5.1-cp314-cp314-win_arm64.whl", hash = "sha256:eaaea962c68cdc68d4a533ba985ab8e9484277910bbfaa2ab3ef7732667bfed8", size = 221219, upload-time = "2026-05-28T12:00:43.15Z" }, + { url = "https://files.pythonhosted.org/packages/23/58/e14ae18759020334646b031e708ab4158d653a938822bfb7b95ef2e93aa3/rpds_py-2026.5.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:21942f52dbbd5f8758bf021213d28bd45c39e873e65e2407faf5f1846f5761ad", size = 352148, upload-time = "2026-05-28T12:00:44.638Z" }, + { url = "https://files.pythonhosted.org/packages/31/9b/5f4a1e2f960bca3ac5d052b139dd31eed97b259f9d909173821760d542e8/rpds_py-2026.5.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f414556f6e3958300ff941e40c9f97e3dc9774ddd1b3434c475d73dd354bbed3", size = 345196, upload-time = "2026-05-28T12:00:46.14Z" }, + { url = "https://files.pythonhosted.org/packages/1a/71/1d9574d6a2fa20ab60eaa55c7467f5aa20cbc770f341a05f09c0876f59e2/rpds_py-2026.5.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef1013a8625c74043210190b246f5b1551e09757c1f356c6e4160ef96c5bc081", size = 374981, upload-time = "2026-05-28T12:00:47.531Z" }, + { url = "https://files.pythonhosted.org/packages/0c/9a/37e99f4915a80aa71670263c1267f7ae0af95f53a3f61e6c3bdc016d4515/rpds_py-2026.5.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cc68e231a77a5f0d774ae278a1f8e55c0456501820847c1e4efb3829f3441df6", size = 379961, upload-time = "2026-05-28T12:00:49.216Z" }, + { url = "https://files.pythonhosted.org/packages/a8/ff/6e73f74b89d2e0715e0fc86b7dde893f9a61ae2f9b256ff3bdfe41ac4e94/rpds_py-2026.5.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9baffb505aff33acc69b422a19f77806680f3c8632227d79f48de8a810d1c2c5", size = 495965, upload-time = "2026-05-28T12:00:51.111Z" }, + { url = "https://files.pythonhosted.org/packages/ea/e0/425faba25f59d74d4638b267f7c7a80e8649d2ef4db10a19b0c4a71e6e6f/rpds_py-2026.5.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b8d2f912928d426e8cfa396f7f3f8d29a59e6689c86dcca3c420730c1096322b", size = 389526, upload-time = "2026-05-28T12:00:52.77Z" }, + { url = "https://files.pythonhosted.org/packages/c6/76/7a41960e3fddae47fab43a28684d5da981401dffd88253de0944148654cb/rpds_py-2026.5.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90f628283be835db980c941767d41c9a27b5239e54ba0a9c1335247e82406964", size = 376190, upload-time = "2026-05-28T12:00:54.215Z" }, + { url = "https://files.pythonhosted.org/packages/27/60/5f38dc70824fc6951b51d35377e577a3a3a4c81a6769cc5a2de25ebe0ad1/rpds_py-2026.5.1-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:1ebb2f0ab7e16132995a72de805170e0203df0c3dd22e1ef1cd1fdd90bd7a131", size = 383921, upload-time = "2026-05-28T12:00:55.673Z" }, + { url = "https://files.pythonhosted.org/packages/60/1a/d60a38caa1505f4b9483c3fbbde12c94e1079154f4f401a6da96f7e77621/rpds_py-2026.5.1-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f3df3d16ded76f1f8c9cdebd0e1ea55fdf4c23b812de189814da7cf229c22a81", size = 404766, upload-time = "2026-05-28T12:00:57.518Z" }, + { url = "https://files.pythonhosted.org/packages/87/ff/602fd3f174d6425f0bce05ad0dfbec0e96b38d0f7d08a79af5aa20083885/rpds_py-2026.5.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:9af8905b8f854990e40d5206aa5ac58d9b0fe0b7f351ff2bb086c20f6c8c6a47", size = 551343, upload-time = "2026-05-28T12:00:58.978Z" }, + { url = "https://files.pythonhosted.org/packages/b8/c1/1be13327acdbead3eca1fde03b6a34dbb011f1e864e217f0d32cc1779a7f/rpds_py-2026.5.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:036a36a87fb1cd3b214d11c4b3c4f7d2ddad933625dca1c900b56a057c07740a", size = 618502, upload-time = "2026-05-28T12:01:00.656Z" }, + { url = "https://files.pythonhosted.org/packages/f3/d7/afb49b49d7f2be8b7ba1a9f0977fa5168003437b93086726f066544e8351/rpds_py-2026.5.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:62ae3853454fe9ef283a03c96c2d835d39e84b14643a9d62c82ef0fb87d702ca", size = 581916, upload-time = "2026-05-28T12:01:02.22Z" }, + { url = "https://files.pythonhosted.org/packages/25/d1/dbef8c1f8a10f07beb62b5f054e20099fd9924b3ec001b8f0b6ac7813a85/rpds_py-2026.5.1-cp314-cp314t-win32.whl", hash = "sha256:6c3d771a46ec18b12af06ce36243a9a80b07a5d0515236332d90863ca8bb326a", size = 207855, upload-time = "2026-05-28T12:01:03.821Z" }, + { url = "https://files.pythonhosted.org/packages/2a/72/bfa4e61ab8e7dc1c8adf397e05e6cbdd4239357bd72b248d3de662f23915/rpds_py-2026.5.1-cp314-cp314t-win_amd64.whl", hash = "sha256:c93c629be4636cf54337bd5f06c104d55e42ced54d681f6fe21ae510a65116f6", size = 225422, upload-time = "2026-05-28T12:01:05.194Z" }, + { url = "https://files.pythonhosted.org/packages/42/56/3fe0fb34820ff667be791b3a3c22b85e8bcba54e9c832f47438c191fa7be/rpds_py-2026.5.1-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:edf2765d84e42447f112ad877af8fe1db0089aaec5b28e88d6eab45e7fe99cea", size = 357151, upload-time = "2026-05-28T12:01:53.43Z" }, + { url = "https://files.pythonhosted.org/packages/8b/f2/3eb9ccdb9f143b8c9b003978898cb497f942a324c077401e6b8834238e63/rpds_py-2026.5.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:ad3773236e95f7f33991eb125224b7da66f206504d032a253a02da7e134519fb", size = 350195, upload-time = "2026-05-28T12:01:54.901Z" }, + { url = "https://files.pythonhosted.org/packages/a7/24/dbda232bc4f3ed732120692ab0d2c8402cb020516556d8bee622dcef2413/rpds_py-2026.5.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a04df86b3f0fade39ec8fd0e0aab089b1da9fbd2b48df778a57ef96f5e7d38df", size = 381850, upload-time = "2026-05-28T12:01:56.601Z" }, + { url = "https://files.pythonhosted.org/packages/40/30/32e769839a358f78810c234f160f2cc21d1e4e47e1c0e0e0d535be5a0219/rpds_py-2026.5.1-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6142dbd80c4df62a5d899f0d616d417f84e0bc8d32526c8e5589019d75d028a7", size = 387899, upload-time = "2026-05-28T12:01:58.212Z" }, + { url = "https://files.pythonhosted.org/packages/ab/86/ec84d243aadb3b34b71dd26a010d0930b2d284ff5fc9a69fec53810ee6fd/rpds_py-2026.5.1-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0b35217adefe87f2fe4db7e9766cabe84744bfe9616d9667be18988928c7f2dc", size = 501618, upload-time = "2026-05-28T12:01:59.888Z" }, + { url = "https://files.pythonhosted.org/packages/74/25/b60e52686bbff777a64f9e4f4d3dd57980dc846913777177a2c92e4937aa/rpds_py-2026.5.1-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b95d5e11fc712b752081183a55a244c03cd00570489edd7014d8899f8ceb8162", size = 394003, upload-time = "2026-05-28T12:02:01.482Z" }, + { url = "https://files.pythonhosted.org/packages/9b/c7/b3a6a588cc2219510ef3f42e207483a93950bedd1e3a0fd4015c95cff9e5/rpds_py-2026.5.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:141c9498daf2ace9eda35d2b0e376f9ea8b058d84f2aef4f96fccfd449a2f251", size = 379778, upload-time = "2026-05-28T12:02:03.197Z" }, + { url = "https://files.pythonhosted.org/packages/31/00/c7dba3fc8a3da8cb3f6db1eb3386be4d79c2e97c6890d20eb9ac66ae8c43/rpds_py-2026.5.1-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:6f249f8b860a200ad35193af961183ebe9132710484e6f6ce0cf89fd83c63a9a", size = 392359, upload-time = "2026-05-28T12:02:04.817Z" }, + { url = "https://files.pythonhosted.org/packages/93/dd/472ba494c70753f93745992c99855bee0636daf74e6984e5e003f150316f/rpds_py-2026.5.1-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e4abbf391a70be864920858bf360f4fb380577c9a0f732438a1996726e2c195b", size = 412820, upload-time = "2026-05-28T12:02:06.401Z" }, + { url = "https://files.pythonhosted.org/packages/1d/6f/93831a3bfe789542ed0c1d0d74b78b440f055d6dc3ea4640eba2d95e6e23/rpds_py-2026.5.1-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:c74005a7bb87752acf351c93897ec63ad77a07a0da7ecad9c050e32e7286ba34", size = 557243, upload-time = "2026-05-28T12:02:08.013Z" }, + { url = "https://files.pythonhosted.org/packages/1f/ff/0b3d604614ffc77522c6b288fdbce68957eb583da1002aa65ba38ac0ee40/rpds_py-2026.5.1-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:8213afbe8a3a906fb9acb2014423fe3359ee783d0bf90995f70623a3217bfa6c", size = 623541, upload-time = "2026-05-28T12:02:09.661Z" }, + { url = "https://files.pythonhosted.org/packages/ea/ea/e7b0251441da9adfeaebcf29601d10f2a1455fcf0772fae9e7e19032bd96/rpds_py-2026.5.1-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:8c43a8a973270fd173bf48cdf80bbe66312421cba68d40845034f174f2389049", size = 586326, upload-time = "2026-05-28T12:02:11.47Z" }, +] + [[package]] name = "ruamel-yaml" version = "0.18.16" From cdf31dac4830d69c4e75a67105643f302697a73e Mon Sep 17 00:00:00 2001 From: estelle Date: Tue, 7 Jul 2026 15:19:39 +0200 Subject: [PATCH 02/14] Ruff --- .../extractors/llm_entity_relation_extractor.py | 4 +++- .../llm_entity_relation_extractor_with_custom_prompt.py | 4 +++- ...lm_entity_relation_extractor_with_structured_output.py | 4 +++- .../components/splitters/fixed_size_splitter.py | 4 +++- .../customize/build_graph/pipeline/kg_builder_from_pdf.py | 4 +++- .../build_graph/pipeline/kg_builder_from_text.py | 4 +++- .../pipeline/lexical_graph_builder_from_text.py | 4 +++- .../build_graph/pipeline/pipeline_with_notifications.py | 4 +++- ...xt_to_lexical_graph_to_entity_graph_single_pipeline.py | 8 ++++++-- ...text_to_lexical_graph_to_entity_graph_two_pipelines.py | 8 ++++++-- examples/kg_builder.py | 4 +++- src/neo4j_graphrag/components/kg_writer.py | 4 +++- src/neo4j_graphrag/components/schema.py | 4 +++- tests/e2e/experimental/test_neo4j_reader_component_e2e.py | 4 +++- tests/unit/components/test_graph_pruning.py | 4 +--- tests/unit/components/test_kg_writer.py | 4 +++- tests/unit/components/test_schema.py | 8 ++++++-- tests/unit/components/text_splitters/test_llamaindex.py | 4 +++- .../config/template_pipeline/test_simple_kg_builder.py | 8 ++++---- 19 files changed, 65 insertions(+), 27 deletions(-) diff --git a/examples/customize/build_graph/components/extractors/llm_entity_relation_extractor.py b/examples/customize/build_graph/components/extractors/llm_entity_relation_extractor.py index 1786695af..1bba3d003 100644 --- a/examples/customize/build_graph/components/extractors/llm_entity_relation_extractor.py +++ b/examples/customize/build_graph/components/extractors/llm_entity_relation_extractor.py @@ -1,4 +1,6 @@ -from neo4j_graphrag.components.entity_relation_extractor import LLMEntityRelationExtractor +from neo4j_graphrag.components.entity_relation_extractor import ( + LLMEntityRelationExtractor, +) from neo4j_graphrag.components.types import ( Neo4jGraph, TextChunk, diff --git a/examples/customize/build_graph/components/extractors/llm_entity_relation_extractor_with_custom_prompt.py b/examples/customize/build_graph/components/extractors/llm_entity_relation_extractor_with_custom_prompt.py index 1786695af..1bba3d003 100644 --- a/examples/customize/build_graph/components/extractors/llm_entity_relation_extractor_with_custom_prompt.py +++ b/examples/customize/build_graph/components/extractors/llm_entity_relation_extractor_with_custom_prompt.py @@ -1,4 +1,6 @@ -from neo4j_graphrag.components.entity_relation_extractor import LLMEntityRelationExtractor +from neo4j_graphrag.components.entity_relation_extractor import ( + LLMEntityRelationExtractor, +) from neo4j_graphrag.components.types import ( Neo4jGraph, TextChunk, diff --git a/examples/customize/build_graph/components/extractors/llm_entity_relation_extractor_with_structured_output.py b/examples/customize/build_graph/components/extractors/llm_entity_relation_extractor_with_structured_output.py index 835ca7b43..7492ef437 100644 --- a/examples/customize/build_graph/components/extractors/llm_entity_relation_extractor_with_structured_output.py +++ b/examples/customize/build_graph/components/extractors/llm_entity_relation_extractor_with_structured_output.py @@ -16,7 +16,9 @@ import asyncio from dotenv import load_dotenv -from neo4j_graphrag.components.entity_relation_extractor import LLMEntityRelationExtractor +from neo4j_graphrag.components.entity_relation_extractor import ( + LLMEntityRelationExtractor, +) from neo4j_graphrag.components.types import ( Neo4jGraph, TextChunk, diff --git a/examples/customize/build_graph/components/splitters/fixed_size_splitter.py b/examples/customize/build_graph/components/splitters/fixed_size_splitter.py index ff1ff033b..690a9eb3d 100644 --- a/examples/customize/build_graph/components/splitters/fixed_size_splitter.py +++ b/examples/customize/build_graph/components/splitters/fixed_size_splitter.py @@ -1,4 +1,6 @@ -from neo4j_graphrag.components.text_splitters.fixed_size_splitter import FixedSizeSplitter +from neo4j_graphrag.components.text_splitters.fixed_size_splitter import ( + FixedSizeSplitter, +) from neo4j_graphrag.components.types import TextChunks diff --git a/examples/customize/build_graph/pipeline/kg_builder_from_pdf.py b/examples/customize/build_graph/pipeline/kg_builder_from_pdf.py index aae29d817..3cf595cd1 100644 --- a/examples/customize/build_graph/pipeline/kg_builder_from_pdf.py +++ b/examples/customize/build_graph/pipeline/kg_builder_from_pdf.py @@ -28,7 +28,9 @@ NodeType, RelationshipType, ) -from neo4j_graphrag.components.text_splitters.fixed_size_splitter import FixedSizeSplitter +from neo4j_graphrag.components.text_splitters.fixed_size_splitter import ( + FixedSizeSplitter, +) from neo4j_graphrag.experimental.pipeline.pipeline import PipelineResult from neo4j_graphrag.llm import LLMInterface, OpenAILLM diff --git a/examples/customize/build_graph/pipeline/kg_builder_from_text.py b/examples/customize/build_graph/pipeline/kg_builder_from_text.py index fc36d5d0f..0b6400395 100644 --- a/examples/customize/build_graph/pipeline/kg_builder_from_text.py +++ b/examples/customize/build_graph/pipeline/kg_builder_from_text.py @@ -29,7 +29,9 @@ PropertyType, RelationshipType, ) -from neo4j_graphrag.components.text_splitters.fixed_size_splitter import FixedSizeSplitter +from neo4j_graphrag.components.text_splitters.fixed_size_splitter import ( + FixedSizeSplitter, +) from neo4j_graphrag.experimental.pipeline import Pipeline from neo4j_graphrag.experimental.pipeline.pipeline import PipelineResult from neo4j_graphrag.llm import LLMInterface, OpenAILLM diff --git a/examples/customize/build_graph/pipeline/lexical_graph_builder_from_text.py b/examples/customize/build_graph/pipeline/lexical_graph_builder_from_text.py index 88358ae24..6766f9e55 100644 --- a/examples/customize/build_graph/pipeline/lexical_graph_builder_from_text.py +++ b/examples/customize/build_graph/pipeline/lexical_graph_builder_from_text.py @@ -6,7 +6,9 @@ from neo4j_graphrag.components.embedder import TextChunkEmbedder from neo4j_graphrag.components.kg_writer import Neo4jWriter from neo4j_graphrag.components.lexical_graph import LexicalGraphBuilder -from neo4j_graphrag.components.text_splitters.fixed_size_splitter import FixedSizeSplitter +from neo4j_graphrag.components.text_splitters.fixed_size_splitter import ( + FixedSizeSplitter, +) from neo4j_graphrag.components.types import LexicalGraphConfig from neo4j_graphrag.experimental.pipeline import Pipeline from neo4j_graphrag.experimental.pipeline.pipeline import PipelineResult diff --git a/examples/customize/build_graph/pipeline/pipeline_with_notifications.py b/examples/customize/build_graph/pipeline/pipeline_with_notifications.py index ad537ef07..0039db908 100644 --- a/examples/customize/build_graph/pipeline/pipeline_with_notifications.py +++ b/examples/customize/build_graph/pipeline/pipeline_with_notifications.py @@ -10,7 +10,9 @@ import neo4j from neo4j_graphrag.components.kg_writer import Neo4jWriter from neo4j_graphrag.components.lexical_graph import LexicalGraphBuilder -from neo4j_graphrag.components.text_splitters.fixed_size_splitter import FixedSizeSplitter +from neo4j_graphrag.components.text_splitters.fixed_size_splitter import ( + FixedSizeSplitter, +) from neo4j_graphrag.experimental.pipeline import Pipeline from neo4j_graphrag.experimental.pipeline.pipeline import PipelineResult from neo4j_graphrag.experimental.pipeline.notification import Event diff --git a/examples/customize/build_graph/pipeline/text_to_lexical_graph_to_entity_graph_single_pipeline.py b/examples/customize/build_graph/pipeline/text_to_lexical_graph_to_entity_graph_single_pipeline.py index aa1e26077..59f8bf26f 100644 --- a/examples/customize/build_graph/pipeline/text_to_lexical_graph_to_entity_graph_single_pipeline.py +++ b/examples/customize/build_graph/pipeline/text_to_lexical_graph_to_entity_graph_single_pipeline.py @@ -9,7 +9,9 @@ from neo4j_graphrag.embeddings.openai import OpenAIEmbeddings from neo4j_graphrag.components.embedder import TextChunkEmbedder -from neo4j_graphrag.components.entity_relation_extractor import LLMEntityRelationExtractor +from neo4j_graphrag.components.entity_relation_extractor import ( + LLMEntityRelationExtractor, +) from neo4j_graphrag.components.kg_writer import Neo4jWriter from neo4j_graphrag.components.lexical_graph import LexicalGraphBuilder from neo4j_graphrag.components.schema import ( @@ -18,7 +20,9 @@ PropertyType, RelationshipType, ) -from neo4j_graphrag.components.text_splitters.fixed_size_splitter import FixedSizeSplitter +from neo4j_graphrag.components.text_splitters.fixed_size_splitter import ( + FixedSizeSplitter, +) from neo4j_graphrag.components.types import LexicalGraphConfig from neo4j_graphrag.experimental.pipeline import Pipeline from neo4j_graphrag.experimental.pipeline.pipeline import PipelineResult diff --git a/examples/customize/build_graph/pipeline/text_to_lexical_graph_to_entity_graph_two_pipelines.py b/examples/customize/build_graph/pipeline/text_to_lexical_graph_to_entity_graph_two_pipelines.py index abf674825..9d7312202 100644 --- a/examples/customize/build_graph/pipeline/text_to_lexical_graph_to_entity_graph_two_pipelines.py +++ b/examples/customize/build_graph/pipeline/text_to_lexical_graph_to_entity_graph_two_pipelines.py @@ -10,7 +10,9 @@ from neo4j_graphrag.embeddings.openai import OpenAIEmbeddings from neo4j_graphrag.components.embedder import TextChunkEmbedder -from neo4j_graphrag.components.entity_relation_extractor import LLMEntityRelationExtractor +from neo4j_graphrag.components.entity_relation_extractor import ( + LLMEntityRelationExtractor, +) from neo4j_graphrag.components.kg_writer import Neo4jWriter from neo4j_graphrag.components.lexical_graph import LexicalGraphBuilder from neo4j_graphrag.components.neo4j_reader import Neo4jChunkReader @@ -20,7 +22,9 @@ PropertyType, RelationshipType, ) -from neo4j_graphrag.components.text_splitters.fixed_size_splitter import FixedSizeSplitter +from neo4j_graphrag.components.text_splitters.fixed_size_splitter import ( + FixedSizeSplitter, +) from neo4j_graphrag.components.types import LexicalGraphConfig from neo4j_graphrag.experimental.pipeline import Pipeline from neo4j_graphrag.experimental.pipeline.pipeline import PipelineResult diff --git a/examples/kg_builder.py b/examples/kg_builder.py index 95575055e..101427f2b 100644 --- a/examples/kg_builder.py +++ b/examples/kg_builder.py @@ -35,7 +35,9 @@ NodeType, RelationshipType, ) -from neo4j_graphrag.components.text_splitters.fixed_size_splitter import FixedSizeSplitter +from neo4j_graphrag.components.text_splitters.fixed_size_splitter import ( + FixedSizeSplitter, +) from neo4j_graphrag.experimental.pipeline.pipeline import PipelineResult from neo4j_graphrag.llm import LLMInterface, OpenAILLM diff --git a/src/neo4j_graphrag/components/kg_writer.py b/src/neo4j_graphrag/components/kg_writer.py index c1a4dcf22..74e921cf8 100644 --- a/src/neo4j_graphrag/components/kg_writer.py +++ b/src/neo4j_graphrag/components/kg_writer.py @@ -22,7 +22,9 @@ import neo4j from pydantic import validate_call -from neo4j_graphrag.components.filename_collision_handler import FilenameCollisionHandler +from neo4j_graphrag.components.filename_collision_handler import ( + FilenameCollisionHandler, +) from neo4j_graphrag.components.parquet_formatter import ( INTERNAL_ID_PROPERTY, Neo4jGraphParquetFormatter, diff --git a/src/neo4j_graphrag/components/schema.py b/src/neo4j_graphrag/components/schema.py index dae9af2ab..349263637 100644 --- a/src/neo4j_graphrag/components/schema.py +++ b/src/neo4j_graphrag/components/schema.py @@ -1784,7 +1784,9 @@ async def _run_with_structured_output(self, prompt: str) -> GraphSchema: RuntimeError: If LLM is not OpenAILLM or VertexAILLM SchemaExtractionError: If LLM generation or validation fails """ - from neo4j_graphrag.components.graph_schema_extraction import GraphSchemaExtractionOutput + from neo4j_graphrag.components.graph_schema_extraction import ( + GraphSchemaExtractionOutput, + ) # Capability check # This should never happen due to __init__ validation diff --git a/tests/e2e/experimental/test_neo4j_reader_component_e2e.py b/tests/e2e/experimental/test_neo4j_reader_component_e2e.py index cb2d0405c..9cce5ee5c 100644 --- a/tests/e2e/experimental/test_neo4j_reader_component_e2e.py +++ b/tests/e2e/experimental/test_neo4j_reader_component_e2e.py @@ -16,7 +16,9 @@ import neo4j import pytest -from neo4j_graphrag.components.entity_relation_extractor import LLMEntityRelationExtractor +from neo4j_graphrag.components.entity_relation_extractor import ( + LLMEntityRelationExtractor, +) from neo4j_graphrag.components.neo4j_reader import Neo4jChunkReader from neo4j_graphrag.components.types import LexicalGraphConfig, TextChunk from neo4j_graphrag.experimental.pipeline import Pipeline diff --git a/tests/unit/components/test_graph_pruning.py b/tests/unit/components/test_graph_pruning.py index 064d7c94f..0187e1daf 100644 --- a/tests/unit/components/test_graph_pruning.py +++ b/tests/unit/components/test_graph_pruning.py @@ -794,9 +794,7 @@ async def test_graph_pruning_run_no_schema() -> None: assert pruner_result.graph == initial_graph -@patch( - "neo4j_graphrag.components.graph_pruning.GraphPruning._enforce_nodes" -) +@patch("neo4j_graphrag.components.graph_pruning.GraphPruning._enforce_nodes") def test_graph_pruning_clean_graph( mock_enforce_nodes: Mock, lexical_graph_config: LexicalGraphConfig, diff --git a/tests/unit/components/test_kg_writer.py b/tests/unit/components/test_kg_writer.py index a6e84e66e..e40936e4d 100644 --- a/tests/unit/components/test_kg_writer.py +++ b/tests/unit/components/test_kg_writer.py @@ -22,7 +22,9 @@ from unittest.mock import MagicMock, Mock import pytest -from neo4j_graphrag.components.filename_collision_handler import FilenameCollisionHandler +from neo4j_graphrag.components.filename_collision_handler import ( + FilenameCollisionHandler, +) from neo4j_graphrag.components.parquet_formatter import ( INTERNAL_ID_PROPERTY, Neo4jGraphParquetFormatter, diff --git a/tests/unit/components/test_schema.py b/tests/unit/components/test_schema.py index c17df2ff4..689e49bc4 100644 --- a/tests/unit/components/test_schema.py +++ b/tests/unit/components/test_schema.py @@ -2455,7 +2455,9 @@ def test_extract_graph_constraints_from_metadata_relationship_uniqueness_maps_to def test_graph_schema_extraction_output_json_schema_lean_root() -> None: """Structured-output schema must not include pipeline-only GraphSchema flags.""" - from neo4j_graphrag.components.graph_schema_extraction import GraphSchemaExtractionOutput + from neo4j_graphrag.components.graph_schema_extraction import ( + GraphSchemaExtractionOutput, + ) raw = GraphSchemaExtractionOutput.model_json_schema() dumped = json.dumps(raw) @@ -2468,7 +2470,9 @@ def test_graph_schema_extraction_constraint_schema_avoids_null_type_for_vertex() None ): """Vertex AI maps JSON Schema to protobuf and rejects ``type: \"null\"`` (e.g. ``Optional``).""" - from neo4j_graphrag.components.graph_schema_extraction import GraphSchemaExtractionOutput + from neo4j_graphrag.components.graph_schema_extraction import ( + GraphSchemaExtractionOutput, + ) raw = GraphSchemaExtractionOutput.model_json_schema() ect = (raw.get("$defs") or {}).get("ExtractedConstraintType") diff --git a/tests/unit/components/text_splitters/test_llamaindex.py b/tests/unit/components/text_splitters/test_llamaindex.py index 8d7df28f6..f1cf0793a 100644 --- a/tests/unit/components/text_splitters/test_llamaindex.py +++ b/tests/unit/components/text_splitters/test_llamaindex.py @@ -14,7 +14,9 @@ # limitations under the License. import pytest from llama_index.core.node_parser.text.sentence import SentenceSplitter -from neo4j_graphrag.components.text_splitters.llamaindex import LlamaIndexTextSplitterAdapter +from neo4j_graphrag.components.text_splitters.llamaindex import ( + LlamaIndexTextSplitterAdapter, +) from neo4j_graphrag.components.types import ( TextChunk, TextChunks, diff --git a/tests/unit/experimental/pipeline/config/template_pipeline/test_simple_kg_builder.py b/tests/unit/experimental/pipeline/config/template_pipeline/test_simple_kg_builder.py index 3a4dbc551..0a863f56c 100644 --- a/tests/unit/experimental/pipeline/config/template_pipeline/test_simple_kg_builder.py +++ b/tests/unit/experimental/pipeline/config/template_pipeline/test_simple_kg_builder.py @@ -33,7 +33,9 @@ SchemaFromTextExtractor, GraphSchema, ) -from neo4j_graphrag.components.text_splitters.fixed_size_splitter import FixedSizeSplitter +from neo4j_graphrag.components.text_splitters.fixed_size_splitter import ( + FixedSizeSplitter, +) from neo4j_graphrag.experimental.pipeline.config.object_config import ( ComponentConfig, ComponentType, @@ -68,9 +70,7 @@ async def test_simple_kg_pipeline_config_default_file_loader_supports_markdown() config = SimpleKGPipelineConfig(from_file=True) loader = config._get_file_loader() assert loader is not None - doc = await loader.run( - filepath="tests/unit/components/sample_data/hello.md" - ) + doc = await loader.run(filepath="tests/unit/components/sample_data/hello.md") assert doc.document_info.document_type == DocumentType.MARKDOWN From 24e94bbe23caa99072820c63c3145a841f51bbfb Mon Sep 17 00:00:00 2001 From: estelle Date: Tue, 7 Jul 2026 15:33:58 +0200 Subject: [PATCH 03/14] Refactor e2e tests --- tests/e2e/components_e2e/__init__.py | 0 .../test_entity_resolver_component_e2e.py | 0 .../test_graph_pruning_component_e2e.py | 0 .../test_kg_writer_component_e2e.py | 0 .../test_lexical_graph_builder_component_e2e.py | 0 .../test_neo4j_reader_component_e2e.py | 0 6 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/e2e/components_e2e/__init__.py rename tests/e2e/{experimental => components_e2e}/test_entity_resolver_component_e2e.py (100%) rename tests/e2e/{experimental => components_e2e}/test_graph_pruning_component_e2e.py (100%) rename tests/e2e/{experimental => components_e2e}/test_kg_writer_component_e2e.py (100%) rename tests/e2e/{experimental => components_e2e}/test_lexical_graph_builder_component_e2e.py (100%) rename tests/e2e/{experimental => components_e2e}/test_neo4j_reader_component_e2e.py (100%) diff --git a/tests/e2e/components_e2e/__init__.py b/tests/e2e/components_e2e/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/e2e/experimental/test_entity_resolver_component_e2e.py b/tests/e2e/components_e2e/test_entity_resolver_component_e2e.py similarity index 100% rename from tests/e2e/experimental/test_entity_resolver_component_e2e.py rename to tests/e2e/components_e2e/test_entity_resolver_component_e2e.py diff --git a/tests/e2e/experimental/test_graph_pruning_component_e2e.py b/tests/e2e/components_e2e/test_graph_pruning_component_e2e.py similarity index 100% rename from tests/e2e/experimental/test_graph_pruning_component_e2e.py rename to tests/e2e/components_e2e/test_graph_pruning_component_e2e.py diff --git a/tests/e2e/experimental/test_kg_writer_component_e2e.py b/tests/e2e/components_e2e/test_kg_writer_component_e2e.py similarity index 100% rename from tests/e2e/experimental/test_kg_writer_component_e2e.py rename to tests/e2e/components_e2e/test_kg_writer_component_e2e.py diff --git a/tests/e2e/experimental/test_lexical_graph_builder_component_e2e.py b/tests/e2e/components_e2e/test_lexical_graph_builder_component_e2e.py similarity index 100% rename from tests/e2e/experimental/test_lexical_graph_builder_component_e2e.py rename to tests/e2e/components_e2e/test_lexical_graph_builder_component_e2e.py diff --git a/tests/e2e/experimental/test_neo4j_reader_component_e2e.py b/tests/e2e/components_e2e/test_neo4j_reader_component_e2e.py similarity index 100% rename from tests/e2e/experimental/test_neo4j_reader_component_e2e.py rename to tests/e2e/components_e2e/test_neo4j_reader_component_e2e.py From 93da63d12987abaf7dc6e53afa912a06dc071b4d Mon Sep 17 00:00:00 2001 From: estelle Date: Tue, 7 Jul 2026 15:43:25 +0200 Subject: [PATCH 04/14] Update documentation --- docs/source/api.rst | 40 +++++++-------- docs/source/types.rst | 34 ++++++------- docs/source/user_guide_kg_builder.rst | 70 +++++++++++++-------------- docs/source/user_guide_pipeline.rst | 8 +-- 4 files changed, 76 insertions(+), 76 deletions(-) diff --git a/docs/source/api.rst b/docs/source/api.rst index 069d21ffe..b2e7be894 100644 --- a/docs/source/api.rst +++ b/docs/source/api.rst @@ -12,81 +12,81 @@ Components Component ========= -.. autoclass:: neo4j_graphrag.experimental.pipeline.component.Component +.. autoclass:: neo4j_graphrag.components.base.Component :members: run, run_with_context DataLoader ========== -.. autoclass:: neo4j_graphrag.experimental.components.data_loader.DataLoader +.. autoclass:: neo4j_graphrag.components.data_loader.DataLoader :members: run, get_document_metadata PdfLoader ========= -.. autoclass:: neo4j_graphrag.experimental.components.data_loader.PdfLoader +.. autoclass:: neo4j_graphrag.components.data_loader.PdfLoader :members: run, load_file MarkdownLoader ============== -.. autoclass:: neo4j_graphrag.experimental.components.data_loader.MarkdownLoader +.. autoclass:: neo4j_graphrag.components.data_loader.MarkdownLoader :members: run, load_file TextSplitter ============ -.. autoclass:: neo4j_graphrag.experimental.components.text_splitters.base.TextSplitter +.. autoclass:: neo4j_graphrag.components.text_splitters.base.TextSplitter :members: run FixedSizeSplitter ================= -.. autoclass:: neo4j_graphrag.experimental.components.text_splitters.fixed_size_splitter.FixedSizeSplitter +.. autoclass:: neo4j_graphrag.components.text_splitters.fixed_size_splitter.FixedSizeSplitter :members: run LangChainTextSplitterAdapter ============================ -.. autoclass:: neo4j_graphrag.experimental.components.text_splitters.langchain.LangChainTextSplitterAdapter +.. autoclass:: neo4j_graphrag.components.text_splitters.langchain.LangChainTextSplitterAdapter :members: run LlamaIndexTextSplitterAdapter ============================= -.. autoclass:: neo4j_graphrag.experimental.components.text_splitters.llamaindex.LlamaIndexTextSplitterAdapter +.. autoclass:: neo4j_graphrag.components.text_splitters.llamaindex.LlamaIndexTextSplitterAdapter :members: run TextChunkEmbedder ================= -.. autoclass:: neo4j_graphrag.experimental.components.embedder.TextChunkEmbedder +.. autoclass:: neo4j_graphrag.components.embedder.TextChunkEmbedder :members: run LexicalGraphBuilder =================== -.. autoclass:: neo4j_graphrag.experimental.components.lexical_graph.LexicalGraphBuilder +.. autoclass:: neo4j_graphrag.components.lexical_graph.LexicalGraphBuilder :members: :exclude-members: component_inputs, component_outputs Neo4jChunkReader ================ -.. autoclass:: neo4j_graphrag.experimental.components.neo4j_reader.Neo4jChunkReader +.. autoclass:: neo4j_graphrag.components.neo4j_reader.Neo4jChunkReader :members: :exclude-members: component_inputs, component_outputs SchemaBuilder ============= -.. autoclass:: neo4j_graphrag.experimental.components.schema.SchemaBuilder +.. autoclass:: neo4j_graphrag.components.schema.SchemaBuilder :members: run SchemaFromTextExtractor ----------------------- -.. autoclass:: neo4j_graphrag.experimental.components.schema.SchemaFromTextExtractor +.. autoclass:: neo4j_graphrag.components.schema.SchemaFromTextExtractor :members: run schema_visualization @@ -98,44 +98,44 @@ schema_visualization EntityRelationExtractor ======================= -.. autoclass:: neo4j_graphrag.experimental.components.entity_relation_extractor.EntityRelationExtractor +.. autoclass:: neo4j_graphrag.components.entity_relation_extractor.EntityRelationExtractor :members: :exclude-members: component_inputs, component_outputs LLMEntityRelationExtractor ========================== -.. autoclass:: neo4j_graphrag.experimental.components.entity_relation_extractor.LLMEntityRelationExtractor +.. autoclass:: neo4j_graphrag.components.entity_relation_extractor.LLMEntityRelationExtractor :members: run KGWriter ======== -.. autoclass:: neo4j_graphrag.experimental.components.kg_writer.KGWriter +.. autoclass:: neo4j_graphrag.components.kg_writer.KGWriter :members: run Neo4jWriter =========== -.. autoclass:: neo4j_graphrag.experimental.components.kg_writer.Neo4jWriter +.. autoclass:: neo4j_graphrag.components.kg_writer.Neo4jWriter :members: run SinglePropertyExactMatchResolver ================================ -.. autoclass:: neo4j_graphrag.experimental.components.resolver.SinglePropertyExactMatchResolver +.. autoclass:: neo4j_graphrag.components.resolver.SinglePropertyExactMatchResolver :members: run SpaCySemanticMatchResolver ========================== -.. autoclass:: neo4j_graphrag.experimental.components.resolver.SpaCySemanticMatchResolver +.. autoclass:: neo4j_graphrag.components.resolver.SpaCySemanticMatchResolver :members: run FuzzyMatchResolver ================== -.. autoclass:: neo4j_graphrag.experimental.components.resolver.FuzzyMatchResolver +.. autoclass:: neo4j_graphrag.components.resolver.FuzzyMatchResolver :members: run .. _pipeline-section: diff --git a/docs/source/types.rst b/docs/source/types.rst index 52b119dff..96669aa7b 100644 --- a/docs/source/types.rst +++ b/docs/source/types.rst @@ -48,88 +48,88 @@ RagResultModel DocumentInfo ============ -.. autoclass:: neo4j_graphrag.experimental.components.types.DocumentInfo +.. autoclass:: neo4j_graphrag.components.types.DocumentInfo LoadedDocument ============== -.. autoclass:: neo4j_graphrag.experimental.components.types.LoadedDocument +.. autoclass:: neo4j_graphrag.components.types.LoadedDocument TextChunk ========= -.. autoclass:: neo4j_graphrag.experimental.components.types.TextChunk +.. autoclass:: neo4j_graphrag.components.types.TextChunk TextChunks ========== -.. autoclass:: neo4j_graphrag.experimental.components.types.TextChunks +.. autoclass:: neo4j_graphrag.components.types.TextChunks Neo4jNode ========= -.. autoclass:: neo4j_graphrag.experimental.components.types.Neo4jNode +.. autoclass:: neo4j_graphrag.components.types.Neo4jNode Neo4jRelationship ================= -.. autoclass:: neo4j_graphrag.experimental.components.types.Neo4jRelationship +.. autoclass:: neo4j_graphrag.components.types.Neo4jRelationship Neo4jGraph ========== -.. autoclass:: neo4j_graphrag.experimental.components.types.Neo4jGraph +.. autoclass:: neo4j_graphrag.components.types.Neo4jGraph GeoPoint ======== -.. autoclass:: neo4j_graphrag.experimental.components.types.GeoPoint +.. autoclass:: neo4j_graphrag.components.types.GeoPoint KGWriterModel ============= -.. autoclass:: neo4j_graphrag.experimental.components.kg_writer.KGWriterModel +.. autoclass:: neo4j_graphrag.components.kg_writer.KGWriterModel PropertyType ============ -.. autoclass:: neo4j_graphrag.experimental.components.schema.PropertyType +.. autoclass:: neo4j_graphrag.components.schema.PropertyType NodeType ======== -.. autoclass:: neo4j_graphrag.experimental.components.schema.NodeType +.. autoclass:: neo4j_graphrag.components.schema.NodeType RelationshipType ================ -.. autoclass:: neo4j_graphrag.experimental.components.schema.RelationshipType +.. autoclass:: neo4j_graphrag.components.schema.RelationshipType Pattern ======= -.. autoclass:: neo4j_graphrag.experimental.components.schema.Pattern +.. autoclass:: neo4j_graphrag.components.schema.Pattern GraphConstraintType ===================== -.. autoclass:: neo4j_graphrag.experimental.components.schema.GraphConstraintType +.. autoclass:: neo4j_graphrag.components.schema.GraphConstraintType ConstraintType ================ -.. autoclass:: neo4j_graphrag.experimental.components.schema.ConstraintType +.. autoclass:: neo4j_graphrag.components.schema.ConstraintType GraphSchema =========== -.. autoclass:: neo4j_graphrag.experimental.components.schema.GraphSchema +.. autoclass:: neo4j_graphrag.components.schema.GraphSchema LexicalGraphConfig =================== -.. autoclass:: neo4j_graphrag.experimental.components.types.LexicalGraphConfig +.. autoclass:: neo4j_graphrag.components.types.LexicalGraphConfig Neo4jDriverType diff --git a/docs/source/user_guide_kg_builder.rst b/docs/source/user_guide_kg_builder.rst index 4a69ac334..a4a0cbdc3 100644 --- a/docs/source/user_guide_kg_builder.rst +++ b/docs/source/user_guide_kg_builder.rst @@ -227,7 +227,7 @@ chunk overlap in the text splitter component: .. code:: python - from neo4j_graphrag.experimental.components.text_splitters.fixed_size_splitter import ( + from neo4j_graphrag.components.text_splitters.fixed_size_splitter import ( FixedSizeSplitter, ) @@ -566,7 +566,7 @@ The YAML equivalent: chunk_size: 100 chunk_overlap: 10 -The `neo4j_graphrag.experimental.components` prefix will be appended automatically +The `neo4j_graphrag.components` prefix will be appended automatically if needed. @@ -581,7 +581,7 @@ Each of these components can be run individually: .. code:: python import asyncio - from neo4j_graphrag.experimental.components.data_loader import PdfLoader + from neo4j_graphrag.components.data_loader import PdfLoader my_component = PdfLoader() asyncio.run(my_component.run("my_file.pdf")) @@ -591,7 +591,7 @@ They can also be used within a pipeline: .. code:: python from neo4j_graphrag.experimental.pipeline import Pipeline - from neo4j_graphrag.experimental.components.data_loader import PdfLoader + from neo4j_graphrag.components.data_loader import PdfLoader pipeline = Pipeline() my_component = PdfLoader() pipeline.add_component(my_component, "component_name") @@ -607,7 +607,7 @@ This package currently supports text extraction from PDFs: .. code:: python from pathlib import Path - from neo4j_graphrag.experimental.components.data_loader import PdfLoader + from neo4j_graphrag.components.data_loader import PdfLoader loader = PdfLoader() await loader.run(filepath=Path("my_file.pdf")) @@ -617,8 +617,8 @@ To implement your own loader, use the `DataLoader` interface: .. code:: python from pathlib import Path - from neo4j_graphrag.experimental.components.data_loader import DataLoader - from neo4j_graphrag.experimental.components.types import LoadedDocument + from neo4j_graphrag.components.data_loader import DataLoader + from neo4j_graphrag.components.types import LoadedDocument class MyDataLoader(DataLoader): async def run(self, filepath: Path, metadata: Optional[Dict[str, str]] = None) -> LoadedDocument: @@ -641,7 +641,7 @@ that can be processed within the LLM token limits: .. code:: python - from neo4j_graphrag.experimental.components.text_splitters.fixed_size_splitter import FixedSizeSplitter + from neo4j_graphrag.components.text_splitters.fixed_size_splitter import FixedSizeSplitter splitter = FixedSizeSplitter(chunk_size=4000, chunk_overlap=200, approximate=False) splitter.run(text="Hello World. Life is beautiful.") @@ -655,7 +655,7 @@ Wrappers for LangChain and LlamaIndex text splitters are included in this packag .. code:: python from langchain_text_splitters import CharacterTextSplitter - from neo4j_graphrag.experimental.components.text_splitters.langchain import LangChainTextSplitterAdapter + from neo4j_graphrag.components.text_splitters.langchain import LangChainTextSplitterAdapter splitter = LangChainTextSplitterAdapter( CharacterTextSplitter(chunk_size=4000, chunk_overlap=200, separator=".") ) @@ -668,8 +668,8 @@ To implement a custom text splitter, the `TextSplitter` interface can be used: .. code:: python - from neo4j_graphrag.experimental.components.text_splitters.base import TextSplitter - from neo4j_graphrag.experimental.components.types import TextChunks, TextChunk + from neo4j_graphrag.components.text_splitters.base import TextSplitter + from neo4j_graphrag.components.types import TextChunks, TextChunk class MyTextSplitter(TextSplitter): @@ -696,7 +696,7 @@ Example usage: .. code:: python - from neo4j_graphrag.experimental.components.embedder import TextChunkEmbedder + from neo4j_graphrag.components.embedder import TextChunkEmbedder from neo4j_graphrag.embeddings.openai import OpenAIEmbeddings text_chunk_embedder = TextChunkEmbedder(embedder=OpenAIEmbeddings()) await text_chunk_embedder.run(text_chunks=TextChunks(chunks=[TextChunk(text="my_text")])) @@ -734,8 +734,8 @@ Example usage: .. code:: python - from neo4j_graphrag.experimental.pipeline.components.lexical_graph_builder import LexicalGraphBuilder - from neo4j_graphrag.experimental.pipeline.components.types import LexicalGraphConfig + from neo4j_graphrag.components.lexical_graph_builder import LexicalGraphBuilder + from neo4j_graphrag.components.types import LexicalGraphConfig lexical_graph_builder = LexicalGraphBuilder(config=LexicalGraphConfig()) graph = await lexical_graph_builder.run( @@ -758,8 +758,8 @@ by the lexical graph builder or another process. .. code:: python import neo4j - from neo4j_graphrag.experimental.components.neo4j_reader import Neo4jChunkReader - from neo4j_graphrag.experimental.components.types import LexicalGraphConfig + from neo4j_graphrag.components.neo4j_reader import Neo4jChunkReader + from neo4j_graphrag.components.types import LexicalGraphConfig reader = Neo4jChunkReader(driver) result = await reader.run() @@ -772,8 +772,8 @@ Optionally, the document and chunk node labels can be configured using a `Lexica .. code:: python - from neo4j_graphrag.experimental.components.neo4j_reader import Neo4jChunkReader - from neo4j_graphrag.experimental.components.types import LexicalGraphConfig, TextChunks + from neo4j_graphrag.components.neo4j_reader import Neo4jChunkReader + from neo4j_graphrag.components.types import LexicalGraphConfig, TextChunks # optionally, define a LexicalGraphConfig object # shown below with the default values @@ -803,7 +803,7 @@ Here is a code block illustrating these concepts: .. code:: python - from neo4j_graphrag.experimental.components.schema import ( + from neo4j_graphrag.components.schema import ( SchemaBuilder, NodeType, PropertyType, @@ -854,7 +854,7 @@ Instead of manually defining the schema, you can use the `SchemaFromTextExtracto .. code:: python - from neo4j_graphrag.experimental.components.schema import SchemaFromTextExtractor + from neo4j_graphrag.components.schema import SchemaFromTextExtractor from neo4j_graphrag.llm import OpenAILLM # Instantiate the automatic schema extractor component @@ -882,18 +882,18 @@ You can also save and reload the extracted schema: extracted_schema.save("my_schema.yaml") # Later, reload the schema from file - from neo4j_graphrag.experimental.components.schema import GraphSchema + from neo4j_graphrag.components.schema import GraphSchema restored_schema = GraphSchema.from_file("my_schema.json") # or my_schema.yaml Using Structured Output with Schema Extraction ----------------------------------------------- -For improved reliability with :ref:`OpenAILLM `, :ref:`VertexAILLM ` or :ref:`AnthropicLLM `, enable structured output mode. When ``use_structured_output=True``, the extractor passes the lean ``GraphSchemaExtractionOutput`` Pydantic model as ``response_format`` to the LLM; the response is validated and converted to a :class:`~neo4j_graphrag.experimental.components.schema.GraphSchema` for the rest of the pipeline: +For improved reliability with :ref:`OpenAILLM `, :ref:`VertexAILLM ` or :ref:`AnthropicLLM `, enable structured output mode. When ``use_structured_output=True``, the extractor passes the lean ``GraphSchemaExtractionOutput`` Pydantic model as ``response_format`` to the LLM; the response is validated and converted to a :class:`~neo4j_graphrag.components.schema.GraphSchema` for the rest of the pipeline: .. code:: python - from neo4j_graphrag.experimental.components.schema import SchemaFromTextExtractor + from neo4j_graphrag.components.schema import SchemaFromTextExtractor from neo4j_graphrag.llm import OpenAILLM llm = OpenAILLM(model_name="gpt-5-mini", model_params={"temperature": 0}) @@ -901,7 +901,7 @@ For improved reliability with :ref:`OpenAILLM `, :ref:`VertexAILLM `, :ref .. code:: python - from neo4j_graphrag.experimental.components.entity_relation_extractor import ( + from neo4j_graphrag.components.entity_relation_extractor import ( LLMEntityRelationExtractor, ) from neo4j_graphrag.llm import OpenAILLM @@ -1037,7 +1037,7 @@ This behaviour can be changed by using the `on_error` flag in the `LLMEntityRela .. code:: python - from neo4j_graphrag.experimental.components.entity_relation_extractor import ( + from neo4j_graphrag.components.entity_relation_extractor import ( LLMEntityRelationExtractor, OnError, ) @@ -1109,8 +1109,8 @@ If more customization is needed, it is possible to subclass the `EntityRelationE .. code:: python from pydantic import validate_call - from neo4j_graphrag.experimental.components.entity_relation_extractor import EntityRelationExtractor - from neo4j_graphrag.experimental.components.types import ( + from neo4j_graphrag.components.entity_relation_extractor import EntityRelationExtractor + from neo4j_graphrag.components.types import ( Neo4jGraph, Neo4jNode, Neo4jRelationship, @@ -1216,8 +1216,8 @@ to a Neo4j database: .. code:: python import neo4j - from neo4j_graphrag.experimental.components.kg_writer import Neo4jWriter - from neo4j_graphrag.experimental.components.types import Neo4jGraph + from neo4j_graphrag.components.kg_writer import Neo4jWriter + from neo4j_graphrag.components.types import Neo4jGraph with neo4j.GraphDatabase.driver( "bolt://localhost:7687", auth=("neo4j", "password") @@ -1243,7 +1243,7 @@ It is possible to create a custom writer using the `KGWriter` interface: import json from pydantic import validate_call - from neo4j_graphrag.experimental.components.kg_writer import KGWriter + from neo4j_graphrag.components.kg_writer import KGWriter class JsonWriter(KGWriter): @@ -1295,7 +1295,7 @@ The resolvers can be used like this: .. code:: python - from neo4j_graphrag.experimental.components.resolver import ( + from neo4j_graphrag.components.resolver import ( SinglePropertyExactMatchResolver, # SpaCySemanticMatchResolver, # FuzzyMatchResolver, @@ -1319,7 +1319,7 @@ in the graph, these entities can be excluded with the following approach: .. code:: python - from neo4j_graphrag.experimental.components.resolver import ( + from neo4j_graphrag.components.resolver import ( SinglePropertyExactMatchResolver, ) filter_query = "WHERE NOT entity:Resolved" diff --git a/docs/source/user_guide_pipeline.rst b/docs/source/user_guide_pipeline.rst index bdf4435f0..fa4fb768a 100644 --- a/docs/source/user_guide_pipeline.rst +++ b/docs/source/user_guide_pipeline.rst @@ -20,8 +20,8 @@ such as chunking documents or saving results to Neo4j. This package includes a few default components, but developers can create their own by following these steps: -1. Create a subclass of the Pydantic `neo4j_graphrag.experimental.pipeline.DataModel` to represent the data being returned by the component -2. Create a subclass of `neo4j_graphrag.experimental.pipeline.Component` +1. Create a subclass of the Pydantic `neo4j_graphrag.components.base.DataModel` to represent the data being returned by the component +2. Create a subclass of `neo4j_graphrag.components.base.Component` 3. Create a `run` method in this new class and specify the required inputs and output model using the just created `DataModel` 4. Implement the run method: it's an `async` method, allowing tasks to be parallelized and awaited within this method. @@ -30,7 +30,7 @@ the resulting sum: .. code:: python - from neo4j_graphrag.experimental.pipeline import Component, DataModel + from neo4j_graphrag.components.base import Component, DataModel class IntResultModel(DataModel): result: int @@ -127,7 +127,7 @@ can be added to the visualization by setting `hide_unused_outputs` to `False`: .. code:: python pipe.draw("pipeline_full.html", hide_unused_outputs=False) - + # To view the full visualization in a browser import webbrowser webbrowser.open("pipeline_full.html") From e07af19176ab71292982a9c0c7b62f6d8993d58a Mon Sep 17 00:00:00 2001 From: estelle Date: Tue, 7 Jul 2026 16:07:36 +0200 Subject: [PATCH 05/14] mypy --- .../pipeline/pipeline_with_component_notifications.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/customize/build_graph/pipeline/pipeline_with_component_notifications.py b/examples/customize/build_graph/pipeline/pipeline_with_component_notifications.py index 3fe5bf16e..646d5e9d4 100644 --- a/examples/customize/build_graph/pipeline/pipeline_with_component_notifications.py +++ b/examples/customize/build_graph/pipeline/pipeline_with_component_notifications.py @@ -8,7 +8,8 @@ import logging from typing import Any -from neo4j_graphrag.experimental.pipeline import Pipeline, Component, DataModel +from neo4j_graphrag.experimental.pipeline import Pipeline +from neo4j_graphrag.components.base import Component, DataModel from neo4j_graphrag.experimental.pipeline.notification import Event, EventType from neo4j_graphrag.experimental.pipeline.types.context import RunContext From 47d4b4bda7d79c2fb8397b97a2713863d431ea4d Mon Sep 17 00:00:00 2001 From: estelle Date: Tue, 7 Jul 2026 16:16:34 +0200 Subject: [PATCH 06/14] Fix after rebase --- tests/unit/llm/test_anthropic_llm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/llm/test_anthropic_llm.py b/tests/unit/llm/test_anthropic_llm.py index 113fd3637..8c7c2a3ee 100644 --- a/tests/unit/llm/test_anthropic_llm.py +++ b/tests/unit/llm/test_anthropic_llm.py @@ -21,7 +21,7 @@ import anthropic import pytest from neo4j_graphrag.exceptions import LLMGenerationError -from neo4j_graphrag.experimental.components.types import Neo4jGraph +from neo4j_graphrag.components.types import Neo4jGraph from neo4j_graphrag.llm.anthropic_llm import ( AnthropicLLM, _is_open_map, From 3dedfc5873a0ba2948444c07bf32d7b90eb07e1a Mon Sep 17 00:00:00 2001 From: estelle Date: Wed, 15 Jul 2026 15:59:50 +0200 Subject: [PATCH 07/14] Fix changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bd4e09f98..01fb04834 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,7 @@ - Import from the experimental namespace will be removed in 2.0 - Update to use `from neo4j_graphrag.components... ` instead - Improperly defined components now raise a `ComponentDefinitionError` instead of `PipelineDefinitionError` - - `TaskProgressNotifier` and `RunContext` have been moved to `neo4j_graphrag.components.base` + - `TaskProgressNotifierProtocol` and `RunContext` have been moved to `neo4j_graphrag.components.base` - The `Component` base class has been moved to `neo4j_graphrag.components.base` From 5f35a7b5364d74fadc220a2b9cf7e04a21dd1349 Mon Sep 17 00:00:00 2001 From: estelle Date: Thu, 16 Jul 2026 09:43:56 +0200 Subject: [PATCH 08/14] Change logic for backward compatible import --- .../experimental/components/__init__.py | 124 ++++++++++++++---- .../components/test_backward_compat.py | 86 ++++++++++++ 2 files changed, 184 insertions(+), 26 deletions(-) create mode 100644 tests/unit/experimental/components/test_backward_compat.py diff --git a/src/neo4j_graphrag/experimental/components/__init__.py b/src/neo4j_graphrag/experimental/components/__init__.py index 505ccd332..b1d05b0f0 100644 --- a/src/neo4j_graphrag/experimental/components/__init__.py +++ b/src/neo4j_graphrag/experimental/components/__init__.py @@ -12,30 +12,102 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -import warnings +"""Backward-compatibility shim. + +Components have moved from ``neo4j_graphrag.experimental.components`` to +``neo4j_graphrag.components``. To keep old imports such as:: + + from neo4j_graphrag.experimental.components.types import LexicalGraphConfig + +working, the meta path finder registered below intercepts any +``neo4j_graphrag.experimental.components.*`` import, strips ``experimental`` from +the path, and — *if* the module exists at its new location — redirects to it +(with a :class:`DeprecationWarning`). The *same* module object is aliased under +both names, so it is not re-executed and ``isinstance`` checks hold across paths. + +Modules that do **not** exist under ``neo4j_graphrag.components`` are left alone, +so components that only ever live in the experimental namespace keep loading from +here. Use ``_EXPERIMENTAL_ONLY`` to additionally force a component to load from +the experimental namespace even when a same-named module exists outside it. +""" import importlib -from typing import Any - - -def __getattr__(name: str) -> Any: - warnings.warn( - f"Importing component {name} from the experimental namespace is deprecated and will be removed in version `2.0`. Use `from neo4j_graphrag.components... import ...` instead.", - DeprecationWarning, - stacklevel=2, - ) - try: - print(name) - module_split = name.rsplit(".", 1) - module_name = "neo4j_graphrag.components" - if len(module_split) == 1: - klass_name = module_split[0] - else: - module_name = module_name + "." + module_split[0] - klass_name = module_split[1] - print(module_split, module_name, klass_name) - module = importlib.import_module(module_name) - klass = getattr(module, klass_name) - return klass - except (ImportError, AttributeError) as e: - print(e) - raise +import importlib.abc +import importlib.util +import sys +import warnings +from importlib.machinery import ModuleSpec +from types import ModuleType +from typing import Optional, Sequence + +_PKG = __name__ # "neo4j_graphrag.experimental.components" + +#: Top-level submodule names under this package that must always be loaded from +#: the experimental namespace, never redirected — e.g. a new component that only +#: exists in experimental but happens to share a name with one outside it. +_EXPERIMENTAL_ONLY: set[str] = set() + + +class I (importlib.abc.Loader): + """Aliases the module from its new location under the old (experimental) name. + + The exact same module object is shared under both names, so it is neither + copied nor re-executed. + """ + + def __init__(self, new_name: str) -> None: + self._new_name = new_name + + def create_module(self, spec: ModuleSpec) -> ModuleType: + # Return the already-loaded module from its new location. The import + # machinery then registers *this same object* under the old name + # (sys.modules[spec.name] = module), so both names alias one object. + return importlib.import_module(self._new_name) + + def exec_module(self, module: ModuleType) -> None: + # No-op: the module was executed once at its new location. A normal + # source loader would re-run the file here — that would *copy* it. + pass + + +class _ComponentsRedirectFinder(importlib.abc.MetaPathFinder): + """Redirects ``experimental.components.*`` to ``components.*`` when it moved.""" + + def find_spec( + self, + fullname: str, + path: Optional[Sequence[str]] = None, + target: Optional[ModuleType] = None, + ) -> Optional[ModuleSpec]: + # Only intercept submodules of this package, never the package itself + # (its real __path__ must keep pointing here so experimental-only + # components remain importable). + if not fullname.startswith(_PKG + "."): + return None + + top_level = fullname[len(_PKG) + 1 :].split(".", 1)[0] + if top_level in _EXPERIMENTAL_ONLY: + return None + + # Strip "experimental" from the path and try to import from there. + new_name = fullname.replace(".experimental", "", 1) + try: + moved = importlib.util.find_spec(new_name) is not None + except ModuleNotFoundError: + moved = False + if not moved: + # Not moved: let the normal machinery load it from experimental. + return None + + warnings.warn( + f"'{fullname}' has moved to '{new_name}'. Importing from the " + "'neo4j_graphrag.experimental.components' namespace is deprecated and " + "will be removed in version 2.0.", + DeprecationWarning, + stacklevel=2, + ) + return importlib.util.spec_from_loader(fullname, I(new_name)) + + +# Register the finder ahead of the default path-based finders, but only once. +if not any(isinstance(f, _ComponentsRedirectFinder) for f in sys.meta_path): + sys.meta_path.insert(0, _ComponentsRedirectFinder()) diff --git a/tests/unit/experimental/components/test_backward_compat.py b/tests/unit/experimental/components/test_backward_compat.py new file mode 100644 index 000000000..f07545631 --- /dev/null +++ b/tests/unit/experimental/components/test_backward_compat.py @@ -0,0 +1,86 @@ +# Copyright (c) "Neo4j" +# Neo4j Sweden AB [https://neo4j.com] +# # +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# # +# https://www.apache.org/licenses/LICENSE-2.0 +# # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Backward-compatibility tests for the moved ``components`` namespace. + +Components moved from ``neo4j_graphrag.experimental.components`` to +``neo4j_graphrag.components``; the old import paths must keep working (with a +``DeprecationWarning``) via the meta path finder in +``neo4j_graphrag/experimental/components/__init__.py``. +""" +import importlib +import warnings + +import pytest + + +def test_old_import_path_redirects_to_new_module() -> None: + with pytest.warns(DeprecationWarning, match="has moved to"): + from neo4j_graphrag.experimental.components.types import ( + LexicalGraphConfig as OldLexicalGraphConfig, + ) + + from neo4j_graphrag.components.types import LexicalGraphConfig + + # Same object under both paths: not a copy, identity/isinstance hold. + assert OldLexicalGraphConfig is LexicalGraphConfig + + +def test_nested_subpackage_redirects() -> None: + with pytest.warns(DeprecationWarning, match="has moved to"): + from neo4j_graphrag.experimental.components.text_splitters.fixed_size_splitter import ( # noqa: E501 + FixedSizeSplitter as OldSplitter, + ) + + from neo4j_graphrag.components.text_splitters.fixed_size_splitter import ( + FixedSizeSplitter, + ) + + assert OldSplitter is FixedSizeSplitter + + +def test_import_module_form_shares_the_same_module() -> None: + with pytest.warns(DeprecationWarning, match="has moved to"): + old = importlib.import_module( + "neo4j_graphrag.experimental.components.kg_writer" + ) + new = importlib.import_module("neo4j_graphrag.components.kg_writer") + + assert old is new + + +def test_experimental_only_module_loads_without_redirect() -> None: + """A module that only exists in experimental keeps loading from there.""" + import os + + import neo4j_graphrag.experimental.components as exp_components + + pkg_dir = exp_components.__path__[0] + marker_file = os.path.join(pkg_dir, "_only_here_test_module.py") + with open(marker_file, "w") as f: + f.write("MARKER = 'from experimental'\n") + + try: + with warnings.catch_warnings(): + warnings.simplefilter("error", DeprecationWarning) + module = importlib.import_module( + "neo4j_graphrag.experimental.components._only_here_test_module" + ) + assert module.MARKER == "from experimental" + assert ( + module.__name__ + == "neo4j_graphrag.experimental.components._only_here_test_module" + ) + finally: + os.remove(marker_file) From 07357926b0d78c4e7af1c1c24a68e0ab07d268c6 Mon Sep 17 00:00:00 2001 From: estelle Date: Thu, 16 Jul 2026 09:46:06 +0200 Subject: [PATCH 09/14] Ruff --- src/neo4j_graphrag/experimental/components/__init__.py | 3 ++- tests/unit/experimental/components/test_backward_compat.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/neo4j_graphrag/experimental/components/__init__.py b/src/neo4j_graphrag/experimental/components/__init__.py index b1d05b0f0..db58e5d7c 100644 --- a/src/neo4j_graphrag/experimental/components/__init__.py +++ b/src/neo4j_graphrag/experimental/components/__init__.py @@ -30,6 +30,7 @@ here. Use ``_EXPERIMENTAL_ONLY`` to additionally force a component to load from the experimental namespace even when a same-named module exists outside it. """ + import importlib import importlib.abc import importlib.util @@ -47,7 +48,7 @@ _EXPERIMENTAL_ONLY: set[str] = set() -class I (importlib.abc.Loader): +class I(importlib.abc.Loader): """Aliases the module from its new location under the old (experimental) name. The exact same module object is shared under both names, so it is neither diff --git a/tests/unit/experimental/components/test_backward_compat.py b/tests/unit/experimental/components/test_backward_compat.py index f07545631..133dbd990 100644 --- a/tests/unit/experimental/components/test_backward_compat.py +++ b/tests/unit/experimental/components/test_backward_compat.py @@ -19,6 +19,7 @@ ``DeprecationWarning``) via the meta path finder in ``neo4j_graphrag/experimental/components/__init__.py``. """ + import importlib import warnings From 40664720474fbb1eae9ae9fb716c1e5b601357e1 Mon Sep 17 00:00:00 2001 From: estelle Date: Thu, 16 Jul 2026 14:15:20 +0200 Subject: [PATCH 10/14] Deprecation warning for old Component/Datamodel imports --- .../experimental/pipeline/__init__.py | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/neo4j_graphrag/experimental/pipeline/__init__.py b/src/neo4j_graphrag/experimental/pipeline/__init__.py index 1b8e4a373..eaa073643 100644 --- a/src/neo4j_graphrag/experimental/pipeline/__init__.py +++ b/src/neo4j_graphrag/experimental/pipeline/__init__.py @@ -12,6 +12,9 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +import warnings +from typing import Any + from .pipeline import Pipeline from .stores import InMemoryStore, Store @@ -20,3 +23,20 @@ "InMemoryStore", "Pipeline", ] + + +def __getattr__(name: str) -> Any: + if name in ("Component", "DataModel"): + warnings.warn( + "neo4j_graphrag.experimental.pipeline.Component " + "and neo4j_graphrag.experimental.pipeline.DataModel are deprecated" + " and will be removed in version 2.0. " + "Please use neo4j_graphrag.components.base.Component " + "and neo4j_graphrag.components.base.DataModel instead.", + DeprecationWarning, + stacklevel=2, + ) + from neo4j_graphrag.components.base import Component, DataModel + + return locals()[name] + raise AttributeError(f"module {__name__} has no attribute {name}") From 064710dd9d3bdac80de50ed517fb563507d75334 Mon Sep 17 00:00:00 2001 From: estelle Date: Fri, 17 Jul 2026 09:10:03 +0200 Subject: [PATCH 11/14] Ruff check --- src/neo4j_graphrag/experimental/components/__init__.py | 4 ++-- src/neo4j_graphrag/experimental/pipeline/__init__.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/neo4j_graphrag/experimental/components/__init__.py b/src/neo4j_graphrag/experimental/components/__init__.py index db58e5d7c..3066a4648 100644 --- a/src/neo4j_graphrag/experimental/components/__init__.py +++ b/src/neo4j_graphrag/experimental/components/__init__.py @@ -48,7 +48,7 @@ _EXPERIMENTAL_ONLY: set[str] = set() -class I(importlib.abc.Loader): +class AliasLoader(importlib.abc.Loader): """Aliases the module from its new location under the old (experimental) name. The exact same module object is shared under both names, so it is neither @@ -106,7 +106,7 @@ def find_spec( DeprecationWarning, stacklevel=2, ) - return importlib.util.spec_from_loader(fullname, I(new_name)) + return importlib.util.spec_from_loader(fullname, AliasLoader(new_name)) # Register the finder ahead of the default path-based finders, but only once. diff --git a/src/neo4j_graphrag/experimental/pipeline/__init__.py b/src/neo4j_graphrag/experimental/pipeline/__init__.py index eaa073643..de8d37799 100644 --- a/src/neo4j_graphrag/experimental/pipeline/__init__.py +++ b/src/neo4j_graphrag/experimental/pipeline/__init__.py @@ -36,7 +36,7 @@ def __getattr__(name: str) -> Any: DeprecationWarning, stacklevel=2, ) - from neo4j_graphrag.components.base import Component, DataModel + from neo4j_graphrag.components.base import Component, DataModel # noqa return locals()[name] raise AttributeError(f"module {__name__} has no attribute {name}") From d5fb316340bf634c1916bdb4dfb07ba9fc5a8b70 Mon Sep 17 00:00:00 2001 From: estelle Date: Fri, 17 Jul 2026 10:15:59 +0200 Subject: [PATCH 12/14] Try to fix test --- tests/unit/experimental/components/test_backward_compat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/experimental/components/test_backward_compat.py b/tests/unit/experimental/components/test_backward_compat.py index 133dbd990..a667393b1 100644 --- a/tests/unit/experimental/components/test_backward_compat.py +++ b/tests/unit/experimental/components/test_backward_compat.py @@ -70,7 +70,7 @@ def test_experimental_only_module_loads_without_redirect() -> None: pkg_dir = exp_components.__path__[0] marker_file = os.path.join(pkg_dir, "_only_here_test_module.py") with open(marker_file, "w") as f: - f.write("MARKER = 'from experimental'\n") + f.write("MARKER = 'from experimental' # pragma: no cover\n") try: with warnings.catch_warnings(): From 0756c78e8ffb46c178b129012a9e6d2e6473344c Mon Sep 17 00:00:00 2001 From: estelle Date: Fri, 17 Jul 2026 10:22:30 +0200 Subject: [PATCH 13/14] Removing this test that's failing due to coverage. I've tested it manually --- .../components/test_backward_compat.py | 26 ------------------- 1 file changed, 26 deletions(-) diff --git a/tests/unit/experimental/components/test_backward_compat.py b/tests/unit/experimental/components/test_backward_compat.py index a667393b1..9a20ec090 100644 --- a/tests/unit/experimental/components/test_backward_compat.py +++ b/tests/unit/experimental/components/test_backward_compat.py @@ -59,29 +59,3 @@ def test_import_module_form_shares_the_same_module() -> None: new = importlib.import_module("neo4j_graphrag.components.kg_writer") assert old is new - - -def test_experimental_only_module_loads_without_redirect() -> None: - """A module that only exists in experimental keeps loading from there.""" - import os - - import neo4j_graphrag.experimental.components as exp_components - - pkg_dir = exp_components.__path__[0] - marker_file = os.path.join(pkg_dir, "_only_here_test_module.py") - with open(marker_file, "w") as f: - f.write("MARKER = 'from experimental' # pragma: no cover\n") - - try: - with warnings.catch_warnings(): - warnings.simplefilter("error", DeprecationWarning) - module = importlib.import_module( - "neo4j_graphrag.experimental.components._only_here_test_module" - ) - assert module.MARKER == "from experimental" - assert ( - module.__name__ - == "neo4j_graphrag.experimental.components._only_here_test_module" - ) - finally: - os.remove(marker_file) From 1887fe7f2b04d0991ea431e87c10fdbfaa0bac4e Mon Sep 17 00:00:00 2001 From: estelle Date: Fri, 17 Jul 2026 10:29:04 +0200 Subject: [PATCH 14/14] ... --- tests/unit/experimental/components/test_backward_compat.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/unit/experimental/components/test_backward_compat.py b/tests/unit/experimental/components/test_backward_compat.py index 9a20ec090..23722e394 100644 --- a/tests/unit/experimental/components/test_backward_compat.py +++ b/tests/unit/experimental/components/test_backward_compat.py @@ -21,7 +21,6 @@ """ import importlib -import warnings import pytest