Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions Doc/library/calendar.rst
Original file line number Diff line number Diff line change
Expand Up @@ -710,8 +710,7 @@ The following options are accepted:
.. option:: month

The month of the specified :option:`year` to print the calendar for.
Must be a number between 1 and 12,
and may only be used in text mode.
Must be a number between 1 and 12.
Defaults to printing a calendar for the full year.


Expand Down
4 changes: 4 additions & 0 deletions Doc/whatsnew/3.15.rst
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,10 @@ calendar
dark mode and have been migrated to the HTML5 standard for improved accessibility.
(Contributed by Jiahao Li and Hugo van Kemenade in :gh:`137634`.)

* The :mod:`calendar`'s :ref:`command-line <calendar-cli>` HTML output now
accepts the year-month option: ``python -m calendar -t html 2009 06``.
(Contributed by Pål Grønås Drange in :gh:`140212`.)


collections
-----------
Expand Down
31 changes: 23 additions & 8 deletions Lib/calendar.py
Original file line number Diff line number Diff line change
Expand Up @@ -574,9 +574,9 @@ def formatyear(self, theyear, width=3):
a('</table>')
return ''.join(v)

def formatyearpage(self, theyear, width=3, css='calendar.css', encoding=None):
def _format_html_page(self, theyear, content, css, encoding):
"""
Return a formatted year as a complete HTML page.
Return a complete HTML page with the given content.
"""
if encoding is None:
encoding = 'utf-8'
Expand All @@ -597,11 +597,25 @@ def formatyearpage(self, theyear, width=3, css='calendar.css', encoding=None):
a(f'<link rel="stylesheet" href="{css}">\n')
a('</head>\n')
a('<body>\n')
a(self.formatyear(theyear, width))
a(content)
a('</body>\n')
a('</html>\n')
return ''.join(v).encode(encoding, "xmlcharrefreplace")

def formatyearpage(self, theyear, width=3, css='calendar.css', encoding=None):
"""
Return a formatted year as a complete HTML page.
"""
content = self.formatyear(theyear, width)
return self._format_html_page(theyear, content, css, encoding)

def formatmonthpage(self, theyear, themonth, width=3, css='calendar.css', encoding=None):
"""
Return a formatted month as a complete HTML page.
"""
content = self.formatmonth(theyear, themonth, width)
return self._format_html_page(theyear, content, css, encoding)


class different_locale:
def __init__(self, locale):
Expand Down Expand Up @@ -886,7 +900,7 @@ def main(args=None):
parser.add_argument(
"month",
nargs='?', type=int,
help="month number (1-12, text only)"
help="month number (1-12)"
)

options = parser.parse_args(args)
Expand All @@ -899,9 +913,6 @@ def main(args=None):
today = datetime.date.today()

if options.type == "html":
if options.month:
parser.error("incorrect number of arguments")
sys.exit(1)
if options.locale:
cal = LocaleHTMLCalendar(locale=locale)
else:
Expand All @@ -912,10 +923,14 @@ def main(args=None):
encoding = 'utf-8'
optdict = dict(encoding=encoding, css=options.css)
write = sys.stdout.buffer.write

if options.year is None:
write(cal.formatyearpage(today.year, **optdict))
else:
write(cal.formatyearpage(options.year, **optdict))
if options.month:
write(cal.formatmonthpage(options.year, options.month, **optdict))
else:
write(cal.formatyearpage(options.year, **optdict))
else:
if options.locale:
cal = _CLIDemoLocaleCalendar(highlight_day=today, locale=locale)
Expand Down
36 changes: 35 additions & 1 deletion Lib/test/test_calendar.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,34 @@
</html>
"""

result_2009_6_html = """\
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Calendar for 2009</title>
<style>
:root { color-scheme: light dark; }
table.year { border: solid; }
table.year > tbody > tr > td { border: solid; vertical-align: top; }
</style>
<link rel="stylesheet" href="calendar.css">
</head>
<body>
<table class="month">
<tr><th colspan="7" class="month">June 2009</th></tr>
<tr><th class="mon">Mon</th><th class="tue">Tue</th><th class="wed">Wed</th><th class="thu">Thu</th><th class="fri">Fri</th><th class="sat">Sat</th><th class="sun">Sun</th></tr>
<tr><td class="mon">1</td><td class="tue">2</td><td class="wed">3</td><td class="thu">4</td><td class="fri">5</td><td class="sat">6</td><td class="sun">7</td></tr>
<tr><td class="mon">8</td><td class="tue">9</td><td class="wed">10</td><td class="thu">11</td><td class="fri">12</td><td class="sat">13</td><td class="sun">14</td></tr>
<tr><td class="mon">15</td><td class="tue">16</td><td class="wed">17</td><td class="thu">18</td><td class="fri">19</td><td class="sat">20</td><td class="sun">21</td></tr>
<tr><td class="mon">22</td><td class="tue">23</td><td class="wed">24</td><td class="thu">25</td><td class="fri">26</td><td class="sat">27</td><td class="sun">28</td></tr>
<tr><td class="mon">29</td><td class="tue">30</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td><td class="noday">&nbsp;</td></tr>
</table>
</body>
</html>
"""

result_2004_days = [
[[[0, 0, 0, 1, 2, 3, 4],
[5, 6, 7, 8, 9, 10, 11],
Expand Down Expand Up @@ -506,6 +534,13 @@ def test_format(self):
calendar.format(["1", "2", "3"], colwidth=3, spacing=1)
self.assertEqual(out.getvalue().strip(), "1 2 3")

def test_format_html_year_with_month(self):
self.assertEqual(
calendar.HTMLCalendar().formatmonthpage(2009, 6).decode("ascii"),
result_2009_6_html
)


class CalendarTestCase(unittest.TestCase):

def test_deprecation_warning(self):
Expand Down Expand Up @@ -1102,7 +1137,6 @@ def test_illegal_arguments(self):
self.assertFailure('2004', '1', 'spam')
self.assertFailure('2004', '1', '1')
self.assertFailure('2004', '1', '1', 'spam')
self.assertFailure('-t', 'html', '2004', '1')

def test_output_current_year(self):
for run in self.runners:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Calendar's HTML formatting now accepts year and month as options.
Previously, running ``python -m calendar -t html 2025 10`` would result in an
error message. It now generates an HTML document displaying the calendar for
the specified month.
Contributed by Pål Grønås Drange.
Loading