migrate to pyright (#646)
* migrate to pyright * Refactor type checking to use Pyright, update dependencies, and clean up code. - Replaced MyPy with Pyright in configuration files and CI workflows. - Updated `pyproject.toml` and `uv.lock` to reflect new dependencies and versions. - Adjusted type hints and fixed minor code issues across various modules for better compatibility with Pyright. - Added new packages `backoff` and `posthog` to the project dependencies. * Update CI workflows to install all extra dependencies for type checking and unit tests * Update dependencies in uv.lock to replace MyPy with Pyright and add nodeenv package. Adjust type hinting in config.py for compatibility with Pyright.
This commit is contained in:
parent
7a8283dbac
commit
8213d10d44
18 changed files with 232 additions and 266 deletions
24
.github/workflows/typecheck.yml
vendored
24
.github/workflows/typecheck.yml
vendored
|
|
@ -1,4 +1,4 @@
|
|||
name: MyPy Type Check
|
||||
name: Pyright Type Check
|
||||
|
||||
on:
|
||||
push:
|
||||
|
|
@ -7,7 +7,7 @@ on:
|
|||
branches: ["main"]
|
||||
|
||||
jobs:
|
||||
mypy:
|
||||
pyright:
|
||||
runs-on: depot-ubuntu-22.04
|
||||
environment: development
|
||||
steps:
|
||||
|
|
@ -22,26 +22,18 @@ jobs:
|
|||
with:
|
||||
version: "latest"
|
||||
- name: Install dependencies
|
||||
run: uv sync --extra dev
|
||||
- name: Run MyPy for graphiti-core
|
||||
run: uv sync --all-extras
|
||||
- name: Run Pyright for graphiti-core
|
||||
shell: bash
|
||||
run: |
|
||||
set -o pipefail
|
||||
uv run mypy ./graphiti_core --show-column-numbers --show-error-codes | sed -E '
|
||||
s/^(.*):([0-9]+):([0-9]+): (error|warning): (.+) \[(.+)\]/::error file=\1,line=\2,endLine=\2,col=\3,title=\6::\5/;
|
||||
s/^(.*):([0-9]+):([0-9]+): note: (.+)/::notice file=\1,line=\2,endLine=\2,col=\3,title=Note::\4/;
|
||||
'
|
||||
uv run pyright ./graphiti_core
|
||||
- name: Install graph-service dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
cd server
|
||||
uv sync --extra dev
|
||||
- name: Run MyPy for graph-service
|
||||
uv sync --all-extras
|
||||
- name: Run Pyright for graph-service
|
||||
shell: bash
|
||||
run: |
|
||||
cd server
|
||||
set -o pipefail
|
||||
uv run mypy . --show-column-numbers --show-error-codes | sed -E '
|
||||
s/^(.*):([0-9]+):([0-9]+): (error|warning): (.+) \[(.+)\]/::error file=\1,line=\2,endLine=\2,col=\3,title=\6::\5/;
|
||||
s/^(.*):([0-9]+):([0-9]+): note: (.+)/::notice file=\1,line=\2,endLine=\2,col=\3,title=Note::\4/;
|
||||
'
|
||||
uv run pyright .
|
||||
|
|
|
|||
2
.github/workflows/unit_tests.yml
vendored
2
.github/workflows/unit_tests.yml
vendored
|
|
@ -30,7 +30,7 @@ jobs:
|
|||
- name: Install redis-cli for FalkorDB health check
|
||||
run: sudo apt-get update && sudo apt-get install -y redis-tools
|
||||
- name: Install dependencies
|
||||
run: uv sync --extra dev
|
||||
run: uv sync --all-extras
|
||||
- name: Run non-integration tests
|
||||
env:
|
||||
PYTHONPATH: ${{ github.workspace }}
|
||||
|
|
|
|||
4
Makefile
4
Makefile
|
|
@ -5,7 +5,7 @@ PYTHON = python3
|
|||
UV = uv
|
||||
PYTEST = $(UV) run pytest
|
||||
RUFF = $(UV) run ruff
|
||||
MYPY = $(UV) run mypy
|
||||
PYRIGHT = $(UV) run pyright
|
||||
|
||||
# Default target
|
||||
all: format lint test
|
||||
|
|
@ -22,7 +22,7 @@ format:
|
|||
# Lint code
|
||||
lint:
|
||||
$(RUFF) check
|
||||
$(MYPY) ./graphiti_core --show-column-numbers --show-error-codes --pretty
|
||||
$(PYRIGHT) ./graphiti_core
|
||||
|
||||
# Run tests
|
||||
test:
|
||||
|
|
|
|||
|
|
@ -14,4 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
"""
|
||||
|
||||
__all__ = ['GraphDriver', 'Neo4jDriver', 'FalkorDriver']
|
||||
from falkordb import FalkorDB
|
||||
from neo4j import Neo4jDriver
|
||||
|
||||
__all__ = ['Neo4jDriver', 'FalkorDB']
|
||||
|
|
|
|||
|
|
@ -51,11 +51,11 @@ class FalkorDriverSession(GraphDriverSession):
|
|||
if isinstance(query, list):
|
||||
for cypher, params in query:
|
||||
params = convert_datetimes_to_strings(params)
|
||||
await self.graph.query(str(cypher), params)
|
||||
await self.graph.query(str(cypher), params) # type: ignore[reportUnknownArgumentType]
|
||||
else:
|
||||
params = dict(kwargs)
|
||||
params = convert_datetimes_to_strings(params)
|
||||
await self.graph.query(str(query), params)
|
||||
await self.graph.query(str(query), params) # type: ignore[reportUnknownArgumentType]
|
||||
# Assuming `graph.query` is async (ideal); otherwise, wrap in executor
|
||||
return None
|
||||
|
||||
|
|
@ -99,7 +99,7 @@ class FalkorDriver(GraphDriver):
|
|||
params = convert_datetimes_to_strings(dict(kwargs))
|
||||
|
||||
try:
|
||||
result = await graph.query(cypher_query_, params)
|
||||
result = await graph.query(cypher_query_, params) # type: ignore[reportUnknownArgumentType]
|
||||
except Exception as e:
|
||||
if 'already indexed' in str(e):
|
||||
# check if index already exists
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import logging
|
|||
from collections.abc import Coroutine
|
||||
from typing import Any
|
||||
|
||||
from neo4j import AsyncGraphDatabase
|
||||
from neo4j import AsyncGraphDatabase, EagerResult
|
||||
from typing_extensions import LiteralString
|
||||
|
||||
from graphiti_core.driver.driver import GraphDriver, GraphDriverSession
|
||||
|
|
@ -42,7 +42,7 @@ class Neo4jDriver(GraphDriver):
|
|||
auth=(user or '', password or ''),
|
||||
)
|
||||
|
||||
async def execute_query(self, cypher_query_: LiteralString, **kwargs: Any) -> Coroutine:
|
||||
async def execute_query(self, cypher_query_: LiteralString, **kwargs: Any) -> EagerResult:
|
||||
params = kwargs.pop('params', None)
|
||||
result = await self.client.execute_query(cypher_query_, parameters_=params, **kwargs)
|
||||
|
||||
|
|
@ -54,7 +54,9 @@ class Neo4jDriver(GraphDriver):
|
|||
async def close(self) -> None:
|
||||
return await self.client.close()
|
||||
|
||||
def delete_all_indexes(self, database_: str = DEFAULT_DATABASE) -> Coroutine:
|
||||
def delete_all_indexes(
|
||||
self, database_: str = DEFAULT_DATABASE
|
||||
) -> Coroutine[Any, Any, EagerResult]:
|
||||
return self.client.execute_query(
|
||||
'CALL db.indexes() YIELD name DROP INDEX name',
|
||||
database_=database_,
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ class VoyageAIEmbedder(EmbedderClient):
|
|||
if config is None:
|
||||
config = VoyageAIEmbedderConfig()
|
||||
self.config = config
|
||||
self.client = voyageai.AsyncClient(api_key=config.api_key)
|
||||
self.client = voyageai.AsyncClient(api_key=config.api_key) # type: ignore[reportUnknownMemberType]
|
||||
|
||||
async def create(
|
||||
self, input_data: str | list[str] | Iterable[int] | Iterable[Iterable[int]]
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import os
|
|||
import re
|
||||
from collections.abc import Coroutine
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
import numpy as np
|
||||
from dotenv import load_dotenv
|
||||
|
|
@ -99,7 +100,7 @@ def normalize_l2(embedding: list[float]) -> NDArray:
|
|||
async def semaphore_gather(
|
||||
*coroutines: Coroutine,
|
||||
max_coroutines: int | None = None,
|
||||
):
|
||||
) -> list[Any]:
|
||||
semaphore = asyncio.Semaphore(max_coroutines or SEMAPHORE_LIMIT)
|
||||
|
||||
async def _wrap_coroutine(coroutine):
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ from enum import Enum
|
|||
from typing import Any
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
from typing_extensions import LiteralString
|
||||
|
||||
|
||||
class ComparisonOperator(Enum):
|
||||
|
|
@ -53,8 +52,8 @@ class SearchFilters(BaseModel):
|
|||
|
||||
def node_search_filter_query_constructor(
|
||||
filters: SearchFilters,
|
||||
) -> tuple[LiteralString, dict[str, Any]]:
|
||||
filter_query: LiteralString = ''
|
||||
) -> tuple[str, dict[str, Any]]:
|
||||
filter_query: str = ''
|
||||
filter_params: dict[str, Any] = {}
|
||||
|
||||
if filters.node_labels is not None:
|
||||
|
|
@ -67,8 +66,8 @@ def node_search_filter_query_constructor(
|
|||
|
||||
def edge_search_filter_query_constructor(
|
||||
filters: SearchFilters,
|
||||
) -> tuple[LiteralString, dict[str, Any]]:
|
||||
filter_query: LiteralString = ''
|
||||
) -> tuple[str, dict[str, Any]]:
|
||||
filter_query: str = ''
|
||||
filter_params: dict[str, Any] = {}
|
||||
|
||||
if filters.edge_types is not None:
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ async def get_community_clusters(
|
|||
database_=DEFAULT_DATABASE,
|
||||
)
|
||||
|
||||
group_ids = group_id_values[0]['group_ids']
|
||||
group_ids = group_id_values[0]['group_ids'] if group_id_values else []
|
||||
|
||||
for group_id in group_ids:
|
||||
projection: dict[str, list[Neighbor]] = {}
|
||||
|
|
|
|||
|
|
@ -297,7 +297,7 @@ async def resolve_extracted_edges(
|
|||
embedder = clients.embedder
|
||||
await create_entity_edge_embeddings(embedder, extracted_edges)
|
||||
|
||||
search_results: tuple[list[list[EntityEdge]], list[list[EntityEdge]]] = await semaphore_gather(
|
||||
search_results = await semaphore_gather(
|
||||
get_relevant_edges(driver, extracted_edges, SearchFilters()),
|
||||
get_edge_invalidation_candidates(driver, extracted_edges, SearchFilters(), 0.2),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ groq = ["groq>=0.2.0"]
|
|||
google-genai = ["google-genai>=1.8.0"]
|
||||
falkord-db = ["falkordb>=1.1.2,<2.0.0"]
|
||||
dev = [
|
||||
"mypy>=1.11.1",
|
||||
"pyright>=1.1.380",
|
||||
"groq>=0.2.0",
|
||||
"anthropic>=0.49.0",
|
||||
"google-genai>=1.8.0",
|
||||
|
|
@ -83,13 +83,11 @@ quote-style = "single"
|
|||
indent-style = "space"
|
||||
docstring-code-format = true
|
||||
|
||||
[tool.mypy]
|
||||
packages = ["graphiti_core"]
|
||||
[tool.pyright]
|
||||
include = ["graphiti_core"]
|
||||
pythonVersion = "3.10"
|
||||
typeCheckingMode = "basic"
|
||||
|
||||
[[tool.mypy.overrides]]
|
||||
module = "falkordb"
|
||||
ignore_missing_imports = true
|
||||
|
||||
[[tool.mypy.overrides]]
|
||||
module = "falkordb.asyncio"
|
||||
ignore_missing_imports = true
|
||||
[[tool.pyright.overrides]]
|
||||
include = ["**/falkordb*"]
|
||||
reportMissingImports = false
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ PYTHON = python3
|
|||
UV = uv
|
||||
PYTEST = $(UV) run pytest
|
||||
RUFF = $(UV) run ruff
|
||||
MYPY = $(UV) run mypy
|
||||
PYRIGHT = $(UV) run pyright
|
||||
|
||||
# Default target
|
||||
all: format lint test
|
||||
|
|
@ -22,7 +22,7 @@ format:
|
|||
# Lint code
|
||||
lint:
|
||||
$(RUFF) check
|
||||
$(MYPY) . --show-column-numbers --show-error-codes --pretty
|
||||
$(PYRIGHT) .
|
||||
|
||||
# Run tests
|
||||
test:
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ class Settings(BaseSettings):
|
|||
|
||||
@lru_cache
|
||||
def get_settings():
|
||||
return Settings()
|
||||
return Settings() # type: ignore[call-arg]
|
||||
|
||||
|
||||
ZepEnvDep = Annotated[Settings, Depends(get_settings)]
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ dependencies = [
|
|||
[project.optional-dependencies]
|
||||
dev = [
|
||||
"pydantic>=2.8.2",
|
||||
"mypy>=1.11.1",
|
||||
"pyright>=1.1.380",
|
||||
"pytest>=8.3.2",
|
||||
"python-dotenv>=1.0.1",
|
||||
"pytest-asyncio>=0.24.0",
|
||||
|
|
@ -61,3 +61,8 @@ ignore = ["E501"]
|
|||
quote-style = "single"
|
||||
indent-style = "space"
|
||||
docstring-code-format = true
|
||||
|
||||
[tool.pyright]
|
||||
include = ["."]
|
||||
pythonVersion = "3.10"
|
||||
typeCheckingMode = "standard"
|
||||
|
|
|
|||
83
server/uv.lock
generated
83
server/uv.lock
generated
|
|
@ -137,8 +137,8 @@ dependencies = [
|
|||
[package.optional-dependencies]
|
||||
dev = [
|
||||
{ name = "fastapi-cli" },
|
||||
{ name = "mypy" },
|
||||
{ name = "pydantic" },
|
||||
{ name = "pyright" },
|
||||
{ name = "pytest" },
|
||||
{ name = "pytest-asyncio" },
|
||||
{ name = "pytest-xdist" },
|
||||
|
|
@ -152,9 +152,9 @@ requires-dist = [
|
|||
{ name = "fastapi-cli", marker = "extra == 'dev'", specifier = ">=0.0.5" },
|
||||
{ name = "graphiti-core" },
|
||||
{ name = "httpx", specifier = ">=0.28.1" },
|
||||
{ name = "mypy", marker = "extra == 'dev'", specifier = ">=1.11.1" },
|
||||
{ name = "pydantic", marker = "extra == 'dev'", specifier = ">=2.8.2" },
|
||||
{ name = "pydantic-settings", specifier = ">=2.4.0" },
|
||||
{ name = "pyright", marker = "extra == 'dev'", specifier = ">=1.1.380" },
|
||||
{ name = "pytest", marker = "extra == 'dev'", specifier = ">=8.3.2" },
|
||||
{ name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=0.24.0" },
|
||||
{ name = "pytest-xdist", marker = "extra == 'dev'", specifier = ">=3.6.1" },
|
||||
|
|
@ -365,54 +365,6 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mypy"
|
||||
version = "1.16.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "mypy-extensions" },
|
||||
{ name = "pathspec" },
|
||||
{ name = "tomli", marker = "python_full_version < '3.11'" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/81/69/92c7fa98112e4d9eb075a239caa4ef4649ad7d441545ccffbd5e34607cbb/mypy-1.16.1.tar.gz", hash = "sha256:6bd00a0a2094841c5e47e7374bb42b83d64c527a502e3334e1173a0c24437bab", size = 3324747 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/8e/12/2bf23a80fcef5edb75de9a1e295d778e0f46ea89eb8b115818b663eff42b/mypy-1.16.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b4f0fed1022a63c6fec38f28b7fc77fca47fd490445c69d0a66266c59dd0b88a", size = 10958644 },
|
||||
{ url = "https://files.pythonhosted.org/packages/08/50/bfe47b3b278eacf348291742fd5e6613bbc4b3434b72ce9361896417cfe5/mypy-1.16.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:86042bbf9f5a05ea000d3203cf87aa9d0ccf9a01f73f71c58979eb9249f46d72", size = 10087033 },
|
||||
{ url = "https://files.pythonhosted.org/packages/21/de/40307c12fe25675a0776aaa2cdd2879cf30d99eec91b898de00228dc3ab5/mypy-1.16.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ea7469ee5902c95542bea7ee545f7006508c65c8c54b06dc2c92676ce526f3ea", size = 11875645 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a6/d8/85bdb59e4a98b7a31495bd8f1a4445d8ffc86cde4ab1f8c11d247c11aedc/mypy-1.16.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:352025753ef6a83cb9e7f2427319bb7875d1fdda8439d1e23de12ab164179574", size = 12616986 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0e/d0/bb25731158fa8f8ee9e068d3e94fcceb4971fedf1424248496292512afe9/mypy-1.16.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ff9fa5b16e4c1364eb89a4d16bcda9987f05d39604e1e6c35378a2987c1aac2d", size = 12878632 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2d/11/822a9beb7a2b825c0cb06132ca0a5183f8327a5e23ef89717c9474ba0bc6/mypy-1.16.1-cp310-cp310-win_amd64.whl", hash = "sha256:1256688e284632382f8f3b9e2123df7d279f603c561f099758e66dd6ed4e8bd6", size = 9484391 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9a/61/ec1245aa1c325cb7a6c0f8570a2eee3bfc40fa90d19b1267f8e50b5c8645/mypy-1.16.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:472e4e4c100062488ec643f6162dd0d5208e33e2f34544e1fc931372e806c0cc", size = 10890557 },
|
||||
{ url = "https://files.pythonhosted.org/packages/6b/bb/6eccc0ba0aa0c7a87df24e73f0ad34170514abd8162eb0c75fd7128171fb/mypy-1.16.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ea16e2a7d2714277e349e24d19a782a663a34ed60864006e8585db08f8ad1782", size = 10012921 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5f/80/b337a12e2006715f99f529e732c5f6a8c143bb58c92bb142d5ab380963a5/mypy-1.16.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:08e850ea22adc4d8a4014651575567b0318ede51e8e9fe7a68f25391af699507", size = 11802887 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d9/59/f7af072d09793d581a745a25737c7c0a945760036b16aeb620f658a017af/mypy-1.16.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22d76a63a42619bfb90122889b903519149879ddbf2ba4251834727944c8baca", size = 12531658 },
|
||||
{ url = "https://files.pythonhosted.org/packages/82/c4/607672f2d6c0254b94a646cfc45ad589dd71b04aa1f3d642b840f7cce06c/mypy-1.16.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:2c7ce0662b6b9dc8f4ed86eb7a5d505ee3298c04b40ec13b30e572c0e5ae17c4", size = 12732486 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b6/5e/136555ec1d80df877a707cebf9081bd3a9f397dedc1ab9750518d87489ec/mypy-1.16.1-cp311-cp311-win_amd64.whl", hash = "sha256:211287e98e05352a2e1d4e8759c5490925a7c784ddc84207f4714822f8cf99b6", size = 9479482 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b4/d6/39482e5fcc724c15bf6280ff5806548c7185e0c090712a3736ed4d07e8b7/mypy-1.16.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:af4792433f09575d9eeca5c63d7d90ca4aeceda9d8355e136f80f8967639183d", size = 11066493 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e6/e5/26c347890efc6b757f4d5bb83f4a0cf5958b8cf49c938ac99b8b72b420a6/mypy-1.16.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:66df38405fd8466ce3517eda1f6640611a0b8e70895e2a9462d1d4323c5eb4b9", size = 10081687 },
|
||||
{ url = "https://files.pythonhosted.org/packages/44/c7/b5cb264c97b86914487d6a24bd8688c0172e37ec0f43e93b9691cae9468b/mypy-1.16.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:44e7acddb3c48bd2713994d098729494117803616e116032af192871aed80b79", size = 11839723 },
|
||||
{ url = "https://files.pythonhosted.org/packages/15/f8/491997a9b8a554204f834ed4816bda813aefda31cf873bb099deee3c9a99/mypy-1.16.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0ab5eca37b50188163fa7c1b73c685ac66c4e9bdee4a85c9adac0e91d8895e15", size = 12722980 },
|
||||
{ url = "https://files.pythonhosted.org/packages/df/f0/2bd41e174b5fd93bc9de9a28e4fb673113633b8a7f3a607fa4a73595e468/mypy-1.16.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb6229b2c9086247e21a83c309754b9058b438704ad2f6807f0d8227f6ebdd", size = 12903328 },
|
||||
{ url = "https://files.pythonhosted.org/packages/61/81/5572108a7bec2c46b8aff7e9b524f371fe6ab5efb534d38d6b37b5490da8/mypy-1.16.1-cp312-cp312-win_amd64.whl", hash = "sha256:1f0435cf920e287ff68af3d10a118a73f212deb2ce087619eb4e648116d1fe9b", size = 9562321 },
|
||||
{ url = "https://files.pythonhosted.org/packages/28/e3/96964af4a75a949e67df4b95318fe2b7427ac8189bbc3ef28f92a1c5bc56/mypy-1.16.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ddc91eb318c8751c69ddb200a5937f1232ee8efb4e64e9f4bc475a33719de438", size = 11063480 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f5/4d/cd1a42b8e5be278fab7010fb289d9307a63e07153f0ae1510a3d7b703193/mypy-1.16.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:87ff2c13d58bdc4bbe7dc0dedfe622c0f04e2cb2a492269f3b418df2de05c536", size = 10090538 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c9/4f/c3c6b4b66374b5f68bab07c8cabd63a049ff69796b844bc759a0ca99bb2a/mypy-1.16.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a7cfb0fe29fe5a9841b7c8ee6dffb52382c45acdf68f032145b75620acfbd6f", size = 11836839 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b4/7e/81ca3b074021ad9775e5cb97ebe0089c0f13684b066a750b7dc208438403/mypy-1.16.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:051e1677689c9d9578b9c7f4d206d763f9bbd95723cd1416fad50db49d52f359", size = 12715634 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/95/bdd40c8be346fa4c70edb4081d727a54d0a05382d84966869738cfa8a497/mypy-1.16.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d5d2309511cc56c021b4b4e462907c2b12f669b2dbeb68300110ec27723971be", size = 12895584 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5a/fd/d486a0827a1c597b3b48b1bdef47228a6e9ee8102ab8c28f944cb83b65dc/mypy-1.16.1-cp313-cp313-win_amd64.whl", hash = "sha256:4f58ac32771341e38a853c5d0ec0dfe27e18e27da9cdb8bbc882d2249c71a3ee", size = 9573886 },
|
||||
{ url = "https://files.pythonhosted.org/packages/cf/d3/53e684e78e07c1a2bf7105715e5edd09ce951fc3f47cf9ed095ec1b7a037/mypy-1.16.1-py3-none-any.whl", hash = "sha256:5fc2ac4027d0ef28d6ba69a0343737a23c4d1b83672bf38d1fe237bdc0643b37", size = 2265923 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mypy-extensions"
|
||||
version = "1.1.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "neo4j"
|
||||
version = "5.28.1"
|
||||
|
|
@ -425,6 +377,15 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/6a/57/94225fe5e9dabdc0ff60c88cbfcedf11277f4b34e7ab1373d3e62dbdd207/neo4j-5.28.1-py3-none-any.whl", hash = "sha256:6755ef9e5f4e14b403aef1138fb6315b120631a0075c138b5ddb2a06b87b09fd", size = 312258 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nodeenv"
|
||||
version = "1.9.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "numpy"
|
||||
version = "2.2.6"
|
||||
|
|
@ -515,15 +476,6 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pathspec"
|
||||
version = "0.12.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pluggy"
|
||||
version = "1.6.0"
|
||||
|
|
@ -658,6 +610,19 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyright"
|
||||
version = "1.1.402"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "nodeenv" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/aa/04/ce0c132d00e20f2d2fb3b3e7c125264ca8b909e693841210534b1ea1752f/pyright-1.1.402.tar.gz", hash = "sha256:85a33c2d40cd4439c66aa946fd4ce71ab2f3f5b8c22ce36a623f59ac22937683", size = 3888207 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/fe/37/1a1c62d955e82adae588be8e374c7f77b165b6cb4203f7d581269959abbc/pyright-1.1.402-py3-none-any.whl", hash = "sha256:2c721f11869baac1884e846232800fe021c33f1b4acb3929cff321f7ea4e2982", size = 5624004 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "8.4.1"
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ NEO4J_PASSWORD = os.getenv('NEO4J_PASSWORD')
|
|||
# Test entity type definitions
|
||||
class Person(BaseModel):
|
||||
"""A human person mentioned in the conversation."""
|
||||
|
||||
|
||||
first_name: str | None = Field(None, description='First name of the person')
|
||||
last_name: str | None = Field(None, description='Last name of the person')
|
||||
occupation: str | None = Field(None, description='Job or profession of the person')
|
||||
|
|
@ -46,15 +46,21 @@ class Person(BaseModel):
|
|||
|
||||
class Organization(BaseModel):
|
||||
"""A company, institution, or organized group."""
|
||||
|
||||
organization_type: str | None = Field(None, description='Type of organization (company, NGO, etc.)')
|
||||
industry: str | None = Field(None, description='Industry or sector the organization operates in')
|
||||
|
||||
organization_type: str | None = Field(
|
||||
None, description='Type of organization (company, NGO, etc.)'
|
||||
)
|
||||
industry: str | None = Field(
|
||||
None, description='Industry or sector the organization operates in'
|
||||
)
|
||||
|
||||
|
||||
class Location(BaseModel):
|
||||
"""A geographic location, place, or address."""
|
||||
|
||||
location_type: str | None = Field(None, description='Type of location (city, country, building, etc.)')
|
||||
|
||||
location_type: str | None = Field(
|
||||
None, description='Type of location (city, country, building, etc.)'
|
||||
)
|
||||
coordinates: str | None = Field(None, description='Geographic coordinates if available')
|
||||
|
||||
|
||||
|
|
@ -62,49 +68,51 @@ class Location(BaseModel):
|
|||
async def test_exclude_default_entity_type():
|
||||
"""Test excluding the default 'Entity' type while keeping custom types."""
|
||||
graphiti = Graphiti(NEO4J_URI, NEO4J_USER, NEO4J_PASSWORD)
|
||||
|
||||
|
||||
try:
|
||||
await graphiti.build_indices_and_constraints()
|
||||
|
||||
|
||||
# Define entity types but exclude the default 'Entity' type
|
||||
entity_types = {
|
||||
'Person': Person,
|
||||
'Organization': Organization,
|
||||
}
|
||||
|
||||
|
||||
# Add an episode that would normally create both Entity and custom type entities
|
||||
episode_content = "John Smith works at Acme Corporation in New York. The weather is nice today."
|
||||
|
||||
episode_content = (
|
||||
'John Smith works at Acme Corporation in New York. The weather is nice today.'
|
||||
)
|
||||
|
||||
result = await graphiti.add_episode(
|
||||
name="Business Meeting",
|
||||
name='Business Meeting',
|
||||
episode_body=episode_content,
|
||||
source_description="Meeting notes",
|
||||
source_description='Meeting notes',
|
||||
reference_time=datetime.now(timezone.utc),
|
||||
entity_types=entity_types,
|
||||
excluded_entity_types=['Entity'], # Exclude default type
|
||||
group_id='test_exclude_default'
|
||||
group_id='test_exclude_default',
|
||||
)
|
||||
|
||||
|
||||
# Verify that nodes were created (custom types should still work)
|
||||
assert result is not None
|
||||
|
||||
|
||||
# Search for nodes to verify only custom types were created
|
||||
search_results = await graphiti.search_(
|
||||
query="John Smith Acme Corporation",
|
||||
group_ids=['test_exclude_default']
|
||||
query='John Smith Acme Corporation', group_ids=['test_exclude_default']
|
||||
)
|
||||
|
||||
|
||||
# Check that entities were created but with specific types, not default 'Entity'
|
||||
found_nodes = search_results.nodes
|
||||
for node in found_nodes:
|
||||
assert 'Entity' in node.labels # All nodes should have Entity label
|
||||
# But they should also have specific type labels
|
||||
assert any(label in ['Person', 'Organization'] for label in node.labels), \
|
||||
f"Node {node.name} should have a specific type label, got: {node.labels}"
|
||||
|
||||
assert any(label in ['Person', 'Organization'] for label in node.labels), (
|
||||
f'Node {node.name} should have a specific type label, got: {node.labels}'
|
||||
)
|
||||
|
||||
# Clean up
|
||||
await _cleanup_test_nodes(graphiti, 'test_exclude_default')
|
||||
|
||||
|
||||
finally:
|
||||
await graphiti.close()
|
||||
|
||||
|
|
@ -113,54 +121,57 @@ async def test_exclude_default_entity_type():
|
|||
async def test_exclude_specific_custom_types():
|
||||
"""Test excluding specific custom entity types while keeping others."""
|
||||
graphiti = Graphiti(NEO4J_URI, NEO4J_USER, NEO4J_PASSWORD)
|
||||
|
||||
|
||||
try:
|
||||
await graphiti.build_indices_and_constraints()
|
||||
|
||||
|
||||
# Define multiple entity types
|
||||
entity_types = {
|
||||
'Person': Person,
|
||||
'Organization': Organization,
|
||||
'Location': Location,
|
||||
}
|
||||
|
||||
|
||||
# Add an episode with content that would create all types
|
||||
episode_content = "Sarah Johnson from Google visited the San Francisco office to discuss the new project."
|
||||
|
||||
episode_content = (
|
||||
'Sarah Johnson from Google visited the San Francisco office to discuss the new project.'
|
||||
)
|
||||
|
||||
result = await graphiti.add_episode(
|
||||
name="Office Visit",
|
||||
name='Office Visit',
|
||||
episode_body=episode_content,
|
||||
source_description="Visit report",
|
||||
source_description='Visit report',
|
||||
reference_time=datetime.now(timezone.utc),
|
||||
entity_types=entity_types,
|
||||
excluded_entity_types=['Organization', 'Location'], # Exclude these types
|
||||
group_id='test_exclude_custom'
|
||||
group_id='test_exclude_custom',
|
||||
)
|
||||
|
||||
|
||||
assert result is not None
|
||||
|
||||
|
||||
# Search for nodes to verify only Person and Entity types were created
|
||||
search_results = await graphiti.search_(
|
||||
query="Sarah Johnson Google San Francisco",
|
||||
group_ids=['test_exclude_custom']
|
||||
query='Sarah Johnson Google San Francisco', group_ids=['test_exclude_custom']
|
||||
)
|
||||
|
||||
|
||||
found_nodes = search_results.nodes
|
||||
|
||||
|
||||
# Should have Person and Entity type nodes, but no Organization or Location
|
||||
for node in found_nodes:
|
||||
assert 'Entity' in node.labels
|
||||
# Should not have excluded types
|
||||
assert 'Organization' not in node.labels, f"Found excluded Organization in node: {node.name}"
|
||||
assert 'Location' not in node.labels, f"Found excluded Location in node: {node.name}"
|
||||
|
||||
assert 'Organization' not in node.labels, (
|
||||
f'Found excluded Organization in node: {node.name}'
|
||||
)
|
||||
assert 'Location' not in node.labels, f'Found excluded Location in node: {node.name}'
|
||||
|
||||
# Should find at least one Person entity (Sarah Johnson)
|
||||
person_nodes = [n for n in found_nodes if 'Person' in n.labels]
|
||||
assert len(person_nodes) > 0, "Should have found at least one Person entity"
|
||||
|
||||
assert len(person_nodes) > 0, 'Should have found at least one Person entity'
|
||||
|
||||
# Clean up
|
||||
await _cleanup_test_nodes(graphiti, 'test_exclude_custom')
|
||||
|
||||
|
||||
finally:
|
||||
await graphiti.close()
|
||||
|
||||
|
|
@ -169,41 +180,42 @@ async def test_exclude_specific_custom_types():
|
|||
async def test_exclude_all_types():
|
||||
"""Test excluding all entity types (edge case)."""
|
||||
graphiti = Graphiti(NEO4J_URI, NEO4J_USER, NEO4J_PASSWORD)
|
||||
|
||||
|
||||
try:
|
||||
await graphiti.build_indices_and_constraints()
|
||||
|
||||
|
||||
entity_types = {
|
||||
'Person': Person,
|
||||
'Organization': Organization,
|
||||
}
|
||||
|
||||
|
||||
# Exclude all types
|
||||
result = await graphiti.add_episode(
|
||||
name="No Entities",
|
||||
episode_body="This text mentions John and Microsoft but no entities should be created.",
|
||||
source_description="Test content",
|
||||
name='No Entities',
|
||||
episode_body='This text mentions John and Microsoft but no entities should be created.',
|
||||
source_description='Test content',
|
||||
reference_time=datetime.now(timezone.utc),
|
||||
entity_types=entity_types,
|
||||
excluded_entity_types=['Entity', 'Person', 'Organization'], # Exclude everything
|
||||
group_id='test_exclude_all'
|
||||
group_id='test_exclude_all',
|
||||
)
|
||||
|
||||
|
||||
assert result is not None
|
||||
|
||||
|
||||
# Search for nodes - should find very few or none from this episode
|
||||
search_results = await graphiti.search_(
|
||||
query="John Microsoft",
|
||||
group_ids=['test_exclude_all']
|
||||
query='John Microsoft', group_ids=['test_exclude_all']
|
||||
)
|
||||
|
||||
|
||||
# There should be minimal to no entities created
|
||||
found_nodes = search_results.nodes
|
||||
assert len(found_nodes) == 0, f"Expected no entities, but found: {[n.name for n in found_nodes]}"
|
||||
|
||||
assert len(found_nodes) == 0, (
|
||||
f'Expected no entities, but found: {[n.name for n in found_nodes]}'
|
||||
)
|
||||
|
||||
# Clean up
|
||||
await _cleanup_test_nodes(graphiti, 'test_exclude_all')
|
||||
|
||||
|
||||
finally:
|
||||
await graphiti.close()
|
||||
|
||||
|
|
@ -212,47 +224,46 @@ async def test_exclude_all_types():
|
|||
async def test_exclude_no_types():
|
||||
"""Test normal behavior when no types are excluded (baseline test)."""
|
||||
graphiti = Graphiti(NEO4J_URI, NEO4J_USER, NEO4J_PASSWORD)
|
||||
|
||||
|
||||
try:
|
||||
await graphiti.build_indices_and_constraints()
|
||||
|
||||
|
||||
entity_types = {
|
||||
'Person': Person,
|
||||
'Organization': Organization,
|
||||
}
|
||||
|
||||
|
||||
# Don't exclude any types
|
||||
result = await graphiti.add_episode(
|
||||
name="Normal Behavior",
|
||||
episode_body="Alice Smith works at TechCorp.",
|
||||
source_description="Normal test",
|
||||
name='Normal Behavior',
|
||||
episode_body='Alice Smith works at TechCorp.',
|
||||
source_description='Normal test',
|
||||
reference_time=datetime.now(timezone.utc),
|
||||
entity_types=entity_types,
|
||||
excluded_entity_types=None, # No exclusions
|
||||
group_id='test_exclude_none'
|
||||
group_id='test_exclude_none',
|
||||
)
|
||||
|
||||
|
||||
assert result is not None
|
||||
|
||||
|
||||
# Search for nodes - should find entities of all types
|
||||
search_results = await graphiti.search_(
|
||||
query="Alice Smith TechCorp",
|
||||
group_ids=['test_exclude_none']
|
||||
query='Alice Smith TechCorp', group_ids=['test_exclude_none']
|
||||
)
|
||||
|
||||
|
||||
found_nodes = search_results.nodes
|
||||
assert len(found_nodes) > 0, "Should have found some entities"
|
||||
|
||||
assert len(found_nodes) > 0, 'Should have found some entities'
|
||||
|
||||
# Should have both Person and Organization entities
|
||||
person_nodes = [n for n in found_nodes if 'Person' in n.labels]
|
||||
org_nodes = [n for n in found_nodes if 'Organization' in n.labels]
|
||||
|
||||
assert len(person_nodes) > 0, "Should have found Person entities"
|
||||
assert len(org_nodes) > 0, "Should have found Organization entities"
|
||||
|
||||
|
||||
assert len(person_nodes) > 0, 'Should have found Person entities'
|
||||
assert len(org_nodes) > 0, 'Should have found Organization entities'
|
||||
|
||||
# Clean up
|
||||
await _cleanup_test_nodes(graphiti, 'test_exclude_none')
|
||||
|
||||
|
||||
finally:
|
||||
await graphiti.close()
|
||||
|
||||
|
|
@ -263,7 +274,7 @@ def test_validation_valid_excluded_types():
|
|||
'Person': Person,
|
||||
'Organization': Organization,
|
||||
}
|
||||
|
||||
|
||||
# Valid exclusions
|
||||
assert validate_excluded_entity_types(['Entity'], entity_types) is True
|
||||
assert validate_excluded_entity_types(['Person'], entity_types) is True
|
||||
|
|
@ -278,12 +289,12 @@ def test_validation_invalid_excluded_types():
|
|||
'Person': Person,
|
||||
'Organization': Organization,
|
||||
}
|
||||
|
||||
|
||||
# Invalid exclusions should raise ValueError
|
||||
with pytest.raises(ValueError, match="Invalid excluded entity types"):
|
||||
with pytest.raises(ValueError, match='Invalid excluded entity types'):
|
||||
validate_excluded_entity_types(['InvalidType'], entity_types)
|
||||
|
||||
with pytest.raises(ValueError, match="Invalid excluded entity types"):
|
||||
|
||||
with pytest.raises(ValueError, match='Invalid excluded entity types'):
|
||||
validate_excluded_entity_types(['Person', 'NonExistentType'], entity_types)
|
||||
|
||||
|
||||
|
|
@ -291,24 +302,24 @@ def test_validation_invalid_excluded_types():
|
|||
async def test_excluded_types_parameter_validation_in_add_episode():
|
||||
"""Test that add_episode validates excluded_entity_types parameter."""
|
||||
graphiti = Graphiti(NEO4J_URI, NEO4J_USER, NEO4J_PASSWORD)
|
||||
|
||||
|
||||
try:
|
||||
entity_types = {
|
||||
'Person': Person,
|
||||
}
|
||||
|
||||
|
||||
# Should raise ValueError for invalid excluded type
|
||||
with pytest.raises(ValueError, match="Invalid excluded entity types"):
|
||||
with pytest.raises(ValueError, match='Invalid excluded entity types'):
|
||||
await graphiti.add_episode(
|
||||
name="Invalid Test",
|
||||
episode_body="Test content",
|
||||
source_description="Test",
|
||||
name='Invalid Test',
|
||||
episode_body='Test content',
|
||||
source_description='Test',
|
||||
reference_time=datetime.now(timezone.utc),
|
||||
entity_types=entity_types,
|
||||
excluded_entity_types=['NonExistentType'],
|
||||
group_id='test_validation'
|
||||
group_id='test_validation',
|
||||
)
|
||||
|
||||
|
||||
finally:
|
||||
await graphiti.close()
|
||||
|
||||
|
|
@ -317,15 +328,12 @@ async def _cleanup_test_nodes(graphiti: Graphiti, group_id: str):
|
|||
"""Helper function to clean up test nodes."""
|
||||
try:
|
||||
# Get all nodes for this group
|
||||
search_results = await graphiti.search_(
|
||||
query="*",
|
||||
group_ids=[group_id]
|
||||
)
|
||||
|
||||
search_results = await graphiti.search_(query='*', group_ids=[group_id])
|
||||
|
||||
# Delete all found nodes
|
||||
for node in search_results.nodes:
|
||||
await node.delete(graphiti.driver)
|
||||
|
||||
|
||||
except Exception as e:
|
||||
# Log but don't fail the test if cleanup fails
|
||||
print(f"Warning: Failed to clean up test nodes for group {group_id}: {e}")
|
||||
print(f'Warning: Failed to clean up test nodes for group {group_id}: {e}')
|
||||
|
|
|
|||
115
uv.lock
generated
115
uv.lock
generated
|
|
@ -266,6 +266,15 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backoff"
|
||||
version = "2.2.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/47/d7/5bbeb12c44d7c4f2fb5b56abce497eb5ed9f34d85701de869acedd602619/backoff-2.2.1.tar.gz", hash = "sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba", size = 17001 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/df/73/b6e24bd22e6720ca8ee9a85a0c4a2971af8497d8f3193fa05390cbd46e09/backoff-2.2.1-py3-none-any.whl", hash = "sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8", size = 15148 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "beautifulsoup4"
|
||||
version = "4.13.4"
|
||||
|
|
@ -531,7 +540,7 @@ name = "exceptiongroup"
|
|||
version = "1.3.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.12'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749 }
|
||||
wheels = [
|
||||
|
|
@ -729,13 +738,14 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "graphiti-core"
|
||||
version = "0.13.2"
|
||||
version = "0.14.0"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "diskcache" },
|
||||
{ name = "neo4j" },
|
||||
{ name = "numpy" },
|
||||
{ name = "openai" },
|
||||
{ name = "posthog" },
|
||||
{ name = "pydantic" },
|
||||
{ name = "python-dotenv" },
|
||||
{ name = "tenacity" },
|
||||
|
|
@ -756,7 +766,7 @@ dev = [
|
|||
{ name = "langchain-openai" },
|
||||
{ name = "langgraph" },
|
||||
{ name = "langsmith" },
|
||||
{ name = "mypy" },
|
||||
{ name = "pyright" },
|
||||
{ name = "pytest" },
|
||||
{ name = "pytest-asyncio" },
|
||||
{ name = "pytest-xdist" },
|
||||
|
|
@ -792,11 +802,12 @@ requires-dist = [
|
|||
{ name = "langchain-openai", marker = "extra == 'dev'", specifier = ">=0.2.6" },
|
||||
{ name = "langgraph", marker = "extra == 'dev'", specifier = ">=0.2.15" },
|
||||
{ name = "langsmith", marker = "extra == 'dev'", specifier = ">=0.1.108" },
|
||||
{ name = "mypy", marker = "extra == 'dev'", specifier = ">=1.11.1" },
|
||||
{ name = "neo4j", specifier = ">=5.26.0" },
|
||||
{ name = "numpy", specifier = ">=1.0.0" },
|
||||
{ name = "openai", specifier = ">=1.91.0" },
|
||||
{ name = "posthog", specifier = ">=3.0.0" },
|
||||
{ name = "pydantic", specifier = ">=2.11.5" },
|
||||
{ name = "pyright", marker = "extra == 'dev'", specifier = ">=1.1.380" },
|
||||
{ name = "pytest", marker = "extra == 'dev'", specifier = ">=8.3.3" },
|
||||
{ name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=0.24.0" },
|
||||
{ name = "pytest-xdist", marker = "extra == 'dev'", specifier = ">=3.6.1" },
|
||||
|
|
@ -1605,54 +1616,6 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/07/9f/d4719ce55a1d8bf6619e8bb92f1e2e7399026ea85ae0c324ec77ee06c050/multidict-6.5.1-py3-none-any.whl", hash = "sha256:895354f4a38f53a1df2cc3fa2223fa714cff2b079a9f018a76cad35e7f0f044c", size = 12185 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mypy"
|
||||
version = "1.16.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "mypy-extensions" },
|
||||
{ name = "pathspec" },
|
||||
{ name = "tomli", marker = "python_full_version < '3.11'" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/81/69/92c7fa98112e4d9eb075a239caa4ef4649ad7d441545ccffbd5e34607cbb/mypy-1.16.1.tar.gz", hash = "sha256:6bd00a0a2094841c5e47e7374bb42b83d64c527a502e3334e1173a0c24437bab", size = 3324747 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/8e/12/2bf23a80fcef5edb75de9a1e295d778e0f46ea89eb8b115818b663eff42b/mypy-1.16.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b4f0fed1022a63c6fec38f28b7fc77fca47fd490445c69d0a66266c59dd0b88a", size = 10958644 },
|
||||
{ url = "https://files.pythonhosted.org/packages/08/50/bfe47b3b278eacf348291742fd5e6613bbc4b3434b72ce9361896417cfe5/mypy-1.16.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:86042bbf9f5a05ea000d3203cf87aa9d0ccf9a01f73f71c58979eb9249f46d72", size = 10087033 },
|
||||
{ url = "https://files.pythonhosted.org/packages/21/de/40307c12fe25675a0776aaa2cdd2879cf30d99eec91b898de00228dc3ab5/mypy-1.16.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ea7469ee5902c95542bea7ee545f7006508c65c8c54b06dc2c92676ce526f3ea", size = 11875645 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a6/d8/85bdb59e4a98b7a31495bd8f1a4445d8ffc86cde4ab1f8c11d247c11aedc/mypy-1.16.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:352025753ef6a83cb9e7f2427319bb7875d1fdda8439d1e23de12ab164179574", size = 12616986 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0e/d0/bb25731158fa8f8ee9e068d3e94fcceb4971fedf1424248496292512afe9/mypy-1.16.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ff9fa5b16e4c1364eb89a4d16bcda9987f05d39604e1e6c35378a2987c1aac2d", size = 12878632 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2d/11/822a9beb7a2b825c0cb06132ca0a5183f8327a5e23ef89717c9474ba0bc6/mypy-1.16.1-cp310-cp310-win_amd64.whl", hash = "sha256:1256688e284632382f8f3b9e2123df7d279f603c561f099758e66dd6ed4e8bd6", size = 9484391 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9a/61/ec1245aa1c325cb7a6c0f8570a2eee3bfc40fa90d19b1267f8e50b5c8645/mypy-1.16.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:472e4e4c100062488ec643f6162dd0d5208e33e2f34544e1fc931372e806c0cc", size = 10890557 },
|
||||
{ url = "https://files.pythonhosted.org/packages/6b/bb/6eccc0ba0aa0c7a87df24e73f0ad34170514abd8162eb0c75fd7128171fb/mypy-1.16.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ea16e2a7d2714277e349e24d19a782a663a34ed60864006e8585db08f8ad1782", size = 10012921 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5f/80/b337a12e2006715f99f529e732c5f6a8c143bb58c92bb142d5ab380963a5/mypy-1.16.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:08e850ea22adc4d8a4014651575567b0318ede51e8e9fe7a68f25391af699507", size = 11802887 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d9/59/f7af072d09793d581a745a25737c7c0a945760036b16aeb620f658a017af/mypy-1.16.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22d76a63a42619bfb90122889b903519149879ddbf2ba4251834727944c8baca", size = 12531658 },
|
||||
{ url = "https://files.pythonhosted.org/packages/82/c4/607672f2d6c0254b94a646cfc45ad589dd71b04aa1f3d642b840f7cce06c/mypy-1.16.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:2c7ce0662b6b9dc8f4ed86eb7a5d505ee3298c04b40ec13b30e572c0e5ae17c4", size = 12732486 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b6/5e/136555ec1d80df877a707cebf9081bd3a9f397dedc1ab9750518d87489ec/mypy-1.16.1-cp311-cp311-win_amd64.whl", hash = "sha256:211287e98e05352a2e1d4e8759c5490925a7c784ddc84207f4714822f8cf99b6", size = 9479482 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b4/d6/39482e5fcc724c15bf6280ff5806548c7185e0c090712a3736ed4d07e8b7/mypy-1.16.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:af4792433f09575d9eeca5c63d7d90ca4aeceda9d8355e136f80f8967639183d", size = 11066493 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e6/e5/26c347890efc6b757f4d5bb83f4a0cf5958b8cf49c938ac99b8b72b420a6/mypy-1.16.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:66df38405fd8466ce3517eda1f6640611a0b8e70895e2a9462d1d4323c5eb4b9", size = 10081687 },
|
||||
{ url = "https://files.pythonhosted.org/packages/44/c7/b5cb264c97b86914487d6a24bd8688c0172e37ec0f43e93b9691cae9468b/mypy-1.16.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:44e7acddb3c48bd2713994d098729494117803616e116032af192871aed80b79", size = 11839723 },
|
||||
{ url = "https://files.pythonhosted.org/packages/15/f8/491997a9b8a554204f834ed4816bda813aefda31cf873bb099deee3c9a99/mypy-1.16.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0ab5eca37b50188163fa7c1b73c685ac66c4e9bdee4a85c9adac0e91d8895e15", size = 12722980 },
|
||||
{ url = "https://files.pythonhosted.org/packages/df/f0/2bd41e174b5fd93bc9de9a28e4fb673113633b8a7f3a607fa4a73595e468/mypy-1.16.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb6229b2c9086247e21a83c309754b9058b438704ad2f6807f0d8227f6ebdd", size = 12903328 },
|
||||
{ url = "https://files.pythonhosted.org/packages/61/81/5572108a7bec2c46b8aff7e9b524f371fe6ab5efb534d38d6b37b5490da8/mypy-1.16.1-cp312-cp312-win_amd64.whl", hash = "sha256:1f0435cf920e287ff68af3d10a118a73f212deb2ce087619eb4e648116d1fe9b", size = 9562321 },
|
||||
{ url = "https://files.pythonhosted.org/packages/28/e3/96964af4a75a949e67df4b95318fe2b7427ac8189bbc3ef28f92a1c5bc56/mypy-1.16.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ddc91eb318c8751c69ddb200a5937f1232ee8efb4e64e9f4bc475a33719de438", size = 11063480 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f5/4d/cd1a42b8e5be278fab7010fb289d9307a63e07153f0ae1510a3d7b703193/mypy-1.16.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:87ff2c13d58bdc4bbe7dc0dedfe622c0f04e2cb2a492269f3b418df2de05c536", size = 10090538 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c9/4f/c3c6b4b66374b5f68bab07c8cabd63a049ff69796b844bc759a0ca99bb2a/mypy-1.16.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a7cfb0fe29fe5a9841b7c8ee6dffb52382c45acdf68f032145b75620acfbd6f", size = 11836839 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b4/7e/81ca3b074021ad9775e5cb97ebe0089c0f13684b066a750b7dc208438403/mypy-1.16.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:051e1677689c9d9578b9c7f4d206d763f9bbd95723cd1416fad50db49d52f359", size = 12715634 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/95/bdd40c8be346fa4c70edb4081d727a54d0a05382d84966869738cfa8a497/mypy-1.16.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d5d2309511cc56c021b4b4e462907c2b12f669b2dbeb68300110ec27723971be", size = 12895584 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5a/fd/d486a0827a1c597b3b48b1bdef47228a6e9ee8102ab8c28f944cb83b65dc/mypy-1.16.1-cp313-cp313-win_amd64.whl", hash = "sha256:4f58ac32771341e38a853c5d0ec0dfe27e18e27da9cdb8bbc882d2249c71a3ee", size = 9573886 },
|
||||
{ url = "https://files.pythonhosted.org/packages/cf/d3/53e684e78e07c1a2bf7105715e5edd09ce951fc3f47cf9ed095ec1b7a037/mypy-1.16.1-py3-none-any.whl", hash = "sha256:5fc2ac4027d0ef28d6ba69a0343737a23c4d1b83672bf38d1fe237bdc0643b37", size = 2265923 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mypy-extensions"
|
||||
version = "1.1.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nbclient"
|
||||
version = "0.10.2"
|
||||
|
|
@ -1738,6 +1701,15 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/b9/54/dd730b32ea14ea797530a4479b2ed46a6fb250f682a9cfb997e968bf0261/networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f", size = 1723263 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nodeenv"
|
||||
version = "1.9.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "notebook-shim"
|
||||
version = "0.2.4"
|
||||
|
|
@ -2127,15 +2099,6 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18", size = 103650 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pathspec"
|
||||
version = "0.12.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pexpect"
|
||||
version = "4.9.0"
|
||||
|
|
@ -2243,6 +2206,23 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "posthog"
|
||||
version = "6.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "backoff" },
|
||||
{ name = "distro" },
|
||||
{ name = "python-dateutil" },
|
||||
{ name = "requests" },
|
||||
{ name = "six" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f3/c3/c83883af8cc5e3b45d1bee85edce546a4db369fb8dc8eb6339fad764178b/posthog-6.0.0.tar.gz", hash = "sha256:b7bfa0da03bd9240891885d3e44b747e62192ac9ee6da280f45320f4ad3479e0", size = 88066 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ab/ec/7a44533c9fe7046ffcfe48ca0e7472ada2633854f474be633f4afed7b044/posthog-6.0.0-py3-none-any.whl", hash = "sha256:01f5d11046a6267d4384f552e819f0f4a7dc885eb19f606c36d44d662df9ff89", size = 104945 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prometheus-client"
|
||||
version = "0.22.1"
|
||||
|
|
@ -2536,6 +2516,19 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/79/84/0fdf9b18ba31d69877bd39c9cd6052b47f3761e9910c15de788e519f079f/PyJWT-2.9.0-py3-none-any.whl", hash = "sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850", size = 22344 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyright"
|
||||
version = "1.1.402"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "nodeenv" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/aa/04/ce0c132d00e20f2d2fb3b3e7c125264ca8b909e693841210534b1ea1752f/pyright-1.1.402.tar.gz", hash = "sha256:85a33c2d40cd4439c66aa946fd4ce71ab2f3f5b8c22ce36a623f59ac22937683", size = 3888207 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/fe/37/1a1c62d955e82adae588be8e374c7f77b165b6cb4203f7d581269959abbc/pyright-1.1.402-py3-none-any.whl", hash = "sha256:2c721f11869baac1884e846232800fe021c33f1b4acb3929cff321f7ea4e2982", size = 5624004 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "8.4.1"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue