mirror of
https://github.com/python/cpython.git
synced 2025-09-27 10:50:04 +00:00
gh-128317: Move CLI calendar highlighting to private class (#129625)
Co-authored-by: Petr Viktorin <encukou@gmail.com>
This commit is contained in:
parent
a56ead089c
commit
1bccd6c34f
3 changed files with 120 additions and 58 deletions
|
@ -166,18 +166,13 @@ interpreted as prescribed by the ISO 8601 standard. Year 0 is 1 BC, year -1 is
|
||||||
the specified width, representing an empty day. The *weekday* parameter
|
the specified width, representing an empty day. The *weekday* parameter
|
||||||
is unused.
|
is unused.
|
||||||
|
|
||||||
.. method:: formatweek(theweek, w=0, highlight_day=None)
|
.. method:: formatweek(theweek, w=0)
|
||||||
|
|
||||||
Return a single week in a string with no newline. If *w* is provided, it
|
Return a single week in a string with no newline. If *w* is provided, it
|
||||||
specifies the width of the date columns, which are centered. Depends
|
specifies the width of the date columns, which are centered. Depends
|
||||||
on the first weekday as specified in the constructor or set by the
|
on the first weekday as specified in the constructor or set by the
|
||||||
:meth:`setfirstweekday` method.
|
:meth:`setfirstweekday` method.
|
||||||
|
|
||||||
.. versionchanged:: 3.14
|
|
||||||
If *highlight_day* is given, this date is highlighted in color.
|
|
||||||
This can be :ref:`controlled using environment variables
|
|
||||||
<using-on-controlling-color>`.
|
|
||||||
|
|
||||||
|
|
||||||
.. method:: formatweekday(weekday, width)
|
.. method:: formatweekday(weekday, width)
|
||||||
|
|
||||||
|
@ -193,7 +188,7 @@ interpreted as prescribed by the ISO 8601 standard. Year 0 is 1 BC, year -1 is
|
||||||
settings and are padded to the specified width.
|
settings and are padded to the specified width.
|
||||||
|
|
||||||
|
|
||||||
.. method:: formatmonth(theyear, themonth, w=0, l=0, highlight_day=None)
|
.. method:: formatmonth(theyear, themonth, w=0, l=0)
|
||||||
|
|
||||||
Return a month's calendar in a multi-line string. If *w* is provided, it
|
Return a month's calendar in a multi-line string. If *w* is provided, it
|
||||||
specifies the width of the date columns, which are centered. If *l* is
|
specifies the width of the date columns, which are centered. If *l* is
|
||||||
|
@ -201,11 +196,6 @@ interpreted as prescribed by the ISO 8601 standard. Year 0 is 1 BC, year -1 is
|
||||||
on the first weekday as specified in the constructor or set by the
|
on the first weekday as specified in the constructor or set by the
|
||||||
:meth:`setfirstweekday` method.
|
:meth:`setfirstweekday` method.
|
||||||
|
|
||||||
.. versionchanged:: 3.14
|
|
||||||
If *highlight_day* is given, this date is highlighted in color.
|
|
||||||
This can be :ref:`controlled using environment variables
|
|
||||||
<using-on-controlling-color>`.
|
|
||||||
|
|
||||||
|
|
||||||
.. method:: formatmonthname(theyear, themonth, width=0, withyear=True)
|
.. method:: formatmonthname(theyear, themonth, width=0, withyear=True)
|
||||||
|
|
||||||
|
@ -220,7 +210,7 @@ interpreted as prescribed by the ISO 8601 standard. Year 0 is 1 BC, year -1 is
|
||||||
Print a month's calendar as returned by :meth:`formatmonth`.
|
Print a month's calendar as returned by :meth:`formatmonth`.
|
||||||
|
|
||||||
|
|
||||||
.. method:: formatyear(theyear, w=2, l=1, c=6, m=3, highlight_day=None)
|
.. method:: formatyear(theyear, w=2, l=1, c=6, m=3)
|
||||||
|
|
||||||
Return a *m*-column calendar for an entire year as a multi-line string.
|
Return a *m*-column calendar for an entire year as a multi-line string.
|
||||||
Optional parameters *w*, *l*, and *c* are for date column width, lines per
|
Optional parameters *w*, *l*, and *c* are for date column width, lines per
|
||||||
|
@ -229,11 +219,6 @@ interpreted as prescribed by the ISO 8601 standard. Year 0 is 1 BC, year -1 is
|
||||||
:meth:`setfirstweekday` method. The earliest year for which a calendar
|
:meth:`setfirstweekday` method. The earliest year for which a calendar
|
||||||
can be generated is platform-dependent.
|
can be generated is platform-dependent.
|
||||||
|
|
||||||
.. versionchanged:: 3.14
|
|
||||||
If *highlight_day* is given, this date is highlighted in color.
|
|
||||||
This can be :ref:`controlled using environment variables
|
|
||||||
<using-on-controlling-color>`.
|
|
||||||
|
|
||||||
|
|
||||||
.. method:: pryear(theyear, w=2, l=1, c=6, m=3)
|
.. method:: pryear(theyear, w=2, l=1, c=6, m=3)
|
||||||
|
|
||||||
|
|
155
Lib/calendar.py
155
Lib/calendar.py
|
@ -349,27 +349,11 @@ class TextCalendar(Calendar):
|
||||||
s = '%2i' % day # right-align single-digit days
|
s = '%2i' % day # right-align single-digit days
|
||||||
return s.center(width)
|
return s.center(width)
|
||||||
|
|
||||||
def formatweek(self, theweek, width, *, highlight_day=None):
|
def formatweek(self, theweek, width):
|
||||||
"""
|
"""
|
||||||
Returns a single week in a string (no newline).
|
Returns a single week in a string (no newline).
|
||||||
"""
|
"""
|
||||||
if highlight_day:
|
return ' '.join(self.formatday(d, wd, width) for (d, wd) in theweek)
|
||||||
from _colorize import get_colors
|
|
||||||
|
|
||||||
ansi = get_colors()
|
|
||||||
highlight = f"{ansi.BLACK}{ansi.BACKGROUND_YELLOW}"
|
|
||||||
reset = ansi.RESET
|
|
||||||
else:
|
|
||||||
highlight = reset = ""
|
|
||||||
|
|
||||||
return ' '.join(
|
|
||||||
(
|
|
||||||
f"{highlight}{self.formatday(d, wd, width)}{reset}"
|
|
||||||
if d == highlight_day
|
|
||||||
else self.formatday(d, wd, width)
|
|
||||||
)
|
|
||||||
for (d, wd) in theweek
|
|
||||||
)
|
|
||||||
|
|
||||||
def formatweekday(self, day, width):
|
def formatweekday(self, day, width):
|
||||||
"""
|
"""
|
||||||
|
@ -404,11 +388,10 @@ class TextCalendar(Calendar):
|
||||||
"""
|
"""
|
||||||
print(self.formatmonth(theyear, themonth, w, l), end='')
|
print(self.formatmonth(theyear, themonth, w, l), end='')
|
||||||
|
|
||||||
def formatmonth(self, theyear, themonth, w=0, l=0, *, highlight_day=None):
|
def formatmonth(self, theyear, themonth, w=0, l=0):
|
||||||
"""
|
"""
|
||||||
Return a month's calendar string (multi-line).
|
Return a month's calendar string (multi-line).
|
||||||
"""
|
"""
|
||||||
highlight_day = highlight_day.day if highlight_day else None
|
|
||||||
w = max(2, w)
|
w = max(2, w)
|
||||||
l = max(1, l)
|
l = max(1, l)
|
||||||
s = self.formatmonthname(theyear, themonth, 7 * (w + 1) - 1)
|
s = self.formatmonthname(theyear, themonth, 7 * (w + 1) - 1)
|
||||||
|
@ -417,11 +400,11 @@ class TextCalendar(Calendar):
|
||||||
s += self.formatweekheader(w).rstrip()
|
s += self.formatweekheader(w).rstrip()
|
||||||
s += '\n' * l
|
s += '\n' * l
|
||||||
for week in self.monthdays2calendar(theyear, themonth):
|
for week in self.monthdays2calendar(theyear, themonth):
|
||||||
s += self.formatweek(week, w, highlight_day=highlight_day).rstrip()
|
s += self.formatweek(week, w).rstrip()
|
||||||
s += '\n' * l
|
s += '\n' * l
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def formatyear(self, theyear, w=2, l=1, c=6, m=3, *, highlight_day=None):
|
def formatyear(self, theyear, w=2, l=1, c=6, m=3):
|
||||||
"""
|
"""
|
||||||
Returns a year's calendar as a multi-line string.
|
Returns a year's calendar as a multi-line string.
|
||||||
"""
|
"""
|
||||||
|
@ -446,23 +429,15 @@ class TextCalendar(Calendar):
|
||||||
a(formatstring(headers, colwidth, c).rstrip())
|
a(formatstring(headers, colwidth, c).rstrip())
|
||||||
a('\n'*l)
|
a('\n'*l)
|
||||||
|
|
||||||
if highlight_day and highlight_day.month in months:
|
|
||||||
month_pos = months.index(highlight_day.month)
|
|
||||||
else:
|
|
||||||
month_pos = None
|
|
||||||
|
|
||||||
# max number of weeks for this row
|
# max number of weeks for this row
|
||||||
height = max(len(cal) for cal in row)
|
height = max(len(cal) for cal in row)
|
||||||
for j in range(height):
|
for j in range(height):
|
||||||
weeks = []
|
weeks = []
|
||||||
for k, cal in enumerate(row):
|
for cal in row:
|
||||||
if j >= len(cal):
|
if j >= len(cal):
|
||||||
weeks.append('')
|
weeks.append('')
|
||||||
else:
|
else:
|
||||||
day = highlight_day.day if k == month_pos else None
|
weeks.append(self.formatweek(cal[j], w))
|
||||||
weeks.append(
|
|
||||||
self.formatweek(cal[j], w, highlight_day=day)
|
|
||||||
)
|
|
||||||
a(formatstring(weeks, colwidth, c).rstrip())
|
a(formatstring(weeks, colwidth, c).rstrip())
|
||||||
a('\n' * l)
|
a('\n' * l)
|
||||||
return ''.join(v)
|
return ''.join(v)
|
||||||
|
@ -672,6 +647,111 @@ class LocaleHTMLCalendar(HTMLCalendar):
|
||||||
with different_locale(self.locale):
|
with different_locale(self.locale):
|
||||||
return super().formatmonthname(theyear, themonth, withyear)
|
return super().formatmonthname(theyear, themonth, withyear)
|
||||||
|
|
||||||
|
|
||||||
|
class _CLIDemoCalendar(LocaleTextCalendar):
|
||||||
|
def __init__(self, highlight_day=None, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.highlight_day = highlight_day
|
||||||
|
|
||||||
|
def formatweek(self, theweek, width, *, highlight_day=None):
|
||||||
|
"""
|
||||||
|
Returns a single week in a string (no newline).
|
||||||
|
"""
|
||||||
|
if highlight_day:
|
||||||
|
from _colorize import get_colors
|
||||||
|
|
||||||
|
ansi = get_colors()
|
||||||
|
highlight = f"{ansi.BLACK}{ansi.BACKGROUND_YELLOW}"
|
||||||
|
reset = ansi.RESET
|
||||||
|
else:
|
||||||
|
highlight = reset = ""
|
||||||
|
|
||||||
|
return ' '.join(
|
||||||
|
(
|
||||||
|
f"{highlight}{self.formatday(d, wd, width)}{reset}"
|
||||||
|
if d == highlight_day
|
||||||
|
else self.formatday(d, wd, width)
|
||||||
|
)
|
||||||
|
for (d, wd) in theweek
|
||||||
|
)
|
||||||
|
|
||||||
|
def formatmonth(self, theyear, themonth, w=0, l=0):
|
||||||
|
"""
|
||||||
|
Return a month's calendar string (multi-line).
|
||||||
|
"""
|
||||||
|
if (
|
||||||
|
self.highlight_day
|
||||||
|
and self.highlight_day.year == theyear
|
||||||
|
and self.highlight_day.month == themonth
|
||||||
|
):
|
||||||
|
highlight_day = self.highlight_day.day
|
||||||
|
else:
|
||||||
|
highlight_day = None
|
||||||
|
w = max(2, w)
|
||||||
|
l = max(1, l)
|
||||||
|
s = self.formatmonthname(theyear, themonth, 7 * (w + 1) - 1)
|
||||||
|
s = s.rstrip()
|
||||||
|
s += '\n' * l
|
||||||
|
s += self.formatweekheader(w).rstrip()
|
||||||
|
s += '\n' * l
|
||||||
|
for week in self.monthdays2calendar(theyear, themonth):
|
||||||
|
s += self.formatweek(week, w, highlight_day=highlight_day).rstrip()
|
||||||
|
s += '\n' * l
|
||||||
|
return s
|
||||||
|
|
||||||
|
def formatyear(self, theyear, w=2, l=1, c=6, m=3):
|
||||||
|
"""
|
||||||
|
Returns a year's calendar as a multi-line string.
|
||||||
|
"""
|
||||||
|
w = max(2, w)
|
||||||
|
l = max(1, l)
|
||||||
|
c = max(2, c)
|
||||||
|
colwidth = (w + 1) * 7 - 1
|
||||||
|
v = []
|
||||||
|
a = v.append
|
||||||
|
a(repr(theyear).center(colwidth*m+c*(m-1)).rstrip())
|
||||||
|
a('\n'*l)
|
||||||
|
header = self.formatweekheader(w)
|
||||||
|
for (i, row) in enumerate(self.yeardays2calendar(theyear, m)):
|
||||||
|
# months in this row
|
||||||
|
months = range(m*i+1, min(m*(i+1)+1, 13))
|
||||||
|
a('\n'*l)
|
||||||
|
names = (self.formatmonthname(theyear, k, colwidth, False)
|
||||||
|
for k in months)
|
||||||
|
a(formatstring(names, colwidth, c).rstrip())
|
||||||
|
a('\n'*l)
|
||||||
|
headers = (header for k in months)
|
||||||
|
a(formatstring(headers, colwidth, c).rstrip())
|
||||||
|
a('\n'*l)
|
||||||
|
|
||||||
|
if (
|
||||||
|
self.highlight_day
|
||||||
|
and self.highlight_day.year == theyear
|
||||||
|
and self.highlight_day.month in months
|
||||||
|
):
|
||||||
|
month_pos = months.index(self.highlight_day.month)
|
||||||
|
else:
|
||||||
|
month_pos = None
|
||||||
|
|
||||||
|
# max number of weeks for this row
|
||||||
|
height = max(len(cal) for cal in row)
|
||||||
|
for j in range(height):
|
||||||
|
weeks = []
|
||||||
|
for k, cal in enumerate(row):
|
||||||
|
if j >= len(cal):
|
||||||
|
weeks.append('')
|
||||||
|
else:
|
||||||
|
day = (
|
||||||
|
self.highlight_day.day if k == month_pos else None
|
||||||
|
)
|
||||||
|
weeks.append(
|
||||||
|
self.formatweek(cal[j], w, highlight_day=day)
|
||||||
|
)
|
||||||
|
a(formatstring(weeks, colwidth, c).rstrip())
|
||||||
|
a('\n' * l)
|
||||||
|
return ''.join(v)
|
||||||
|
|
||||||
|
|
||||||
# Support for old module level interface
|
# Support for old module level interface
|
||||||
c = TextCalendar()
|
c = TextCalendar()
|
||||||
|
|
||||||
|
@ -813,26 +893,21 @@ def main(args=None):
|
||||||
write(cal.formatyearpage(options.year, **optdict))
|
write(cal.formatyearpage(options.year, **optdict))
|
||||||
else:
|
else:
|
||||||
if options.locale:
|
if options.locale:
|
||||||
cal = LocaleTextCalendar(locale=locale)
|
cal = _CLIDemoCalendar(highlight_day=today, locale=locale)
|
||||||
else:
|
else:
|
||||||
cal = TextCalendar()
|
cal = _CLIDemoCalendar(highlight_day=today)
|
||||||
cal.setfirstweekday(options.first_weekday)
|
cal.setfirstweekday(options.first_weekday)
|
||||||
optdict = dict(w=options.width, l=options.lines)
|
optdict = dict(w=options.width, l=options.lines)
|
||||||
if options.month is None:
|
if options.month is None:
|
||||||
optdict["c"] = options.spacing
|
optdict["c"] = options.spacing
|
||||||
optdict["m"] = options.months
|
optdict["m"] = options.months
|
||||||
if options.month is not None:
|
else:
|
||||||
_validate_month(options.month)
|
_validate_month(options.month)
|
||||||
if options.year is None:
|
if options.year is None:
|
||||||
optdict["highlight_day"] = today
|
|
||||||
result = cal.formatyear(today.year, **optdict)
|
result = cal.formatyear(today.year, **optdict)
|
||||||
elif options.month is None:
|
elif options.month is None:
|
||||||
if options.year == today.year:
|
|
||||||
optdict["highlight_day"] = today
|
|
||||||
result = cal.formatyear(options.year, **optdict)
|
result = cal.formatyear(options.year, **optdict)
|
||||||
else:
|
else:
|
||||||
if options.year == today.year and options.month == today.month:
|
|
||||||
optdict["highlight_day"] = today
|
|
||||||
result = cal.formatmonth(options.year, options.month, **optdict)
|
result = cal.formatmonth(options.year, options.month, **optdict)
|
||||||
write = sys.stdout.write
|
write = sys.stdout.write
|
||||||
if options.encoding:
|
if options.encoding:
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Put CLI calendar highlighting in private class, removing ``highlight_day``
|
||||||
|
from public :class:`calendar.TextCalendar` API. Patch by Hugo van Kemenade.
|
Loading…
Add table
Add a link
Reference in a new issue