From b7a55ee5a49ac37155fa10c2dac0d8b0ac9c239a Mon Sep 17 00:00:00 2001 From: Dzmitry Plashchynski Date: Wed, 12 Mar 2025 15:44:56 +0300 Subject: [PATCH 01/12] gh-131146: Fix month names in a genitive case in calendar module. The calendar module displays month names in some locales using the genitive case. This is grammatically incorrect, as the nominative case should be used when the month is named by itself. To address this issue, this change introduces new lists `alt_month_name` and `alt_month_abbr` that contain month names in the nominative case. The module now uses `%OB` format specifier to get month names in the nominative case where available. --- Lib/calendar.py | 24 +++++++++++++++++++++--- Lib/test/test_calendar.py | 3 ++- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/Lib/calendar.py b/Lib/calendar.py index 01a76ff8e78c45..33a62adb777e6a 100644 --- a/Lib/calendar.py +++ b/Lib/calendar.py @@ -139,6 +139,24 @@ def __len__(self): month_name = _localized_month('%B') month_abbr = _localized_month('%b') +# Check if the platform supports the %OB format code +def _is_alt_mon_available(): + try: + datetime.date(2001, 1, 1).strftime('%OB') + datetime.date(2001, 1, 1).strftime('%Ob') + except ValueError: + return False + return True + +# In Greek and in many Slavic and Baltic languages, "%OB" will produce +# the month in nominative case. +if _is_alt_mon_available(): + alt_month_name = _localized_month('%OB') + alt_month_abbr = _localized_month('%Ob') +else: + alt_month_name = month_name + alt_month_abbr = month_abbr + def isleap(year): """Return True for leap years, False for non-leap years.""" @@ -377,7 +395,7 @@ def formatmonthname(self, theyear, themonth, width, withyear=True): """ _validate_month(themonth) - s = month_name[themonth] + s = alt_month_name[themonth] if withyear: s = "%s %r" % (s, theyear) return s.center(width) @@ -510,9 +528,9 @@ def formatmonthname(self, theyear, themonth, withyear=True): """ _validate_month(themonth) if withyear: - s = '%s %s' % (month_name[themonth], theyear) + s = '%s %s' % (alt_month_name[themonth], theyear) else: - s = '%s' % month_name[themonth] + s = '%s' % alt_month_name[themonth] return '%s' % ( self.cssclass_month_head, s) diff --git a/Lib/test/test_calendar.py b/Lib/test/test_calendar.py index 073df310bb49eb..704f8e30004a15 100644 --- a/Lib/test/test_calendar.py +++ b/Lib/test/test_calendar.py @@ -1126,7 +1126,8 @@ def test__all__(self): not_exported = { 'mdays', 'January', 'February', 'EPOCH', 'different_locale', 'c', 'prweek', 'week', 'format', - 'formatstring', 'main', 'monthlen', 'prevmonth', 'nextmonth', ""} + 'formatstring', 'main', 'monthlen', 'prevmonth', 'nextmonth', + 'alt_month_name', 'alt_month_abbr', ""} support.check__all__(self, calendar, not_exported=not_exported) From fb1c5ee50af9f0b8d4cdadf23eb31e514139b24f Mon Sep 17 00:00:00 2001 From: Dzmitry Plashchynski Date: Mon, 17 Mar 2025 20:37:57 +0300 Subject: [PATCH 02/12] Make `alt_month_name` and `alt_month_abbr` public in the `calendar` module. Expose alternative month names/abbreviations so users can benefit from alternative forms when they are available. Update documentation and tests accordingly. --- Doc/library/calendar.rst | 37 ++++++++++++++++++++++++++++++++----- Lib/calendar.py | 12 +++++++----- Lib/test/test_calendar.py | 13 ++++++++++--- 3 files changed, 49 insertions(+), 13 deletions(-) diff --git a/Doc/library/calendar.rst b/Doc/library/calendar.rst index 39090e36ed9c0d..3d602fd916ee29 100644 --- a/Doc/library/calendar.rst +++ b/Doc/library/calendar.rst @@ -493,9 +493,10 @@ The :mod:`calendar` module exports the following data attributes: .. data:: month_name - A sequence that represents the months of the year in the current locale. This - follows normal convention of January being month number 1, so it has a length of - 13 and ``month_name[0]`` is the empty string. + A sequence that represents the months of the year in the current locale + in the grammatical form used when the month is part of a complete date. + This follows normal convention of January being month number 1, so it has + a length of 13 and ``month_name[0]`` is the empty string. >>> import calendar >>> list(calendar.month_name) @@ -505,13 +506,39 @@ The :mod:`calendar` module exports the following data attributes: .. data:: month_abbr A sequence that represents the abbreviated months of the year in the current - locale. This follows normal convention of January being month number 1, so it - has a length of 13 and ``month_abbr[0]`` is the empty string. + locale in the grammatical form used when the month is part of a complete date. + This follows normal convention of January being month number 1, so it has + a length of 13 and ``month_abbr[0]`` is the empty string. >>> import calendar >>> list(calendar.month_abbr) ['', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] + +.. data:: alt_month_name + + A sequence that represents the months of the year in the current locale + in the grammatical form used when the month is named by itself if the locale + provides one. If the locale does not supply an alternative form, it falls back + to the behavior of :data:`month_name`. + + >>> import calendar + >>> list(calendar.alt_month_name) + ['', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'] + + +.. data:: alt_month_abbr + + A sequence that represents the abbreviated months of the year in the current + locale in the grammatical form used when the month is named by itself if the + locale provides one. If the locale does not supply an alternative form, it falls + back to the behavior of :data:`month_abbr`. + + >>> import calendar + >>> list(calendar.alt_month_abbr) + ['', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] + + .. data:: JANUARY FEBRUARY MARCH diff --git a/Lib/calendar.py b/Lib/calendar.py index 33a62adb777e6a..ee8f96b0fdbe16 100644 --- a/Lib/calendar.py +++ b/Lib/calendar.py @@ -14,8 +14,9 @@ __all__ = ["IllegalMonthError", "IllegalWeekdayError", "setfirstweekday", "firstweekday", "isleap", "leapdays", "weekday", "monthrange", "monthcalendar", "prmonth", "month", "prcal", "calendar", - "timegm", "month_name", "month_abbr", "day_name", "day_abbr", - "Calendar", "TextCalendar", "HTMLCalendar", "LocaleTextCalendar", + "timegm", "month_name", "month_abbr", "alt_month_name", + "alt_month_abbr", "day_name", "day_abbr", "Calendar", + "TextCalendar", "HTMLCalendar", "LocaleTextCalendar", "LocaleHTMLCalendar", "weekheader", "Day", "Month", "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE", "JULY", @@ -139,7 +140,7 @@ def __len__(self): month_name = _localized_month('%B') month_abbr = _localized_month('%b') -# Check if the platform supports the %OB format code +# Check if the platform supports %OB and %Ob specifiers def _is_alt_mon_available(): try: datetime.date(2001, 1, 1).strftime('%OB') @@ -148,8 +149,9 @@ def _is_alt_mon_available(): return False return True -# In Greek and in many Slavic and Baltic languages, "%OB" will produce -# the month in nominative case. +# On platforms that support the %OB and %Ob specifiers, it is used to get the +# standalone form of the month name. This is required for some languages +# such as Greek, Slavic, and Baltic languages. if _is_alt_mon_available(): alt_month_name = _localized_month('%OB') alt_month_abbr = _localized_month('%Ob') diff --git a/Lib/test/test_calendar.py b/Lib/test/test_calendar.py index 704f8e30004a15..dd2803cdcc26fc 100644 --- a/Lib/test/test_calendar.py +++ b/Lib/test/test_calendar.py @@ -546,7 +546,8 @@ def test_days(self): self.assertEqual(value[::-1], list(reversed(value))) def test_months(self): - for attr in "month_name", "month_abbr": + for attr in ["month_name", "month_abbr", "alt_month_name", + "alt_month_abbr"]: value = getattr(calendar, attr) self.assertEqual(len(value), 13) self.assertEqual(len(value[:]), 13) @@ -556,6 +557,13 @@ def test_months(self): # verify it "acts like a sequence" in two forms of iteration self.assertEqual(value[::-1], list(reversed(value))) + def test_alt_month_name_and_abbr(self): + # Ensure that the alternate month names and abbreviations are equal + # to the regular month names and abbreviations for the "C" locale. + with calendar.different_locale("C"): + self.assertEqual(list(calendar.month_name), list(calendar.alt_month_name)) + self.assertEqual(list(calendar.month_abbr), list(calendar.alt_month_abbr)) + def test_locale_text_calendar(self): try: cal = calendar.LocaleTextCalendar(locale='') @@ -1126,8 +1134,7 @@ def test__all__(self): not_exported = { 'mdays', 'January', 'February', 'EPOCH', 'different_locale', 'c', 'prweek', 'week', 'format', - 'formatstring', 'main', 'monthlen', 'prevmonth', 'nextmonth', - 'alt_month_name', 'alt_month_abbr', ""} + 'formatstring', 'main', 'monthlen', 'prevmonth', 'nextmonth', ""} support.check__all__(self, calendar, not_exported=not_exported) From ab5258648182a7e6eb9f84f0747ef8279fe47a66 Mon Sep 17 00:00:00 2001 From: Dzmitry Plashchynski Date: Mon, 17 Mar 2025 21:21:13 +0300 Subject: [PATCH 03/12] Add NEWS entries. --- .../Library/2025-03-17-21-15-04.gh-issue-131146.P9Cdx0.rst | 4 ++++ .../Library/2025-03-17-21-21-06.gh-issue-131146.A5Obgv.rst | 3 +++ 2 files changed, 7 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2025-03-17-21-15-04.gh-issue-131146.P9Cdx0.rst create mode 100644 Misc/NEWS.d/next/Library/2025-03-17-21-21-06.gh-issue-131146.A5Obgv.rst diff --git a/Misc/NEWS.d/next/Library/2025-03-17-21-15-04.gh-issue-131146.P9Cdx0.rst b/Misc/NEWS.d/next/Library/2025-03-17-21-15-04.gh-issue-131146.P9Cdx0.rst new file mode 100644 index 00000000000000..233f232d135160 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-03-17-21-15-04.gh-issue-131146.P9Cdx0.rst @@ -0,0 +1,4 @@ +Add :func:`alt_month_name` and :func:`alt_month_abbr` in :mod:`calendar` to +provide alternative month names and abbreviations for the current locale +when available. These are used when the month is named by itself, such as in +a standalone date. diff --git a/Misc/NEWS.d/next/Library/2025-03-17-21-21-06.gh-issue-131146.A5Obgv.rst b/Misc/NEWS.d/next/Library/2025-03-17-21-21-06.gh-issue-131146.A5Obgv.rst new file mode 100644 index 00000000000000..705b082972ae13 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-03-17-21-21-06.gh-issue-131146.A5Obgv.rst @@ -0,0 +1,3 @@ +Fix :class:`calendar.TextCalendar` and :class:`calendar.HTMLCalendar` and +:mod:`calendar` CLI to display month names in the nominative case if +provided by the locale. From 6177415eb15e67ee633807bb35e2b8086386d1cc Mon Sep 17 00:00:00 2001 From: Dzmitry Plashchynski Date: Mon, 17 Mar 2025 21:37:22 +0300 Subject: [PATCH 04/12] Fix py:func references in NEWS.d --- .../next/Library/2025-03-17-21-15-04.gh-issue-131146.P9Cdx0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-03-17-21-15-04.gh-issue-131146.P9Cdx0.rst b/Misc/NEWS.d/next/Library/2025-03-17-21-15-04.gh-issue-131146.P9Cdx0.rst index 233f232d135160..1db3bbe4c5650e 100644 --- a/Misc/NEWS.d/next/Library/2025-03-17-21-15-04.gh-issue-131146.P9Cdx0.rst +++ b/Misc/NEWS.d/next/Library/2025-03-17-21-15-04.gh-issue-131146.P9Cdx0.rst @@ -1,4 +1,4 @@ -Add :func:`alt_month_name` and :func:`alt_month_abbr` in :mod:`calendar` to +Add :func:`calendar.alt_month_name` and :func:`calendar.alt_month_abbr` to provide alternative month names and abbreviations for the current locale when available. These are used when the month is named by itself, such as in a standalone date. From a11ecfbe039066a89a9e6b1ebabe1b4b254a2407 Mon Sep 17 00:00:00 2001 From: Dzmitry Plashchynski Date: Mon, 17 Mar 2025 22:13:13 +0300 Subject: [PATCH 05/12] Refinement changes: * Use assertListEqual to ensure alternate month names the same as regular for the "C" locale. * Use `_supports_alternative_month_names` as more descriptive name. * Add `versionadded:: next` tags to the new APIs. --- Doc/library/calendar.rst | 4 ++++ Lib/calendar.py | 6 +++--- Lib/test/test_calendar.py | 4 ++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Doc/library/calendar.rst b/Doc/library/calendar.rst index 3d602fd916ee29..068e9c8754a14b 100644 --- a/Doc/library/calendar.rst +++ b/Doc/library/calendar.rst @@ -526,6 +526,8 @@ The :mod:`calendar` module exports the following data attributes: >>> list(calendar.alt_month_name) ['', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'] + .. versionadded:: next + .. data:: alt_month_abbr @@ -538,6 +540,8 @@ The :mod:`calendar` module exports the following data attributes: >>> list(calendar.alt_month_abbr) ['', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] + .. versionadded:: next + .. data:: JANUARY FEBRUARY diff --git a/Lib/calendar.py b/Lib/calendar.py index ee8f96b0fdbe16..4da288f2154e94 100644 --- a/Lib/calendar.py +++ b/Lib/calendar.py @@ -141,7 +141,7 @@ def __len__(self): month_abbr = _localized_month('%b') # Check if the platform supports %OB and %Ob specifiers -def _is_alt_mon_available(): +def _supports_alternative_month_names(): try: datetime.date(2001, 1, 1).strftime('%OB') datetime.date(2001, 1, 1).strftime('%Ob') @@ -152,7 +152,7 @@ def _is_alt_mon_available(): # On platforms that support the %OB and %Ob specifiers, it is used to get the # standalone form of the month name. This is required for some languages # such as Greek, Slavic, and Baltic languages. -if _is_alt_mon_available(): +if _supports_alternative_month_names(): alt_month_name = _localized_month('%OB') alt_month_abbr = _localized_month('%Ob') else: @@ -532,7 +532,7 @@ def formatmonthname(self, theyear, themonth, withyear=True): if withyear: s = '%s %s' % (alt_month_name[themonth], theyear) else: - s = '%s' % alt_month_name[themonth] + s = alt_month_name[themonth] return '%s' % ( self.cssclass_month_head, s) diff --git a/Lib/test/test_calendar.py b/Lib/test/test_calendar.py index dd2803cdcc26fc..91c0e70b9032ef 100644 --- a/Lib/test/test_calendar.py +++ b/Lib/test/test_calendar.py @@ -561,8 +561,8 @@ def test_alt_month_name_and_abbr(self): # Ensure that the alternate month names and abbreviations are equal # to the regular month names and abbreviations for the "C" locale. with calendar.different_locale("C"): - self.assertEqual(list(calendar.month_name), list(calendar.alt_month_name)) - self.assertEqual(list(calendar.month_abbr), list(calendar.alt_month_abbr)) + self.assertListEqual(list(calendar.month_name), list(calendar.alt_month_name)) + self.assertListEqual(list(calendar.month_abbr), list(calendar.alt_month_abbr)) def test_locale_text_calendar(self): try: From 46c7513af41c4083c4fa3862048fed0dad636477 Mon Sep 17 00:00:00 2001 From: Dzmitry Plashchynski Date: Mon, 17 Mar 2025 23:04:38 +0300 Subject: [PATCH 06/12] Apply suggested style changes --- Lib/calendar.py | 14 +++----------- Lib/test/test_calendar.py | 4 ++-- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/Lib/calendar.py b/Lib/calendar.py index 4da288f2154e94..acdaeea22c63b9 100644 --- a/Lib/calendar.py +++ b/Lib/calendar.py @@ -140,22 +140,14 @@ def __len__(self): month_name = _localized_month('%B') month_abbr = _localized_month('%b') -# Check if the platform supports %OB and %Ob specifiers -def _supports_alternative_month_names(): - try: - datetime.date(2001, 1, 1).strftime('%OB') - datetime.date(2001, 1, 1).strftime('%Ob') - except ValueError: - return False - return True - # On platforms that support the %OB and %Ob specifiers, it is used to get the # standalone form of the month name. This is required for some languages # such as Greek, Slavic, and Baltic languages. -if _supports_alternative_month_names(): +try: alt_month_name = _localized_month('%OB') alt_month_abbr = _localized_month('%Ob') -else: +except ValueError: + # The platform does not support the %OB and %Ob specifiers. alt_month_name = month_name alt_month_abbr = month_abbr diff --git a/Lib/test/test_calendar.py b/Lib/test/test_calendar.py index 91c0e70b9032ef..7de0d8f1d8a4cf 100644 --- a/Lib/test/test_calendar.py +++ b/Lib/test/test_calendar.py @@ -546,8 +546,8 @@ def test_days(self): self.assertEqual(value[::-1], list(reversed(value))) def test_months(self): - for attr in ["month_name", "month_abbr", "alt_month_name", - "alt_month_abbr"]: + for attr in ("month_name", "month_abbr", "alt_month_name", + "alt_month_abbr"): value = getattr(calendar, attr) self.assertEqual(len(value), 13) self.assertEqual(len(value[:]), 13) From 9badac0e860dac39f3d5ad2a482607975766b710 Mon Sep 17 00:00:00 2001 From: Dzmitry Plashchynski Date: Tue, 18 Mar 2025 03:53:04 +0300 Subject: [PATCH 07/12] Rename `calendar.alt_month_name` to `calendar.standalone_month_name`, and `calendar.alt_month_abbr` to `calendar.standalone_month_abbr`. --- Doc/library/calendar.rst | 42 ++++++++++++------- Lib/calendar.py | 18 ++++---- Lib/test/test_calendar.py | 12 +++--- ...-03-17-21-15-04.gh-issue-131146.P9Cdx0.rst | 2 +- 4 files changed, 43 insertions(+), 31 deletions(-) diff --git a/Doc/library/calendar.rst b/Doc/library/calendar.rst index 068e9c8754a14b..0c8d7ed7f076d3 100644 --- a/Doc/library/calendar.rst +++ b/Doc/library/calendar.rst @@ -493,8 +493,7 @@ The :mod:`calendar` module exports the following data attributes: .. data:: month_name - A sequence that represents the months of the year in the current locale - in the grammatical form used when the month is part of a complete date. + A sequence that represents the months of the year in the current locale. This follows normal convention of January being month number 1, so it has a length of 13 and ``month_name[0]`` is the empty string. @@ -502,42 +501,55 @@ The :mod:`calendar` module exports the following data attributes: >>> list(calendar.month_name) ['', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'] + .. caution:: + + In locales with alternative forms of month names, the :data:`month_name` sequence + may not be suitable when a month name stands by itself and not as part of a date. + For instance, in Greek and in many Slavic and Baltic languages, :data:`month_name` + will produce the month in genitive case. Use :data:`standalone_month_name` for a form + suitable for standalone use. + .. data:: month_abbr A sequence that represents the abbreviated months of the year in the current - locale in the grammatical form used when the month is part of a complete date. - This follows normal convention of January being month number 1, so it has - a length of 13 and ``month_abbr[0]`` is the empty string. + locale. This follows normal convention of January being month number 1, so + it has a length of 13 and ``month_abbr[0]`` is the empty string. >>> import calendar >>> list(calendar.month_abbr) ['', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] + .. caution:: + + In locales with alternative forms of month names, the :data:`month_abbr` sequence + may not be suitable when a month name stands by itself and not as part of a date. + Use :data:`standalone_month_abbr` for a form suitable for standalone use. + -.. data:: alt_month_name +.. data:: standalone_month_name A sequence that represents the months of the year in the current locale - in the grammatical form used when the month is named by itself if the locale - provides one. If the locale does not supply an alternative form, it falls back - to the behavior of :data:`month_name`. + in the grammatical form used when a month name stands by itself if the locale + provides one. If the locale does not supply an alternative form, it is equal to + :data:`month_name`. >>> import calendar - >>> list(calendar.alt_month_name) + >>> list(calendar.standalone_month_name) ['', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'] .. versionadded:: next -.. data:: alt_month_abbr +.. data:: standalone_month_abbr A sequence that represents the abbreviated months of the year in the current - locale in the grammatical form used when the month is named by itself if the - locale provides one. If the locale does not supply an alternative form, it falls - back to the behavior of :data:`month_abbr`. + locale in the grammatical form used when a month name stands by itself if the + locale provides one. If the locale does not supply an alternative form, it is equal to + :data:`month_abbr`. >>> import calendar - >>> list(calendar.alt_month_abbr) + >>> list(calendar.standalone_month_abbr) ['', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] .. versionadded:: next diff --git a/Lib/calendar.py b/Lib/calendar.py index acdaeea22c63b9..31037c583fb054 100644 --- a/Lib/calendar.py +++ b/Lib/calendar.py @@ -14,8 +14,8 @@ __all__ = ["IllegalMonthError", "IllegalWeekdayError", "setfirstweekday", "firstweekday", "isleap", "leapdays", "weekday", "monthrange", "monthcalendar", "prmonth", "month", "prcal", "calendar", - "timegm", "month_name", "month_abbr", "alt_month_name", - "alt_month_abbr", "day_name", "day_abbr", "Calendar", + "timegm", "month_name", "month_abbr", "standalone_month_name", + "standalone_month_abbr", "day_name", "day_abbr", "Calendar", "TextCalendar", "HTMLCalendar", "LocaleTextCalendar", "LocaleHTMLCalendar", "weekheader", "Day", "Month", "JANUARY", "FEBRUARY", "MARCH", @@ -144,12 +144,12 @@ def __len__(self): # standalone form of the month name. This is required for some languages # such as Greek, Slavic, and Baltic languages. try: - alt_month_name = _localized_month('%OB') - alt_month_abbr = _localized_month('%Ob') + standalone_month_name = _localized_month('%OB') + standalone_month_abbr = _localized_month('%Ob') except ValueError: # The platform does not support the %OB and %Ob specifiers. - alt_month_name = month_name - alt_month_abbr = month_abbr + standalone_month_name = month_name + standalone_month_abbr = month_abbr def isleap(year): @@ -389,7 +389,7 @@ def formatmonthname(self, theyear, themonth, width, withyear=True): """ _validate_month(themonth) - s = alt_month_name[themonth] + s = standalone_month_name[themonth] if withyear: s = "%s %r" % (s, theyear) return s.center(width) @@ -522,9 +522,9 @@ def formatmonthname(self, theyear, themonth, withyear=True): """ _validate_month(themonth) if withyear: - s = '%s %s' % (alt_month_name[themonth], theyear) + s = '%s %s' % (standalone_month_name[themonth], theyear) else: - s = alt_month_name[themonth] + s = standalone_month_name[themonth] return '%s' % ( self.cssclass_month_head, s) diff --git a/Lib/test/test_calendar.py b/Lib/test/test_calendar.py index 7de0d8f1d8a4cf..27cf30a79dc531 100644 --- a/Lib/test/test_calendar.py +++ b/Lib/test/test_calendar.py @@ -546,8 +546,8 @@ def test_days(self): self.assertEqual(value[::-1], list(reversed(value))) def test_months(self): - for attr in ("month_name", "month_abbr", "alt_month_name", - "alt_month_abbr"): + for attr in ("month_name", "month_abbr", "standalone_month_name", + "standalone_month_abbr"): value = getattr(calendar, attr) self.assertEqual(len(value), 13) self.assertEqual(len(value[:]), 13) @@ -557,12 +557,12 @@ def test_months(self): # verify it "acts like a sequence" in two forms of iteration self.assertEqual(value[::-1], list(reversed(value))) - def test_alt_month_name_and_abbr(self): - # Ensure that the alternate month names and abbreviations are equal + def test_standalone_month_name_and_abbr(self): + # Ensure that the standalone month names and abbreviations are equal # to the regular month names and abbreviations for the "C" locale. with calendar.different_locale("C"): - self.assertListEqual(list(calendar.month_name), list(calendar.alt_month_name)) - self.assertListEqual(list(calendar.month_abbr), list(calendar.alt_month_abbr)) + self.assertListEqual(list(calendar.month_name), list(calendar.standalone_month_name)) + self.assertListEqual(list(calendar.month_abbr), list(calendar.standalone_month_abbr)) def test_locale_text_calendar(self): try: diff --git a/Misc/NEWS.d/next/Library/2025-03-17-21-15-04.gh-issue-131146.P9Cdx0.rst b/Misc/NEWS.d/next/Library/2025-03-17-21-15-04.gh-issue-131146.P9Cdx0.rst index 1db3bbe4c5650e..a2933243c10087 100644 --- a/Misc/NEWS.d/next/Library/2025-03-17-21-15-04.gh-issue-131146.P9Cdx0.rst +++ b/Misc/NEWS.d/next/Library/2025-03-17-21-15-04.gh-issue-131146.P9Cdx0.rst @@ -1,4 +1,4 @@ -Add :func:`calendar.alt_month_name` and :func:`calendar.alt_month_abbr` to +Add :func:`calendar.standalone_month_name` and :func:`calendar.standalone_month_abbr` to provide alternative month names and abbreviations for the current locale when available. These are used when the month is named by itself, such as in a standalone date. From fce8599a097bf6dae8d7a77195b1c7df2171e0b2 Mon Sep 17 00:00:00 2001 From: Dzmitry Plashchynski Date: Tue, 18 Mar 2025 04:11:46 +0300 Subject: [PATCH 08/12] Refine news message wording for better clarity --- .../Library/2025-03-17-21-15-04.gh-issue-131146.P9Cdx0.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS.d/next/Library/2025-03-17-21-15-04.gh-issue-131146.P9Cdx0.rst b/Misc/NEWS.d/next/Library/2025-03-17-21-15-04.gh-issue-131146.P9Cdx0.rst index a2933243c10087..1a5d98af276004 100644 --- a/Misc/NEWS.d/next/Library/2025-03-17-21-15-04.gh-issue-131146.P9Cdx0.rst +++ b/Misc/NEWS.d/next/Library/2025-03-17-21-15-04.gh-issue-131146.P9Cdx0.rst @@ -1,4 +1,3 @@ Add :func:`calendar.standalone_month_name` and :func:`calendar.standalone_month_abbr` to -provide alternative month names and abbreviations for the current locale -when available. These are used when the month is named by itself, such as in -a standalone date. +provide month names and abbreviations in a grammatical form used when a month name stands +by itself if the locale provides one. From 7a175d52b4c6d1376c1600c642304bd5ae920f18 Mon Sep 17 00:00:00 2001 From: Dzmitry Plashchynski Date: Tue, 18 Mar 2025 16:49:23 +0300 Subject: [PATCH 09/12] Style guide compliance: * Limit line length to 79 characters according to PEP8 * Suppress current unit links according to the Documentation Style Guide --- Doc/library/calendar.rst | 6 +++--- Lib/calendar.py | 6 +++--- Lib/test/test_calendar.py | 11 +++++++---- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/Doc/library/calendar.rst b/Doc/library/calendar.rst index 0c8d7ed7f076d3..dd5c6c6ed3c63e 100644 --- a/Doc/library/calendar.rst +++ b/Doc/library/calendar.rst @@ -503,9 +503,9 @@ The :mod:`calendar` module exports the following data attributes: .. caution:: - In locales with alternative forms of month names, the :data:`month_name` sequence + In locales with alternative forms of month names, the :data:`!month_name` sequence may not be suitable when a month name stands by itself and not as part of a date. - For instance, in Greek and in many Slavic and Baltic languages, :data:`month_name` + For instance, in Greek and in many Slavic and Baltic languages, :data:`!month_name` will produce the month in genitive case. Use :data:`standalone_month_name` for a form suitable for standalone use. @@ -522,7 +522,7 @@ The :mod:`calendar` module exports the following data attributes: .. caution:: - In locales with alternative forms of month names, the :data:`month_abbr` sequence + In locales with alternative forms of month names, the :data:`!month_abbr` sequence may not be suitable when a month name stands by itself and not as part of a date. Use :data:`standalone_month_abbr` for a form suitable for standalone use. diff --git a/Lib/calendar.py b/Lib/calendar.py index 31037c583fb054..a055c68f640ff5 100644 --- a/Lib/calendar.py +++ b/Lib/calendar.py @@ -140,9 +140,9 @@ def __len__(self): month_name = _localized_month('%B') month_abbr = _localized_month('%b') -# On platforms that support the %OB and %Ob specifiers, it is used to get the -# standalone form of the month name. This is required for some languages -# such as Greek, Slavic, and Baltic languages. +# On platforms that support the %OB and %Ob specifiers, it is used +# to get the standalone form of the month name. This is required for +# some languages such as Greek, Slavic, and Baltic languages. try: standalone_month_name = _localized_month('%OB') standalone_month_abbr = _localized_month('%Ob') diff --git a/Lib/test/test_calendar.py b/Lib/test/test_calendar.py index 27cf30a79dc531..f2c6c6686ee203 100644 --- a/Lib/test/test_calendar.py +++ b/Lib/test/test_calendar.py @@ -558,11 +558,14 @@ def test_months(self): self.assertEqual(value[::-1], list(reversed(value))) def test_standalone_month_name_and_abbr(self): - # Ensure that the standalone month names and abbreviations are equal - # to the regular month names and abbreviations for the "C" locale. + # Ensure that the standalone month names and abbreviations are + # equal to the regular month names and abbreviations for + # the "C" locale. with calendar.different_locale("C"): - self.assertListEqual(list(calendar.month_name), list(calendar.standalone_month_name)) - self.assertListEqual(list(calendar.month_abbr), list(calendar.standalone_month_abbr)) + self.assertListEqual(list(calendar.month_name), + list(calendar.standalone_month_name)) + self.assertListEqual(list(calendar.month_abbr), + list(calendar.standalone_month_abbr)) def test_locale_text_calendar(self): try: From 36bb4561959b6f2330035be57d7322800866a010 Mon Sep 17 00:00:00 2001 From: Dzmitry Plashchynski Date: Sun, 23 Mar 2025 22:44:06 +0300 Subject: [PATCH 10/12] Fix roles of and in the NEWS.d entry. --- .../next/Library/2025-03-17-21-15-04.gh-issue-131146.P9Cdx0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-03-17-21-15-04.gh-issue-131146.P9Cdx0.rst b/Misc/NEWS.d/next/Library/2025-03-17-21-15-04.gh-issue-131146.P9Cdx0.rst index 1a5d98af276004..6284f2140bc0a0 100644 --- a/Misc/NEWS.d/next/Library/2025-03-17-21-15-04.gh-issue-131146.P9Cdx0.rst +++ b/Misc/NEWS.d/next/Library/2025-03-17-21-15-04.gh-issue-131146.P9Cdx0.rst @@ -1,3 +1,3 @@ -Add :func:`calendar.standalone_month_name` and :func:`calendar.standalone_month_abbr` to +Add :data:`calendar.standalone_month_name` and :data:`calendar.standalone_month_abbr` to provide month names and abbreviations in a grammatical form used when a month name stands by itself if the locale provides one. From 5feb1dcdb82c19a613a2c51d8af175bb199d4fc2 Mon Sep 17 00:00:00 2001 From: Dzmitry Plashchynski Date: Sun, 11 May 2025 12:51:46 +0300 Subject: [PATCH 11/12] Fix grammar and wording --- Doc/library/calendar.rst | 14 +++++++------- Lib/calendar.py | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Doc/library/calendar.rst b/Doc/library/calendar.rst index dd5c6c6ed3c63e..d01c7b818ef62a 100644 --- a/Doc/library/calendar.rst +++ b/Doc/library/calendar.rst @@ -522,7 +522,7 @@ The :mod:`calendar` module exports the following data attributes: .. caution:: - In locales with alternative forms of month names, the :data:`!month_abbr` sequence + In locales with alternative month names forms, the :data:`!month_abbr` sequence may not be suitable when a month name stands by itself and not as part of a date. Use :data:`standalone_month_abbr` for a form suitable for standalone use. @@ -530,9 +530,9 @@ The :mod:`calendar` module exports the following data attributes: .. data:: standalone_month_name A sequence that represents the months of the year in the current locale - in the grammatical form used when a month name stands by itself if the locale - provides one. If the locale does not supply an alternative form, it is equal to - :data:`month_name`. + in the grammatical form used when a month name stands by itself if + the locale provides one. If the locale does not supply a standalone form, + it is equal to :data:`month_name`. >>> import calendar >>> list(calendar.standalone_month_name) @@ -544,9 +544,9 @@ The :mod:`calendar` module exports the following data attributes: .. data:: standalone_month_abbr A sequence that represents the abbreviated months of the year in the current - locale in the grammatical form used when a month name stands by itself if the - locale provides one. If the locale does not supply an alternative form, it is equal to - :data:`month_abbr`. + locale in the grammatical form used when a month name stands by itself if + the locale provides one. If the locale does not supply a standalone form + it is equal to :data:`month_abbr`. >>> import calendar >>> list(calendar.standalone_month_abbr) diff --git a/Lib/calendar.py b/Lib/calendar.py index a055c68f640ff5..f3cb92b1289a15 100644 --- a/Lib/calendar.py +++ b/Lib/calendar.py @@ -140,7 +140,7 @@ def __len__(self): month_name = _localized_month('%B') month_abbr = _localized_month('%b') -# On platforms that support the %OB and %Ob specifiers, it is used +# On platforms that support the %OB and %Ob specifiers, they are used # to get the standalone form of the month name. This is required for # some languages such as Greek, Slavic, and Baltic languages. try: From 1ecc61307a4a2230438a899daa53a42356869052 Mon Sep 17 00:00:00 2001 From: Dzmitry Plashchynski Date: Sun, 11 May 2025 12:55:23 +0300 Subject: [PATCH 12/12] Rewording --- Doc/library/calendar.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/calendar.rst b/Doc/library/calendar.rst index d01c7b818ef62a..5fb6140ff1acbb 100644 --- a/Doc/library/calendar.rst +++ b/Doc/library/calendar.rst @@ -503,7 +503,7 @@ The :mod:`calendar` module exports the following data attributes: .. caution:: - In locales with alternative forms of month names, the :data:`!month_name` sequence + In locales with alternative month names forms, the :data:`!month_name` sequence may not be suitable when a month name stands by itself and not as part of a date. For instance, in Greek and in many Slavic and Baltic languages, :data:`!month_name` will produce the month in genitive case. Use :data:`standalone_month_name` for a form