Skip to content

Commit bed269a

Browse files
committed
Add graphrag-factory package
1 parent 60670d8 commit bed269a

File tree

20 files changed

+288
-22
lines changed

20 files changed

+288
-22
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# GraphRAG Factory
2+
3+
```python
4+
from abc import ABC, abstractmethod
5+
6+
from graphrag_factory import Factory
7+
8+
class SampleABC(ABC):
9+
10+
@abstractmethod
11+
def get_value(self) -> str:
12+
msg = "Subclasses must implement the get_value method."
13+
raise NotImplementedError(msg)
14+
15+
16+
class ConcreteClass(SampleABC):
17+
def __init__(self, value: str):
18+
self._value = value
19+
20+
def get_value(self) -> str:
21+
return self._value
22+
23+
class SampleFactory(Factory[SampleABC]):
24+
"""A Factory for SampleABC classes."""
25+
26+
factory = SampleFactory()
27+
28+
# Registering transient services
29+
# A new one is created for every request
30+
factory.register("some_strategy", ConcreteTestClass)
31+
32+
trans1 = factory.create("some_strategy", {"value": "test1"})
33+
trans2 = factory.create("some_strategy", {"value": "test2"})
34+
35+
assert trans1 is not trans2
36+
assert trans1.get_value() == "test1"
37+
assert trans2.get_value() == "test2"
38+
39+
# Registering singleton services
40+
# After first creation, the same one is returned every time
41+
factory.register("some_other_strategy", ConcreteTestClass, scope="singleton")
42+
43+
single1 = factory.create("some_other_strategy", {"value": "singleton"})
44+
single2 = factory.create("some_other_strategy", {"value": "ignored"})
45+
46+
assert single1 is single2
47+
assert single1.get_value() == "singleton"
48+
assert single2.get_value() == "singleton"
49+
```
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Copyright (c) 2024 Microsoft Corporation.
2+
# Licensed under the MIT License
3+
4+
"""The GraphRAG Factory package."""
5+
6+
from graphrag_factory.factory import Factory
7+
8+
__all__ = ["Factory"]

packages/graphrag/graphrag/factory/factory.py renamed to packages/graphrag-factory/graphrag_factory/factory.py

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55

66
from abc import ABC
77
from collections.abc import Callable
8-
from typing import Any, ClassVar, Generic, TypeVar
8+
from typing import Any, ClassVar, Generic, Literal, TypeVar
99

1010
T = TypeVar("T", covariant=True)
1111

12+
ServiceScope = Literal["singleton", "transient"]
13+
1214

1315
class Factory(ABC, Generic[T]):
1416
"""Abstract base class for factories."""
@@ -23,27 +25,36 @@ def __new__(cls, *args: Any, **kwargs: Any) -> "Factory":
2325

2426
def __init__(self):
2527
if not hasattr(self, "_initialized"):
26-
self._services: dict[str, Callable[..., T]] = {}
28+
self._service_initializers: dict[
29+
str, tuple[ServiceScope, Callable[..., T]]
30+
] = {}
31+
self._initialized_services: dict[str, T] = {}
2732
self._initialized = True
2833

2934
def __contains__(self, strategy: str) -> bool:
3035
"""Check if a strategy is registered."""
31-
return strategy in self._services
36+
return strategy in self._service_initializers
3237

3338
def keys(self) -> list[str]:
3439
"""Get a list of registered strategy names."""
35-
return list(self._services.keys())
36-
37-
def register(self, strategy: str, initializer: Callable[..., T]) -> None:
40+
return list(self._service_initializers.keys())
41+
42+
def register(
43+
self,
44+
strategy: str,
45+
initializer: Callable[..., T],
46+
scope: ServiceScope = "transient",
47+
) -> None:
3848
"""
3949
Register a new service.
4050
4151
Args
4252
----
4353
strategy: The name of the strategy.
4454
initializer: A callable that creates an instance of T.
55+
scope: The service scope, either 'singleton' or 'transient'.
4556
"""
46-
self._services[strategy] = initializer
57+
self._service_initializers[strategy] = (scope, initializer)
4758

4859
def create(self, strategy: str, init_args: dict[str, Any] | None = None) -> T:
4960
"""
@@ -62,7 +73,16 @@ def create(self, strategy: str, init_args: dict[str, Any] | None = None) -> T:
6273
------
6374
ValueError: If the strategy is not registered.
6475
"""
65-
if strategy not in self._services:
76+
if strategy not in self._service_initializers:
6677
msg = f"Strategy '{strategy}' is not registered."
6778
raise ValueError(msg)
68-
return self._services[strategy](**(init_args or {}))
79+
80+
scope, service_initializer = self._service_initializers[strategy]
81+
if scope == "singleton":
82+
if strategy not in self._initialized_services:
83+
self._initialized_services[strategy] = service_initializer(
84+
**(init_args or {})
85+
)
86+
return self._initialized_services[strategy]
87+
88+
return service_initializer(**(init_args or {}))

packages/graphrag-factory/graphrag_factory/py.typed

Whitespace-only changes.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
[project]
2+
name = "graphrag-factory"
3+
version = "2.7.0"
4+
description = "GraphRAG: A graph-based retrieval-augmented generation (RAG) system."
5+
authors = [
6+
{name = "Alonso Guevara Fernández", email = "[email protected]"},
7+
{name = "Andrés Morales Esquivel", email = "[email protected]"},
8+
{name = "Chris Trevino", email = "[email protected]"},
9+
{name = "David Tittsworth", email = "[email protected]"},
10+
{name = "Dayenne de Souza", email = "[email protected]"},
11+
{name = "Derek Worthen", email = "[email protected]"},
12+
{name = "Gaudy Blanco Meneses", email = "[email protected]"},
13+
{name = "Ha Trinh", email = "[email protected]"},
14+
{name = "Jonathan Larson", email = "[email protected]"},
15+
{name = "Josh Bradley", email = "[email protected]"},
16+
{name = "Kate Lytvynets", email = "[email protected]"},
17+
{name = "Kenny Zhang", email = "[email protected]"},
18+
{name = "Mónica Carvajal"},
19+
{name = "Nathan Evans", email = "[email protected]"},
20+
{name = "Rodrigo Racanicci", email = "[email protected]"},
21+
{name = "Sarah Smith", email = "[email protected]"},
22+
]
23+
license = "MIT"
24+
readme = "README.md"
25+
license-files = ["LICENSE"]
26+
requires-python = ">=3.10,<3.13"
27+
classifiers = [
28+
"Programming Language :: Python :: 3",
29+
"Programming Language :: Python :: 3.10",
30+
"Programming Language :: Python :: 3.11",
31+
"Programming Language :: Python :: 3.12",
32+
]
33+
dependencies = []
34+
35+
[project.urls]
36+
Source = "https://github.com/microsoft/graphrag"
37+
38+
[build-system]
39+
requires = ["hatchling>=1.27.0,<2.0.0"]
40+
build-backend = "hatchling.build"
41+

packages/graphrag/graphrag/cache/factory.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@
55

66
from __future__ import annotations
77

8+
from graphrag_factory import Factory
9+
810
from graphrag.cache.json_pipeline_cache import JsonPipelineCache
911
from graphrag.cache.memory_pipeline_cache import InMemoryCache
1012
from graphrag.cache.noop_pipeline_cache import NoopPipelineCache
1113
from graphrag.cache.pipeline_cache import PipelineCache
1214
from graphrag.config.enums import CacheType
13-
from graphrag.factory.factory import Factory
1415
from graphrag.storage.blob_pipeline_storage import BlobPipelineStorage
1516
from graphrag.storage.cosmosdb_pipeline_storage import CosmosDBPipelineStorage
1617
from graphrag.storage.file_pipeline_storage import FilePipelineStorage

packages/graphrag/graphrag/factory/__init__.py

Lines changed: 0 additions & 4 deletions
This file was deleted.

packages/graphrag/graphrag/index/input/factory.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55

66
import logging
77

8+
from graphrag_factory import Factory
9+
810
from graphrag.config.enums import InputFileType
9-
from graphrag.factory.factory import Factory
1011
from graphrag.index.input.csv import CSVFileReader
1112
from graphrag.index.input.input_reader import InputReader
1213
from graphrag.index.input.json import JSONFileReader

packages/graphrag/graphrag/language_model/factory.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33

44
"""A package containing a factory for supported llm types."""
55

6+
from graphrag_factory import Factory
7+
68
from graphrag.config.enums import ModelType
7-
from graphrag.factory.factory import Factory
89
from graphrag.language_model.protocol.base import ChatModel, EmbeddingModel
910
from graphrag.language_model.providers.litellm.chat_model import LitellmChatModel
1011
from graphrag.language_model.providers.litellm.embedding_model import (

packages/graphrag/graphrag/language_model/providers/litellm/services/rate_limiter/rate_limiter_factory.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33

44
"""LiteLLM Rate Limiter Factory."""
55

6-
from graphrag.factory.factory import Factory
6+
from graphrag_factory import Factory
7+
78
from graphrag.language_model.providers.litellm.services.rate_limiter.rate_limiter import (
89
RateLimiter,
910
)

0 commit comments

Comments
 (0)