diff --git a/Lib/calendar.py b/Lib/calendar.py
index 7550d52c0a..657396439c 100644
--- a/Lib/calendar.py
+++ b/Lib/calendar.py
@@ -15,7 +15,9 @@
"monthcalendar", "prmonth", "month", "prcal", "calendar",
"timegm", "month_name", "month_abbr", "day_name", "day_abbr",
"Calendar", "TextCalendar", "HTMLCalendar", "LocaleTextCalendar",
- "LocaleHTMLCalendar", "weekheader"]
+ "LocaleHTMLCalendar", "weekheader",
+ "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY",
+ "SATURDAY", "SUNDAY"]
# Exception raised for bad input (with string parameter for details)
error = ValueError
@@ -546,71 +548,67 @@ def formatyearpage(self, theyear, width=3, css='calendar.css', encoding=None):
class different_locale:
def __init__(self, locale):
self.locale = locale
+ self.oldlocale = None
def __enter__(self):
- self.oldlocale = _locale.getlocale(_locale.LC_TIME)
+ self.oldlocale = _locale.setlocale(_locale.LC_TIME, None)
_locale.setlocale(_locale.LC_TIME, self.locale)
def __exit__(self, *args):
+ if self.oldlocale is None:
+ return
_locale.setlocale(_locale.LC_TIME, self.oldlocale)
+def _get_default_locale():
+ locale = _locale.setlocale(_locale.LC_TIME, None)
+ if locale == "C":
+ with different_locale(""):
+ # The LC_TIME locale does not seem to be configured:
+ # get the user preferred locale.
+ locale = _locale.setlocale(_locale.LC_TIME, None)
+ return locale
+
+
class LocaleTextCalendar(TextCalendar):
"""
This class can be passed a locale name in the constructor and will return
- month and weekday names in the specified locale. If this locale includes
- an encoding all strings containing month and weekday names will be returned
- as unicode.
+ month and weekday names in the specified locale.
"""
def __init__(self, firstweekday=0, locale=None):
TextCalendar.__init__(self, firstweekday)
if locale is None:
- locale = _locale.getdefaultlocale()
+ locale = _get_default_locale()
self.locale = locale
def formatweekday(self, day, width):
with different_locale(self.locale):
- if width >= 9:
- names = day_name
- else:
- names = day_abbr
- name = names[day]
- return name[:width].center(width)
+ return super().formatweekday(day, width)
def formatmonthname(self, theyear, themonth, width, withyear=True):
with different_locale(self.locale):
- s = month_name[themonth]
- if withyear:
- s = "%s %r" % (s, theyear)
- return s.center(width)
+ return super().formatmonthname(theyear, themonth, width, withyear)
class LocaleHTMLCalendar(HTMLCalendar):
"""
This class can be passed a locale name in the constructor and will return
- month and weekday names in the specified locale. If this locale includes
- an encoding all strings containing month and weekday names will be returned
- as unicode.
+ month and weekday names in the specified locale.
"""
def __init__(self, firstweekday=0, locale=None):
HTMLCalendar.__init__(self, firstweekday)
if locale is None:
- locale = _locale.getdefaultlocale()
+ locale = _get_default_locale()
self.locale = locale
def formatweekday(self, day):
with different_locale(self.locale):
- s = day_abbr[day]
- return '
%s | ' % (self.cssclasses[day], s)
+ return super().formatweekday(day)
def formatmonthname(self, theyear, themonth, withyear=True):
with different_locale(self.locale):
- s = month_name[themonth]
- if withyear:
- s = '%s %s' % (s, theyear)
- return '%s |
' % s
-
+ return super().formatmonthname(theyear, themonth, withyear)
# Support for old module level interface
c = TextCalendar()
diff --git a/Lib/test/test_calendar.py b/Lib/test/test_calendar.py
index 091ab4a4d2..42490c8366 100644
--- a/Lib/test/test_calendar.py
+++ b/Lib/test/test_calendar.py
@@ -564,6 +564,43 @@ def test_locale_calendars(self):
new_october = calendar.TextCalendar().formatmonthname(2010, 10, 10)
self.assertEqual(old_october, new_october)
+ def test_locale_calendar_formatweekday(self):
+ try:
+ # formatweekday uses different day names based on the available width.
+ cal = calendar.LocaleTextCalendar(locale='en_US')
+ # For short widths, a centered, abbreviated name is used.
+ self.assertEqual(cal.formatweekday(0, 5), " Mon ")
+ # For really short widths, even the abbreviated name is truncated.
+ self.assertEqual(cal.formatweekday(0, 2), "Mo")
+ # For long widths, the full day name is used.
+ self.assertEqual(cal.formatweekday(0, 10), " Monday ")
+ except locale.Error:
+ raise unittest.SkipTest('cannot set the en_US locale')
+
+ def test_locale_html_calendar_custom_css_class_month_name(self):
+ try:
+ cal = calendar.LocaleHTMLCalendar(locale='')
+ local_month = cal.formatmonthname(2010, 10, 10)
+ except locale.Error:
+ # cannot set the system default locale -- skip rest of test
+ raise unittest.SkipTest('cannot set the system default locale')
+ self.assertIn('class="month"', local_month)
+ cal.cssclass_month_head = "text-center month"
+ local_month = cal.formatmonthname(2010, 10, 10)
+ self.assertIn('class="text-center month"', local_month)
+
+ def test_locale_html_calendar_custom_css_class_weekday(self):
+ try:
+ cal = calendar.LocaleHTMLCalendar(locale='')
+ local_weekday = cal.formatweekday(6)
+ except locale.Error:
+ # cannot set the system default locale -- skip rest of test
+ raise unittest.SkipTest('cannot set the system default locale')
+ self.assertIn('class="sun"', local_weekday)
+ cal.cssclasses_weekday_head = ["mon2", "tue2", "wed2", "thu2", "fri2", "sat2", "sun2"]
+ local_weekday = cal.formatweekday(6)
+ self.assertIn('class="sun2"', local_weekday)
+
def test_itermonthdays3(self):
# ensure itermonthdays3 doesn't overflow after datetime.MAXYEAR
list(calendar.Calendar().itermonthdays3(datetime.MAXYEAR, 12))
@@ -595,6 +632,14 @@ def test_itermonthdays2(self):
self.assertEqual(days[0][1], firstweekday)
self.assertEqual(days[-1][1], (firstweekday - 1) % 7)
+ def test_iterweekdays(self):
+ week0 = list(range(7))
+ for firstweekday in range(7):
+ cal = calendar.Calendar(firstweekday)
+ week = list(cal.iterweekdays())
+ expected = week0[firstweekday:] + week0[:firstweekday]
+ self.assertEqual(week, expected)
+
class MonthCalendarTestCase(unittest.TestCase):
def setUp(self):
@@ -837,7 +882,8 @@ def test_option_locale(self):
self.assertFailure('-L')
self.assertFailure('--locale')
self.assertFailure('-L', 'en')
- lang, enc = locale.getdefaultlocale()
+
+ lang, enc = locale.getlocale()
lang = lang or 'C'
enc = enc or 'UTF-8'
try:
@@ -912,11 +958,10 @@ def test_html_output_year_css(self):
class MiscTestCase(unittest.TestCase):
def test__all__(self):
- not_exported = {'mdays', 'January', 'February', 'EPOCH',
- 'MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY',
- 'SATURDAY', 'SUNDAY', 'different_locale', 'c',
- 'prweek', 'week', 'format', 'formatstring', 'main',
- 'monthlen', 'prevmonth', 'nextmonth'}
+ not_exported = {
+ 'mdays', 'January', 'February', 'EPOCH',
+ 'different_locale', 'c', 'prweek', 'week', 'format',
+ 'formatstring', 'main', 'monthlen', 'prevmonth', 'nextmonth'}
support.check__all__(self, calendar, not_exported=not_exported)