[build-system] requires = ["hatchling>=1.8.0"] build-backend = "hatchling.build" [project] name = "haystack-ai" dynamic = ["version"] description = "LLM framework to build customizable, production-ready LLM applications. Connect components (models, vector DBs, file converters) to pipelines or agents that can interact with your data." readme = "README.md" license = "Apache-2.0" requires-python = ">=3.10" authors = [{ name = "deepset.ai", email = "malte.pietsch@deepset.ai" }] keywords = [ "BERT", "QA", "Question-Answering", "Reader", "Retriever", "albert", "language-model", "mrc", "roberta", "search", "semantic-search", "squad", "transfer-learning", "transformer", ] classifiers = [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Science/Research", "License :: Freely Distributable", "License :: OSI Approved :: Apache Software License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Scientific/Engineering :: Artificial Intelligence", ] dependencies = [ "tqdm", "tenacity!=8.4.0", "lazy-imports", "openai>=1.99.2", "pydantic", "Jinja2", "MarkupSafe", # already required by Jinja2 but used directly in templatize_part "posthog!=3.12.0", # telemetry # 3.12.0 was problematic https://github.com/PostHog/posthog-python/issues/187 "pyyaml", "more-itertools", # DocumentSplitter "networkx", # Pipeline graphs "typing_extensions>=4.7", # Extended typing features (NotRequired, etc.) "httpx", "numpy", "python-dateutil", "jsonschema", # JsonSchemaValidator, Tool "docstring-parser", # ComponentTool "filetype", # MIME type guessing for ImageContent ] [tool.hatch.envs.default] installer = "uv" dependencies = [ "pre-commit", "ruff>=0.15.0", # RUF104 (unmatched-suppression-comment) added in 0.15.0 "toml", "reno", # dulwich is a reno dependency, they pin it at >=0.15.0 so pip takes ton of time to resolve the dependency tree. # We pin it here to avoid taking too much time. # https://opendev.org/openstack/reno/src/branch/master/requirements.txt#L7 "dulwich>=0.21.0,<1.0.0", "haystack-pydoc-tools", ] [tool.hatch.envs.default.scripts] release-note = "reno new {args}" fmt = "ruff check --fix {args}; ruff format {args}" fmt-check = "ruff check {args} && ruff format --check {args}" docs = "haystack-pydoc pydoc tmp_api_reference" [tool.hatch.envs.test] # we override dependencies from the default environment dependencies = [ "numpy>=2", # Haystack is compatible both with numpy 1.x and 2.x, but we test with 2.x "numba>=0.54.0", # This pin helps uv resolve the dependency tree. See https://github.com/astral-sh/uv/issues/7881 "pandas", # AzureOCRDocumentConverter, CSVDocumentCleaner, CSVDocumentSplitter, # EvaluationRunResult, XLSXToDocument, and pipeline tests "transformers[torch, sentencepiece]>=4.57", # SASEvaluator and TopPSampler "sentence-transformers>=5.0.0", # SASEvaluator "arrow>=1.3.0", # Jinja2TimeExtension "pillow", # ImageContent "pypdfium2", # PDFToImageContent # Converters "pypdf", # PyPDFToDocument "pdfminer.six", # PDFMinerToDocument "markdown-it-py", # MarkdownToDocument "mdit_plain", # MarkdownToDocument "trafilatura", # HTMLToDocument "python-pptx", # PPTXToDocument "python-docx", # DocxToDocument "jq", # JSONConverter "openpyxl", # XLSXToDocument "tabulate", # XLSXToDocument "python-oxmsg", # MSGToDocument "nltk>=3.9.1", # NLTKDocumentSplitter, RecursiveDocumentSplitter "tiktoken", # RecursiveDocumentSplitter # Human in the Loop "rich", # Console rendering for HITL # Structured logging "structlog", # needed in link content fetcher tests "httpx[http2]", # Azure Utils "azure-identity", # Test "pytest", "pytest-bdd", "pytest-cov", "pytest-asyncio", "pytest-rerunfailures", "coverage", "mypy", "pip", # mypy needs pip to install missing stub packages "ipython", "colorama==0.4.6", # Pipeline checkpoints test ] [tool.hatch.envs.test.scripts] unit = 'pytest --cov="haystack" -m "not integration" {args:test}' integration = 'pytest --maxfail=5 -m "integration" {args:test}' integration-only-fast = 'pytest --maxfail=5 -m "integration and not slow" {args:test}' integration-only-slow = 'pytest --maxfail=5 -m "integration and slow" {args:test}' all = 'pytest {args:test}' e2e = 'pytest {args:e2e}' # TODO We want to eventually type the whole test folder types = "mypy --install-types --non-interactive --cache-dir=.mypy_cache/ {args:haystack test/core/ test/marshal/ test/testing/ test/tracing/ test/tools/ test/human_in_the_loop test/evaluation test/document_stores test/dataclasses test/utils/ test/components/embedders/}" [project.urls] "CI: GitHub" = "https://github.com/deepset-ai/haystack/actions" "Docs: RTD" = "https://haystack.deepset.ai/overview/intro" "GitHub: issues" = "https://github.com/deepset-ai/haystack/issues" "GitHub: repo" = "https://github.com/deepset-ai/haystack" Homepage = "https://github.com/deepset-ai/haystack" [tool.hatch.version] path = "VERSION.txt" pattern = "(?P.+)" [tool.hatch.metadata] allow-direct-references = true [tool.hatch.build.targets.sdist] include = ["/haystack", "/VERSION.txt"] [tool.hatch.build.targets.wheel] packages = ["haystack"] [tool.codespell] ignore-words-list = "ans,astroid,nd,ned,nin,ue,rouge,ist, Claus,SME" quiet-level = 3 skip = "./test,./e2e,*.svg,*/abbreviations/*" [tool.pytest.ini_options] minversion = "6.0" addopts = "--strict-markers" markers = [ "unit: unit tests", "integration: integration tests", # integration tests that are slow (e.g. model inference on CPU), unstable (e.g. call unstable external services) # or require special setup (e.g. installing system dependencies, running Docker containers) "slow: slow/unstable integration tests", ] log_cli = true asyncio_mode = "auto" asyncio_default_fixture_loop_scope = "class" [tool.mypy] python_version = "3.10" check_untyped_defs = true disallow_incomplete_defs = true ignore_missing_imports = true warn_unused_ignores = true warn_redundant_casts = true warn_return_any = false [[tool.mypy.overrides]] # TODO: Fix testing typings module = ["haystack.testing.*"] disallow_incomplete_defs = false [tool.ruff] exclude = ["e2e/**", "proposals"] line-length = 120 [tool.ruff.format] skip-magic-trailing-comma = true [tool.ruff.lint.isort] split-on-trailing-comma = false [tool.ruff.lint.mccabe] max-complexity = 20 # Default is 10 for Ruff [tool.ruff.lint.pylint] allow-magic-value-types = ["float", "int", "str"] max-args = 13 # Default is 5 max-branches = 21 # Default is 12 max-public-methods = 20 # Default is 20 max-returns = 7 # Default is 6 max-statements = 56 # Default is 50 [tool.ruff.lint] select = [ "A001", # builtin-variable-shadowing "A002", # builtin-argument-shadowing "A003", # builtin-attribute-shadowing "ANN", # flake8-annotations "ARG", # flake8-unused-arguments "ASYNC", # flake8-async "B", # flake8-bugbear "BLE", # flake8-blind-except "C4", # flake8-comprehensions "C90", # mccabe complexity "COM818", # trailing-comma-on-bare-tuple "D102", # Missing docstring in public method "D103", # Missing docstring in public function "D205", # 1 blank line required between summary line and description "D209", # Closing triple quotes go to new line "D213", # summary lines must be positioned on the second physical line of the docstring "D417", # undocumented-parameter "D419", # undocumented-returns "E", # pycodestyle errors "EXE", # flake8-executable "F", # pyflakes "G001", # logging-format-interpolation "G002", # logging-percent-format "G004", # logging-f-string "I", # isort "ISC001", # implicit-string-concatenation "INT", # flake8-gettext "PERF", # perflint "PIE", # flake8-pie "PL", # pylint "RET", # flake8-return "RUF104", # unmatched-suppression-comment "S102", # flake8-bandit (exec-builtin) "S307", # flake8-bandit (eval) "SIM", # flake8-simplify "SLOT", # flake8-slots "T10", # flake8-debugger "TID252", # relative-imports "TRY", # tryceratops "UP", # pyupgrade "W", # pycodestyle warnings "YTT", # flake8-2020 ] ignore = [ "ANN401", # Allow `Any` - used legitimately for dynamic types and SDK boundaries "B008", # function-call-as-argument-default "B904", # raise-without-from-inside-except "BLE001", # blind-except "E721", # type-comparison "E722", # bare-except "PERF203", # try-except-in-loop "PERF401", # manual-list-comprehension "PIE790", # unnecessary-pass # we re-export symbols in __init__ for correct type checking # https://typing.python.org/en/latest/spec/distributing.html#import-conventions "PLC0414", # useless-import-alias "PLC0415", # import-outside-top-level "PLR1714", # repeated-equality-comparison "PLW0603", # global-statement "PLW1514", # unspecified-encoding "PLW2901", # redefined-loop-name "RET505", # superfluous-else-return "SIM108", # if-else-block-instead-of-ternary "SIM109", # multiple-comparisons-with-in "SIM118", # in-dict-keys "TRY002", # raise-vanilla-class "TRY003", # raise-vanilla-args "TRY201", # verbose-raise "TRY300", # try-consider-else "UP008", # super-with-arguments "UP032", # use-f-string "UP037", # quoted-annotation ] [tool.ruff.lint.per-file-ignores] "test/**" = [ "ANN", # flake8-annotations "ARG", # flake8-unused-arguments "B018", # useless-expression "D", # pydocstyle (docstring checks) "E711", # none-comparison "E731", # lambda-assignment "PLC0206", # dict-index-missing-items "SIM105", # suppressible-exception "SIM117", # multiple-with-statements ] # in the following files, we still allow old type hints to handle and test them # UP006: generics like typing.List, typing.Dict # UP007: Union[X, Y] syntax # UP035: Deprecated import # UP045: Optional[X] syntax "haystack/testing/**" = ["ANN"] "haystack/components/agents/state/state_utils.py" = ["UP007"] "haystack/core/super_component/utils.py" = ["UP007"] "haystack/core/type_utils.py" = ["UP007"] "haystack/tools/parameters_schema_utils.py" = ["UP007"] "test/components/agents/test_state_class.py" = ["UP006", "UP007", "UP035", "UP045"] "test/components/converters/test_output_adapter.py" = ["UP006", "UP035"] "test/components/joiners/test_list_joiner.py" = ["UP006", "UP035"] "test/core/pipeline/test_type_syntax_compatibility.py" = ["UP007", "UP045"] "test/core/super_component/test_utils.py" = ["UP007", "UP045"] "test/core/test_type_utils.py" = ["UP006", "UP007", "UP035", "UP045"] "test/tools/test_parameters_schema_utils.py" = ["UP007"] "test/utils/test_type_serialization.py" = ["UP006", "UP007", "UP035", "UP045"] [tool.uv] # Exclude package versions published within the last 24 hours to protect against supply chain # attacks via compromised dependencies. uv resolves this relative to the current clock at # install/lock time, so no manual date updates are needed. # First-party packages are exempted so freshly published releases are always resolvable. exclude-newer = "24 hours" exclude-newer-package = { haystack-pydoc-tools = "0 days" } [tool.coverage.run] omit = ["haystack/testing/*"] relative_files = true