Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
Add more colour to calendar
  • Loading branch information
hugovk committed Apr 10, 2026
commit 9e95c430d77a21125729cae4afa0f8b3b7f50ec7
12 changes: 12 additions & 0 deletions Lib/_colorize.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,14 @@ class Argparse(ThemeSection):
message: str = ANSIColors.MAGENTA


@dataclass(frozen=True, kw_only=True)
class Calendar(ThemeSection):
header: str = ANSIColors.BOLD
highlight: str = ANSIColors.BLACK + ANSIColors.BACKGROUND_YELLOW
weekday: str = ANSIColors.CYAN
reset: str = ANSIColors.RESET


@dataclass(frozen=True, kw_only=True)
class Difflib(ThemeSection):
"""A 'git diff'-like theme for `difflib.unified_diff`."""
Expand Down Expand Up @@ -404,6 +412,7 @@ class Theme:
below.
"""
argparse: Argparse = field(default_factory=Argparse)
calendar: Calendar = field(default_factory=Calendar)
difflib: Difflib = field(default_factory=Difflib)
fancycompleter: FancyCompleter = field(default_factory=FancyCompleter)
http_server: HttpServer = field(default_factory=HttpServer)
Expand All @@ -417,6 +426,7 @@ def copy_with(
self,
*,
argparse: Argparse | None = None,
calendar: Calendar | None = None,
difflib: Difflib | None = None,
fancycompleter: FancyCompleter | None = None,
http_server: HttpServer | None = None,
Expand All @@ -433,6 +443,7 @@ def copy_with(
"""
return type(self)(
argparse=argparse or self.argparse,
calendar=calendar or self.calendar,
difflib=difflib or self.difflib,
fancycompleter=fancycompleter or self.fancycompleter,
http_server=http_server or self.http_server,
Expand All @@ -453,6 +464,7 @@ def no_colors(cls) -> Self:
"""
return cls(
argparse=Argparse.no_colors(),
calendar=Calendar.no_colors(),
difflib=Difflib.no_colors(),
fancycompleter=FancyCompleter.no_colors(),
http_server=HttpServer.no_colors(),
Expand Down
65 changes: 50 additions & 15 deletions Lib/calendar.py
Original file line number Diff line number Diff line change
Expand Up @@ -686,28 +686,61 @@ 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):
def _get_theme(self):
from _colorize import get_theme

return get_theme(tty_file=sys.stdout)

def formatday(self, day, weekday, width, *, highlight_day=None):
"""
Returns a single week in a string (no newline).
Returns a formatted day.
"""
if highlight_day:
from _colorize import get_colors

ansi = get_colors()
highlight = f"{ansi.BLACK}{ansi.BACKGROUND_YELLOW}"
reset = ansi.RESET
if day == 0:
s = ''
else:
highlight = reset = ""
s = f'{day:2}'
s = s.center(width)
if day == highlight_day:
theme = self._get_theme().calendar
s = f"{theme.highlight}{s}{theme.reset}"
return s

def formatweek(self, theweek, width, *, highlight_day=None):
"""
Returns a single week in a string (no newline).
"""
return ' '.join(
(
f"{highlight}{self.formatday(d, wd, width)}{reset}"
if d == highlight_day
else self.formatday(d, wd, width)
)
self.formatday(d, wd, width, highlight_day=highlight_day)
for (d, wd) in theweek
)

def formatweekheader(self, width):
"""
Return a header for a week.
"""
header = super().formatweekheader(width)
theme = self._get_theme().calendar
return f"{theme.weekday}{header}{theme.reset}"

def formatmonthname(self, theyear, themonth, width, withyear=True):
"""
Return a formatted month name.
"""
name = super().formatmonthname(theyear, themonth, width, withyear)
theme = self._get_theme().calendar
if (
self.highlight_day
and self.highlight_day.year == theyear
and self.highlight_day.month == themonth
):
color = theme.highlight
name_only = name.strip()
colored_name = f"{color}{name_only}{theme.reset}"
return name.replace(name_only, colored_name, 1)
else:
color = theme.header
return f"{color}{name}{theme.reset}"

def formatmonth(self, theyear, themonth, w=0, l=0):
"""
Return a month's calendar string (multi-line).
Expand Down Expand Up @@ -742,7 +775,9 @@ def formatyear(self, theyear, w=2, l=1, c=6, m=3):
colwidth = (w + 1) * 7 - 1
v = []
a = v.append
a(repr(theyear).center(colwidth*m+c*(m-1)).rstrip())
theme = self._get_theme().calendar
year = repr(theyear).center(colwidth*m+c*(m-1)).rstrip()
a(f"{theme.header}{year}{theme.reset}")
a('\n'*l)
header = self.formatweekheader(w)
for (i, row) in enumerate(self.yeardays2calendar(theyear, m)):
Expand Down
1 change: 1 addition & 0 deletions Lib/test/test_calendar.py
Original file line number Diff line number Diff line change
Expand Up @@ -1063,6 +1063,7 @@ def test_several_leapyears_in_range(self):
def conv(s):
return s.replace('\n', os.linesep).encode()

@support.force_not_colorized_test_class
class CommandLineTestCase(unittest.TestCase):
def setUp(self):
self.runners = [self.run_cli_ok, self.run_cmd_ok]
Expand Down