Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ readme = "README.md"
license = { text = "MIT" }
requires-python = ">=3.10,<3.13"
dependencies = [
"langgraph>=1.2.14",
"langchain-core>=1.6.9",
"langgraph>=1.2.15",
"langchain-core>=1.6.11",
"pandas>=2.3.3,<3.0",
"pyyaml>=6.0.3",
"quant-factors @ git+https://github.com/PureSaber/quant-factors.git@1c798bc737bc92fa5eca85dd0663dc608104f721",
Expand All @@ -21,9 +21,9 @@ dependencies = [
]

[project.optional-dependencies]
llm = ["langchain-openai>=1.7.0"]
llm = ["langchain-openai>=1.7.2"]
workspace = []
dev = ["coverage>=7.16.2", "pytest>=9.1.1", "ruff>=0.16.10"]
dev = ["coverage>=7.16.2", "pytest>=9.1.1", "ruff>=0.17.1"]

[project.scripts]
quant-review = "quant_agent.cli:main"
Expand Down
12 changes: 6 additions & 6 deletions requirements.lock
Original file line number Diff line number Diff line change
Expand Up @@ -71,31 +71,31 @@ jsonschema-rs==0.58.0
# via quant-data-kit
jsonschema-specifications==2025.9.1
# via jsonschema
langchain-core==1.6.9
langchain-core==1.6.11
# via
# langchain-openai
# langgraph
# langgraph-checkpoint
# langgraph-prebuilt
# langgraph-sdk
# quant-agent (pyproject.toml)
langchain-openai==1.7.0
langchain-openai==1.7.2
# via quant-agent (pyproject.toml)
langchain-protocol==0.0.19
# via
# langchain-core
# langgraph-sdk
langgraph==1.2.14
langgraph==1.2.15
# via quant-agent (pyproject.toml)
langgraph-checkpoint==4.2.0
langgraph-checkpoint==4.3.0
# via
# langgraph
# langgraph-prebuilt
langgraph-prebuilt==1.1.0
# via langgraph
langgraph-sdk==0.4.6
# via langgraph
langsmith==0.11.2
langsmith==0.14.12
# via langchain-core
numpy==2.2.6
# via
Expand Down Expand Up @@ -182,7 +182,7 @@ rpds-py==0.30.0
# via
# jsonschema
# referencing
ruff==0.16.10
ruff==0.17.1
# via quant-agent (pyproject.toml)
six==1.17.0
# via python-dateutil
Expand Down
56 changes: 56 additions & 0 deletions tests/test_declared_dependency_lock.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
"""The environment used by CI must satisfy declared runtime and development requirements."""

from pathlib import Path

try:
import tomllib
except ModuleNotFoundError:
import tomli as tomllib

from packaging.markers import default_environment
from packaging.requirements import Requirement
from packaging.utils import canonicalize_name

ROOT = Path(__file__).resolve().parents[1]
LOCKS = ["requirements.lock"]
EXTRAS = ["dev", "llm"]


def test_locked_environment_satisfies_declared_requirements():
metadata = tomllib.loads((ROOT / "pyproject.toml").read_text(encoding="utf-8"))
declared = list(metadata["project"].get("dependencies", []))
declared.extend(metadata["build-system"]["requires"])
for extra in EXTRAS:
declared.extend(metadata["project"]["optional-dependencies"][extra])
for filename in LOCKS:
locked = [
Requirement(line)
for line in (ROOT / filename).read_text(encoding="utf-8").splitlines()
if line and not line.startswith(("#", " ", "-"))
]
for version in ("3.10", "3.11", "3.12"):
for platform in ("win32", "linux"):
environment = {
**default_environment(),
"python_version": version,
"python_full_version": version + ".0",
"sys_platform": platform,
}
active = {
canonicalize_name(item.name): item
for item in locked
if item.marker is None or item.marker.evaluate(environment)
}
for text in declared:
requirement = Requirement(text)
if requirement.url or (
requirement.marker and not requirement.marker.evaluate(environment)
):
continue
name = canonicalize_name(requirement.name)
assert name in active, f"{filename}: missing {name} on {version}/{platform}"
pins = [pin.version for pin in active[name].specifier if pin.operator == "=="]
assert len(pins) == 1, f"{filename}: {name} must have one exact version"
assert requirement.specifier.contains(pins[0]), (
f"{filename}: {name}=={pins[0]} does not satisfy {requirement.specifier}"
)
Loading