From 675377b830c9584bdff7ef9c87fcea3cf5350f26 Mon Sep 17 00:00:00 2001 From: Scott Noyes Date: Wed, 6 Aug 2025 13:18:55 -0500 Subject: [PATCH 01/10] Fix #137481 Find the length of the longest day name in the current locale. Use that length, rather than a constant "9", to decide if the names should be abbreviated. --- Lib/calendar.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/calendar.py b/Lib/calendar.py index 45bb265a65602c..3b7f0b49a0236b 100644 --- a/Lib/calendar.py +++ b/Lib/calendar.py @@ -370,7 +370,7 @@ def formatweekday(self, day, width): """ Returns a formatted week day name. """ - if width >= 9: + if width >= max(map(len, day_name)): names = day_name else: names = day_abbr From fab014effea611b99cc2384da15fc319fa8be66b Mon Sep 17 00:00:00 2001 From: Scott Noyes Date: Wed, 6 Aug 2025 16:22:05 -0500 Subject: [PATCH 02/10] added test --- Lib/test/test_calendar.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Lib/test/test_calendar.py b/Lib/test/test_calendar.py index 589a21baf7bd61..51c08b0f0e176a 100644 --- a/Lib/test/test_calendar.py +++ b/Lib/test/test_calendar.py @@ -695,6 +695,26 @@ def test_locale_calendar_formatweekday(self): self.assertEqual(cal.formatweekday(0, 10), " Monday ") except locale.Error: raise unittest.SkipTest('cannot set the en_US locale') + + def test_locale_calendar_shorter_day_names(self): + locale_tested = False + for locale_name in [ + 'french', 'fr_FR.UTF-8', + 'malay', 'ms_MY.UTF-8', + 'norwegian', 'nb_NO.UTF-8', + 'danish', 'da_DK.UTF-8' + ]: + try: + cal = calendar.LocaleTextCalendar(locale=locale_name) + week_header_split = lambda width: cal.formatweekheader(width).split() + self.assertEqual(week_header_split(8), week_header_split(9)) + locale_tested = True + break + except locale.Error: + continue + + if not locale_tested: + raise unittest.SkipTest('cannot set the locale to a language with short weekday names') def test_locale_calendar_formatmonthname(self): try: From 29a18cc879657451655182dab52c5f692c3bb3e1 Mon Sep 17 00:00:00 2001 From: Scott Noyes Date: Wed, 6 Aug 2025 16:54:53 -0500 Subject: [PATCH 03/10] news for calendar abbrev width --- .../next/Library/2025-08-06-16-54-22.gh-issue-137481.eSTkK0.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2025-08-06-16-54-22.gh-issue-137481.eSTkK0.rst diff --git a/Misc/NEWS.d/next/Library/2025-08-06-16-54-22.gh-issue-137481.eSTkK0.rst b/Misc/NEWS.d/next/Library/2025-08-06-16-54-22.gh-issue-137481.eSTkK0.rst new file mode 100644 index 00000000000000..57d8d0521e39aa --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-08-06-16-54-22.gh-issue-137481.eSTkK0.rst @@ -0,0 +1,2 @@ +Calendar uses the lengths of the locale's weekdays to decide if the width +requires abbreviation. From 62b065c99685ea650836dd0a0e156c5dea7ed599 Mon Sep 17 00:00:00 2001 From: Scott Noyes Date: Thu, 7 Aug 2025 07:28:06 -0500 Subject: [PATCH 04/10] test all locales --- Lib/test/test_calendar.py | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_calendar.py b/Lib/test/test_calendar.py index 51c08b0f0e176a..ea35a70a0965f1 100644 --- a/Lib/test/test_calendar.py +++ b/Lib/test/test_calendar.py @@ -698,20 +698,23 @@ def test_locale_calendar_formatweekday(self): def test_locale_calendar_shorter_day_names(self): locale_tested = False - for locale_name in [ - 'french', 'fr_FR.UTF-8', - 'malay', 'ms_MY.UTF-8', - 'norwegian', 'nb_NO.UTF-8', - 'danish', 'da_DK.UTF-8' - ]: - try: - cal = calendar.LocaleTextCalendar(locale=locale_name) - week_header_split = lambda width: cal.formatweekheader(width).split() - self.assertEqual(week_header_split(8), week_header_split(9)) - locale_tested = True - break - except locale.Error: - continue + for locale_name in locale.locale_alias.keys(): + if len(locale_name) < 16: # avoiding a crashing bug on older versions of Python on Windows + try: + with calendar.different_locale(locale_name): + max_length = max(map(len, (datetime.date(2001, 1, i+1).strftime('%A') for i in range(7)))) + + cal = calendar.TextCalendar() + week_header_split = lambda width: cal.formatweekheader(width).split() + + # Full weekday name should be used whenever the width is sufficient + self.assertEqual(week_header_split(max_length), week_header_split(max_length + 10)) + # Any width shorter than the longest necessary should return abbreviations + self.assertNotEqual(week_header_split(max_length), week_header_split(max_length - 1)) + + locale_tested = True + except locale.Error: + continue if not locale_tested: raise unittest.SkipTest('cannot set the locale to a language with short weekday names') From c7966895ff5d28789a73b9581d4fca103ee8fcf9 Mon Sep 17 00:00:00 2001 From: Scott Noyes Date: Thu, 7 Aug 2025 21:45:48 -0500 Subject: [PATCH 05/10] provide a few locales to test --- Lib/test/test_calendar.py | 40 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/Lib/test/test_calendar.py b/Lib/test/test_calendar.py index ea35a70a0965f1..06d6e56513bdd6 100644 --- a/Lib/test/test_calendar.py +++ b/Lib/test/test_calendar.py @@ -696,28 +696,24 @@ def test_locale_calendar_formatweekday(self): except locale.Error: raise unittest.SkipTest('cannot set the en_US locale') - def test_locale_calendar_shorter_day_names(self): - locale_tested = False - for locale_name in locale.locale_alias.keys(): - if len(locale_name) < 16: # avoiding a crashing bug on older versions of Python on Windows - try: - with calendar.different_locale(locale_name): - max_length = max(map(len, (datetime.date(2001, 1, i+1).strftime('%A') for i in range(7)))) - - cal = calendar.TextCalendar() - week_header_split = lambda width: cal.formatweekheader(width).split() - - # Full weekday name should be used whenever the width is sufficient - self.assertEqual(week_header_split(max_length), week_header_split(max_length + 10)) - # Any width shorter than the longest necessary should return abbreviations - self.assertNotEqual(week_header_split(max_length), week_header_split(max_length - 1)) - - locale_tested = True - except locale.Error: - continue - - if not locale_tested: - raise unittest.SkipTest('cannot set the locale to a language with short weekday names') + # These locales have weekday names all shorter than English's longest 'Wednesday' + # They should not be abbreviated unnecessarily + @support.run_with_locale("LC_ALL", + 'Chinese', 'zh_CN.UTF-8', + 'French', 'fr_FR.UTF-8', + 'Norwegian', 'nb_NO.UTF-8', + 'Malay', 'ms_MY.UTF8' + ) + def test_locale_calendar_weekday_names(self): + max_length = max(map(len, (datetime.date(2001, 1, i+1).strftime('%A') for i in range(7)))) + + get_weekday_names = lambda width: calendar.TextCalendar().formatweekheader(width).split() + + # Full weekday name, not an abbreviation, should be used if the width is sufficient + self.assertEqual(get_weekday_names(max_length), get_weekday_names(max_length + 10)) + + # Any width shorter than the longest necessary should produce abbreviations + self.assertNotEqual(get_weekday_names(max_length), get_weekday_names(max_length - 1)) def test_locale_calendar_formatmonthname(self): try: From 95cabcdd8de557c4e4838ad21d660e9010781e4c Mon Sep 17 00:00:00 2001 From: Scott Noyes Date: Thu, 7 Aug 2025 23:41:12 -0500 Subject: [PATCH 06/10] test for proper abbreviation of long names --- Lib/test/test_calendar.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Lib/test/test_calendar.py b/Lib/test/test_calendar.py index 06d6e56513bdd6..219d255f937b72 100644 --- a/Lib/test/test_calendar.py +++ b/Lib/test/test_calendar.py @@ -715,6 +715,18 @@ def test_locale_calendar_weekday_names(self): # Any width shorter than the longest necessary should produce abbreviations self.assertNotEqual(get_weekday_names(max_length), get_weekday_names(max_length - 1)) + # These locales have a weekday name longer than English's longest 'Wednesday' + # They should be properly abbreviated rather than truncated + @support.run_with_locale("LC_ALL", + 'Portuguese', 'pt_PT.UTF-8', + 'German', 'de_DE.UTF-8', + 'Russian', 'ru_RU.UTF-8', + 'Sinhala', 'si_LK.UTF-8' + ) + def test_locale_calendar_long_weekday_names(self): + get_weekday_names = lambda width: calendar.TextCalendar().formatweekheader(width).split() + self.assertEqual(get_weekday_names(4), get_weekday_names(9)) + def test_locale_calendar_formatmonthname(self): try: # formatmonthname uses the same month names regardless of the width argument. From a5d46d0979be5379caaf0070a6b3e5f0e9e7bbd2 Mon Sep 17 00:00:00 2001 From: Scott Noyes Date: Fri, 8 Aug 2025 00:08:59 -0500 Subject: [PATCH 07/10] remove sinhala, abbreviation is not 4 characters --- Lib/test/test_calendar.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/test/test_calendar.py b/Lib/test/test_calendar.py index 219d255f937b72..0081112ee146e8 100644 --- a/Lib/test/test_calendar.py +++ b/Lib/test/test_calendar.py @@ -721,7 +721,6 @@ def test_locale_calendar_weekday_names(self): 'Portuguese', 'pt_PT.UTF-8', 'German', 'de_DE.UTF-8', 'Russian', 'ru_RU.UTF-8', - 'Sinhala', 'si_LK.UTF-8' ) def test_locale_calendar_long_weekday_names(self): get_weekday_names = lambda width: calendar.TextCalendar().formatweekheader(width).split() From 51e122089bfc6f2db065c2e0615422898d82a895 Mon Sep 17 00:00:00 2001 From: Scott Noyes Date: Fri, 8 Aug 2025 09:46:13 -0500 Subject: [PATCH 08/10] shorter lines, removed lambda --- Lib/test/test_calendar.py | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_calendar.py b/Lib/test/test_calendar.py index 0081112ee146e8..2800259f07f9ce 100644 --- a/Lib/test/test_calendar.py +++ b/Lib/test/test_calendar.py @@ -696,8 +696,8 @@ def test_locale_calendar_formatweekday(self): except locale.Error: raise unittest.SkipTest('cannot set the en_US locale') - # These locales have weekday names all shorter than English's longest 'Wednesday' - # They should not be abbreviated unnecessarily + # These locales have weekday names all shorter than English's longest + # 'Wednesday'. They should not be abbreviated unnecessarily @support.run_with_locale("LC_ALL", 'Chinese', 'zh_CN.UTF-8', 'French', 'fr_FR.UTF-8', @@ -705,17 +705,25 @@ def test_locale_calendar_formatweekday(self): 'Malay', 'ms_MY.UTF8' ) def test_locale_calendar_weekday_names(self): - max_length = max(map(len, (datetime.date(2001, 1, i+1).strftime('%A') for i in range(7)))) + names = (datetime.date(2001, 1, i+1).strftime('%A') for i in range(7)) + max_length = max(map(len, names)) - get_weekday_names = lambda width: calendar.TextCalendar().formatweekheader(width).split() + def get_weekday_names(width): + return calendar.TextCalendar().formatweekheader(width).split() - # Full weekday name, not an abbreviation, should be used if the width is sufficient - self.assertEqual(get_weekday_names(max_length), get_weekday_names(max_length + 10)) + # Weekday names should not be abbreviated if the width is sufficient + self.assertEqual( + get_weekday_names(max_length), + get_weekday_names(max_length + 10) + ) - # Any width shorter than the longest necessary should produce abbreviations - self.assertNotEqual(get_weekday_names(max_length), get_weekday_names(max_length - 1)) + # Any width shorter than necessary should produce abbreviations + self.assertNotEqual( + get_weekday_names(max_length), + get_weekday_names(max_length - 1) + ) - # These locales have a weekday name longer than English's longest 'Wednesday' + # These locales have a weekday name longer than 'Wednesday' # They should be properly abbreviated rather than truncated @support.run_with_locale("LC_ALL", 'Portuguese', 'pt_PT.UTF-8', @@ -723,7 +731,8 @@ def test_locale_calendar_weekday_names(self): 'Russian', 'ru_RU.UTF-8', ) def test_locale_calendar_long_weekday_names(self): - get_weekday_names = lambda width: calendar.TextCalendar().formatweekheader(width).split() + def get_weekday_names(width): + return calendar.TextCalendar().formatweekheader(width).split() self.assertEqual(get_weekday_names(4), get_weekday_names(9)) def test_locale_calendar_formatmonthname(self): From 79e013468706da4c541b1c1c9588546d5d88523a Mon Sep 17 00:00:00 2001 From: Scott Noyes Date: Fri, 8 Aug 2025 10:08:44 -0500 Subject: [PATCH 09/10] test all provided locales --- Lib/test/test_calendar.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_calendar.py b/Lib/test/test_calendar.py index 2800259f07f9ce..307e7ca2d64bb9 100644 --- a/Lib/test/test_calendar.py +++ b/Lib/test/test_calendar.py @@ -695,18 +695,20 @@ def test_locale_calendar_formatweekday(self): self.assertEqual(cal.formatweekday(0, 10), " Monday ") except locale.Error: raise unittest.SkipTest('cannot set the en_US locale') - + # These locales have weekday names all shorter than English's longest # 'Wednesday'. They should not be abbreviated unnecessarily - @support.run_with_locale("LC_ALL", + @support.run_with_locales("LC_ALL", 'Chinese', 'zh_CN.UTF-8', 'French', 'fr_FR.UTF-8', 'Norwegian', 'nb_NO.UTF-8', 'Malay', 'ms_MY.UTF8' ) - def test_locale_calendar_weekday_names(self): + def test_locale_calendar_short_weekday_names(self): names = (datetime.date(2001, 1, i+1).strftime('%A') for i in range(7)) max_length = max(map(len, names)) + if max_length >= 9: + self.skipTest('weekday names are too long') def get_weekday_names(width): return calendar.TextCalendar().formatweekheader(width).split() @@ -725,12 +727,17 @@ def get_weekday_names(width): # These locales have a weekday name longer than 'Wednesday' # They should be properly abbreviated rather than truncated - @support.run_with_locale("LC_ALL", + @support.run_with_locales("LC_ALL", 'Portuguese', 'pt_PT.UTF-8', 'German', 'de_DE.UTF-8', 'Russian', 'ru_RU.UTF-8', ) def test_locale_calendar_long_weekday_names(self): + names = (datetime.date(2001, 1, i+1).strftime('%A') for i in range(7)) + max_length = max(map(len, names)) + if max_length <= 9: + self.skipTest('weekday names are too short') + def get_weekday_names(width): return calendar.TextCalendar().formatweekheader(width).split() self.assertEqual(get_weekday_names(4), get_weekday_names(9)) From b86dffbbca26ef72f089be484adc4b406c64d468 Mon Sep 17 00:00:00 2001 From: Scott Noyes Date: Fri, 8 Aug 2025 10:34:39 -0500 Subject: [PATCH 10/10] remove trailing whitespace --- Lib/test/test_calendar.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_calendar.py b/Lib/test/test_calendar.py index 307e7ca2d64bb9..410063e01582f9 100644 --- a/Lib/test/test_calendar.py +++ b/Lib/test/test_calendar.py @@ -696,12 +696,12 @@ def test_locale_calendar_formatweekday(self): except locale.Error: raise unittest.SkipTest('cannot set the en_US locale') - # These locales have weekday names all shorter than English's longest + # These locales have weekday names all shorter than English's longest # 'Wednesday'. They should not be abbreviated unnecessarily - @support.run_with_locales("LC_ALL", - 'Chinese', 'zh_CN.UTF-8', + @support.run_with_locales("LC_ALL", + 'Chinese', 'zh_CN.UTF-8', 'French', 'fr_FR.UTF-8', - 'Norwegian', 'nb_NO.UTF-8', + 'Norwegian', 'nb_NO.UTF-8', 'Malay', 'ms_MY.UTF8' ) def test_locale_calendar_short_weekday_names(self): @@ -715,19 +715,19 @@ def get_weekday_names(width): # Weekday names should not be abbreviated if the width is sufficient self.assertEqual( - get_weekday_names(max_length), + get_weekday_names(max_length), get_weekday_names(max_length + 10) ) # Any width shorter than necessary should produce abbreviations self.assertNotEqual( - get_weekday_names(max_length), + get_weekday_names(max_length), get_weekday_names(max_length - 1) ) # These locales have a weekday name longer than 'Wednesday' # They should be properly abbreviated rather than truncated - @support.run_with_locales("LC_ALL", + @support.run_with_locales("LC_ALL", 'Portuguese', 'pt_PT.UTF-8', 'German', 'de_DE.UTF-8', 'Russian', 'ru_RU.UTF-8',