diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b445c14..1d1261a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -33,6 +33,7 @@ jobs: uses: astral-sh/setup-uv@v10.2.0 with: version: "latest" + python-version: "3.12" - name: Set up Python uses: actions/setup-python@v7 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 65cf271..3beda2f 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -27,6 +27,7 @@ jobs: uses: astral-sh/setup-uv@v10.2.0 with: version: "latest" + python-version: "3.12" - name: Set up Python uses: actions/setup-python@v7 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8735b72..2e2610c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -114,6 +114,8 @@ jobs: uses: astral-sh/setup-uv@v10.2.0 with: version: "latest" + # uv reads .python-version, not the interpreter setup-python puts on PATH. + python-version: ${{ matrix.python-version }} - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v7 @@ -193,6 +195,7 @@ jobs: uses: astral-sh/setup-uv@v10.2.0 with: version: "latest" + python-version: "3.12" - name: Set up Python uses: actions/setup-python@v7 diff --git a/CHANGELOG.md b/CHANGELOG.md index 0096678..8fd6ce8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,6 +58,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `options.expirations()` returns a `no_data` DataFrame with the same index as a populated one (`expirations` index, `updated` column), so concatenating results across symbols keeps the index name and gains no stray `expirations` column (#84) - The CSV output of `stocks.candles()` and `options.quotes()` is merged from the answers themselves: the file keeps the header the API sent (the requested `columns`, the human-readable names) and every row of every chunk or symbol; it used to compare each body against the model's field list and silently drop every body that differed, so a `columns=` request or a human-readable `options.quotes()` produced a header-only file, and an undecodable body (an HTML error page) vanished without a word. Such a body now raises `ParseError`, and so does a body the `csv` module cannot read (a field past its size limit), which escaped as a raw `csv.Error` (#86) - DataFrame dates under `DateFormat.TIMESTAMP` and `DateFormat.SPREADSHEET` are the US/Eastern datetimes the default format gives, on pandas and polars. polars left `timestamp` datetimes as strings, a `timestamp` date (`2026-09-21`) landed at 20:00 the day before on both, and a spreadsheet serial, which the API writes as US/Eastern wall-clock time, was read as UTC, four or five hours early. A serial now reads to the second, without the float noise pandas kept (#143) +- CI runs each job on the Python version it names. uv took the version from `.python-version` (3.10) instead of the interpreter `actions/setup-python` installed, so the `test (3.11)` and `test (3.12)` jobs and the live suite, set up on 3.12, all ran on 3.10, and so did the release gate that calls the `Tests` workflow. The 3.11 and 3.12 jobs now also run numpy 2.3.5, which the lock installs from 3.11 on. `Lint` and the release build run on the 3.12 they set up as well (#156) - The `no_data` DataFrame and the header-only CSV carry the requested columns under a `columns=` filter, in request order, as a populated answer does; API names select the human-readable twins under `use_human_readable=True`, and under `add_headers=False` the empty CSV is an empty file. Known limit: the API's own aliases (`open` for `o`, `price`, `date`) are not translated, because the accepted set depends on the endpoint, so filtering on one of those still gives an empty frame of a different shape than the populated answer (#87) - A `404` `no_data` whose body is not JSON (a CDN or a proxy answering the 404 without one) returns the empty result on the JSON output too, instead of raising `ParseError` there while the other three formats returned their empty value: the output format never decides whether a call raises (#87) - The CSV fan-out merge compares the headers of two answers through the same case- and space-insensitive key it validates them with, so the same column spelled differently no longer fails a valid request; a different column order is still refused (#86)