Skip to content

fix(tz): default to UTC when /etc/localtime is a bare zoneinfo copy - #1079

Open
faresrafat3 wants to merge 1 commit into
python-pendulum:masterfrom
faresrafat3:989-now-returns-none-slurm
Open

faresrafat3 wants to merge 1 commit into
python-pendulum:masterfrom
faresrafat3:989-now-returns-none-slurm

Conversation

@faresrafat3

Copy link
Copy Markdown

Summary

pendulum.now() crashed with TypeError: 'None' is not an instance of 'str'
when /etc/localtime is a bare copy of a zoneinfo file (minimal containers,
Slurm jobs). _get_unix_timezone returned a Timezone whose key is None,
and the Rust precise_diff helper assumed the key is a str.

Root cause: _get_unix_timezone falls through to Timezone.from_file(f) when
no named configuration is found. A zoneinfo file without an IANA key yields a
Timezone with key is None. precise_diff then calls get_tz_name, which
casts that None to PyString and raises.

Verification

$ python3.12 -c "import pendulum; from io import BytesIO; import pendulum.tz.timezone as t; d=open('/tmp/scratchpad/pendulum-src/tests/fixtures/tz/Paris','rb').read(); tz=t.Timezone.from_file(BytesIO(d)); a=pendulum.now(tz); b=pendulum.now(tz); print(b-a)"
TypeError: 'None' is not an instance of 'str'

$ PYTHONPATH=src python3.12 -m pytest tests/tz/ -q
641 passed, 3 skipped, 1 warning

Fix

When the bare-file fallback yields a keyless Timezone, fall through to the
existing UTC default (with the existing warning) instead of returning it.
Timezone.from_file itself still allows a keyless result for pickling and
utcoffset use, so test_from_file_without_a_key_can_be_pickled still
passes. _tz_from_env now passes the file path as the key so that path never
produces a keyless Timezone.

New test test_unix_localtime_regular_file_defaults_to_utc builds a root with
/etc/localtime as a regular file and asserts the resolver returns a named
(UTC) timezone. Against the unfixed code this test fails (resolver returns
the keyless Timezone).

What I did not verify

  • Timezone.from_file(f) called directly with no key still produces a
    keyless Timezone; precise_diff against it still crashes in the Rust
    extension. A one-line guard in rust/src/python/helpers.rs (get_tz_name:
    return an empty string when the key is None) would close that path and
    preserve the local offset; I did not build the Rust extension (no cargo
    on this machine) so that guard is not included here.
  • The change makes the Slurm case report UTC rather than the container's
    real offset. That matches the reporter's own workaround
    (pendulum.now('UTC')); preserving the offset needs the Rust guard above.

Pull Request Check List

  • Added tests for changed code.
  • Updated documentation for changed code.

Fixes #989.

_get_unix_timezone returned a Timezone with key=None when /etc/localtime
was a regular file (Slurm/minimal containers). pendulum.now() then crashed
in the Rust precise_diff helper, which casts the key to str.

Fall through to the existing UTC default when from_file yields a keyless
Timezone. Pass the file path as the key in _tz_from_env so that path never
produces a keyless Timezone.

Closes python-pendulum#989.
Copilot AI balanced review requested due to automatic review settings November 2, 2026 11:47

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

This branch has not been deployed

No deployments
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.

pendulum.now() returning None when executed via Slurm

2 participants