diff -r 0308f97616a3 Lib/calendar.py --- a/Lib/calendar.py Fri Sep 16 13:54:05 2016 -0400 +++ b/Lib/calendar.py Mon Sep 26 19:19:54 2016 -0400 @@ -8,6 +8,7 @@ import sys import datetime import locale as _locale +from itertools import repeat __all__ = ["IllegalMonthError", "IllegalWeekdayError", "setfirstweekday", "firstweekday", "isleap", "leapdays", "weekday", "monthrange", @@ -176,22 +177,20 @@ Like itermonthdates(), but will yield (day number, weekday number) tuples. For days outside the specified month the day number is 0. """ - for date in self.itermonthdates(year, month): - if date.month != month: - yield (0, date.weekday()) - else: - yield (date.day, date.weekday()) + for i, d in enumerate(self.itermonthdays(year, month), self.firstweekday): + yield d, i % 7 def itermonthdays(self, year, month): """ Like itermonthdates(), but will yield day numbers. For days outside the specified month the day number is 0. """ - for date in self.itermonthdates(year, month): - if date.month != month: - yield 0 - else: - yield date.day + day1, ndays = monthrange(year, month) + days_before = (day1 - self.firstweekday) % 7 + yield from repeat(0, days_before) + yield from range(1, ndays + 1) + days_after = (self.firstweekday - day1 - ndays) % 7 + yield from repeat(0, days_after) def monthdatescalendar(self, year, month): """ diff -r 0308f97616a3 Lib/test/test_calendar.py --- a/Lib/test/test_calendar.py Fri Sep 16 13:54:05 2016 -0400 +++ b/Lib/test/test_calendar.py Mon Sep 26 19:19:54 2016 -0400 @@ -422,85 +422,108 @@ calendar.format(["1", "2", "3"], colwidth=3, spacing=1) self.assertEqual(out.getvalue().strip(), "1 2 3") -class CalendarTestCase(unittest.TestCase): - def test_isleap(self): - # Make sure that the return is right for a few years, and - # ensure that the return values are 1 or 0, not just true or - # false (see SF bug #485794). Specific additional tests may - # be appropriate; this tests a single "cycle". - self.assertEqual(calendar.isleap(2000), 1) - self.assertEqual(calendar.isleap(2001), 0) - self.assertEqual(calendar.isleap(2002), 0) - self.assertEqual(calendar.isleap(2003), 0) - - def test_setfirstweekday(self): - self.assertRaises(TypeError, calendar.setfirstweekday, 'flabber') - self.assertRaises(ValueError, calendar.setfirstweekday, -1) - self.assertRaises(ValueError, calendar.setfirstweekday, 200) - orig = calendar.firstweekday() - calendar.setfirstweekday(calendar.SUNDAY) - self.assertEqual(calendar.firstweekday(), calendar.SUNDAY) - calendar.setfirstweekday(calendar.MONDAY) - self.assertEqual(calendar.firstweekday(), calendar.MONDAY) - calendar.setfirstweekday(orig) - - def test_illegal_weekday_reported(self): - with self.assertRaisesRegex(calendar.IllegalWeekdayError, '123'): - calendar.setfirstweekday(123) - - def test_enumerate_weekdays(self): - self.assertRaises(IndexError, calendar.day_abbr.__getitem__, -10) - self.assertRaises(IndexError, calendar.day_name.__getitem__, 10) - self.assertEqual(len([d for d in calendar.day_abbr]), 7) +if __name__ == '__main__': + class CalendarTestCase(unittest.TestCase): + def test_isleap(self): + # Make sure that the return is right for a few years, and + # ensure that the return values are 1 or 0, not just true or + # false (see SF bug #485794). Specific additional tests may + # be appropriate; this tests a single "cycle". + self.assertEqual(calendar.isleap(2000), 1) + self.assertEqual(calendar.isleap(2001), 0) + self.assertEqual(calendar.isleap(2002), 0) + self.assertEqual(calendar.isleap(2003), 0) - def test_days(self): - for attr in "day_name", "day_abbr": - value = getattr(calendar, attr) - self.assertEqual(len(value), 7) - self.assertEqual(len(value[:]), 7) - # ensure they're all unique - self.assertEqual(len(set(value)), 7) - # verify it "acts like a sequence" in two forms of iteration - self.assertEqual(value[::-1], list(reversed(value))) - - def test_months(self): - for attr in "month_name", "month_abbr": - value = getattr(calendar, attr) - self.assertEqual(len(value), 13) - self.assertEqual(len(value[:]), 13) - self.assertEqual(value[0], "") - # ensure they're all unique - self.assertEqual(len(set(value)), 13) - # verify it "acts like a sequence" in two forms of iteration - self.assertEqual(value[::-1], list(reversed(value))) + def test_setfirstweekday(self): + self.assertRaises(TypeError, calendar.setfirstweekday, 'flabber') + self.assertRaises(ValueError, calendar.setfirstweekday, -1) + self.assertRaises(ValueError, calendar.setfirstweekday, 200) + orig = calendar.firstweekday() + calendar.setfirstweekday(calendar.SUNDAY) + self.assertEqual(calendar.firstweekday(), calendar.SUNDAY) + calendar.setfirstweekday(calendar.MONDAY) + self.assertEqual(calendar.firstweekday(), calendar.MONDAY) + calendar.setfirstweekday(orig) - def test_locale_calendars(self): - # ensure that Locale{Text,HTML}Calendar resets the locale properly - # (it is still not thread-safe though) - old_october = calendar.TextCalendar().formatmonthname(2010, 10, 10) - try: - cal = calendar.LocaleTextCalendar(locale='') - local_weekday = cal.formatweekday(1, 10) - 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.assertIsInstance(local_weekday, str) - self.assertIsInstance(local_month, str) - self.assertEqual(len(local_weekday), 10) - self.assertGreaterEqual(len(local_month), 10) - cal = calendar.LocaleHTMLCalendar(locale='') - local_weekday = cal.formatweekday(1) - local_month = cal.formatmonthname(2010, 10) - self.assertIsInstance(local_weekday, str) - self.assertIsInstance(local_month, str) - new_october = calendar.TextCalendar().formatmonthname(2010, 10, 10) - self.assertEqual(old_october, new_october) + def test_illegal_weekday_reported(self): + with self.assertRaisesRegex(calendar.IllegalWeekdayError, '123'): + calendar.setfirstweekday(123) - def test_itermonthdates(self): - # ensure itermonthdates doesn't overflow after datetime.MAXYEAR - # see #15421 - list(calendar.Calendar().itermonthdates(datetime.MAXYEAR, 12)) + def test_enumerate_weekdays(self): + self.assertRaises(IndexError, calendar.day_abbr.__getitem__, -10) + self.assertRaises(IndexError, calendar.day_name.__getitem__, 10) + self.assertEqual(len([d for d in calendar.day_abbr]), 7) + + def test_days(self): + for attr in "day_name", "day_abbr": + value = getattr(calendar, attr) + self.assertEqual(len(value), 7) + self.assertEqual(len(value[:]), 7) + # ensure they're all unique + self.assertEqual(len(set(value)), 7) + # verify it "acts like a sequence" in two forms of iteration + self.assertEqual(value[::-1], list(reversed(value))) + + def test_months(self): + for attr in "month_name", "month_abbr": + value = getattr(calendar, attr) + self.assertEqual(len(value), 13) + self.assertEqual(len(value[:]), 13) + self.assertEqual(value[0], "") + # ensure they're all unique + self.assertEqual(len(set(value)), 13) + # verify it "acts like a sequence" in two forms of iteration + self.assertEqual(value[::-1], list(reversed(value))) + + def test_locale_calendars(self): + # ensure that Locale{Text,HTML}Calendar resets the locale properly + # (it is still not thread-safe though) + old_october = calendar.TextCalendar().formatmonthname(2010, 10, 10) + try: + cal = calendar.LocaleTextCalendar(locale='') + local_weekday = cal.formatweekday(1, 10) + 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.assertIsInstance(local_weekday, str) + self.assertIsInstance(local_month, str) + self.assertEqual(len(local_weekday), 10) + self.assertGreaterEqual(len(local_month), 10) + cal = calendar.LocaleHTMLCalendar(locale='') + local_weekday = cal.formatweekday(1) + local_month = cal.formatmonthname(2010, 10) + self.assertIsInstance(local_weekday, str) + self.assertIsInstance(local_month, str) + new_october = calendar.TextCalendar().formatmonthname(2010, 10, 10) + self.assertEqual(old_october, new_october) + + def test_itermonthdates(self): + # ensure itermonthdates doesn't overflow after datetime.MAXYEAR + # see #15421 + list(calendar.Calendar().itermonthdates(datetime.MAXYEAR, 12)) + + def test_itermonthdays(self): + for firstweekday in range(7): + cal = calendar.Calendar(firstweekday) + # Test the extremes, see #28253 and #26650 + for y, m in [(1, 1), (9999, 12)]: + days = list(cal.itermonthdays(y, m)) + self.assertEqual(len(days, 35)) + # Test a short month + cal = calendar.Calendar(firstweekday=3) + days = list(cal.itermonthdays(2001, 2)) + self.assertEqual(days, list(range(28))) + + def test_itermonthdays2(self): + for firstweekday in range(7): + cal = calendar.Calendar(firstweekday) + # Test the extremes, see #28253 and #26650 + for y, m in [(1, 1), (9999, 12)]: + days = list(cal.itermonthdays2(y, m)) + self.assertEqual(len(days, 35)) + self.assertEqual(days[0][0], firstweekday) + self.assertEqual(days[0][-1], (firstweekday - 1) % 7) class MonthCalendarTestCase(unittest.TestCase):