File size: 5,718 Bytes
069f0a0
 
 
 
 
 
 
 
53c4c46
 
d7e5abb
 
ce644a9
 
 
 
 
4e2ccbf
 
 
1efef06
731a241
316dc7d
20f762e
cd46aca
 
 
 
53c4c46
 
 
cb48bd4
53c4c46
 
 
 
 
 
ce644a9
 
 
069f0a0
 
 
 
ce644a9
 
 
 
 
 
 
 
 
069f0a0
53c4c46
ce644a9
 
 
 
 
 
3aa91e9
069f0a0
 
 
 
 
 
 
 
 
 
 
 
3ab54ea
 
 
 
 
 
 
069f0a0
 
 
 
 
 
 
 
 
 
 
 
 
 
15459e9
3aa91e9
 
 
15459e9
ecbc47b
731a241
ecbc47b
069f0a0
 
ce644a9
 
448c679
ce644a9
069f0a0
 
 
 
 
 
 
 
 
 
15459e9
731a241
 
0a480cb
9d21bf8
 
731a241
ce644a9
0a480cb
069f0a0
 
 
 
 
 
 
 
 
cd46aca
 
069f0a0
ce644a9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
069f0a0
 
 
 
cd46aca
 
 
 
069f0a0
 
 
 
 
ce644a9
 
 
 
069f0a0
 
 
 
 
 
1922dbd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
[project]
name = "deepcritical"
version = "0.1.0"
description = "AI-Native Drug Repurposing Research Agent"
readme = "README.md"
requires-python = ">=3.11"
dependencies = [
    "pydantic>=2.7",
    "pydantic-settings>=2.2",
    "pydantic-ai>=0.0.16",
    "openai>=1.0.0",
    "anthropic>=0.18.0",
    "httpx>=0.27",
    "beautifulsoup4>=4.12",
    "xmltodict>=0.13",
    "huggingface-hub>=0.20.0",
    "gradio[mcp,oauth]>=6.0.0",
    "python-dotenv>=1.0", # .env loading
    "tenacity>=8.2", # Retry logic
    "structlog>=24.1", # Structured logging
    "requests>=2.32.5", # ClinicalTrials.gov (httpx blocked by WAF)
    "pydantic-graph>=1.22.0",
    "limits>=3.0", # Rate limiting
    "duckduckgo-search>=5.0", # Web search
    "llama-index-llms-huggingface>=0.6.1",
    "llama-index-llms-huggingface-api>=0.6.1",
    "llama-index-vector-stores-chroma>=0.5.3",
    "llama-index>=0.14.8",
    "tokenizers>=0.22.0,<=0.23.0",
    "transformers>=4.57.2",
    "chromadb>=0.4.0",
    "rpds-py>=0.29.0",  # Python implementation of rpds (required by chromadb on Windows)
    "sentence-transformers>=2.2.0",
    "numpy<2.0",
    "agent-framework-core>=1.0.0b251120,<2.0.0",
    "modal>=0.63.0",
    "llama-index-llms-openai>=0.6.9",
    "llama-index-embeddings-openai>=0.5.1",
    "pydantic-ai-slim[huggingface]>=0.0.18",
    "pytest>=9.0.1",
    "pytest-cov>=7.0.0",
]

[project.optional-dependencies]
dev = [
    "pytest>=9.0.1",
    "pytest-asyncio>=1.3.0",
    "pytest-sugar>=1.1.1",
    "pytest-cov>=7.0.0",
    "pytest-mock>=3.15.1",
    "respx>=0.22.0",
    "typer>=0.9.0",
    "ruff>=0.14.6",
    "mypy>=1.18.2",
    "pre-commit>=3.7",
    "mkdocs>=1.5.0",
    "mkdocs-material>=9.7.0",
    "mkdocs-mermaid2-plugin>=1.2.3",
    "mkdocs-minify-plugin>=0.8.0",
    "mkdocs-codeinclude-plugin>=0.2.1",
    "mkdocs-macros-plugin>=1.5.0",
    "pymdown-extensions>=10.17.2",
]

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.build.targets.wheel]
packages = ["src"]

# ============== RUFF CONFIG ==============
[tool.ruff]
line-length = 100
target-version = "py311"
src = ["src"]
exclude = [
    "tests/",
    "examples/",
    "reference_repos/",
    "folder/",
]

[tool.ruff.lint]
select = [
    "E",    # pycodestyle errors
    "F",    # pyflakes
    "B",    # flake8-bugbear
    "I",    # isort
    "N",    # pep8-naming
    "UP",   # pyupgrade
    "PL",   # pylint
    "RUF",  # ruff-specific
]
ignore = [
    "PLR0913",  # Too many arguments (agents need many params)
    "PLR0912",  # Too many branches (complex orchestrator logic)
    "PLR0911",  # Too many return statements (complex agent logic)
    "PLR2004",  # Magic values (statistical constants like p-values)
    "PLW0603",  # Global statement (singleton pattern for Modal)
    "PLC0415",  # Lazy imports for optional dependencies
    "E402",     # Module level import not at top (needed for pytest.importorskip)
    "E501",     # Line too long (ignore line length violations)
    "RUF100",   # Unused noqa (version differences between local/CI)
]

[tool.ruff.lint.per-file-ignores]
"src/app.py" = ["PLR0915"]  # Too many statements (Gradio UI setup is complex)
".pre-commit-hooks/run_pytest_with_sync.py" = ["PLR0915"]  # Too many statements (pre-commit hook with comprehensive cache cleaning)

[tool.ruff.lint.isort]
known-first-party = ["src"]

# ============== MYPY CONFIG ==============
[tool.mypy]
python_version = "3.11"
strict = true
ignore_missing_imports = true
disallow_untyped_defs = true
warn_return_any = true
warn_unused_ignores = false
explicit_package_bases = true
mypy_path = "."
exclude = [
    "^reference_repos/",
    "^examples/",
    "^folder/",
    "^src/app\\.py$",  # Gradio UI setup - ignore mypy checks
]

# ============== PYTEST CONFIG ==============
[tool.pytest.ini_options]
testpaths = ["tests"]
asyncio_mode = "auto"
addopts = [
    "-v",
    "--tb=short",
    "--strict-markers",
    "-p",
    "no:logfire",
]
# Suppress known warnings that don't indicate test failures
# These are from third-party libraries and don't affect test correctness
filterwarnings = [
    # Pydantic deprecation warnings from unittest.mock introspection
    # These occur when mock tries to introspect Pydantic models
    "ignore::pydantic.warnings.PydanticDeprecatedSince20",
    "ignore::pydantic.warnings.PydanticDeprecatedSince211",
    # Gradio UI warnings (not relevant for unit tests)
    "ignore::UserWarning:gradio.components.dropdown",
    "ignore::UserWarning:gradio.oauth",
    # Pattern-based filters for Pydantic deprecation messages (catch-all)
    "ignore:The `__fields__` attribute is deprecated.*",
    "ignore:The `__fields_set__` attribute is deprecated.*",
    "ignore:Accessing the 'model_computed_fields' attribute.*",
    "ignore:Accessing the 'model_fields' attribute.*",
    # Also catch warnings from unittest.mock module
    "ignore::DeprecationWarning:unittest.mock",
]
# Note: pytest only runs test files, so source files don't need exclusion
markers = [
    "unit: Unit tests (mocked)",
    "integration: Integration tests (real APIs)",
    "slow: Slow tests",
    "openai: Tests that require OpenAI API key",
    "huggingface: Tests that require HuggingFace API key or use HuggingFace models",
    "embedding_provider: Tests that require API-based embedding providers (OpenAI, etc.)",
    "local_embeddings: Tests that use local embeddings (sentence-transformers, ChromaDB)",
]

# ============== COVERAGE CONFIG ==============
[tool.coverage.run]
source = ["src"]
omit = [
    "*/__init__.py",
    "src/app.py",  # Exclude Gradio UI from coverage
]

[tool.coverage.report]
exclude_lines = [
    "pragma: no cover",
    "if TYPE_CHECKING:",
    "raise NotImplementedError",
]