Skip to content

test(ohlcv): seed the cache mtime in local time so the cache tests pass outside UTC - #1367

Closed
codify88 wants to merge 1 commit into
TauricResearch:mainfrom
codify88:fix/ohlcv-cache-tests-timezone
Closed

codify88 wants to merge 1 commit into
TauricResearch:mainfrom
codify88:fix/ohlcv-cache-tests-timezone

Conversation

@codify88

Copy link
Copy Markdown

What's wrong

Eight tests in tests/test_ohlcv_latest_bar.py and
tests/test_ohlcv_cache_freshness.py fail on any machine whose local timezone is
behind UTC. They pass in CI, which runs ubuntu-latest in UTC.

The fixtures seed a cache file's mtime through pandas:

os.utime(cache_file, (today.timestamp(), today.timestamp()))

pd.Timestamp.timestamp() reads a naive Timestamp as UTC. But
_cache_is_fresh reads the same mtime back with
pd.Timestamp.fromtimestamp(), which returns local time:

written = pd.Timestamp.fromtimestamp(os.path.getmtime(data_file))
if written.date() != now.date():
    return False

The round trip loses the UTC offset. On America/New_York:

seeded mtime : 2026-05-08 00:00:00  -> epoch 1778198400.0
read back as : 2026-05-07 20:00:00
dates equal? : False   <- _cache_is_fresh rejects the file

So load_ohlcv treats a file it was just handed as written yesterday, refetches,
and trips the fixtures' _fail_download guard — surfacing as
AssertionError: should use the seeded cache, not download and
AssertionError: fresh cache must not refetch.

Why this is worth taking

It is a test-only fix. load_ohlcv is already self-consistent: both now
(pd.Timestamp.today()) and written (fromtimestamp) are local. No production
behaviour changes, and the freshness rule from #1150 is untouched. The fixtures
were the only thing straddling two time frames.

It removes a false failure that only contributors see. Because CI is UTC, the
suite is green on every PR while being red for any contributor in the Americas
who runs pytest locally. That asymmetry is expensive in a way that does not
show up in CI: eight red tests on a first checkout look like a broken repo or a
broken change, and the natural response is to go hunting in stockstats_utils.py
— which is correct — or to stop trusting the local suite. Both cost maintainer
time in triage.

It protects a guard that is meant to be strict. These tests exist to prove
load_ohlcv does not hit the network when a same-day cache is present. Right
now, for a large fraction of contributors, they fail for a reason unrelated to
that property, so a genuine regression in the caching path would be
indistinguishable from the usual local noise.

The fix

Seed the mtime through datetime.timestamp(), which reads a naive datetime as
local, so both sides of the comparison are in the same frame. Four call sites, a
comment at each explaining the trap.

Verification

pytest -q on the full suite, and the two affected files across the range:

TZ Result
UTC 19 passed
America/New_York (UTC-4) 19 passed
America/Los_Angeles (UTC-7) 19 passed
Pacific/Midway (UTC-11) 19 passed
Pacific/Kiritimati (UTC+14) 19 passed

Before the change, all five non-UTC zones fail 8 of those 19.

Reproduced on 2d17df8 (v0.5.0).

🤖 Generated with Claude Code

The cache tests seed a file's mtime with `pd.Timestamp.timestamp()`, which
reads a naive Timestamp as UTC. `load_ohlcv` reads it back through
`_cache_is_fresh` with `pd.Timestamp.fromtimestamp()`, which returns local
time. The two disagree by the UTC offset, so anywhere west of UTC the seeded
file appears to have been written the previous day, `_cache_is_fresh` returns
False, and the test's `_fail_download` guard fires.

Eight tests fail this way on any machine behind UTC, and none in CI, which runs
on ubuntu-latest in UTC.

`load_ohlcv` itself is consistent -- both `now` and `written` are local -- so
this is a fixture bug, not a behaviour change. Seeding through
`datetime.timestamp()`, which reads a naive datetime as local, keeps both sides
in the same frame.

Verified from UTC-11 (Pacific/Midway) through UTC+14 (Pacific/Kiritimati).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
codify88 pushed a commit to codify88/TradingAgents that referenced this pull request Sep 18, 2026
… to render

The three CliRunner tests in test_cli_mandate_commands.py compare against
`result.output` directly, which carries whatever the ambient environment made
rich do. Two things leak in, and pytest isolates neither:

- Styling, from FORCE_COLOR / COLORTERM / TERM. "Mandate: equity_value" arrives
  as "\x1b[36mMandate:\x1b[0m equity_value" in a colour-capable shell. NO_COLOR
  is not enough on its own: it drops colour but keeps rich's bold highlighting
  on numbers, so a date still arrives as "\x1b[1m2026\x1b[0m-\x1b[1m09\x1b[0m-".
- Width. rich wraps to the width detected when the Console was built, at import,
  so the COLUMNS that CliRunner passes into the invocation arrives too late and
  the asserted command breaks across lines mid-string.

All three passed in CI and failed in an interactive shell. A `plain()` helper
strips the escapes and collapses whitespace, so the assertions test content.

Verified green across FORCE_COLOR=3, NO_COLOR=1, TERM=dumb, and COLUMNS 30/40,
in each case with the rest of the suite.

Same class as the two fixes now open upstream as TauricResearch#1367 and TauricResearch#1368: a test that
reads its environment rather than isolating from it is green on the machine that
wrote it and red on the next one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Yijia-Xiao

Copy link
Copy Markdown
Member

Thanks @codify88. Fixed in 2340fe4 (#1372).

@Yijia-Xiao Yijia-Xiao closed this Sep 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants