Skip to content

Commit f9715c4

Browse files
authored
Merge pull request #4669 from carlosmiei/update-calendar
Update calendar.py from CPython 3.11
2 parents e73a1c3 + 7710ed0 commit f9715c4

File tree

2 files changed

+76
-33
lines changed

2 files changed

+76
-33
lines changed

Lib/calendar.py

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
"monthcalendar", "prmonth", "month", "prcal", "calendar",
1616
"timegm", "month_name", "month_abbr", "day_name", "day_abbr",
1717
"Calendar", "TextCalendar", "HTMLCalendar", "LocaleTextCalendar",
18-
"LocaleHTMLCalendar", "weekheader"]
18+
"LocaleHTMLCalendar", "weekheader",
19+
"MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY",
20+
"SATURDAY", "SUNDAY"]
1921

2022
# Exception raised for bad input (with string parameter for details)
2123
error = ValueError
@@ -546,71 +548,67 @@ def formatyearpage(self, theyear, width=3, css='calendar.css', encoding=None):
546548
class different_locale:
547549
def __init__(self, locale):
548550
self.locale = locale
551+
self.oldlocale = None
549552

550553
def __enter__(self):
551-
self.oldlocale = _locale.getlocale(_locale.LC_TIME)
554+
self.oldlocale = _locale.setlocale(_locale.LC_TIME, None)
552555
_locale.setlocale(_locale.LC_TIME, self.locale)
553556

554557
def __exit__(self, *args):
558+
if self.oldlocale is None:
559+
return
555560
_locale.setlocale(_locale.LC_TIME, self.oldlocale)
556561

557562

563+
def _get_default_locale():
564+
locale = _locale.setlocale(_locale.LC_TIME, None)
565+
if locale == "C":
566+
with different_locale(""):
567+
# The LC_TIME locale does not seem to be configured:
568+
# get the user preferred locale.
569+
locale = _locale.setlocale(_locale.LC_TIME, None)
570+
return locale
571+
572+
558573
class LocaleTextCalendar(TextCalendar):
559574
"""
560575
This class can be passed a locale name in the constructor and will return
561-
month and weekday names in the specified locale. If this locale includes
562-
an encoding all strings containing month and weekday names will be returned
563-
as unicode.
576+
month and weekday names in the specified locale.
564577
"""
565578

566579
def __init__(self, firstweekday=0, locale=None):
567580
TextCalendar.__init__(self, firstweekday)
568581
if locale is None:
569-
locale = _locale.getdefaultlocale()
582+
locale = _get_default_locale()
570583
self.locale = locale
571584

572585
def formatweekday(self, day, width):
573586
with different_locale(self.locale):
574-
if width >= 9:
575-
names = day_name
576-
else:
577-
names = day_abbr
578-
name = names[day]
579-
return name[:width].center(width)
587+
return super().formatweekday(day, width)
580588

581589
def formatmonthname(self, theyear, themonth, width, withyear=True):
582590
with different_locale(self.locale):
583-
s = month_name[themonth]
584-
if withyear:
585-
s = "%s %r" % (s, theyear)
586-
return s.center(width)
591+
return super().formatmonthname(theyear, themonth, width, withyear)
587592

588593

589594
class LocaleHTMLCalendar(HTMLCalendar):
590595
"""
591596
This class can be passed a locale name in the constructor and will return
592-
month and weekday names in the specified locale. If this locale includes
593-
an encoding all strings containing month and weekday names will be returned
594-
as unicode.
597+
month and weekday names in the specified locale.
595598
"""
596599
def __init__(self, firstweekday=0, locale=None):
597600
HTMLCalendar.__init__(self, firstweekday)
598601
if locale is None:
599-
locale = _locale.getdefaultlocale()
602+
locale = _get_default_locale()
600603
self.locale = locale
601604

602605
def formatweekday(self, day):
603606
with different_locale(self.locale):
604-
s = day_abbr[day]
605-
return '<th class="%s">%s</th>' % (self.cssclasses[day], s)
607+
return super().formatweekday(day)
606608

607609
def formatmonthname(self, theyear, themonth, withyear=True):
608610
with different_locale(self.locale):
609-
s = month_name[themonth]
610-
if withyear:
611-
s = '%s %s' % (s, theyear)
612-
return '<tr><th colspan="7" class="month">%s</th></tr>' % s
613-
611+
return super().formatmonthname(theyear, themonth, withyear)
614612

615613
# Support for old module level interface
616614
c = TextCalendar()

Lib/test/test_calendar.py

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,43 @@ def test_locale_calendars(self):
564564
new_october = calendar.TextCalendar().formatmonthname(2010, 10, 10)
565565
self.assertEqual(old_october, new_october)
566566

567+
def test_locale_calendar_formatweekday(self):
568+
try:
569+
# formatweekday uses different day names based on the available width.
570+
cal = calendar.LocaleTextCalendar(locale='en_US')
571+
# For short widths, a centered, abbreviated name is used.
572+
self.assertEqual(cal.formatweekday(0, 5), " Mon ")
573+
# For really short widths, even the abbreviated name is truncated.
574+
self.assertEqual(cal.formatweekday(0, 2), "Mo")
575+
# For long widths, the full day name is used.
576+
self.assertEqual(cal.formatweekday(0, 10), " Monday ")
577+
except locale.Error:
578+
raise unittest.SkipTest('cannot set the en_US locale')
579+
580+
def test_locale_html_calendar_custom_css_class_month_name(self):
581+
try:
582+
cal = calendar.LocaleHTMLCalendar(locale='')
583+
local_month = cal.formatmonthname(2010, 10, 10)
584+
except locale.Error:
585+
# cannot set the system default locale -- skip rest of test
586+
raise unittest.SkipTest('cannot set the system default locale')
587+
self.assertIn('class="month"', local_month)
588+
cal.cssclass_month_head = "text-center month"
589+
local_month = cal.formatmonthname(2010, 10, 10)
590+
self.assertIn('class="text-center month"', local_month)
591+
592+
def test_locale_html_calendar_custom_css_class_weekday(self):
593+
try:
594+
cal = calendar.LocaleHTMLCalendar(locale='')
595+
local_weekday = cal.formatweekday(6)
596+
except locale.Error:
597+
# cannot set the system default locale -- skip rest of test
598+
raise unittest.SkipTest('cannot set the system default locale')
599+
self.assertIn('class="sun"', local_weekday)
600+
cal.cssclasses_weekday_head = ["mon2", "tue2", "wed2", "thu2", "fri2", "sat2", "sun2"]
601+
local_weekday = cal.formatweekday(6)
602+
self.assertIn('class="sun2"', local_weekday)
603+
567604
def test_itermonthdays3(self):
568605
# ensure itermonthdays3 doesn't overflow after datetime.MAXYEAR
569606
list(calendar.Calendar().itermonthdays3(datetime.MAXYEAR, 12))
@@ -595,6 +632,14 @@ def test_itermonthdays2(self):
595632
self.assertEqual(days[0][1], firstweekday)
596633
self.assertEqual(days[-1][1], (firstweekday - 1) % 7)
597634

635+
def test_iterweekdays(self):
636+
week0 = list(range(7))
637+
for firstweekday in range(7):
638+
cal = calendar.Calendar(firstweekday)
639+
week = list(cal.iterweekdays())
640+
expected = week0[firstweekday:] + week0[:firstweekday]
641+
self.assertEqual(week, expected)
642+
598643

599644
class MonthCalendarTestCase(unittest.TestCase):
600645
def setUp(self):
@@ -837,7 +882,8 @@ def test_option_locale(self):
837882
self.assertFailure('-L')
838883
self.assertFailure('--locale')
839884
self.assertFailure('-L', 'en')
840-
lang, enc = locale.getdefaultlocale()
885+
886+
lang, enc = locale.getlocale()
841887
lang = lang or 'C'
842888
enc = enc or 'UTF-8'
843889
try:
@@ -912,11 +958,10 @@ def test_html_output_year_css(self):
912958

913959
class MiscTestCase(unittest.TestCase):
914960
def test__all__(self):
915-
not_exported = {'mdays', 'January', 'February', 'EPOCH',
916-
'MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY',
917-
'SATURDAY', 'SUNDAY', 'different_locale', 'c',
918-
'prweek', 'week', 'format', 'formatstring', 'main',
919-
'monthlen', 'prevmonth', 'nextmonth'}
961+
not_exported = {
962+
'mdays', 'January', 'February', 'EPOCH',
963+
'different_locale', 'c', 'prweek', 'week', 'format',
964+
'formatstring', 'main', 'monthlen', 'prevmonth', 'nextmonth'}
920965
support.check__all__(self, calendar, not_exported=not_exported)
921966

922967

0 commit comments

Comments
 (0)