Fix arrow.get() crash when tzinfo kwarg is explicitly None - #1339
Fix arrow.get() crash when tzinfo kwarg is explicitly None#1339mayuriphad wants to merge 2 commits into
Conversation
The kwarg-count check in ArrowFactory.get() used 'tz is None' to detect that only the tzinfo kwarg was passed, so it could fall back to the 3+ positional-argument constructor path. This meant an explicitly passed tzinfo=None (as opposed to omitting the kwarg entirely) was misidentified, and arrow.get(<str>, <fmt>, tzinfo=None) incorrectly routed to self.type(*args, **kwargs), raising a confusing TypeError about a missing 'day' argument instead of parsing the string as expected. Check for the key's presence instead of its value. Fixes arrow-py#1259
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1339 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 10 10
Lines 2315 2315
Branches 358 358
=========================================
Hits 2315 2315 ☔ View full report in Codecov by Harness. |
Mukller
left a comment
There was a problem hiding this comment.
Verified locally on the PR branch (Python 3.13, editable install) — real crash fixed, minimal correct change:
Before/after (release 1.4.0 vs branch):
arrow.get("2013-01-01", "YYYY-MM-DD", tzinfo=None)
release: TypeError: Arrow.__init__() missing 1 required positional argument: 'day'
branch: <Arrow [2013-01-01T00:00:00+00:00]>Root cause confirmed by reading factory.get: the old guard len(kwargs) == 1 and tz is None cannot distinguish absent tzinfo from explicitly passed tzinfo=None, so the explicit-None call falls into the 3+-arg direct-constructor path with wrong arity. The new "tzinfo" not in kwargs condition is exactly the right distinction, and it preserves every other branch (verified: no-tz call returns an equal Arrow on the branch).
pytest tests/test_factory.py — green on the branch including the new regression test.
The single failing CI check is windows-latest (pypy-3.11) — unrelated to this one-line factory change; everything else is green.
Approving.
Summary
Fixes #1259.
ArrowFactory.get()decides whether kwargs should be routed to the directArrow(...)constructor (the 3+ positional args path) based on whether the only kwarg present istzinfo. It did this by checkingtz is None, which cannot distinguish between "tzinfowas not passed at all" and "tzinfo=Nonewas passed explicitly". As a result:was routed to
self.type(*args, **kwargs)(the constructor path meant for calls likearrow.get(2013, 5, 5, 12, 30, 45)), which raised:This is a real-world footgun for callers that pass an optional, possibly-
None, timezone straight through as a kwarg (e.g.arrow.get(value, fmt, tzinfo=account.timezone)whereaccount.timezonecan beNone).Fix
Check for the key's presence rather than its value:
Now
tzinfo=Nonebehaves the same as omittingtzinfoentirely (defaults to UTC), while an explicit non-tzinfosingle kwarg still correctly routes to the constructor path, andtzinfo=<value>still works as before.Test plan
test_kwarg_tzinfo_none_with_string_and_formattotests/test_factory.py, assertingarrow.get(str, fmt, tzinfo=None)produces the same result asarrow.get(str, fmt)(UTC).python -m pytest tests/test_factory.py -q→ 49 passed, 1 skipped.TypeError, and after the fixarrow.get('2025-01-01', 'YYYY-MM-DD', tzinfo=None),tzinfo='US/Pacific', and omitted-tzinfoall behave correctly.python -m black --check arrow/factory.py tests/test_factory.py→ clean.