Home | History | Annotate | Download | only in Lib
      1 """Calendar printing functions
      2 
      3 Note when comparing these calendars to the ones printed by cal(1): By
      4 default, these calendars have Monday as the first day of the week, and
      5 Sunday as the last (the European convention). Use setfirstweekday() to
      6 set the first day of the week (0=Monday, 6=Sunday)."""
      7 
      8 import sys
      9 import datetime
     10 import locale as _locale
     11 
     12 __all__ = ["IllegalMonthError", "IllegalWeekdayError", "setfirstweekday",
     13            "firstweekday", "isleap", "leapdays", "weekday", "monthrange",
     14            "monthcalendar", "prmonth", "month", "prcal", "calendar",
     15            "timegm", "month_name", "month_abbr", "day_name", "day_abbr"]
     16 
     17 # Exception raised for bad input (with string parameter for details)

     18 error = ValueError
     19 
     20 # Exceptions raised for bad input

     21 class IllegalMonthError(ValueError):
     22     def __init__(self, month):
     23         self.month = month
     24     def __str__(self):
     25         return "bad month number %r; must be 1-12" % self.month
     26 
     27 
     28 class IllegalWeekdayError(ValueError):
     29     def __init__(self, weekday):
     30         self.weekday = weekday
     31     def __str__(self):
     32         return "bad weekday number %r; must be 0 (Monday) to 6 (Sunday)" % self.weekday
     33 
     34 
     35 # Constants for months referenced later

     36 January = 1
     37 February = 2
     38 
     39 # Number of days per month (except for February in leap years)

     40 mdays = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
     41 
     42 # This module used to have hard-coded lists of day and month names, as

     43 # English strings.  The classes following emulate a read-only version of

     44 # that, but supply localized names.  Note that the values are computed

     45 # fresh on each call, in case the user changes locale between calls.

     46 
     47 class _localized_month:
     48 
     49     _months = [datetime.date(2001, i+1, 1).strftime for i in range(12)]
     50     _months.insert(0, lambda x: "")
     51 
     52     def __init__(self, format):
     53         self.format = format
     54 
     55     def __getitem__(self, i):
     56         funcs = self._months[i]
     57         if isinstance(i, slice):
     58             return [f(self.format) for f in funcs]
     59         else:
     60             return funcs(self.format)
     61 
     62     def __len__(self):
     63         return 13
     64 
     65 
     66 class _localized_day:
     67 
     68     # January 1, 2001, was a Monday.

     69     _days = [datetime.date(2001, 1, i+1).strftime for i in range(7)]
     70 
     71     def __init__(self, format):
     72         self.format = format
     73 
     74     def __getitem__(self, i):
     75         funcs = self._days[i]
     76         if isinstance(i, slice):
     77             return [f(self.format) for f in funcs]
     78         else:
     79             return funcs(self.format)
     80 
     81     def __len__(self):
     82         return 7
     83 
     84 
     85 # Full and abbreviated names of weekdays

     86 day_name = _localized_day('%A')
     87 day_abbr = _localized_day('%a')
     88 
     89 # Full and abbreviated names of months (1-based arrays!!!)

     90 month_name = _localized_month('%B')
     91 month_abbr = _localized_month('%b')
     92 
     93 # Constants for weekdays

     94 (MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY) = range(7)
     95 
     96 
     97 def isleap(year):
     98     """Return True for leap years, False for non-leap years."""
     99     return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
    100 
    101 
    102 def leapdays(y1, y2):
    103     """Return number of leap years in range [y1, y2).
    104        Assume y1 <= y2."""
    105     y1 -= 1
    106     y2 -= 1
    107     return (y2//4 - y1//4) - (y2//100 - y1//100) + (y2//400 - y1//400)
    108 
    109 
    110 def weekday(year, month, day):
    111     """Return weekday (0-6 ~ Mon-Sun) for year (1970-...), month (1-12),
    112        day (1-31)."""
    113     return datetime.date(year, month, day).weekday()
    114 
    115 
    116 def monthrange(year, month):
    117     """Return weekday (0-6 ~ Mon-Sun) and number of days (28-31) for
    118        year, month."""
    119     if not 1 <= month <= 12:
    120         raise IllegalMonthError(month)
    121     day1 = weekday(year, month, 1)
    122     ndays = mdays[month] + (month == February and isleap(year))
    123     return day1, ndays
    124 
    125 
    126 class Calendar(object):
    127     """
    128     Base calendar class. This class doesn't do any formatting. It simply
    129     provides data to subclasses.
    130     """
    131 
    132     def __init__(self, firstweekday=0):
    133         self.firstweekday = firstweekday # 0 = Monday, 6 = Sunday

    134 
    135     def getfirstweekday(self):
    136         return self._firstweekday % 7
    137 
    138     def setfirstweekday(self, firstweekday):
    139         self._firstweekday = firstweekday
    140 
    141     firstweekday = property(getfirstweekday, setfirstweekday)
    142 
    143     def iterweekdays(self):
    144         """
    145         Return a iterator for one week of weekday numbers starting with the
    146         configured first one.
    147         """
    148         for i in range(self.firstweekday, self.firstweekday + 7):
    149             yield i%7
    150 
    151     def itermonthdates(self, year, month):
    152         """
    153         Return an iterator for one month. The iterator will yield datetime.date
    154         values and will always iterate through complete weeks, so it will yield
    155         dates outside the specified month.
    156         """
    157         date = datetime.date(year, month, 1)
    158         # Go back to the beginning of the week

    159         days = (date.weekday() - self.firstweekday) % 7
    160         date -= datetime.timedelta(days=days)
    161         oneday = datetime.timedelta(days=1)
    162         while True:
    163             yield date
    164             date += oneday
    165             if date.month != month and date.weekday() == self.firstweekday:
    166                 break
    167 
    168     def itermonthdays2(self, year, month):
    169         """
    170         Like itermonthdates(), but will yield (day number, weekday number)
    171         tuples. For days outside the specified month the day number is 0.
    172         """
    173         for date in self.itermonthdates(year, month):
    174             if date.month != month:
    175                 yield (0, date.weekday())
    176             else:
    177                 yield (date.day, date.weekday())
    178 
    179     def itermonthdays(self, year, month):
    180         """
    181         Like itermonthdates(), but will yield day numbers. For days outside
    182         the specified month the day number is 0.
    183         """
    184         for date in self.itermonthdates(year, month):
    185             if date.month != month:
    186                 yield 0
    187             else:
    188                 yield date.day
    189 
    190     def monthdatescalendar(self, year, month):
    191         """
    192         Return a matrix (list of lists) representing a month's calendar.
    193         Each row represents a week; week entries are datetime.date values.
    194         """
    195         dates = list(self.itermonthdates(year, month))
    196         return [ dates[i:i+7] for i in range(0, len(dates), 7) ]
    197 
    198     def monthdays2calendar(self, year, month):
    199         """
    200         Return a matrix representing a month's calendar.
    201         Each row represents a week; week entries are
    202         (day number, weekday number) tuples. Day numbers outside this month
    203         are zero.
    204         """
    205         days = list(self.itermonthdays2(year, month))
    206         return [ days[i:i+7] for i in range(0, len(days), 7) ]
    207 
    208     def monthdayscalendar(self, year, month):
    209         """
    210         Return a matrix representing a month's calendar.
    211         Each row represents a week; days outside this month are zero.
    212         """
    213         days = list(self.itermonthdays(year, month))
    214         return [ days[i:i+7] for i in range(0, len(days), 7) ]
    215 
    216     def yeardatescalendar(self, year, width=3):
    217         """
    218         Return the data for the specified year ready for formatting. The return
    219         value is a list of month rows. Each month row contains upto width months.
    220         Each month contains between 4 and 6 weeks and each week contains 1-7
    221         days. Days are datetime.date objects.
    222         """
    223         months = [
    224             self.monthdatescalendar(year, i)
    225             for i in range(January, January+12)
    226         ]
    227         return [months[i:i+width] for i in range(0, len(months), width) ]
    228 
    229     def yeardays2calendar(self, year, width=3):
    230         """
    231         Return the data for the specified year ready for formatting (similar to
    232         yeardatescalendar()). Entries in the week lists are
    233         (day number, weekday number) tuples. Day numbers outside this month are
    234         zero.
    235         """
    236         months = [
    237             self.monthdays2calendar(year, i)
    238             for i in range(January, January+12)
    239         ]
    240         return [months[i:i+width] for i in range(0, len(months), width) ]
    241 
    242     def yeardayscalendar(self, year, width=3):
    243         """
    244         Return the data for the specified year ready for formatting (similar to
    245         yeardatescalendar()). Entries in the week lists are day numbers.
    246         Day numbers outside this month are zero.
    247         """
    248         months = [
    249             self.monthdayscalendar(year, i)
    250             for i in range(January, January+12)
    251         ]
    252         return [months[i:i+width] for i in range(0, len(months), width) ]
    253 
    254 
    255 class TextCalendar(Calendar):
    256     """
    257     Subclass of Calendar that outputs a calendar as a simple plain text
    258     similar to the UNIX program cal.
    259     """
    260 
    261     def prweek(self, theweek, width):
    262         """
    263         Print a single week (no newline).
    264         """
    265         print self.formatweek(theweek, width),
    266 
    267     def formatday(self, day, weekday, width):
    268         """
    269         Returns a formatted day.
    270         """
    271         if day == 0:
    272             s = ''
    273         else:
    274             s = '%2i' % day             # right-align single-digit days

    275         return s.center(width)
    276 
    277     def formatweek(self, theweek, width):
    278         """
    279         Returns a single week in a string (no newline).
    280         """
    281         return ' '.join(self.formatday(d, wd, width) for (d, wd) in theweek)
    282 
    283     def formatweekday(self, day, width):
    284         """
    285         Returns a formatted week day name.
    286         """
    287         if width >= 9:
    288             names = day_name
    289         else:
    290             names = day_abbr
    291         return names[day][:width].center(width)
    292 
    293     def formatweekheader(self, width):
    294         """
    295         Return a header for a week.
    296         """
    297         return ' '.join(self.formatweekday(i, width) for i in self.iterweekdays())
    298 
    299     def formatmonthname(self, theyear, themonth, width, withyear=True):
    300         """
    301         Return a formatted month name.
    302         """
    303         s = month_name[themonth]
    304         if withyear:
    305             s = "%s %r" % (s, theyear)
    306         return s.center(width)
    307 
    308     def prmonth(self, theyear, themonth, w=0, l=0):
    309         """
    310         Print a month's calendar.
    311         """
    312         print self.formatmonth(theyear, themonth, w, l),
    313 
    314     def formatmonth(self, theyear, themonth, w=0, l=0):
    315         """
    316         Return a month's calendar string (multi-line).
    317         """
    318         w = max(2, w)
    319         l = max(1, l)
    320         s = self.formatmonthname(theyear, themonth, 7 * (w + 1) - 1)
    321         s = s.rstrip()
    322         s += '\n' * l
    323         s += self.formatweekheader(w).rstrip()
    324         s += '\n' * l
    325         for week in self.monthdays2calendar(theyear, themonth):
    326             s += self.formatweek(week, w).rstrip()
    327             s += '\n' * l
    328         return s
    329 
    330     def formatyear(self, theyear, w=2, l=1, c=6, m=3):
    331         """
    332         Returns a year's calendar as a multi-line string.
    333         """
    334         w = max(2, w)
    335         l = max(1, l)
    336         c = max(2, c)
    337         colwidth = (w + 1) * 7 - 1
    338         v = []
    339         a = v.append
    340         a(repr(theyear).center(colwidth*m+c*(m-1)).rstrip())
    341         a('\n'*l)
    342         header = self.formatweekheader(w)
    343         for (i, row) in enumerate(self.yeardays2calendar(theyear, m)):
    344             # months in this row

    345             months = range(m*i+1, min(m*(i+1)+1, 13))
    346             a('\n'*l)
    347             names = (self.formatmonthname(theyear, k, colwidth, False)
    348                      for k in months)
    349             a(formatstring(names, colwidth, c).rstrip())
    350             a('\n'*l)
    351             headers = (header for k in months)
    352             a(formatstring(headers, colwidth, c).rstrip())
    353             a('\n'*l)
    354             # max number of weeks for this row

    355             height = max(len(cal) for cal in row)
    356             for j in range(height):
    357                 weeks = []
    358                 for cal in row:
    359                     if j >= len(cal):
    360                         weeks.append('')
    361                     else:
    362                         weeks.append(self.formatweek(cal[j], w))
    363                 a(formatstring(weeks, colwidth, c).rstrip())
    364                 a('\n' * l)
    365         return ''.join(v)
    366 
    367     def pryear(self, theyear, w=0, l=0, c=6, m=3):
    368         """Print a year's calendar."""
    369         print self.formatyear(theyear, w, l, c, m)
    370 
    371 
    372 class HTMLCalendar(Calendar):
    373     """
    374     This calendar returns complete HTML pages.
    375     """
    376 
    377     # CSS classes for the day <td>s

    378     cssclasses = ["mon", "tue", "wed", "thu", "fri", "sat", "sun"]
    379 
    380     def formatday(self, day, weekday):
    381         """
    382         Return a day as a table cell.
    383         """
    384         if day == 0:
    385             return '<td class="noday">&nbsp;</td>' # day outside month

    386         else:
    387             return '<td class="%s">%d</td>' % (self.cssclasses[weekday], day)
    388 
    389     def formatweek(self, theweek):
    390         """
    391         Return a complete week as a table row.
    392         """
    393         s = ''.join(self.formatday(d, wd) for (d, wd) in theweek)
    394         return '<tr>%s</tr>' % s
    395 
    396     def formatweekday(self, day):
    397         """
    398         Return a weekday name as a table header.
    399         """
    400         return '<th class="%s">%s</th>' % (self.cssclasses[day], day_abbr[day])
    401 
    402     def formatweekheader(self):
    403         """
    404         Return a header for a week as a table row.
    405         """
    406         s = ''.join(self.formatweekday(i) for i in self.iterweekdays())
    407         return '<tr>%s</tr>' % s
    408 
    409     def formatmonthname(self, theyear, themonth, withyear=True):
    410         """
    411         Return a month name as a table row.
    412         """
    413         if withyear:
    414             s = '%s %s' % (month_name[themonth], theyear)
    415         else:
    416             s = '%s' % month_name[themonth]
    417         return '<tr><th colspan="7" class="month">%s</th></tr>' % s
    418 
    419     def formatmonth(self, theyear, themonth, withyear=True):
    420         """
    421         Return a formatted month as a table.
    422         """
    423         v = []
    424         a = v.append
    425         a('<table border="0" cellpadding="0" cellspacing="0" class="month">')
    426         a('\n')
    427         a(self.formatmonthname(theyear, themonth, withyear=withyear))
    428         a('\n')
    429         a(self.formatweekheader())
    430         a('\n')
    431         for week in self.monthdays2calendar(theyear, themonth):
    432             a(self.formatweek(week))
    433             a('\n')
    434         a('</table>')
    435         a('\n')
    436         return ''.join(v)
    437 
    438     def formatyear(self, theyear, width=3):
    439         """
    440         Return a formatted year as a table of tables.
    441         """
    442         v = []
    443         a = v.append
    444         width = max(width, 1)
    445         a('<table border="0" cellpadding="0" cellspacing="0" class="year">')
    446         a('\n')
    447         a('<tr><th colspan="%d" class="year">%s</th></tr>' % (width, theyear))
    448         for i in range(January, January+12, width):
    449             # months in this row

    450             months = range(i, min(i+width, 13))
    451             a('<tr>')
    452             for m in months:
    453                 a('<td>')
    454                 a(self.formatmonth(theyear, m, withyear=False))
    455                 a('</td>')
    456             a('</tr>')
    457         a('</table>')
    458         return ''.join(v)
    459 
    460     def formatyearpage(self, theyear, width=3, css='calendar.css', encoding=None):
    461         """
    462         Return a formatted year as a complete HTML page.
    463         """
    464         if encoding is None:
    465             encoding = sys.getdefaultencoding()
    466         v = []
    467         a = v.append
    468         a('<?xml version="1.0" encoding="%s"?>\n' % encoding)
    469         a('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\n')
    470         a('<html>\n')
    471         a('<head>\n')
    472         a('<meta http-equiv="Content-Type" content="text/html; charset=%s" />\n' % encoding)
    473         if css is not None:
    474             a('<link rel="stylesheet" type="text/css" href="%s" />\n' % css)
    475         a('<title>Calendar for %d</title>\n' % theyear)
    476         a('</head>\n')
    477         a('<body>\n')
    478         a(self.formatyear(theyear, width))
    479         a('</body>\n')
    480         a('</html>\n')
    481         return ''.join(v).encode(encoding, "xmlcharrefreplace")
    482 
    483 
    484 class TimeEncoding:
    485     def __init__(self, locale):
    486         self.locale = locale
    487 
    488     def __enter__(self):
    489         self.oldlocale = _locale.getlocale(_locale.LC_TIME)
    490         _locale.setlocale(_locale.LC_TIME, self.locale)
    491 
    492     def __exit__(self, *args):
    493         _locale.setlocale(_locale.LC_TIME, self.oldlocale)
    494 
    495 
    496 class LocaleTextCalendar(TextCalendar):
    497     """
    498     This class can be passed a locale name in the constructor and will return
    499     month and weekday names in the specified locale. If this locale includes
    500     an encoding all strings containing month and weekday names will be returned
    501     as unicode.
    502     """
    503 
    504     def __init__(self, firstweekday=0, locale=None):
    505         TextCalendar.__init__(self, firstweekday)
    506         if locale is None:
    507             locale = _locale.getdefaultlocale()
    508         self.locale = locale
    509 
    510     def formatweekday(self, day, width):
    511         with TimeEncoding(self.locale) as encoding:
    512             if width >= 9:
    513                 names = day_name
    514             else:
    515                 names = day_abbr
    516             name = names[day]
    517             if encoding is not None:
    518                 name = name.decode(encoding)
    519             return name[:width].center(width)
    520 
    521     def formatmonthname(self, theyear, themonth, width, withyear=True):
    522         with TimeEncoding(self.locale) as encoding:
    523             s = month_name[themonth]
    524             if encoding is not None:
    525                 s = s.decode(encoding)
    526             if withyear:
    527                 s = "%s %r" % (s, theyear)
    528             return s.center(width)
    529 
    530 
    531 class LocaleHTMLCalendar(HTMLCalendar):
    532     """
    533     This class can be passed a locale name in the constructor and will return
    534     month and weekday names in the specified locale. If this locale includes
    535     an encoding all strings containing month and weekday names will be returned
    536     as unicode.
    537     """
    538     def __init__(self, firstweekday=0, locale=None):
    539         HTMLCalendar.__init__(self, firstweekday)
    540         if locale is None:
    541             locale = _locale.getdefaultlocale()
    542         self.locale = locale
    543 
    544     def formatweekday(self, day):
    545         with TimeEncoding(self.locale) as encoding:
    546             s = day_abbr[day]
    547             if encoding is not None:
    548                 s = s.decode(encoding)
    549             return '<th class="%s">%s</th>' % (self.cssclasses[day], s)
    550 
    551     def formatmonthname(self, theyear, themonth, withyear=True):
    552         with TimeEncoding(self.locale) as encoding:
    553             s = month_name[themonth]
    554             if encoding is not None:
    555                 s = s.decode(encoding)
    556             if withyear:
    557                 s = '%s %s' % (s, theyear)
    558             return '<tr><th colspan="7" class="month">%s</th></tr>' % s
    559 
    560 
    561 # Support for old module level interface

    562 c = TextCalendar()
    563 
    564 firstweekday = c.getfirstweekday
    565 
    566 def setfirstweekday(firstweekday):
    567     try:
    568         firstweekday.__index__
    569     except AttributeError:
    570         raise IllegalWeekdayError(firstweekday)
    571     if not MONDAY <= firstweekday <= SUNDAY:
    572         raise IllegalWeekdayError(firstweekday)
    573     c.firstweekday = firstweekday
    574 
    575 monthcalendar = c.monthdayscalendar
    576 prweek = c.prweek
    577 week = c.formatweek
    578 weekheader = c.formatweekheader
    579 prmonth = c.prmonth
    580 month = c.formatmonth
    581 calendar = c.formatyear
    582 prcal = c.pryear
    583 
    584 
    585 # Spacing of month columns for multi-column year calendar

    586 _colwidth = 7*3 - 1         # Amount printed by prweek()

    587 _spacing = 6                # Number of spaces between columns

    588 
    589 
    590 def format(cols, colwidth=_colwidth, spacing=_spacing):
    591     """Prints multi-column formatting for year calendars"""
    592     print formatstring(cols, colwidth, spacing)
    593 
    594 
    595 def formatstring(cols, colwidth=_colwidth, spacing=_spacing):
    596     """Returns a string formatted from n strings, centered within n columns."""
    597     spacing *= ' '
    598     return spacing.join(c.center(colwidth) for c in cols)
    599 
    600 
    601 EPOCH = 1970
    602 _EPOCH_ORD = datetime.date(EPOCH, 1, 1).toordinal()
    603 
    604 
    605 def timegm(tuple):
    606     """Unrelated but handy function to calculate Unix timestamp from GMT."""
    607     year, month, day, hour, minute, second = tuple[:6]
    608     days = datetime.date(year, month, 1).toordinal() - _EPOCH_ORD + day - 1
    609     hours = days*24 + hour
    610     minutes = hours*60 + minute
    611     seconds = minutes*60 + second
    612     return seconds
    613 
    614 
    615 def main(args):
    616     import optparse
    617     parser = optparse.OptionParser(usage="usage: %prog [options] [year [month]]")
    618     parser.add_option(
    619         "-w", "--width",
    620         dest="width", type="int", default=2,
    621         help="width of date column (default 2, text only)"
    622     )
    623     parser.add_option(
    624         "-l", "--lines",
    625         dest="lines", type="int", default=1,
    626         help="number of lines for each week (default 1, text only)"
    627     )
    628     parser.add_option(
    629         "-s", "--spacing",
    630         dest="spacing", type="int", default=6,
    631         help="spacing between months (default 6, text only)"
    632     )
    633     parser.add_option(
    634         "-m", "--months",
    635         dest="months", type="int", default=3,
    636         help="months per row (default 3, text only)"
    637     )
    638     parser.add_option(
    639         "-c", "--css",
    640         dest="css", default="calendar.css",
    641         help="CSS to use for page (html only)"
    642     )
    643     parser.add_option(
    644         "-L", "--locale",
    645         dest="locale", default=None,
    646         help="locale to be used from month and weekday names"
    647     )
    648     parser.add_option(
    649         "-e", "--encoding",
    650         dest="encoding", default=None,
    651         help="Encoding to use for output"
    652     )
    653     parser.add_option(
    654         "-t", "--type",
    655         dest="type", default="text",
    656         choices=("text", "html"),
    657         help="output type (text or html)"
    658     )
    659 
    660     (options, args) = parser.parse_args(args)
    661 
    662     if options.locale and not options.encoding:
    663         parser.error("if --locale is specified --encoding is required")
    664         sys.exit(1)
    665 
    666     locale = options.locale, options.encoding
    667 
    668     if options.type == "html":
    669         if options.locale:
    670             cal = LocaleHTMLCalendar(locale=locale)
    671         else:
    672             cal = HTMLCalendar()
    673         encoding = options.encoding
    674         if encoding is None:
    675             encoding = sys.getdefaultencoding()
    676         optdict = dict(encoding=encoding, css=options.css)
    677         if len(args) == 1:
    678             print cal.formatyearpage(datetime.date.today().year, **optdict)
    679         elif len(args) == 2:
    680             print cal.formatyearpage(int(args[1]), **optdict)
    681         else:
    682             parser.error("incorrect number of arguments")
    683             sys.exit(1)
    684     else:
    685         if options.locale:
    686             cal = LocaleTextCalendar(locale=locale)
    687         else:
    688             cal = TextCalendar()
    689         optdict = dict(w=options.width, l=options.lines)
    690         if len(args) != 3:
    691             optdict["c"] = options.spacing
    692             optdict["m"] = options.months
    693         if len(args) == 1:
    694             result = cal.formatyear(datetime.date.today().year, **optdict)
    695         elif len(args) == 2:
    696             result = cal.formatyear(int(args[1]), **optdict)
    697         elif len(args) == 3:
    698             result = cal.formatmonth(int(args[1]), int(args[2]), **optdict)
    699         else:
    700             parser.error("incorrect number of arguments")
    701             sys.exit(1)
    702         if options.encoding:
    703             result = result.encode(options.encoding)
    704         print result
    705 
    706 
    707 if __name__ == "__main__":
    708     main(sys.argv)
    709