pyproject.toml
Rama main · réplica de lectura del repositorio original.
# 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", "optional-dependencies"]
description = "An agent-native intelligent learning companion with multi-agent collaboration and RAG"
# Python 3.14 is supported by the core app now that compiled base dependencies
# such as FAISS publish compatible wheels. Keep a forward cap so a future
# interpreter is not advertised before the compiled dependency stack is ready.
# Individual optional integrations may carry tighter markers below.
requires-python = ">=3.11,<3.15"
readme = "README.md"
license = {text = "Apache-2.0"}
dependencies = [
"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",
"packaging>=24.2",
"jsonschema>=4.20.0,<5.0.0",
"aiosqlite>=0.19.0",
"typer>=0.9.0",
"rich>=13.0.0",
"markdown-it-py>=3.0.0,<5.0.0",
"prompt_toolkit>=3.0.36",
"pyte>=0.8.1",
"mcp>=1.26.0,<2.0.0",
"tzdata>=2024.1",
"loguru>=0.7.3,<1.0.0",
"json-repair>=0.57.0,<1.0.0",
"psutil>=5.9.0,<8.0.0",
"python-docx>=1.1.0",
"openpyxl>=3.1.0"
]
[project.scripts]
deeptutor = "deeptutor_cli.main:main"
[tool.deeptutor.optional-dependencies]
# Optional modules own their code and dependencies. Full is an installation profile.
cli = []
codebuddy = ["codebuddy-agent-sdk>=0.3,<0.4"]
claude-code = ["claude-agent-sdk>=0.2.174,<0.3"]
video-learning = ["deeptutor-reading=={version}"]
edge-tts = ["edge-tts>=7.0,<8.0"]
video-lesson = ["deeptutor-video-lesson=={version}", "edge-tts>=7.0,<8.0"]
server = ["deeptutor-server=={version}"]
partners = ["deeptutor-partners=={version}"]
parse-markitdown = ["deeptutor-parser-markitdown=={version}"]
parse-docling = ["deeptutor-parser-docling=={version}"]
parse-pymupdf4llm = ["deeptutor-parser-pymupdf4llm=={version}"]
parse-liteparse = ["deeptutor-parser-liteparse=={version}"]
parse = ["deeptutor[parse-markitdown]=={version}", "deeptutor[parse-docling]=={version}", "deeptutor[parse-pymupdf4llm]=={version}", "deeptutor[parse-liteparse]=={version}"]
tutorbot = ["deeptutor[partners]=={version}"]
matrix = ["matrix-nio>=0.25.2,<1.0.0", "mistune>=3.0.0,<4.0.0", "nh3>=0.2.18,<1.0.0"]
matrix-e2e = ["deeptutor[matrix]=={version}", "matrix-nio[e2e]>=0.25.2,<1.0.0"]
math-animator = ["deeptutor-renderer-manim=={version}"]
graphrag = ["graphrag>=3.0.1,<4.0.0; python_version < '3.14'"]
rag-lightrag = ["lightrag-hku==1.5.7"]
rag-rerank = ["sentence-transformers>=3.0.0,<6.0.0; python_version < '3.14'"]
guard = ["fastapi-guard>=8.1.1,<9.0.0"]
dev = ["deeptutor[server]=={version}", "pytest>=7.0.0", "pytest-asyncio>=0.23.0", "pre-commit>=3.0.0", "safety<3.0.0", "bandit>=1.8.0", "import-linter>=2.1.0,<3.0.0", "python-docx>=1.1.0", "openpyxl>=3.1.0", "python-pptx>=1.0.0", "pypdf>=4.0.0", "defusedxml>=0.7.1"]
all = ["deeptutor[full,math-animator,dev]=={version}"]
audio-overview = ["deeptutor-audio-overview=={version}"]
solve = ["deeptutor-solve=={version}"]
reading = ["deeptutor-reading=={version}"]
memory = ["deeptutor-memory=={version}"]
providers = ["deeptutor-providers=={version}"]
questions = ["deeptutor-questions=={version}"]
notebook = ["deeptutor-notebook=={version}"]
web = ["deeptutor-web=={version}"]
parsing = ["deeptutor-parsing=={version}"]
books = ["deeptutor-books=={version}"]
research = ["deeptutor-research=={version}"]
visualize = ["deeptutor-visualize=={version}"]
renderer-manim = ["deeptutor-renderer-manim=={version}"]
calendar = ["deeptutor-calendar=={version}"]
knowledge = ["deeptutor-knowledge=={version}"]
co-writer = ["deeptutor-co-writer=={version}"]
mastery = ["deeptutor-mastery=={version}"]
full = ["deeptutor-audio-overview=={version}", "deeptutor-solve=={version}", "deeptutor-server=={version}", "deeptutor-reading=={version}", "deeptutor-partners=={version}", "deeptutor-memory=={version}", "deeptutor-providers=={version}", "deeptutor-questions=={version}", "deeptutor-notebook=={version}", "deeptutor-web=={version}", "deeptutor-video-lesson=={version}", "deeptutor-parsing=={version}", "deeptutor-books=={version}", "deeptutor-research=={version}", "deeptutor-visualize=={version}", "deeptutor-calendar=={version}", "deeptutor-knowledge=={version}", "deeptutor-co-writer=={version}", "deeptutor-mastery=={version}"]
[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",
"**/*.ts",
"**/*.tsx",
"**/*.mjs",
]
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",
"integration: requires explicitly configured external services",
"redis_integration: requires DEEPTUTOR_TEST_REDIS_URL",
"real_llm_resolver: exercises LLM config resolution itself, so it keeps the real resolver",
]
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"]