[project] name = "unstructured" description = "A library that prepares raw documents for downstream ML tasks." requires-python = ">=3.11, <3.14" authors = [{name = "Unstructured Technologies", email = "devops@unstructuredai.io"}] classifiers = [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "Intended Audience :: Education", "Intended Audience :: Science/Research", "License :: OSI Approved :: Apache Software License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Topic :: Scientific/Engineering :: Artificial Intelligence", ] readme = "README.md" license = "Apache-2.0" keywords = ["NLP", "PDF", "HTML", "CV", "XML", "parsing", "preprocessing"] dynamic = ["version"] dependencies = [ "beautifulsoup4>=4.14.3, <5.0.0", "charset-normalizer>=3.4.4, <4.0.0", "emoji>=2.15.0, <3.0.0", "filetype>=1.2.0, <2.0.0", "html5lib>=1.1, <2.0.0", "langdetect>=1.0.9, <2.0.0", "lxml>=5.0.0, <7.0.0", "nh3>=0.3.0, <1.0.0", "spacy>=3.7.0, <4.0.0", "installer>=0.7.0, <1.0.0", "numba>=0.60.0, <1.0.0", "numpy>=1.26.0, <3.0.0", "psutil>=7.2.2, <8.0.0", "python-iso639>=2026.1.31, <2027.0.0", "python-magic>=0.4.27, <1.0.0", "python-oxmsg>=0.0.2, <1.0.0", "rapidfuzz>=3.14.3, <4.0.0", "regex>=2024.0.0, <2027.0.0", "requests>=2.32.5, <3.0.0", "tqdm>=4.67.3, <5.0.0", "typing-extensions>=4.15.0, <5.0.0", "unstructured-client>=0.25.9, <1.0.0", "wrapt>=2.1.1, <3.0.0", "filelock>=3.12.0,<4.0.0", ] [project.optional-dependencies] # Document type extras csv = [ "pandas>=2.0.0, <3.0.0", ] doc = [ "unstructured[docx]", ] docx = [ "python-docx>=1.2.0, <2.0.0", ] epub = [ "pypandoc-binary>=1.16.2, <2.0.0; platform_system != 'Windows'", "pypandoc-binary>=1.16.2, <2.0.0; platform_system == 'Windows' and python_version < '3.13'", ] image = [ "google-cloud-vision>=3.12.1, <4.0.0", "pdf2image>=1.17.0, <2.0.0", "pdfminer.six>=20251230, <20270000", "pi-heif>=1.2.0, <2.0.0", "pikepdf>=10.3.0, <11.0.0", "pypdf>=6.6.2, <7.0.0", "unstructured-inference>=1.6.12, <2.0.0; platform_system != 'Windows'", "unstructured-inference>=1.6.12, <2.0.0; platform_system == 'Windows' and python_version >= '3.12' and python_version < '3.13'", "unstructured-pytesseract>=0.3.15, <1.0.0", ] md = [ "markdown>=3.10.1, <4.0.0", ] odt = [ "pypandoc-binary>=1.16.2, <2.0.0; platform_system != 'Windows'", "pypandoc-binary>=1.16.2, <2.0.0; platform_system == 'Windows' and python_version < '3.13'", "python-docx>=1.2.0, <2.0.0", ] org = [ "pypandoc-binary>=1.16.2, <2.0.0; platform_system != 'Windows'", "pypandoc-binary>=1.16.2, <2.0.0; platform_system == 'Windows' and python_version < '3.13'", ] pdf = [ "unstructured[image]", ] ppt = [ "unstructured[pptx]", ] pptx = [ "python-pptx>=1.0.2, <2.0.0", ] rtf = [ "pypandoc-binary>=1.16.2, <2.0.0; platform_system != 'Windows'", "pypandoc-binary>=1.16.2, <2.0.0; platform_system == 'Windows' and python_version < '3.13'", ] rst = [ "pypandoc-binary>=1.16.2, <2.0.0; platform_system != 'Windows'", "pypandoc-binary>=1.16.2, <2.0.0; platform_system == 'Windows' and python_version < '3.13'", ] tsv = [ "unstructured[csv]", ] xlsx = [ "msoffcrypto-tool>=6.0.0, <7.0.0", "networkx>=3.2.0, <4.0.0", "openpyxl>=3.1.5, <4.0.0", "pandas>=2.0.0, <3.0.0", "xlrd>=2.0.1, <3.0.0", ] # Speech-to-text for partition_audio (multimodal: audio -> elements) audio = [ "openai-whisper>=20231117, <20270000", ] all-docs = [ "unstructured[audio,csv,doc,docx,epub,image,md,odt,org,pdf,ppt,pptx,rtf,rst,tsv,xlsx]", ] # Feature extras chunking-tokens = [ "tiktoken>=0.12.0, <1.0.0", ] huggingface = [ "sentencepiece>=0.2.0, <1.0.0", "torch>=2.10.0, <3.0.0; platform_system != 'Windows'", "torch>=2.10.0, <3.0.0; platform_system == 'Windows' and python_version < '3.13'", "transformers>=5.2.0, <6.0.0", ] local-inference = [ "unstructured[all-docs]", ] paddleocr = [ "paddlepaddle>=3.3.0, <4.0.0; platform_machine != 'aarch64' and platform_system != 'Windows'", "paddlepaddle>=3.3.0, <4.0.0; platform_system == 'Windows' and python_version < '3.13'", "unstructured-paddleocr==2.10.0", ] ingest = [ "unstructured-ingest[airtable,astradb,azure,azure-ai-search,bedrock,biomed,box,chroma,confluence,couchbase,databricks-volumes,delta-table,discord,dropbox,elasticsearch,gcs,github,gitlab,google-drive,hubspot,huggingface,jira,kafka,kdbai,milvus,mongodb,notion,octoai,onedrive,openai,opensearch,outlook,pinecone,postgres,qdrant,reddit,remote,s3,salesforce,sftp,sharepoint,singlestore,slack,vectara,vertexai,voyageai,weaviate,wikipedia]>=1.4.0, <2.0.0; platform_system != 'Windows'", "unstructured-ingest[airtable,astradb,azure,azure-ai-search,bedrock,biomed,box,chroma,confluence,couchbase,databricks-volumes,delta-table,discord,dropbox,elasticsearch,gcs,github,gitlab,google-drive,hubspot,huggingface,jira,kafka,kdbai,milvus,mongodb,notion,octoai,onedrive,openai,opensearch,outlook,pinecone,postgres,qdrant,reddit,remote,s3,salesforce,sftp,sharepoint,singlestore,slack,vectara,vertexai,voyageai,weaviate,wikipedia]>=1.4.0, <2.0.0; platform_system == 'Windows' and python_version < '3.13'", ] [project.scripts] unstructured = "unstructured.cli:main" [project.urls] Homepage = "https://github.com/Unstructured-IO/unstructured" [build-system] requires = ["hatchling"] build-backend = "hatchling.build" [tool.hatch.version] path = "unstructured/__version__.py" [tool.hatch.build.targets.wheel] packages = ["/unstructured"] [tool.hatch.build.targets.sdist] packages = ["/unstructured"] [dependency-groups] test = [ "coverage>=7.13.3, <8.0.0", "freezegun>=1.5.5, <2.0.0", "grpcio>=1.78.0, <2.0.0", "pip-licenses>=5.0.0, <6.0.0", "mypy>=1.19.1, <2.0.0", "pydantic>=2.12.5, <3.0.0", "pytest>=9.0.2, <10.0.0", "pytest-cov>=7.0.0, <8.0.0", "pytest-mock>=3.15.1, <4.0.0", "pytest-xdist>=3.8.0, <4.0.0", "types-click>=7.1.8, <8.0.0", "types-Markdown>=3.10.0.20251106, <4.0.0", "types-requests>=2.32.4.20260107, <3.0.0", "types-tabulate>=0.9.0.20241207, <1.0.0", "unstructured-pytesseract>=0.3.15, <1.0.0", "weaviate-client>=4.20.1, <5.0.0", "pytest-benchmark>=5.2.3", ] dev = [ "pre-commit>=4.5.1, <5.0.0", ] lint = [ "ruff>=0.15.0, <1.0.0", ] release = [ "twine>=6.0.0, <7.0.0", ] [tool.uv] required-environments = [ "sys_platform == 'linux' and platform_machine == 'x86_64'", "sys_platform == 'linux' and platform_machine == 'aarch64'", "sys_platform == 'darwin' and platform_machine == 'arm64'", "sys_platform == 'win32'", ] constraint-dependencies = [ # Temporary pin for Azure public-container ingest regression in adlfs 2026.4.0 stack "adlfs==2026.2.0", # deltalake 1.3.0 is missing Linux ARM64 wheels, causing Docker ARM64 builds to fail "deltalake<1.3.0", "fonttools>=4.60.2", "protobuf>=6.30.0", "pykx>=3.1.6", # 3.1.2 is missing macOS wheels (transitive dep of kdbai-client) "tokenizers>=0.21", "unstructured-client>=0.25.9", "urllib3>=2.0.0", "weaviate-client>=4.20.1", ] [tool.pyright] pythonPlatform = "Linux" pythonVersion = "3.11" reportUnnecessaryCast = true reportUnnecessaryTypeIgnoreComment = true stubPath = "./typings" typeCheckingMode = "strict" verboseOutput = true [tool.ruff] line-length = 100 target-version = "py311" [tool.ruff.lint] ignore = [ "COM812", # -- over aggressively insists on trailing commas where not desireable -- "PT001", # -- wants empty parens on @pytest.fixture where not used (essentially always) -- "PT011", # -- pytest.raises({exc}) too broad, use match param or more specific exception -- "PT012", # -- pytest.raises() block should contain a single simple statement -- "SIM117", # -- merge `with` statements for context managers that have same scope -- ] select = [ "C4", # -- flake8-comprehensions -- "COM", # -- flake8-commas -- "E", # -- pycodestyle errors -- "F", # -- pyflakes -- "I", # -- isort (imports) -- "PLR0402", # -- Name compared with itself like `foo == foo` -- "PT", # -- flake8-pytest-style -- "SIM", # -- flake8-simplify -- "UP015", # -- redundant `open()` mode parameter (like "r" is default) -- "UP018", # -- Unnecessary {literal_type} call like `str("abc")`. (rewrite as a literal) -- "UP032", # -- Use f-string instead of `.format()` call -- "UP034", # -- Avoid extraneous parentheses -- "W", # -- Warnings, including invalid escape-sequence -- ] [tool.ruff.lint.per-file-ignores] "test_*/**" = ["D"] [tool.pytest.ini_options] filterwarnings = [ "ignore::DeprecationWarning", ] python_classes = ["Test", "Describe"] python_functions = ["test_", "it_", "they_", "but_", "and_"] testpaths = [ "test_unstructured", "test_unstructured_ingest", ] [tool.coverage.run] omit = [ # Entrypoint only; exercised via `unstructured` console script, not imports in tests. "unstructured/__main__.py", ] [tool.coverage.report] fail_under = 90 [tool.codeflash] module-root = "unstructured" tests-root = "test_unstructured" test-framework = "pytest" ignore-paths = [] formatter-cmds = ["ruff check --exit-zero --fix-only $file", "ruff format $file"] benchmarks-root = "test_unstructured/benchmarks"