anxkhn opened a new pull request, #69405:
URL: https://github.com/apache/airflow/pull/69405
```markdown
The `@deprecated` decorator in the Google provider parses and formats the
`planned_removal_date` using `strptime`/`strftime` with the `%B` directive.
`%B` resolves the full month name against the process `LC_TIME` locale, so it
only recognizes the English month names ("June 30, 2026") when the process
runs
under an English (or C) locale.
Under a non-English `LC_TIME`/`LC_ALL` (for example `de_DE`, `fr_FR`,
`es_ES`),
`datetime.strptime("June 30, 2026", "%B %d, %Y")` raises `ValueError`, which
`AirflowDeprecationAdapter._validate_date` re-wraps as
`ValueError: Invalid date 'June 30, 2026'`. This happens at decoration time,
which is import time: the BigQuery operators decorate a class member with
`@deprecated(planned_removal_date="June 30, 2026", ...)` at class-body
level, so
importing `airflow.providers.google.cloud.operators.bigquery` under a
non-English
process locale fails outright. Any module that uses this decorator with a
`planned_removal_date` is affected the same way.
The formatting side has the same root cause: `sunset_message()` used
`strftime('%B %d, %Y')`, which renders a localized month name (for example
`Juni`/`juin`) in the deprecation warning under a non-English locale, even
though
the developer wrote an English date.
This makes the month handling locale independent while keeping the accepted
input
format, the error message, and the rendered output identical:
- Parsing translates the English month name to its number through a fixed
mapping, then parses the numeric parts with the locale-independent `%m %d,
%Y`.
The mapping is case-insensitive, matching the previous `%B` behavior (which
accepted `"june 30, 2026"` / `"JUNE 30, 2026"` too).
- `sunset_message()` formats the month from the same fixed English names and
the
day/year with digit-only directives.
The month names are hardcoded on purpose: `calendar.month_name` and
`strftime`
are themselves locale-dependent, so they cannot be used to make this
locale-independent.
### Reproduction (before this change)
```python
import locale
locale.setlocale(locale.LC_ALL, "de_DE.UTF-8")
from deprecated import deprecated # airflow's Google-provider
AirflowDeprecationAdapter
@deprecated(planned_removal_date="June 30, 2026")
def f(): ...
# ValueError: Invalid date 'June 30, 2026'. Expected format: 'Month DD,
YYYY', ...
```
or simply, under such a locale:
```python
from airflow.providers.google.cloud.operators.bigquery import
BigQueryGetDataOperator
# ValueError: Invalid date 'June 30, 2026'. ...
```
### Tests
- Reworked `test_validate_date` from mock-based assertions on the internal
`strptime(value, "%B %d, %Y")` call (which this change replaces) to
behavioral,
parametrized parsing assertions, including case-insensitive month
spellings.
- Added `test_validate_date_is_locale_independent` (parses `June 30, 2026`
under
`de_DE.UTF-8`/`fr_FR.UTF-8`) and
`test_sunset_message_uses_english_month_regardless_of_locale` (message
stays
`after June 30, 2026`). Both skip cleanly if the locale is not installed
on the
runner.
Both new locale tests fail against `main` with the exact
`Invalid date 'June 30, 2026'` crash and pass with this change.
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]