Ctrl K
ComunidadGuías…

pyproject.toml

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
[project]
name = "basic-memory"
dynamic = ["version"]
description = "Local-first knowledge management combining Zettelkasten with knowledge graphs"
readme = "README.md"
requires-python = ">=3.12"
license = { text = "AGPL-3.0-or-later" }
authors = [
    { name = "Basic Machines", email = "hello@basic-machines.co" }
]
dependencies = [
    "sqlalchemy>=2.0.0",
    "pyyaml>=6.0.1",
    "typer>=0.9.0",
    "aiosqlite>=0.20.0",
    "greenlet>=3.1.1",
    "pydantic[email,timezone]>=2.12.0",
    "mcp>=2,<3",
    "pydantic-settings>=2.6.1",
    "loguru>=0.7.3",
    "pyright>=1.1.390",
    "markdown-it-py>=3.0.0",
    "python-frontmatter>=1.1.0",
    "rich>=13.9.4",
    "unidecode>=1.3.8",
    "dateparser>=1.2.0",
    "watchfiles>=1.0.4",
    "fastapi[standard]==0.162.0",
    "alembic>=1.14.1",
    "pillow>=11.1.0",
    "pybars3>=0.9.7",
    "fastmcp==4.1.3",
    "pyjwt>=2.15.0",
    "python-dotenv>=1.1.0",
    "pytest-aio>=1.9.0",
    "aiofiles>=24.1.0",
    "asyncpg>=0.30.0",
    "pytest-asyncio>=1.2.0",
    "psycopg==3.3.1",
    "sniffio>=1.3.1",
    "anyio>=4.10.0",
    "httpx>=0.28.0",
    "fastembed>=0.7.4",
    "sqlite-vec>=0.1.6",
    "openai>=1.100.2",
    # The fastapi extra lets read-cache tests instrument the app as production does.
    "logfire[fastapi]>=4.19.0",
    "psutil>=5.9.0",
    # uvloop's C event loop has no self._ready.popleft() codepath, so the
    # asyncpg engine-dispose race ("IndexError: pop from an empty deque") that
    # crashes the Postgres backend cannot fire under it. Not available on Windows.
    "uvloop>=0.21.0; sys_platform != 'win32'",
    # Cross-platform advisory file lock (already resolved transitively via
    # huggingface-hub; declared directly since the hook flush path imports it).
    # Serializes concurrent `bm hook flush` runs so a stale sweep can't overwrite
    # an artifact without a sibling flush's just-retired event.
    "filelock>=3.12",
    "fastapi-redis-sdk==0.8.1",
    "pathspec>=1.1.1,<2",
]

[project.optional-dependencies]
# Explicit opt-in: default local and OpenAI embeddings do not need this SDK.
# Preserve the Python 3.14-compatible range; 1.92 introduced an incompatible Rust bridge.
litellm = [
    "litellm>=1.91.5,<1.92.0",
]
milvus = [
    "pymilvus>=3.0.0,<4; sys_platform == 'win32'",
    "pymilvus[milvus-lite]>=3.0.0,<4; sys_platform != 'win32'",
]
redis = [
    "redis>=8.0.0,<9",
]
# Native PDF extraction for document ingestion. Optional so the default install
# stays parser-free; the worker records the installed version in run identity.
pdf = [
    "pdf-inspector>=0.2.6,<2",
]
documents = [
    "markitdown[docx,pptx]>=0.1.7,<0.2",
    # Footnote parsing for the document page-citation tests.
    "mdit-py-plugins>=0.6.1",
]

[project.urls]
Homepage = "https://github.com/basicmachines-co/basic-memory"
Repository = "https://github.com/basicmachines-co/basic-memory"
Documentation = "https://github.com/basicmachines-co/basic-memory#readme"

[project.scripts]
basic-memory = "basic_memory.cli.main:app"
bm = "basic_memory.cli.main:app"

[build-system]
requires = ["hatchling", "uv-dynamic-versioning>=0.7.0"]
build-backend = "hatchling.build"

[tool.pytest.ini_options]
pythonpath = ["src", "tests"]
# plugins/ carries the co-located uv hook-script tests (one per script).
testpaths = ["tests", "test-int", "plugins"]
asyncio_mode = "strict"
asyncio_default_fixture_loop_scope = "function"
# Any test hanging >120s fails with a stack dump instead of stalling the CI job
# until the runner times out (the FastMCP/asyncpg cleanup-hang family).
timeout = 120
timeout_method = "thread"
filterwarnings = [
    "ignore:The @wait_container_is_ready decorator is deprecated.*:DeprecationWarning:testcontainers\\.core\\.waiting_utils",
    "ignore:The default datetime adapter is deprecated as of Python 3\\.12.*:DeprecationWarning:aiosqlite\\.core",
    "ignore:codecs\\.open\\(\\) is deprecated\\. Use open\\(\\) instead\\.:DeprecationWarning:frontmatter",
    "ignore:Parsing dates involving a day of month without a year specified is ambiguous.*:DeprecationWarning:dateparser\\.utils\\.strptime",
]
markers = [
    "benchmark: Performance benchmark tests (deselect with '-m \"not benchmark\"')",
    "slow: Slow-running tests (deselect with '-m \"not slow\"')",
    "postgres: Tests that run against Postgres backend (deselect with '-m \"not postgres\"')",
    "redis: Tests that run against a real Redis server",
    "windows: Windows-specific tests (deselect with '-m \"not windows\"')",
    "smoke: Fast end-to-end smoke tests for MCP flows",
    "semantic: Tests requiring semantic dependencies (fastembed, sqlite-vec, openai)",
    "real_embedder: Tests that exercise the real FastEmbed provider instead of the test embedder",
    "live: Tests that call external provider APIs and require explicit opt-in",
]

[tool.ruff]
extend-exclude = ["*.md"]
line-length = 100
target-version = "py312"

[tool.ruff.lint]
# Ruff 0.16 expanded its defaults; preserve the repository's established lint baseline.
select = ["E4", "E7", "E9", "F"]

[dependency-groups]
dev = [
    # The fastapi extra lets read-cache tests instrument the app as production does.
    "logfire[fastapi]>=4.19.0",
    "icecream>=2.1.3",
    "pytest>=8.3.4",
    "pytest-cov>=4.1.0",
    "pytest-mock>=3.12.0",
    "pytest-asyncio>=0.24.0",
    "pytest-xdist>=3.0.0",
    "ruff>=0.16.0",
    "freezegun>=1.5.5",
    "testcontainers[postgres]>=4.0.0",
    "redis>=8.0.0,<9",
    "pdf-inspector>=0.2.6,<2",
    "psycopg>=3.2.0",
    "pyright>=1.1.408",
    "pytest-testmon>=2.2.0",
    "ty>=0.0.64",
    "cst-lsp>=0.1.3",
    "libcst>=1.8.6",
    "pytest-timeout>=2.4.0",
    "pytest-split>=0.11.0",
    "markitdown[docx,pptx]>=0.1.7,<0.2",
    # Footnote parsing for the document page-citation tests.
    "mdit-py-plugins>=0.6.1",
]

[tool.hatch.version]
source = "uv-dynamic-versioning"

# Explicit resources only: never ship integration venvs, caches, or test data.
[tool.hatch.build.targets.wheel.force-include]
"integrations/tau/Basic Memory.py" = "basic_memory/data/tau/extension/Basic Memory.py"
"integrations/tau/extension.py" = "basic_memory/data/tau/extension/extension.py"
"integrations/tau/bridge.py" = "basic_memory/data/tau/extension/bridge.py"
"integrations/tau/continuity.py" = "basic_memory/data/tau/extension/continuity.py"
"integrations/tau/knowledge.py" = "basic_memory/data/tau/extension/knowledge.py"
"integrations/tau/privacy.py" = "basic_memory/data/tau/extension/privacy.py"
"integrations/tau/results.py" = "basic_memory/data/tau/extension/results.py"
"integrations/tau/pyproject.toml" = "basic_memory/data/tau/extension/pyproject.toml"
"integrations/tau/uv.lock" = "basic_memory/data/tau/extension/uv.lock"
"integrations/tau/README.md" = "basic_memory/data/tau/extension/README.md"
"integrations/tau/schemas" = "basic_memory/data/tau/extension/schemas"
"integrations/tau/prompts" = "basic_memory/data/tau/prompts"
# Distributed skills, for hosts that load SKILL.md files from the installed package
# (Cloud agents). Same set as the release archives: internal skills, evals/ and
# agents/ stay out. tests/test_skills_dist.py fails when this list drifts.
# Skills the Tau mapping below also copies are keyed by SKILL.md: TOML keys are unique.
"skills/memory-agents" = "basic_memory/data/skills/memory-agents"
"skills/memory-capture" = "basic_memory/data/skills/memory-capture"
"skills/memory-comark" = "basic_memory/data/skills/memory-comark"
"skills/memory-continue/SKILL.md" = "basic_memory/data/skills/memory-continue/SKILL.md"
"skills/memory-curate" = "basic_memory/data/skills/memory-curate"
"skills/memory-doctor" = "basic_memory/data/skills/memory-doctor"
"skills/memory-defrag" = "basic_memory/data/skills/memory-defrag"
"skills/memory-ingest" = "basic_memory/data/skills/memory-ingest"
"skills/memory-lifecycle" = "basic_memory/data/skills/memory-lifecycle"
"skills/memory-literary-analysis" = "basic_memory/data/skills/memory-literary-analysis"
"skills/memory-metadata-search" = "basic_memory/data/skills/memory-metadata-search"
"skills/memory-notes/SKILL.md" = "basic_memory/data/skills/memory-notes/SKILL.md"
"skills/memory-okf" = "basic_memory/data/skills/memory-okf"
"skills/memory-onboarding/SKILL.md" = "basic_memory/data/skills/memory-onboarding/SKILL.md"
"skills/memory-onboarding/references" = "basic_memory/data/skills/memory-onboarding/references"
"skills/memory-quest/SKILL.md" = "basic_memory/data/skills/memory-quest/SKILL.md"
"skills/memory-reflect" = "basic_memory/data/skills/memory-reflect"
"skills/memory-research" = "basic_memory/data/skills/memory-research"
"skills/memory-schema/SKILL.md" = "basic_memory/data/skills/memory-schema/SKILL.md"
"skills/memory-start" = "basic_memory/data/skills/memory-start"
"skills/memory-tasks/SKILL.md" = "basic_memory/data/skills/memory-tasks/SKILL.md"
"integrations/tau/skills/basic-memory-setup" = "basic_memory/data/tau/skills/basic-memory-setup"
"skills/memory-continue" = "basic_memory/data/tau/skills/memory-continue"
"skills/memory-tasks" = "basic_memory/data/tau/skills/memory-tasks"
"skills/memory-notes" = "basic_memory/data/tau/skills/memory-notes"
"skills/memory-schema" = "basic_memory/data/tau/skills/memory-schema"
"integrations/pi/extensions" = "basic_memory/data/pi/package/extensions"
"integrations/pi/skills" = "basic_memory/data/pi/package/skills"
"integrations/pi/skill-references" = "basic_memory/data/pi/package/skill-references"
"integrations/pi/package.json" = "basic_memory/data/pi/package/package.json"
"integrations/pi/package-lock.json" = "basic_memory/data/pi/package/package-lock.json"
"integrations/pi/README.md" = "basic_memory/data/pi/package/README.md"
"integrations/pi/SKILLS.md" = "basic_memory/data/pi/package/SKILLS.md"
"integrations/pi/LICENSE" = "basic_memory/data/pi/package/LICENSE"

[tool.uv-dynamic-versioning]
vcs = "git"
style = "pep440"
bump = true
fallback-version = "0.0.0"

[tool.ty.environment]
# Mirrors pytest's pythonpath, which puts tests/ on the import path for shared helpers.
extra-paths = ["tests"]

[tool.ty.rules]
all = "error"



[tool.coverage.run]
# Nothing in basic_memory uses gevent. Declaring it forced the slower C tracer on
# every coverage run and doubled test time; sysmon (COVERAGE_CORE) needs it gone.
concurrency = ["thread"]
parallel = true
source = ["basic_memory"]

[tool.coverage.report]
# A ratchet, not the goal: CI's combined coverage over all four suites measured
# 96.34% when it started enforcing it (97.16% locally on macOS). Raise it as gaps
# close; the target is 100%.
fail_under = 96
exclude_lines = [
    "pragma: no cover",
    "def __repr__",
    "if self.debug:",
    "if settings.DEBUG",
    "raise AssertionError",
    "raise NotImplementedError",
    "if 0:",
    "if __name__ == .__main__.:",
    "class .*\\bProtocol\\):",
    "@(abc\\.)?abstractmethod",
]

# Exclude specific modules that are difficult to test comprehensively
omit = [
    "*/external_auth_provider.py",  # External HTTP calls to OAuth providers
    "*/supabase_auth_provider.py",  # External HTTP calls to Supabase APIs
    "*/watch_service.py",           # File system watching - complex integration testing
    "*/background_sync.py",         # Background processes
    "*/cli/**",                    # CLI is an interactive wrapper; core logic is covered via API/MCP/service tests
    "*/db.py",                     # Backend/runtime-dependent (sqlite/postgres/windows tuning); validated via integration tests
    "*/services/initialization.py", # Startup orchestration + background tasks (watchers); exercised indirectly in entrypoints
    "*/sync/sync_service.py",      # Heavy filesystem/db integration; covered by integration suite, not enforced in unit coverage
    "*/services/migration_service.py", # Complex migration scenarios
]