Files
wehub-resource-sync e4dcfc49aa
Tests / Import Check (Python 3.13) (push) Has been cancelled
Tests / Import Check (Python 3.14) (push) Has been cancelled
Tests / Python Tests (Python 3.11) (push) Has been cancelled
Tests / Python Tests (Python 3.12) (push) Has been cancelled
Tests / Python Tests (Python 3.14) (push) Has been cancelled
Tests / Test Summary (push) Has been cancelled
Tests / Lint and Format (push) Has been cancelled
Tests / Web Node Tests (push) Has been cancelled
Tests / Import Check (Python 3.11) (push) Has been cancelled
Tests / Import Check (Python 3.12) (push) Has been cancelled
Tests / Python Tests (Python 3.13) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:00:43 +08:00

467 lines
16 KiB
TOML

# Python project configuration for DeepTutor
# This file configures Black, Ruff, and other Python tools
[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "deeptutor"
dynamic = ["version"]
description = "An agent-native intelligent learning companion with multi-agent collaboration and RAG"
requires-python = ">=3.11"
readme = "README.md"
license = {text = "Apache-2.0"}
dependencies = [
# Core runtime
"PyYAML>=6.0",
"jinja2>=3.1.0",
"openai>=1.30.0",
"tiktoken>=0.5.0",
"aiohttp>=3.9.4",
"httpx>=0.27.0",
"requests>=2.32.2",
"ddgs>=9.9.1",
"nest_asyncio>=1.5.8",
"tenacity>=8.0.0",
"pydantic>=2.0.0",
"pydantic-settings>=2.0.0",
"aiosqlite>=0.19.0",
"typer[all]>=0.9.0",
"rich>=13.0.0",
"prompt_toolkit>=3.0.36",
"pyte>=0.8.1", # in-memory terminal emulator: scrape Claude Code's /model TUI on sync
# Full app dependencies included by default for `pip install deeptutor`.
"anthropic>=0.30.0",
"dashscope>=1.14.0",
"perplexityai>=0.1.0",
"oauth-cli-kit>=0.1.1",
"llama-index>=0.14.12",
"llama-index-retrievers-bm25>=0.7.1,<0.8.0",
# FAISS vector store: vectorized ANN retrieval that replaces SimpleVectorStore's
# brute-force per-query scan for large knowledge bases (issue #552). The
# pipeline imports it lazily and falls back to SimpleVectorStore if absent.
"llama-index-vector-stores-faiss>=0.4.0,<1.0.0",
"faiss-cpu>=1.8.0,<2.0.0",
"PyMuPDF>=1.26.0",
"numpy>=1.24.0,<3.0.0",
"arxiv>=2.0.0",
"python-docx>=1.1.0",
"openpyxl>=3.1.0",
"python-pptx>=1.0.0",
"pypdf>=4.0.0",
"pdfplumber>=0.11.0,<0.11.8", # 0.11.8+ pins pdfminer.six==20251230, conflicts with mineru (via raganything)
"reportlab>=4.0.0",
"defusedxml>=0.7.1",
"fastapi>=0.100.0",
"uvicorn[standard]>=0.24.0",
"websockets>=12.0",
"python-multipart>=0.0.6",
"bcrypt>=4.0.0",
"python-jose[cryptography]>=3.3.0",
"pocketbase>=0.12.0",
"loguru>=0.7.3,<1.0.0",
"json-repair>=0.57.0,<1.0.0",
]
[project.scripts]
deeptutor = "deeptutor_cli.main:main"
[project.optional-dependencies]
# Compatibility extra for source installs and older docs. These packages are
# already included in the public `deeptutor` wheel; the local CLI-only project
# under `packaging/deeptutor-cli` uses the same list without Web assets/server deps.
cli = [
# LLM provider SDKs
"anthropic>=0.30.0",
"dashscope>=1.14.0",
"perplexityai>=0.1.0",
"oauth-cli-kit>=0.1.1",
# RAG (LlamaIndex)
"llama-index>=0.14.12",
"llama-index-retrievers-bm25>=0.7.1,<0.8.0",
# FAISS vector store: vectorized ANN retrieval that replaces SimpleVectorStore's
# brute-force per-query scan for large knowledge bases (issue #552). The
# pipeline imports it lazily and falls back to SimpleVectorStore if absent.
"llama-index-vector-stores-faiss>=0.4.0,<1.0.0",
"faiss-cpu>=1.8.0,<2.0.0",
"PyMuPDF>=1.26.0",
"numpy>=1.24.0,<3.0.0",
"arxiv>=2.0.0",
# Document text extraction (chat attachments) + office-skill authoring libs
"python-docx>=1.1.0",
"openpyxl>=3.1.0",
"python-pptx>=1.0.0",
"pypdf>=4.0.0",
"pdfplumber>=0.11.0,<0.11.8", # 0.11.8+ pins pdfminer.six==20251230, conflicts with mineru (via raganything)
"reportlab>=4.0.0",
"defusedxml>=0.7.1",
]
# Compatibility extra for source installs and older docs. These packages are
# already included in the public `deeptutor` wheel.
server = [
"deeptutor[cli]",
"fastapi>=0.100.0",
"uvicorn[standard]>=0.24.0",
"websockets>=12.0",
"python-multipart>=0.0.6",
"bcrypt>=4.0.0",
"python-jose[cryptography]>=3.3.0",
"pocketbase>=0.12.0",
"loguru>=0.7.3,<1.0.0",
"json-repair>=0.57.0,<1.0.0",
"croniter>=6.0.0,<7.0.0",
]
# Partner channel SDKs + MCP client. Mirrors requirements/partners.txt.
# Partners run on the chat agent loop, so there is no engine here — just the
# IM platform SDKs and the MCP client used for deferred tools.
partners = [
"deeptutor[server]",
"mcp>=1.26.0,<2.0.0",
"python-telegram-bot[socks]>=22.6,<23.0",
"wecom-aibot-sdk>=1.0.8,<2.0.0",
"lark-oapi>=1.5.0,<2.0.0",
"dingtalk-stream>=0.24.0,<1.0.0",
"slack-sdk>=3.39.0,<4.0.0",
"slackify-markdown>=0.2.0,<1.0.0",
"qq-botpy>=1.2.0,<2.0.0",
"python-socketio>=5.16.0,<6.0.0",
"msgpack>=1.1.0,<2.0.0",
"python-socks[asyncio]>=2.8.0,<3.0.0",
"socksio>=1.0.0,<2.0.0",
"websocket-client>=1.9.0,<2.0.0",
"zulip>=0.8.0,<1.0.0",
# slack-sdk Socket Mode + napcat need the async `websockets` lib — pin it
# explicitly instead of relying on dingtalk-stream/lark-oapi transitives.
"websockets>=12.0",
# napcat (OneBot v11) media downloads
"aiohttp>=3.10.0,<4.0.0",
# msteams Bot Framework token validation
"PyJWT[crypto]>=2.8.0,<3.0.0",
# weixin QR-code login
"qrcode>=7.4.0,<9.0.0",
]
# Optional document-parsing engines for the shared parse layer
# (deeptutor/services/parsing). MinerU is an external CLI / hosted API and is
# not a pip dependency. Engines import lazily, so these stay opt-in and an
# absent engine simply reports unavailable in Settings → Document Parsing.
parse-markitdown = ["markitdown[pdf,docx,pptx,xlsx]>=0.0.1a2"]
parse-docling = ["docling>=2.0.0"]
# PyMuPDF4LLM rides on PyMuPDF (already a core dep); the extra adds only the
# thin Markdown layer, so it is the lightest image-capable engine. Pinned to the
# pre-1.0 line on purpose: 1.x defaults to an onnxruntime layout-AI path that
# pulls a heavy dep, downloads a model, and can't extract images — defeating the
# "lightweight, runs on a Pi, extracts images" point of this engine.
parse-pymupdf4llm = ["pymupdf4llm>=0.0.17,<1.0"]
parse = [
"deeptutor[parse-markitdown]",
"deeptutor[parse-docling]",
"deeptutor[parse-pymupdf4llm]",
]
# Legacy alias kept for one release: `pip install deeptutor[tutorbot]`.
tutorbot = ["deeptutor[partners]"]
# Matrix (Element) channel for partners. Mirrors requirements/matrix.txt.
# Default Matrix install is non-E2EE so it works without libolm/python-olm.
matrix = [
"matrix-nio>=0.25.2,<1.0.0",
"mistune>=3.0.0,<4.0.0",
"nh3>=0.2.18,<1.0.0",
]
# Optional Matrix E2EE addon. Mirrors requirements/matrix-e2e.txt and requires libolm.
matrix-e2e = [
"deeptutor[matrix]",
"matrix-nio[e2e]>=0.25.2,<1.0.0",
]
# Math Animator addon (Manim). Mirrors requirements/math-animator.txt.
# System prerequisites (installed outside pip): LaTeX, pkg-config, cairo, cmake, ffmpeg.
math-animator = ["manim>=0.19.0"]
# GraphRAG knowledge-base engine (microsoft/graphrag). Optional, heavy
# (LiteLLM + lancedb + graspologic) and kept out of `all` so it stays a
# deliberate opt-in. The pipeline imports lazily and the adapter targets the
# 3.x API (see services/rag/pipelines/graphrag/engine.py). Every graphrag 3.x
# release is capped at python <3.14; the `python_version` marker mirrors that
# so on 3.14+ the extra resolves to a no-op instead of an unsatisfiable hard
# dep — otherwise pip backtracks deeptutor to the last extra-free version
# (1.4.5) and silently downgrades. Floor is 3.0.1 (3.0.0/3.0.3 were yanked).
graphrag = ["graphrag>=3.0.1,<4.0.0; python_version < '3.14'"]
# LightRAG knowledge-base engine (HKUDS/LightRAG) with multimodal parsing via
# RAG-Anything (HKUDS/RAG-Anything). Optional, heavy (pulls MinerU transitively —
# see the pdfplumber pin above). The pipeline imports lazily and the adapter is
# isolated in services/rag/pipelines/lightrag/engine.py. raganything pulls
# `mineru[core]`, which is capped at python <3.14, so this carries the same
# `python_version` marker as graphrag to avoid a silent backtrack/downgrade on
# 3.14+. Floor is 1.0.1 (no 1.0.0 was ever published) with a <2.0.0 ceiling so
# a future API-breaking 2.x isn't pulled in silently.
rag-lightrag = ["raganything>=1.0.1,<2.0.0; python_version < '3.14'"]
# Dev/test tooling. Mirrors requirements/dev.txt.
dev = [
"deeptutor[server]",
"pytest>=7.0.0",
"pytest-asyncio>=0.23.0",
"pre-commit>=3.0.0",
"safety<3.0.0",
"bandit>=1.8.0",
# Test fixture builders for document-loader tests. Runtime pulls these via
# cli/server, but dev keeps them explicit for pytest collection.
"python-docx>=1.1.0",
"openpyxl>=3.1.0",
"python-pptx>=1.0.0",
"pypdf>=4.0.0",
"defusedxml>=0.7.1",
]
# Everything: server + partners + non-E2EE matrix + math-animator + dev tools.
all = [
"deeptutor[partners]",
"deeptutor[matrix]",
"deeptutor[math-animator]",
"deeptutor[dev]",
]
[tool.setuptools]
include-package-data = true
[tool.setuptools.dynamic]
version = {attr = "deeptutor.__version__.__version__"}
[tool.setuptools.packages.find]
where = ["."]
include = ["deeptutor*", "deeptutor_cli*"]
[tool.setuptools.package-data]
# Runtime data shipped inside the deeptutor package: prompt YAMLs (loaded by
# PromptManager from PACKAGE_ROOT/deeptutor/.../prompts/*.yaml), markdown
# templates (builtin SKILL.md files, vision_solver prompts), and helper shell
# scripts. Without these, ``pip install deeptutor`` ships a wheel missing
# every agent prompt and capability fails at first use.
deeptutor = [
"**/*.yaml",
"**/*.yml",
"**/*.md",
"**/*.json",
"**/*.sh",
"**/*.j2",
"**/*.jinja",
]
deeptutor_cli = ["**/*.md"]
deeptutor_web = ["**/*", ".next/**/*"]
# ============================================
# Black code formatter configuration
# ============================================
[tool.black]
line-length = 100
target-version = ['py311', 'py312', 'py313', 'py314']
include = '\.pyi?$'
extend-exclude = '''
/(
# Exclude directories
\.eggs
| \.git
| \.hg
| \.mypy_cache
| \.tox
| \.venv
| venv
| _build
| buck-out
| build
| dist
| __pycache__
| node_modules
| \.next
)/
'''
# ============================================
# Ruff linter and formatter configuration
# ============================================
[tool.ruff]
# Target Python version
target-version = "py311"
line-length = 100
[tool.ruff.lint]
# Enable only foundational lint rules (intentionally relaxed)
select = [
"E", # pycodestyle errors (语法错误)
"F", # pyflakes (未使用的导入、变量等)
"I", # isort (import 排序)
# Keep only essential checks; other rules stay relaxed
]
extend-select = [
"B006", # Do not use mutable data structures for argument defaults
]
# Ignore specific rules (keep the lint profile relaxed)
ignore = [
"E501", # Line too long (handled by formatter)
"B008", # Do not perform function calls in argument defaults
"PLR0911", # Too many return statements
"PLR0912", # Too many branches
"PLR0913", # Too many arguments
"PLR0915", # Too many statements
"PLR2004", # Magic value used in comparison
"TRY003", # Avoid specifying long messages outside exception class
"T201", # print found (allowed for debugging scripts)
"E722", # Do not use bare except (kept relaxed for legacy paths)
"E402", # Module level import not at top of file (kept relaxed)
"PLC0415", # import should be at top-level (kept relaxed)
"PTH123", # open() should be replaced by Path.open() (standard open allowed)
"PTH103", # os.makedirs() should be replaced by Path.mkdir() (os.makedirs allowed)
"PTH118", # os.path.join() should be replaced by Path (os.path.join allowed)
"EM101", # Exception must not use a string literal
"EM102", # Exception must not use an f-string literal
"TRY002", # Create your own exception
"TRY300", # Consider moving this statement to an else block
"DTZ005", # datetime.now() called without tz argument
"RET504", # Unnecessary assignment before return
"PLW2901", # for loop variable overwritten by assignment target
"F841", # Local variable assigned but never used
"ERA001", # Found commented-out code (kept relaxed)
]
# Exclude patterns
exclude = [
".bzr",
".direnv",
".eggs",
".git",
".git-rewrite",
".hg",
".mypy_cache",
".nox",
".pants.d",
".pyenv",
".pytest_cache",
".pytype",
".ruff_cache",
".svn",
".tox",
".venv",
".vscode",
"__pypackages__",
"_build",
"buck-out",
"build",
"dist",
"node_modules",
".next",
"out",
"venv",
"__pycache__",
]
# Allow autofix for all enabled rules
fixable = ["ALL"]
unfixable = []
# Allow unused variables when underscore-prefixed
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
[tool.ruff.format]
# Use double quotes for strings
quote-style = "double"
# Indent with spaces
indent-style = "space"
# Respect magic trailing comma
skip-magic-trailing-comma = false
# Automatically detect the appropriate line ending
line-ending = "auto"
# ============================================
# Ruff import sorting (isort replacement)
# ============================================
[tool.ruff.lint.isort]
known-first-party = ["deeptutor", "deeptutor_cli", "scripts"]
force-sort-within-sections = true
split-on-trailing-comma = true
# ============================================
# Ruff per-file-ignores
# ============================================
[tool.ruff.lint.per-file-ignores]
# Allow longer lines in test files
# F401: Allow unused imports for availability checks in tests
"**/test_*.py" = ["E501", "PLR2004", "F401"]
"**/__init__.py" = ["F401"] # Allow unused imports in __init__.py
# ============================================
# Ruff mccabe complexity
# ============================================
[tool.ruff.lint.mccabe]
max-complexity = 10
# ============================================
# Pytest configuration
# ============================================
[tool.pytest.ini_options]
testpaths = ["tests", "deeptutor/learning/tests"]
pythonpath = ["."]
markers = [
"asyncio: mark async tests that require pytest-asyncio",
]
asyncio_default_fixture_loop_scope = "function"
addopts = [
"--strict-markers",
"--strict-config",
"--disable-warnings",
"--tb=short",
"--import-mode=importlib",
]
# ============================================
# MyPy type checking configuration
# ============================================
[tool.mypy]
python_version = "3.11"
# Relaxed type checking for gradual adoption
pretty = false
show_error_context = false
warn_return_any = false
warn_no_return = false
show_error_codes = true
ignore_missing_imports = true
follow_imports = "silent"
# Disable strict checks that generate too many errors
check_untyped_defs = false
disallow_untyped_defs = false
disallow_incomplete_defs = false
no_implicit_optional = false
# Module-specific overrides
[[tool.mypy.overrides]]
module = "tests.*"
ignore_errors = true
[[tool.mypy.overrides]]
module = "deeptutor.tools.*"
ignore_errors = true # Some tools may have dynamic imports
# ============================================
# Bandit security linting configuration
# ============================================
[tool.bandit]
exclude_dirs = ["tests", "scripts"]
# B101=assert, B311=random, B403/B404=pickle/subprocess imports
# B110=try_except_pass (intentional for non-critical error handling)
# B104=hardcoded_bind_all_interfaces (required for server binding)
# B112=try_except_continue (intentional for iteration)
# B105=hardcoded_password_string (false positive on empty string initialization)
# B301=pickle (used for internal embedding cache, not untrusted data)
# B501=request_with_no_cert_validation (opt-in via env var for dev/testing)
# B603=subprocess_without_shell_equals_true (controlled execution)
# B202=tarfile_unsafe_members (already using safe_members filter)
skips = ["B101", "B311", "B403", "B404", "B110", "B104", "B112", "B105", "B301", "B501", "B603", "B202"]