Skip to content

Fix from_format AttributeError for ordinal tokens - #1075

Open
rahul05ranjan wants to merge 1 commit into
python-pendulum:masterfrom
rahul05ranjan:fix-from-format-ordinal-tokens
Open

rahul05ranjan wants to merge 1 commit into
python-pendulum:masterfrom
rahul05ranjan:fix-from-format-ordinal-tokens

Conversation

@rahul05ranjan

Copy link
Copy Markdown

Fixes #1074.

Summary

from_format crashed with a raw AttributeError: 'NoneType' object has no attribute 'values' for every ordinal token:

input before after
from_format("7 Juni 1982", "Do MMMM YYYY", locale="de") (no ordinals in de) AttributeError 1982-06-07
from_format("2nd 1982", "Qo YYYY", locale="en") AttributeError (any locale) 1982-04-01
from_format("6th 1982", "Mo YYYY") AttributeError 1982-06-01
from_format("158th 1982", "DDDo YYYY") AttributeError 1982-06-07
from_format(..., "do/e/eo/Wo/wo ...") AttributeError ValueError: Unsupported token: ...

Meanwhile format() happily emits all of these (format("Qo YYYY") → '2nd 1982'), so no ordinal token could ever be round-tripped.

Root cause

src/pendulum/formatting/formatter.py:

  1. The Do entry in _LOCALIZABLE_TOKENS calls locale.get("custom.ordinal").values() — None for locales without ordinals (bg, de, ru, pl, uk, da, sv, ...). Locale.ordinalize() (the format() side) already falls back to the plain number there, so the parse pattern must accept plain digits too.
  2. Qo/Mo/DDDo/do/e/eo/Wo/wo are None in _LOCALIZABLE_TOKENS; _replace_tokens passes that to locale.translation(None).values() and crashes before reaching its own ValueError("Unsupported token: ...") guard.

Fix

  • _ordinal_candidates(locale): builds \d+<suffix> patterns from custom.ordinal, falling back to \d+ for locales without ordinals — mirroring Locale.ordinalize(), so format()/from_format round-trip in every locale.
  • Do, Mo, Qo, DDDo now parse to their fields (day/month/quarter/day_of_year), all of which _check_parsed already consumes.
  • The deliberately unparseable do, e, eo, Wo, wo now raise the regular ValueError("Unsupported token: X") instead of AttributeError.
  • The bracket-literal / escaped-character protection issue is out of scope here (it is being addressed in Fix from_format crash on multi-character literal blocks #972).

Verification

  • 10 new regression tests in tests/datetime/test_from_format.py (Do with/without locale ordinals incl. de, Mo, Qo, DDDo, and the clean ValueError for the unsupported tokens).
  • The pre-existing failure set of tests/datetime/test_from_format.py is byte-identical before/after (those 49 failures are the time-machine-gated travel tests; time_machine is unavailable in this environment — diff of failing test names verified with git stash).
  • tests/formatting + tests/parsing: identical failure set before/after (all previously-passing tests still pass).
  • Python 3.13, Linux, system tzdata + dateutil from source (no optional deps installed).

from_format crashed with a raw AttributeError instead of a ValueError
for every ordinal token: 'Do' in locales without ordinal suffixes
(bg, de, ru, ...), because the Do pattern builder called .values() on
locale.get('custom.ordinal') which is None there; and Qo/Mo/DDDo/do/
e/eo/Wo/wo in every locale, whose None entries went to
locale.translation(None).values().

- Do now falls back to plain \d+ for locales without ordinals,
  mirroring Locale.ordinalize(), so format/from_format round-trips
  work in all locales.
- Mo, Qo and DDDo get real parse support (month/quarter/day-of-year
  are all consumed by _check_parsed).
- The remaining None tokens (do, e, eo, Wo, wo) raise the regular
  'Unsupported token' ValueError.

Fixes python-pendulum#1074

Co-authored-by: rahul05ranjan <11793455+rahul05ranjan@users.noreply.github.com>

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.

from_format raises AttributeError for ordinal tokens (Do in locales without ordinals; Qo/Mo/DDDo/e/eo/do/Wo/wo everywhere)

1 participant