vContent

vCalendar.py

15:7668ad359843
2011-07-18 Paul Boddie Added documentation and packaging-related files. Added some docstrings to the tests.
     1 #!/usr/bin/env python     2      3 """     4 Parsing of vCalendar and iCalendar files.     5      6 Copyright (C) 2008, 2009, 2011 Paul Boddie <paul@boddie.org.uk>     7      8 This program is free software; you can redistribute it and/or modify it under     9 the terms of the GNU General Public License as published by the Free Software    10 Foundation; either version 3 of the License, or (at your option) any later    11 version.    12     13 This program is distributed in the hope that it will be useful, but WITHOUT    14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS    15 FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more    16 details.    17     18 You should have received a copy of the GNU General Public License along with    19 this program.  If not, see <http://www.gnu.org/licenses/>.    20     21 --------    22     23 References:    24     25 RFC 2445: Internet Calendaring and Scheduling Core Object Specification    26           (iCalendar)    27           http://rfc.net/rfc2445.html    28 """    29     30 import vContent    31     32 try:    33     set    34 except NameError:    35     from sets import Set as set    36     37 # Format details.    38     39 QUOTED_PARAMETERS = set([    40     "ALTREP", "DELEGATED-FROM", "DELEGATED-TO", "DIR", "MEMBER", "SENT-BY"    41     ])    42 MULTIVALUED_PARAMETERS = set([    43     "DELEGATED-FROM", "DELEGATED-TO", "MEMBER"    44     ])    45 QUOTED_TYPES = set(["URI"])    46     47 # Parser classes.    48     49 class vCalendarStreamParser(vContent.StreamParser):    50     51     "A stream parser specifically for vCalendar/iCalendar."    52     53     def next(self):    54     55         """    56         Return the next content item in the file as a tuple of the form    57         (name, parameters, value).    58         """    59     60         name, parameters, value = vContent.StreamParser.next(self)    61         return name, self.decode_parameters(parameters), self.decode_content(value)    62     63     def decode_content(self, value):    64     65         "Decode the given 'value', replacing quoted separator characters."    66     67         # Replace quoted characters (see 4.3.11 in RFC 2445).    68     69         value = vContent.StreamParser.decode_content(self, value)    70         return value.replace(r"\,", ",").replace(r"\;", ";")    71     72     # Internal methods.    73     74     def decode_quoted_value(self, value):    75     76         "Decode the given 'value', returning a list of decoded values."    77     78         if value[0] == '"' and value[-1] == '"':    79             return value[1:-1]    80         else:    81             return value    82     83     def decode_parameters(self, parameters):    84     85         """    86         Decode the given 'parameters' according to the vCalendar specification.    87         """    88     89         decoded_parameters = {}    90     91         for param_name, param_value in parameters.items():    92             if param_name in QUOTED_PARAMETERS:    93                 param_value = self.decode_quoted_value(param_value)    94                 separator = '","'    95             else:    96                 separator = ","    97             if param_name in MULTIVALUED_PARAMETERS:    98                 param_value = param_value.split(separator)    99             decoded_parameters[param_name] = param_value   100    101         return decoded_parameters   102    103 class vCalendarParser(vContent.Parser):   104    105     "A parser specifically for vCalendar/iCalendar."   106    107     def parse(self, f, parser_cls=None):   108         return vContent.Parser.parse(self, f, (parser_cls or vCalendarStreamParser))   109    110 # Writer classes.   111    112 class vCalendarStreamWriter(vContent.StreamWriter):   113    114     "A stream writer specifically for vCard."   115    116     # Overridden methods.   117    118     def encode_parameters(self, parameters):   119    120         """   121         Encode the given 'parameters' according to the vCalendar specification.   122         """   123    124         encoded_parameters = {}   125    126         for param_name, param_value in parameters.items():   127             if param_name in QUOTED_PARAMETERS:   128                 param_value = self.encode_quoted_parameter_value(param_value)   129                 separator = '","'   130             else:   131                 separator = ","   132             if param_name in MULTIVALUED_PARAMETERS:   133                 param_value = separator.join(param_value)   134             encoded_parameters[param_name] = param_value   135    136         return encoded_parameters   137    138     def encode_content(self, value):   139    140         "Encode the given 'value', quoting characters."   141    142         # Replace quoted characters (see 4.3.11 in RFC 2445).   143    144         value = vContent.StreamWriter.encode_content(self, value)   145         return value.replace(";", r"\;").replace(",", r"\,")   146    147 # Public functions.   148    149 def parse(stream_or_string, encoding=None, non_standard_newline=0):   150    151     """   152     Parse the resource data found through the use of the 'stream_or_string',   153     which is either a stream providing Unicode data (the codecs module can be   154     used to open files or to wrap streams in order to provide Unicode data) or a   155     filename identifying a file to be parsed.   156    157     The optional 'encoding' can be used to specify the character encoding used   158     by the file to be parsed.   159    160     The optional 'non_standard_newline' can be set to a true value (unlike the   161     default) in order to attempt to process files with CR as the end of line   162     character.   163    164     As a result of parsing the resource, the root node of the imported resource   165     is returned.   166     """   167    168     return vContent.parse(stream_or_string, encoding, non_standard_newline, vCalendarParser)   169    170 def iterparse(stream_or_string, encoding=None, non_standard_newline=0):   171    172     """   173     Parse the resource data found through the use of the 'stream_or_string',   174     which is either a stream providing Unicode data (the codecs module can be   175     used to open files or to wrap streams in order to provide Unicode data) or a   176     filename identifying a file to be parsed.   177    178     The optional 'encoding' can be used to specify the character encoding used   179     by the file to be parsed.   180    181     The optional 'non_standard_newline' can be set to a true value (unlike the   182     default) in order to attempt to process files with CR as the end of line   183     character.   184    185     An iterator is returned which provides event tuples describing parsing   186     events of the form (name, parameters, value).   187     """   188    189     return vContent.iterparse(stream_or_string, encoding, non_standard_newline, vCalendarStreamParser)   190    191 def iterwrite(stream_or_string, encoding=None, line_length=None):   192    193     """   194     Return a writer which will send data to the resource found through the use   195     of 'stream_or_string', which is either a stream accepting Unicode data (the   196     codecs module can be used to open files or to wrap streams in order to   197     accept Unicode data) or a filename identifying a file to be parsed.   198    199     The optional 'encoding' can be used to specify the character encoding used   200     by the file to be written.   201    202     The optional 'line_length' can be used to specify how long lines should be   203     in the resulting data.   204     """   205    206     return vContent.iterwrite(stream_or_string, encoding, line_length, vCalendarStreamWriter)   207    208 # vim: tabstop=4 expandtab shiftwidth=4