10
10
from enum import IntEnum , global_enum
11
11
import locale as _locale
12
12
from itertools import repeat
13
- import warnings
14
13
15
14
__all__ = ["IllegalMonthError" , "IllegalWeekdayError" , "setfirstweekday" ,
16
15
"firstweekday" , "isleap" , "leapdays" , "weekday" , "monthrange" ,
28
27
error = ValueError
29
28
30
29
# Exceptions raised for bad input
31
- class IllegalMonthError (ValueError ):
30
+ # This is trick for backward compatibility. Since 3.13, we will raise IllegalMonthError instead of
31
+ # IndexError for bad month number(out of 1-12). But we can't remove IndexError for backward compatibility.
32
+ class IllegalMonthError (ValueError , IndexError ):
32
33
def __init__ (self , month ):
33
34
self .month = month
34
35
def __str__ (self ):
@@ -44,6 +45,7 @@ def __str__(self):
44
45
45
46
def __getattr__ (name ):
46
47
if name in ('January' , 'February' ):
48
+ import warnings
47
49
warnings .warn (f"The '{ name } ' attribute is deprecated, use '{ name .upper ()} ' instead" ,
48
50
DeprecationWarning , stacklevel = 2 )
49
51
if name == 'January' :
@@ -158,11 +160,14 @@ def weekday(year, month, day):
158
160
return Day (datetime .date (year , month , day ).weekday ())
159
161
160
162
161
- def monthrange (year , month ):
162
- """Return weekday (0-6 ~ Mon-Sun) and number of days (28-31) for
163
- year, month."""
163
+ def _validate_month (month ):
164
164
if not 1 <= month <= 12 :
165
165
raise IllegalMonthError (month )
166
+
167
+ def monthrange (year , month ):
168
+ """Return weekday of first day of month (0-6 ~ Mon-Sun)
169
+ and number of days (28-31) for year, month."""
170
+ _validate_month (month )
166
171
day1 = weekday (year , month , 1 )
167
172
ndays = mdays [month ] + (month == FEBRUARY and isleap (year ))
168
173
return day1 , ndays
@@ -370,6 +375,8 @@ def formatmonthname(self, theyear, themonth, width, withyear=True):
370
375
"""
371
376
Return a formatted month name.
372
377
"""
378
+ _validate_month (themonth )
379
+
373
380
s = month_name [themonth ]
374
381
if withyear :
375
382
s = "%s %r" % (s , theyear )
@@ -500,6 +507,7 @@ def formatmonthname(self, theyear, themonth, withyear=True):
500
507
"""
501
508
Return a month name as a table row.
502
509
"""
510
+ _validate_month (themonth )
503
511
if withyear :
504
512
s = '%s %s' % (month_name [themonth ], theyear )
505
513
else :
@@ -585,8 +593,6 @@ def __enter__(self):
585
593
_locale .setlocale (_locale .LC_TIME , self .locale )
586
594
587
595
def __exit__ (self , * args ):
588
- if self .oldlocale is None :
589
- return
590
596
_locale .setlocale (_locale .LC_TIME , self .oldlocale )
591
597
592
598
@@ -690,7 +696,7 @@ def timegm(tuple):
690
696
return seconds
691
697
692
698
693
- def main (args ):
699
+ def main (args = None ):
694
700
import argparse
695
701
parser = argparse .ArgumentParser ()
696
702
textgroup = parser .add_argument_group ('text only arguments' )
@@ -736,18 +742,23 @@ def main(args):
736
742
choices = ("text" , "html" ),
737
743
help = "output type (text or html)"
738
744
)
745
+ parser .add_argument (
746
+ "-f" , "--first-weekday" ,
747
+ type = int , default = 0 ,
748
+ help = "weekday (0 is Monday, 6 is Sunday) to start each week (default 0)"
749
+ )
739
750
parser .add_argument (
740
751
"year" ,
741
752
nargs = '?' , type = int ,
742
- help = "year number (1-9999) "
753
+ help = "year number"
743
754
)
744
755
parser .add_argument (
745
756
"month" ,
746
757
nargs = '?' , type = int ,
747
758
help = "month number (1-12, text only)"
748
759
)
749
760
750
- options = parser .parse_args (args [ 1 :] )
761
+ options = parser .parse_args (args )
751
762
752
763
if options .locale and not options .encoding :
753
764
parser .error ("if --locale is specified --encoding is required" )
@@ -756,31 +767,35 @@ def main(args):
756
767
locale = options .locale , options .encoding
757
768
758
769
if options .type == "html" :
770
+ if options .month :
771
+ parser .error ("incorrect number of arguments" )
772
+ sys .exit (1 )
759
773
if options .locale :
760
774
cal = LocaleHTMLCalendar (locale = locale )
761
775
else :
762
776
cal = HTMLCalendar ()
777
+ cal .setfirstweekday (options .first_weekday )
763
778
encoding = options .encoding
764
779
if encoding is None :
765
780
encoding = sys .getdefaultencoding ()
766
781
optdict = dict (encoding = encoding , css = options .css )
767
782
write = sys .stdout .buffer .write
768
783
if options .year is None :
769
784
write (cal .formatyearpage (datetime .date .today ().year , ** optdict ))
770
- elif options .month is None :
771
- write (cal .formatyearpage (options .year , ** optdict ))
772
785
else :
773
- parser .error ("incorrect number of arguments" )
774
- sys .exit (1 )
786
+ write (cal .formatyearpage (options .year , ** optdict ))
775
787
else :
776
788
if options .locale :
777
789
cal = LocaleTextCalendar (locale = locale )
778
790
else :
779
791
cal = TextCalendar ()
792
+ cal .setfirstweekday (options .first_weekday )
780
793
optdict = dict (w = options .width , l = options .lines )
781
794
if options .month is None :
782
795
optdict ["c" ] = options .spacing
783
796
optdict ["m" ] = options .months
797
+ if options .month is not None :
798
+ _validate_month (options .month )
784
799
if options .year is None :
785
800
result = cal .formatyear (datetime .date .today ().year , ** optdict )
786
801
elif options .month is None :
@@ -795,4 +810,4 @@ def main(args):
795
810
796
811
797
812
if __name__ == "__main__" :
798
- main (sys . argv )
813
+ main ()
0 commit comments