diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 0e1b0db..30ecddd 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -15,11 +15,19 @@ permissions: jobs: build: - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: - python-version: ["3.9", "3.10", "3.11"] + # Windows 是 tdx2db 用户主场景(本地读通达信文件),必须纳入矩阵 + os: [ubuntu-latest, windows-latest] + python-version: ["3.9", "3.11"] + include: + - os: ubuntu-latest + python-version: "3.10" + defaults: + run: + shell: bash steps: - uses: actions/checkout@v4 diff --git a/CLAUDE.md b/CLAUDE.md index 038c1d3..bbb42e4 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -30,7 +30,7 @@ tdx2db status `python main.py <子命令>` 与 `tdx2db <子命令>` 等价(main.py 是薄封装,保留老用户习惯)。包目录为 `tdx2db/`(v0.3.0 起从 `src/` 改名,发布到 PyPI)。psycopg2-binary/pymysql 为可选依赖(extras: postgres/mysql/all),默认安装仅支持 SQLite。 -测试:`pytest tests/`(processor 纯函数 + 模块导入冒烟,CI 三矩阵 3.9/3.10/3.11 运行)。数据正确性验证仍以运行 `sync` 后检查数据库为准。 +测试:`pytest tests/`。CI 矩阵:ubuntu + windows × 3.9/3.11(+ ubuntu 3.10)——Windows 是用户主场景必须覆盖。`tests/fixtures/` 存 .day/.lc5 二进制解析 fixture(合成字节,生成器 `make_fixtures.py`;断言值与生成参数一一对应)。数据正确性验证仍以运行 `sync` 后检查数据库为准。 ## 发布 PyPI(维护者) diff --git a/tests/fixtures/make_fixtures.py b/tests/fixtures/make_fixtures.py new file mode 100644 index 0000000..93dc573 --- /dev/null +++ b/tests/fixtures/make_fixtures.py @@ -0,0 +1,51 @@ +"""生成 tests/fixtures/ 下的二进制解析 fixture(issue #34)。 + +fixture 是确定性合成字节,格式与通达信实际文件逐字段一致: +- .day 32 字节/条:/sh/lday/sh688001.day of=sh688001.day bs=32 count=5 +""" +import struct +from pathlib import Path + +HERE = Path(__file__).parent + +# 与 tests/test_reader.py 的断言一一对应,改动需同步 +DAY_RECORDS_SZ = [ + # (date, open, high, low, close, amount, volume)——open 等为 ×100 整型 + (20260605, 1050, 1075, 1025, 1050, 5250000.0, 500000), + (20260608, 1050, 1100, 1050, 1075, 5375000.0, 400000), +] +DAY_RECORDS_688 = [ + (20260605, 5000, 5150, 4950, 5075, 25375000.0, 300000), +] +LC5_RECORDS = [ + # (year, month, day, hour, minute, open, high, low, close, amount, volume) + (2026, 6, 5, 9, 35, 10.5, 10.75, 10.25, 10.5, 2100000.0, 200000), + (2026, 6, 5, 9, 40, 10.5, 10.5, 10.25, 10.25, 1025000.0, 100000), +] + + +def write_day(path: Path, records) -> None: + with open(path, 'wb') as f: + for date, o, h, l, c, amount, vol in records: + f.write(struct.pack(' None: + with open(path, 'wb') as f: + for year, month, day, hour, minute, o, h, l, c, amount, vol in records: + date_num = (year - 2004) * 2048 + month * 100 + day + time_num = hour * 60 + minute + f.write(struct.pack('