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
5 changes: 5 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,8 @@
__pycache__
*.py[cod]
.env
build
dist
*.egg-info
.venv-*
.ruff_cache
22 changes: 7 additions & 15 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,20 +58,12 @@ jobs:
- name: Install dependencies
run: |
set -euo pipefail
python -m pip install --upgrade pip
python -m pip install --upgrade pip
# Install non-git packages first to avoid cross-package dependency conflicts
grep -vE "^\s*(#|$)|git\+" requirements.txt | xargs -r python -m pip install -c https://raw.githubusercontent.com/QuantStrategyLab/QuantPlatformKit/main/constraints.txt
# Install git-based packages individually with --no-deps
grep 'git+' requirements.txt | while IFS= read -r pkg; do
[ -n "$pkg" ] && python -m pip install --no-deps "$pkg"
done
python -m pip install pytest pytest-cov ruff

python -m pip install --upgrade pip uv
uv sync --frozen --extra test --no-install-project
- name: Smoke import pinned shared packages
run: |
set -euo pipefail
python - <<'PY'
uv run --no-sync python - <<'PY'
from quant_platform_kit.common.port_adapters import CallableNotificationPort, CallablePortfolioPort
from hk_equity_strategies import resolve_canonical_profile as resolve_hk_canonical_profile
from us_equity_strategies import resolve_canonical_profile
Expand All @@ -85,17 +77,17 @@ jobs:
- name: Install editable shared repositories
run: |
set -euo pipefail
python -m pip install --no-deps -e external/QuantPlatformKit -e external/UsEquityStrategies
uv pip install --no-deps -e external/QuantPlatformKit -e external/UsEquityStrategies

- name: Run ruff
run: |
set -euo pipefail
ruff check --exclude external .
uv run --no-sync ruff check --exclude external .

- name: Check QPK pin consistency
run: python scripts/check_qpk_pin_consistency.py
run: uv run --no-sync python scripts/check_qpk_pin_consistency.py

- name: Run unit tests
run: |
set -euo pipefail
PYTHONPATH=. python -m pytest -q tests || true --cov --cov-report=term --cov-report=xml
PYTHONPATH=. uv run --no-sync python -m pytest -q tests || true --cov --cov-report=term --cov-report=xml
7 changes: 3 additions & 4 deletions .github/workflows/sync-cloud-run-env.yml
Original file line number Diff line number Diff line change
Expand Up @@ -341,15 +341,14 @@ jobs:
if: steps.config.outputs.env_sync_enabled == 'true'
run: |
set -euo pipefail
python -m pip install --upgrade pip
python -m pip install -r requirements.txt

python -m pip install --upgrade pip uv
uv sync --frozen --no-dev --no-install-project
- name: Resolve Cloud Run sync targets
id: strategy_requirements
if: steps.config.outputs.env_sync_enabled == 'true'
run: |
set -euo pipefail
sync_plan_json="$(python scripts/build_cloud_run_env_sync_plan.py --json)"
sync_plan_json="$(uv run --no-sync python scripts/build_cloud_run_env_sync_plan.py --json)"
{
echo "sync_plan_json<<__SYNC_PLAN_JSON__"
printf '%s\n' "${sync_plan_json}"
Expand Down
10 changes: 6 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ FROM python:3.12-slim

ENV PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1 \
UV_COMPILE_BYTECODE=1 \
UV_NO_CACHE=1 \
PATH="/app/.venv/bin:${PATH}" \
PORT=8080

WORKDIR /app
Expand All @@ -10,10 +13,9 @@ RUN apt-get update \
&& apt-get install -y --no-install-recommends git \
&& rm -rf /var/lib/apt/lists/*

COPY requirements.txt ./
COPY constraints.txt ./
RUN python -m pip install --upgrade pip \
&& python -m pip install -r requirements.txt -c constraints.txt
COPY pyproject.toml uv.lock ./
RUN python -m pip install --upgrade pip uv \
&& uv sync --frozen --no-dev --no-install-project

COPY . .

Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ Direct runtime profiles can usually run from market history or portfolio state.
## Quick start

```bash
python -m pip install -r requirements.txt
python -m pytest -q
uv sync --frozen --extra test --no-install-project
uv run --no-sync ruff check --exclude external .
uv run --no-sync python scripts/check_qpk_pin_consistency.py
```

## Useful docs
Expand Down
5 changes: 3 additions & 2 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ LongBridgePlatform 是 QuantStrategyLab 的LongBridge 美股/港股执行平台
## 快速开始

```bash
python -m pip install -r requirements.txt
python -m pytest -q
uv sync --frozen --extra test --no-install-project
uv run --no-sync ruff check --exclude external .
uv run --no-sync python scripts/check_qpk_pin_consistency.py
```

## 延伸文档
Expand Down
22 changes: 22 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,28 @@ name = "longbridge-platform"
version = "0.1.0"
description = "QuantStrategyLab platform layer for LongBridge broker."
requires-python = ">=3.11"
dependencies = [
"flask",
"gunicorn",
"pandas",
"requests",
"pytz",
"pandas-market-calendars",
"google-cloud-secret-manager",
"google-cloud-storage",
"google-auth",
"longport==3.0.23",
"quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@0063af3b4a974650ea58a7d3f26dd1b94f65d3e8",
"us-equity-strategies @ git+https://github.com/QuantStrategyLab/UsEquityStrategies.git@46887bc3f5454d5b59623b1f5efb7c65912c6b8b",
"hk-equity-strategies @ git+https://github.com/QuantStrategyLab/HkEquityStrategies.git@61993bf261aeccf64b5a75428b9405f4e1d1d682",
]

[project.optional-dependencies]
test = [
"pytest",
"pytest-cov",
"ruff",
]

[tool.coverage.run]
branch = true
Expand Down
2 changes: 1 addition & 1 deletion tests/test_dependency_pin_guard.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,5 @@ def test_dependency_pin_guard_is_blocking_in_ci() -> None:
next_step = workflow.find("\n - name:", step_start + 1)
step = workflow[step_start : next_step if next_step != -1 else len(workflow)]

assert "python scripts/check_qpk_pin_consistency.py" in step
assert "uv run --no-sync python scripts/check_qpk_pin_consistency.py" in step
assert "continue-on-error" not in step
3 changes: 2 additions & 1 deletion tests/test_sync_cloud_run_env_workflow.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ grep -Fq 'workload_identity_provider: ${{ env.GCP_WORKLOAD_IDENTITY_PROVIDER }}'
grep -Fq 'service_account: ${{ env.GCP_WORKLOAD_IDENTITY_SERVICE_ACCOUNT }}' "$workflow_file"
grep -Fq 'uses: actions/checkout@v6' "$workflow_file"
grep -Fq 'uses: actions/setup-python@v6' "$workflow_file"
grep -Fq 'python -m pip install -r requirements.txt' "$workflow_file"
grep -Fq 'uv sync --frozen --no-dev --no-install-project' "$workflow_file"
grep -Fq 'id: strategy_requirements' "$workflow_file"
grep -Fq 'name: Resolve Cloud Run sync targets' "$workflow_file"
grep -Fq 'uv run --no-sync python scripts/build_cloud_run_env_sync_plan.py --json' "$workflow_file"
grep -Fq 'scripts/build_cloud_run_env_sync_plan.py --json' "$workflow_file"
grep -Fq 'sync_plan_json<<__SYNC_PLAN_JSON__' "$workflow_file"
grep -Fq 'SYNC_PLAN_JSON: ${{ steps.strategy_requirements.outputs.sync_plan_json }}' "$workflow_file"
Expand Down
29 changes: 29 additions & 0 deletions tests/test_uv_dependency_workflow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from pathlib import Path


def test_pyproject_declares_runtime_and_test_dependencies() -> None:
pyproject = Path("pyproject.toml").read_text(encoding="utf-8")

assert "dependencies = [" in pyproject
assert "quant-platform-kit @ git+https://github.com/QuantStrategyLab/" in pyproject
assert "us-equity-strategies @ git+https://github.com/QuantStrategyLab/" in pyproject
assert "hk-equity-strategies @ git+https://github.com/QuantStrategyLab/" in pyproject
assert "[project.optional-dependencies]" in pyproject
assert "test = [" in pyproject


def test_ci_docker_and_env_sync_use_uv_lock() -> None:
ci = Path(".github/workflows/ci.yml").read_text(encoding="utf-8")
dockerfile = Path("Dockerfile").read_text(encoding="utf-8")
env_sync = Path(".github/workflows/sync-cloud-run-env.yml").read_text(encoding="utf-8")
lockfile = Path("uv.lock").read_text(encoding="utf-8")

assert lockfile.startswith("version = ")
assert "uv sync --frozen --extra test --no-install-project" in ci
assert "uv run --no-sync ruff check --exclude external ." in ci
assert "uv run --no-sync python scripts/check_qpk_pin_consistency.py" in ci
assert "uv sync --frozen --no-dev --no-install-project" in env_sync
assert "uv run --no-sync python scripts/build_cloud_run_env_sync_plan.py --json" in env_sync
assert "COPY pyproject.toml uv.lock ./" in dockerfile
assert "uv sync --frozen --no-dev --no-install-project" in dockerfile
assert "python -m pip install -r requirements.txt" not in dockerfile
Loading
Loading