kopia lustrzana https://github.com/collective/icalendar
unify API - use to_ical and from_ical
rodzic
4d0cc5fae7
commit
aa7fe2016e
9
TODO.txt
9
TODO.txt
|
@ -1,6 +1,15 @@
|
|||
Todo
|
||||
====
|
||||
|
||||
* unify api and make it python 3 compliant.
|
||||
- deprecate usage of __str__, ical, str(
|
||||
- deprecate usage of from_string, as_string, string
|
||||
- use from_ical, to_ical
|
||||
|
||||
- use @static instead of staticmethod
|
||||
|
||||
%s/from_string/from_ical/gc
|
||||
|
||||
* Automatic encoding and decoding of parameter values. Most of the
|
||||
work is done already. Just need to get it finished. Look at line 153
|
||||
in 'src/icalendar/parser.py'
|
||||
|
|
|
@ -31,7 +31,7 @@ class ComponentFactory(CaselessDict):
|
|||
>>> factory = ComponentFactory()
|
||||
>>> component = factory['VEVENT']
|
||||
>>> event = component(dtstart='19700101')
|
||||
>>> event.as_string()
|
||||
>>> event.to_ical()
|
||||
'BEGIN:VEVENT\\r\\nDTSTART:19700101\\r\\nEND:VEVENT\\r\\n'
|
||||
|
||||
>>> factory.get('VCALENDAR', Component)
|
||||
|
@ -103,7 +103,7 @@ class Component(CaselessDict):
|
|||
>>> c = Component()
|
||||
>>> c.name = 'VCALENDAR'
|
||||
>>> c.add('attendee', 'Max M')
|
||||
>>> c.as_string()
|
||||
>>> c.to_ical()
|
||||
'BEGIN:VCALENDAR\\r\\nATTENDEE:Max M\\r\\nEND:VCALENDAR\\r\\n'
|
||||
|
||||
>>> from icalendar.prop import vDatetime
|
||||
|
@ -113,7 +113,7 @@ class Component(CaselessDict):
|
|||
>>> e.name = 'VEVENT'
|
||||
>>> e.add('dtend', '20000102T000000', encode=0)
|
||||
>>> e.add('dtstart', '20000101T000000', encode=0)
|
||||
>>> e.as_string()
|
||||
>>> e.to_ical()
|
||||
'BEGIN:VEVENT\\r\\nDTEND:20000102T000000\\r\\nDTSTART:20000101T000000\\r\\nSUMMARY:A brief history of time\\r\\nEND:VEVENT\\r\\n'
|
||||
|
||||
>>> c.add_component(e)
|
||||
|
@ -135,7 +135,7 @@ class Component(CaselessDict):
|
|||
Text fields which span multiple mulitple lines require proper indenting
|
||||
>>> c = Calendar()
|
||||
>>> c['description']=u'Paragraph one\\n\\nParagraph two'
|
||||
>>> c.as_string()
|
||||
>>> c.to_ical()
|
||||
'BEGIN:VCALENDAR\\r\\nDESCRIPTION:Paragraph one\\r\\n \\r\\n Paragraph two\\r\\nEND:VCALENDAR\\r\\n'
|
||||
|
||||
INLINE properties have their values on one property line. Note the double
|
||||
|
@ -145,7 +145,7 @@ class Component(CaselessDict):
|
|||
>>> c
|
||||
VCALENDAR({'RESOURCES': 'Chair, Table, "Room: 42"'})
|
||||
|
||||
>>> c.as_string()
|
||||
>>> c.to_ical()
|
||||
'BEGIN:VCALENDAR\\r\\nRESOURCES:Chair, Table, "Room: 42"\\r\\nEND:VCALENDAR\\r\\n'
|
||||
|
||||
The inline values must be handled by the get_inline() and set_inline()
|
||||
|
@ -324,7 +324,7 @@ class Component(CaselessDict):
|
|||
[(name, value), ...]
|
||||
"""
|
||||
vText = types_factory['text']
|
||||
properties = [('BEGIN', vText(self.name).ical())]
|
||||
properties = [('BEGIN', vText(self.name).to_ical())]
|
||||
property_names = self.keys()
|
||||
property_names.sort()
|
||||
for name in property_names:
|
||||
|
@ -338,17 +338,17 @@ class Component(CaselessDict):
|
|||
# recursion is fun!
|
||||
for subcomponent in self.subcomponents:
|
||||
properties += subcomponent.property_items()
|
||||
properties.append(('END', vText(self.name).ical()))
|
||||
properties.append(('END', vText(self.name).to_ical()))
|
||||
return properties
|
||||
|
||||
|
||||
def from_string(st, multiple=False):
|
||||
def from_ical(st, multiple=False):
|
||||
"""
|
||||
Populates the component recursively from a string
|
||||
"""
|
||||
stack = [] # a stack of components
|
||||
comps = []
|
||||
for line in Contentlines.from_string(st): # raw parsing
|
||||
for line in Contentlines.from_ical(st): # raw parsing
|
||||
if not line:
|
||||
continue
|
||||
name, params, vals = line.parts()
|
||||
|
@ -396,7 +396,7 @@ class Component(CaselessDict):
|
|||
raise ValueError('Found no components where '
|
||||
'exactly one is required: {st!r}'.format(**locals()))
|
||||
return comps[0]
|
||||
from_string = staticmethod(from_string)
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
|
@ -418,15 +418,10 @@ class Component(CaselessDict):
|
|||
return contentlines
|
||||
|
||||
|
||||
def as_string(self):
|
||||
def to_ical(self):
|
||||
return str(self.content_lines())
|
||||
|
||||
|
||||
def __str__(self):
|
||||
"Returns rendered iCalendar"
|
||||
return self.as_string()
|
||||
|
||||
|
||||
|
||||
#######################################
|
||||
# components defined in RFC 2445
|
||||
|
@ -536,13 +531,13 @@ class Calendar(Component):
|
|||
>>> event['uid'] = '42'
|
||||
>>> event.set('dtstart', datetime(2005,4,4,8,0,0))
|
||||
>>> cal.add_component(event)
|
||||
>>> cal.subcomponents[0].as_string()
|
||||
>>> cal.subcomponents[0].to_ical()
|
||||
'BEGIN:VEVENT\\r\\nDTSTART;VALUE=DATE-TIME:20050404T080000\\r\\nSUMMARY:Python meeting about calendaring\\r\\nUID:42\\r\\nEND:VEVENT\\r\\n'
|
||||
|
||||
Write to disc
|
||||
>>> import tempfile, os
|
||||
>>> directory = tempfile.mkdtemp()
|
||||
>>> open(os.path.join(directory, 'test.ics'), 'wb').write(cal.as_string())
|
||||
>>> open(os.path.join(directory, 'test.ics'), 'wb').write(cal.to_ical())
|
||||
|
||||
Parsing a complete calendar from a string will silently ignore bogus events.
|
||||
The bogosity in the following is the third EXDATE: it has an empty DATE.
|
||||
|
@ -567,7 +562,7 @@ class Calendar(Component):
|
|||
... 'EXDATE;VALUE=DATE:',
|
||||
... 'END:VEVENT',
|
||||
... 'END:VCALENDAR'))
|
||||
>>> [e['DESCRIPTION'].ical() for e in Calendar.from_string(s).walk('VEVENT')]
|
||||
>>> [e['DESCRIPTION'].to_ical() for e in Calendar.from_ical(s).walk('VEVENT')]
|
||||
['Perfectly OK event']
|
||||
"""
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ class IComponent(Interface):
|
|||
"""
|
||||
|
||||
# static method, can be called on class directly
|
||||
def from_string(st, multiple=False):
|
||||
def from_ical(st, multiple=False):
|
||||
"""Populates the component recursively from a iCalendar string.
|
||||
|
||||
Reads the iCalendar string and constructs components and
|
||||
|
@ -99,7 +99,7 @@ class IComponent(Interface):
|
|||
Returns list of python objects.
|
||||
"""
|
||||
|
||||
def as_string():
|
||||
def to_ical():
|
||||
"""Render the component in the RFC 2445 (iCalendar) format.
|
||||
|
||||
Returns a string in RFC 2445 format.
|
||||
|
@ -162,10 +162,10 @@ class IPropertyValue(Interface):
|
|||
|
||||
This invariance should always be true:
|
||||
|
||||
assert x == vDataType.from_ical(vDataType(x).ical())
|
||||
assert x == vDataType.from_ical(vDataType(x).to_ical())
|
||||
"""
|
||||
|
||||
def ical():
|
||||
def to_ical():
|
||||
"""Render property as string, as defined in iCalendar RFC 2445.
|
||||
"""
|
||||
|
||||
|
@ -173,7 +173,7 @@ class IPropertyValue(Interface):
|
|||
def from_ical(ical):
|
||||
"""Parse property from iCalendar RFC 2445 text.
|
||||
|
||||
Inverse of ical().
|
||||
Inverse of to_ical().
|
||||
"""
|
||||
|
||||
class IBinary(IPropertyValue):
|
||||
|
|
|
@ -103,7 +103,7 @@ class Parameters(CaselessDict):
|
|||
|
||||
Simple parameter:value pair
|
||||
>>> p = Parameters(parameter1='Value1')
|
||||
>>> str(p)
|
||||
>>> p.to_ical()
|
||||
'PARAMETER1=Value1'
|
||||
|
||||
|
||||
|
@ -121,47 +121,47 @@ class Parameters(CaselessDict):
|
|||
|
||||
Parameter with list of values must be seperated by comma
|
||||
>>> p = Parameters({'parameter1':['Value1', 'Value2']})
|
||||
>>> str(p)
|
||||
>>> p.to_ical()
|
||||
'PARAMETER1=Value1,Value2'
|
||||
|
||||
|
||||
Multiple parameters must be seperated by a semicolon
|
||||
>>> p = Parameters({'RSVP':'TRUE', 'ROLE':'REQ-PARTICIPANT'})
|
||||
>>> str(p)
|
||||
>>> p.to_ical()
|
||||
'ROLE=REQ-PARTICIPANT;RSVP=TRUE'
|
||||
|
||||
|
||||
Parameter values containing ',;:' must be double quoted
|
||||
>>> p = Parameters({'ALTREP':'http://www.wiz.org'})
|
||||
>>> str(p)
|
||||
>>> p.to_ical()
|
||||
'ALTREP="http://www.wiz.org"'
|
||||
|
||||
|
||||
list items must be quoted seperately
|
||||
>>> p = Parameters({'MEMBER':['MAILTO:projectA@host.com', 'MAILTO:projectB@host.com', ]})
|
||||
>>> str(p)
|
||||
>>> p.to_ical()
|
||||
'MEMBER="MAILTO:projectA@host.com","MAILTO:projectB@host.com"'
|
||||
|
||||
Now the whole sheebang
|
||||
>>> p = Parameters({'parameter1':'Value1', 'parameter2':['Value2', 'Value3'],\
|
||||
'ALTREP':['http://www.wiz.org', 'value4']})
|
||||
>>> str(p)
|
||||
>>> p.to_ical()
|
||||
'ALTREP="http://www.wiz.org",value4;PARAMETER1=Value1;PARAMETER2=Value2,Value3'
|
||||
|
||||
We can also parse parameter strings
|
||||
>>> Parameters.from_string('PARAMETER1=Value 1;param2=Value 2')
|
||||
>>> Parameters.from_ical('PARAMETER1=Value 1;param2=Value 2')
|
||||
Parameters({'PARAMETER1': 'Value 1', 'PARAM2': 'Value 2'})
|
||||
|
||||
Including empty strings
|
||||
>>> Parameters.from_string('param=')
|
||||
>>> Parameters.from_ical('param=')
|
||||
Parameters({'PARAM': ''})
|
||||
|
||||
We can also parse parameter strings
|
||||
>>> Parameters.from_string('MEMBER="MAILTO:projectA@host.com","MAILTO:projectB@host.com"')
|
||||
>>> Parameters.from_ical('MEMBER="MAILTO:projectA@host.com","MAILTO:projectB@host.com"')
|
||||
Parameters({'MEMBER': ['MAILTO:projectA@host.com', 'MAILTO:projectB@host.com']})
|
||||
|
||||
We can also parse parameter strings
|
||||
>>> Parameters.from_string('ALTREP="http://www.wiz.org",value4;PARAMETER1=Value1;PARAMETER2=Value2,Value3')
|
||||
>>> Parameters.from_ical('ALTREP="http://www.wiz.org",value4;PARAMETER1=Value1;PARAMETER2=Value2,Value3')
|
||||
Parameters({'PARAMETER1': 'Value1', 'ALTREP': ['http://www.wiz.org', 'value4'], 'PARAMETER2': ['Value2', 'Value3']})
|
||||
"""
|
||||
|
||||
|
@ -194,7 +194,7 @@ class Parameters(CaselessDict):
|
|||
return 'Parameters(' + dict.__repr__(self) + ')'
|
||||
|
||||
|
||||
def __str__(self):
|
||||
def to_ical(self):
|
||||
result = []
|
||||
items = self.items()
|
||||
items.sort() # To make doctests work
|
||||
|
@ -204,7 +204,7 @@ class Parameters(CaselessDict):
|
|||
return ';'.join(result)
|
||||
|
||||
|
||||
def from_string(st, strict=False):
|
||||
def from_ical(st, strict=False):
|
||||
"Parses the parameter format from ical text format"
|
||||
|
||||
# parse into strings
|
||||
|
@ -238,7 +238,7 @@ class Parameters(CaselessDict):
|
|||
except ValueError, e:
|
||||
raise ValueError, '%r is not a valid parameter string: %s' % (param, e)
|
||||
return result
|
||||
from_string = staticmethod(from_string)
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
|
||||
#########################################
|
||||
|
@ -250,36 +250,36 @@ class Contentline(str):
|
|||
parts.
|
||||
|
||||
>>> c = Contentline('Si meliora dies, ut vina, poemata reddit')
|
||||
>>> str(c)
|
||||
>>> c.to_ical()
|
||||
'Si meliora dies, ut vina, poemata reddit'
|
||||
|
||||
A long line gets folded
|
||||
>>> c = Contentline(''.join(['123456789 ']*10))
|
||||
>>> str(c)
|
||||
>>> c.to_ical()
|
||||
'123456789 123456789 123456789 123456789 123456789 123456789 123456789 1234\\r\\n 56789 123456789 123456789'
|
||||
|
||||
A folded line gets unfolded
|
||||
>>> c = Contentline.from_string(str(c))
|
||||
>>> c = Contentline.from_ical(str(c))
|
||||
>>> c
|
||||
'123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789'
|
||||
|
||||
Newlines in a string get need to be preserved
|
||||
>>> c = Contentline('1234\\n\\n1234')
|
||||
>>> str(c)
|
||||
>>> c.to_ical()
|
||||
'1234\\r\\n \\r\\n 1234'
|
||||
|
||||
We do not fold within a UTF-8 character:
|
||||
>>> c = Contentline('This line has a UTF-8 character where it should be folded. Make sure it g\xc3\xabts folded before that character.')
|
||||
>>> '\xc3\xab' in str(c)
|
||||
>>> '\xc3\xab' in c.to_ical()
|
||||
True
|
||||
|
||||
Another test of the above
|
||||
>>> c = Contentline('x' * 73 + '\xc3\xab' + '\\n ' + 'y' * 10)
|
||||
>>> str(c).count('\xc3')
|
||||
>>> c.to_ical().count('\xc3')
|
||||
1
|
||||
|
||||
Don't fail if we fold a line that is exactly X times 74 characters long:
|
||||
>>> c = str(Contentline(''.join(['x']*148)))
|
||||
>>> c = Contentline(''.join(['x']*148)).to_ical()
|
||||
|
||||
It can parse itself into parts. Which is a tuple of (name, params, vals)
|
||||
|
||||
|
@ -294,7 +294,7 @@ class Contentline(str):
|
|||
>>> c = Contentline('ATTENDEE;CN=Max Rasmussen;ROLE=REQ-PARTICIPANT:MAILTO:maxm@example.com')
|
||||
>>> c.parts()
|
||||
('ATTENDEE', Parameters({'ROLE': 'REQ-PARTICIPANT', 'CN': 'Max Rasmussen'}), 'MAILTO:maxm@example.com')
|
||||
>>> str(c)
|
||||
>>> c.to_ical()
|
||||
'ATTENDEE;CN=Max Rasmussen;ROLE=REQ-PARTICIPANT:MAILTO:maxm@example.com'
|
||||
|
||||
and back again
|
||||
|
@ -353,7 +353,7 @@ class Contentline(str):
|
|||
('key', Parameters({'PARAM': 'pvalue'}), 'value')
|
||||
|
||||
Should bomb on missing param:
|
||||
>>> c = Contentline.from_string("k;:no param")
|
||||
>>> c = Contentline.from_ical("k;:no param")
|
||||
>>> c.parts() #doctest: +ELLIPSIS
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
|
@ -384,7 +384,7 @@ class Contentline(str):
|
|||
|
||||
def from_parts(parts):
|
||||
"Turns a tuple of parts into a content line"
|
||||
(name, params, values) = [str(p) for p in parts]
|
||||
(name, params, values) = [str(p) for p in parts] # TODO: str or to_ical?
|
||||
try:
|
||||
if params:
|
||||
return Contentline('%s;%s:%s' % (name, params, values))
|
||||
|
@ -418,23 +418,23 @@ class Contentline(str):
|
|||
validate_token(name)
|
||||
if name_split+1 == value_split:
|
||||
raise ValueError, 'Invalid content line'
|
||||
params = Parameters.from_string(self[name_split+1:value_split],
|
||||
params = Parameters.from_ical(self[name_split+1:value_split],
|
||||
strict=self.strict)
|
||||
values = self[value_split+1:]
|
||||
return (name, params, values)
|
||||
except ValueError, e:
|
||||
raise ValueError, "Content line could not be parsed into parts: %r: %s" % (self, e)
|
||||
|
||||
def from_string(st, strict=False):
|
||||
def from_ical(st, strict=False):
|
||||
"Unfolds the content lines in an iCalendar into long content lines"
|
||||
try:
|
||||
# a fold is carriage return followed by either a space or a tab
|
||||
return Contentline(FOLD.sub('', st), strict=strict)
|
||||
except:
|
||||
raise ValueError, 'Expected StringType with content line'
|
||||
from_string = staticmethod(from_string)
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
def __str__(self):
|
||||
def to_ical(self):
|
||||
"Long content lines are folded so they are less than 75 characters wide"
|
||||
l_line = len(self)
|
||||
new_lines = []
|
||||
|
@ -480,29 +480,29 @@ class Contentlines(list):
|
|||
used instead.
|
||||
|
||||
>>> c = Contentlines([Contentline('BEGIN:VEVENT\\r\\n')])
|
||||
>>> str(c)
|
||||
>>> c.to_ical()
|
||||
'BEGIN:VEVENT\\r\\n'
|
||||
|
||||
Lets try appending it with a 100 charater wide string
|
||||
>>> c.append(Contentline(''.join(['123456789 ']*10)+'\\r\\n'))
|
||||
>>> str(c)
|
||||
>>> c.to_ical()
|
||||
'BEGIN:VEVENT\\r\\n\\r\\n123456789 123456789 123456789 123456789 123456789 123456789 123456789 1234\\r\\n 56789 123456789 123456789 \\r\\n'
|
||||
|
||||
Notice that there is an extra empty string in the end of the content lines.
|
||||
That is so they can be easily joined with: '\r\n'.join(contentlines)).
|
||||
>>> Contentlines.from_string('A short line\\r\\n')
|
||||
>>> Contentlines.from_ical('A short line\\r\\n')
|
||||
['A short line', '']
|
||||
>>> Contentlines.from_string('A faked\\r\\n long line\\r\\n')
|
||||
>>> Contentlines.from_ical('A faked\\r\\n long line\\r\\n')
|
||||
['A faked long line', '']
|
||||
>>> Contentlines.from_string('A faked\\r\\n long line\\r\\nAnd another lin\\r\\n\\te that is folded\\r\\n')
|
||||
>>> Contentlines.from_ical('A faked\\r\\n long line\\r\\nAnd another lin\\r\\n\\te that is folded\\r\\n')
|
||||
['A faked long line', 'And another line that is folded', '']
|
||||
"""
|
||||
|
||||
def __str__(self):
|
||||
def to_ical(self):
|
||||
"Simply join self."
|
||||
return '\r\n'.join(map(str, self))
|
||||
|
||||
def from_string(st):
|
||||
def from_ical(st):
|
||||
"Parses a string into content lines"
|
||||
try:
|
||||
# a fold is carriage return followed by either a space or a tab
|
||||
|
@ -512,12 +512,12 @@ class Contentlines(list):
|
|||
return Contentlines(lines)
|
||||
except:
|
||||
raise ValueError, 'Expected StringType with content lines'
|
||||
from_string = staticmethod(from_string)
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
|
||||
# ran this:
|
||||
# sample = open('./samples/test.ics', 'rb').read() # binary file in windows!
|
||||
# lines = Contentlines.from_string(sample)
|
||||
# lines = Contentlines.from_ical(sample)
|
||||
# for line in lines[:-1]:
|
||||
# print line.parts()
|
||||
|
||||
|
|
|
@ -23,18 +23,18 @@ for the classes/datatypes that are used in Icalendar:
|
|||
|
||||
|
||||
iCalendar properties has values. The values are strongly typed. This module
|
||||
defines these types, calling val.ical() on them, Will render them as defined in
|
||||
defines these types, calling val.to_ical() on them, Will render them as defined in
|
||||
rfc2445.
|
||||
|
||||
If you pass any of these classes a Python primitive, you will have an object
|
||||
that can render itself as iCalendar formatted date.
|
||||
|
||||
Property Value Data Types starts with a 'v'. they all have an ical() and
|
||||
from_ical() method. The ical() method generates a text string in the iCalendar
|
||||
Property Value Data Types starts with a 'v'. they all have an to_ical() and
|
||||
from_ical() method. The to_ical() method generates a text string in the iCalendar
|
||||
format. The from_ical() method can parse this format and return a primitive
|
||||
Python datatype. So it should allways be true that:
|
||||
|
||||
x == vDataType.from_ical(VDataType(x).ical())
|
||||
x == vDataType.from_ical(VDataType(x).to_ical())
|
||||
|
||||
These types are mainly used for parsing and file generation. But you can set
|
||||
them directly.
|
||||
|
@ -66,7 +66,7 @@ class vBinary:
|
|||
"""
|
||||
Binary property values are base 64 encoded
|
||||
>>> b = vBinary('This is gibberish')
|
||||
>>> b.ical()
|
||||
>>> b.to_ical()
|
||||
'VGhpcyBpcyBnaWJiZXJpc2g='
|
||||
>>> b = vBinary.from_ical('VGhpcyBpcyBnaWJiZXJpc2g=')
|
||||
>>> b
|
||||
|
@ -74,7 +74,7 @@ class vBinary:
|
|||
|
||||
The roundtrip test
|
||||
>>> x = 'Binary data æ ø å \x13 \x56'
|
||||
>>> vBinary(x).ical()
|
||||
>>> vBinary(x).to_ical()
|
||||
'QmluYXJ5IGRhdGEg5iD4IOUgEyBW'
|
||||
>>> vBinary.from_ical('QmluYXJ5IGRhdGEg5iD4IOUgEyBW')
|
||||
'Binary data \\xe6 \\xf8 \\xe5 \\x13 V'
|
||||
|
@ -85,7 +85,7 @@ class vBinary:
|
|||
|
||||
Long data should not have line breaks, as that would interfere
|
||||
>>> x = 'a'*99
|
||||
>>> vBinary(x).ical() == 'YWFh' * 33
|
||||
>>> vBinary(x).to_ical() == 'YWFh' * 33
|
||||
True
|
||||
>>> vBinary.from_ical('YWFh' * 33) == 'a' * 99
|
||||
True
|
||||
|
@ -99,7 +99,7 @@ class vBinary:
|
|||
def __repr__(self):
|
||||
return "vBinary(%s)" % str.__repr__(self.obj)
|
||||
|
||||
def ical(self):
|
||||
def to_ical(self):
|
||||
return binascii.b2a_base64(self.obj)[:-1]
|
||||
|
||||
def from_ical(ical):
|
||||
|
@ -110,24 +110,21 @@ class vBinary:
|
|||
raise ValueError, 'Not valid base 64 encoding.'
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
def __str__(self):
|
||||
return self.ical()
|
||||
|
||||
|
||||
|
||||
class vBoolean(int):
|
||||
"""
|
||||
Returns specific string according to state
|
||||
>>> bin = vBoolean(True)
|
||||
>>> bin.ical()
|
||||
>>> bin.to_ical()
|
||||
'TRUE'
|
||||
>>> bin = vBoolean(0)
|
||||
>>> bin.ical()
|
||||
>>> bin.to_ical()
|
||||
'FALSE'
|
||||
|
||||
The roundtrip test
|
||||
>>> x = True
|
||||
>>> x == vBoolean.from_ical(vBoolean(x).ical())
|
||||
>>> x == vBoolean.from_ical(vBoolean(x).to_ical())
|
||||
True
|
||||
>>> vBoolean.from_ical('true')
|
||||
True
|
||||
|
@ -138,7 +135,7 @@ class vBoolean(int):
|
|||
self.params = Parameters()
|
||||
return self
|
||||
|
||||
def ical(self):
|
||||
def to_ical(self):
|
||||
if self:
|
||||
return 'TRUE'
|
||||
return 'FALSE'
|
||||
|
@ -153,8 +150,6 @@ class vBoolean(int):
|
|||
raise ValueError, "Expected 'TRUE' or 'FALSE'. Got %s" % ical
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
def __str__(self):
|
||||
return self.ical()
|
||||
|
||||
|
||||
|
||||
|
@ -163,9 +158,7 @@ class vCalAddress(str):
|
|||
This just returns an unquoted string
|
||||
>>> a = vCalAddress('MAILTO:maxm@mxm.dk')
|
||||
>>> a.params['cn'] = 'Max M'
|
||||
>>> a.ical()
|
||||
'MAILTO:maxm@mxm.dk'
|
||||
>>> str(a)
|
||||
>>> a.to_ical()
|
||||
'MAILTO:maxm@mxm.dk'
|
||||
>>> a.params
|
||||
Parameters({'CN': 'Max M'})
|
||||
|
@ -181,7 +174,7 @@ class vCalAddress(str):
|
|||
def __repr__(self):
|
||||
return u"vCalAddress(%s)" % str.__repr__(self)
|
||||
|
||||
def ical(self):
|
||||
def to_ical(self):
|
||||
return str(self)
|
||||
|
||||
def from_ical(ical):
|
||||
|
@ -192,8 +185,6 @@ class vCalAddress(str):
|
|||
raise ValueError, 'Expected vCalAddress, got: %s' % ical
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
def __str__(self):
|
||||
return str.__str__(self)
|
||||
|
||||
####################################################
|
||||
# handy tzinfo classes you can use.
|
||||
|
@ -280,14 +271,14 @@ class vDatetime:
|
|||
>>> d = datetime(2001, 1,1, 12, 30, 0)
|
||||
|
||||
>>> dt = vDatetime(d)
|
||||
>>> dt.ical()
|
||||
>>> dt.to_ical()
|
||||
'20010101T123000'
|
||||
|
||||
>>> vDatetime.from_ical('20000101T120000')
|
||||
datetime.datetime(2000, 1, 1, 12, 0)
|
||||
|
||||
>>> dutc = datetime(2001, 1,1, 12, 30, 0, tzinfo=UTC)
|
||||
>>> vDatetime(dutc).ical()
|
||||
>>> vDatetime(dutc).to_ical()
|
||||
'20010101T123000Z'
|
||||
|
||||
>>> vDatetime.from_ical('20010101T000000')
|
||||
|
@ -299,7 +290,7 @@ class vDatetime:
|
|||
ValueError: Wrong datetime format: 20010101T000000A
|
||||
|
||||
>>> utc = vDatetime.from_ical('20010101T000000Z')
|
||||
>>> vDatetime(utc).ical()
|
||||
>>> vDatetime(utc).to_ical()
|
||||
'20010101T000000Z'
|
||||
"""
|
||||
|
||||
|
@ -307,7 +298,7 @@ class vDatetime:
|
|||
self.dt = dt
|
||||
self.params = Parameters()
|
||||
|
||||
def ical(self):
|
||||
def to_ical(self):
|
||||
if self.dt.tzinfo:
|
||||
utc_time = self.dt - self.dt.tzinfo.utcoffset(self.dt)
|
||||
return utc_time.strftime("%Y%m%dT%H%M%SZ")
|
||||
|
@ -335,8 +326,6 @@ class vDatetime:
|
|||
raise ValueError, 'Wrong datetime format: %s' % ical
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
def __str__(self):
|
||||
return self.ical()
|
||||
|
||||
|
||||
|
||||
|
@ -344,13 +333,13 @@ class vDate:
|
|||
"""
|
||||
Render and generates iCalendar date format.
|
||||
>>> d = date(2001, 1,1)
|
||||
>>> vDate(d).ical()
|
||||
>>> vDate(d).to_ical()
|
||||
'20010101'
|
||||
|
||||
>>> vDate.from_ical('20010102')
|
||||
datetime.date(2001, 1, 2)
|
||||
|
||||
>>> vDate('d').ical()
|
||||
>>> vDate('d').to_ical()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Value MUST be a date instance
|
||||
|
@ -362,7 +351,7 @@ class vDate:
|
|||
self.dt = dt
|
||||
self.params = Parameters(dict(value='DATE'))
|
||||
|
||||
def ical(self):
|
||||
def to_ical(self):
|
||||
return self.dt.strftime("%Y%m%d")
|
||||
|
||||
def from_ical(ical):
|
||||
|
@ -378,8 +367,6 @@ class vDate:
|
|||
raise ValueError, 'Wrong date format %s' % ical
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
def __str__(self):
|
||||
return self.ical()
|
||||
|
||||
|
||||
|
||||
|
@ -387,32 +374,32 @@ class vDuration:
|
|||
"""
|
||||
Subclass of timedelta that renders itself in the iCalendar DURATION format.
|
||||
|
||||
>>> vDuration(timedelta(11)).ical()
|
||||
>>> vDuration(timedelta(11)).to_ical()
|
||||
'P11D'
|
||||
>>> vDuration(timedelta(-14)).ical()
|
||||
>>> vDuration(timedelta(-14)).to_ical()
|
||||
'-P14D'
|
||||
>>> vDuration(timedelta(1, 7384)).ical()
|
||||
>>> vDuration(timedelta(1, 7384)).to_ical()
|
||||
'P1DT2H3M4S'
|
||||
>>> vDuration(timedelta(1, 7380)).ical()
|
||||
>>> vDuration(timedelta(1, 7380)).to_ical()
|
||||
'P1DT2H3M'
|
||||
>>> vDuration(timedelta(1, 7200)).ical()
|
||||
>>> vDuration(timedelta(1, 7200)).to_ical()
|
||||
'P1DT2H'
|
||||
>>> vDuration(timedelta(0, 7200)).ical()
|
||||
>>> vDuration(timedelta(0, 7200)).to_ical()
|
||||
'PT2H'
|
||||
>>> vDuration(timedelta(0, 7384)).ical()
|
||||
>>> vDuration(timedelta(0, 7384)).to_ical()
|
||||
'PT2H3M4S'
|
||||
>>> vDuration(timedelta(0, 184)).ical()
|
||||
>>> vDuration(timedelta(0, 184)).to_ical()
|
||||
'PT3M4S'
|
||||
>>> vDuration(timedelta(0, 22)).ical()
|
||||
>>> vDuration(timedelta(0, 22)).to_ical()
|
||||
'PT22S'
|
||||
>>> vDuration(timedelta(0, 3622)).ical()
|
||||
>>> vDuration(timedelta(0, 3622)).to_ical()
|
||||
'PT1H0M22S'
|
||||
|
||||
>>> vDuration(timedelta(days=1, hours=5)).ical()
|
||||
>>> vDuration(timedelta(days=1, hours=5)).to_ical()
|
||||
'P1DT5H'
|
||||
>>> vDuration(timedelta(hours=-5)).ical()
|
||||
>>> vDuration(timedelta(hours=-5)).to_ical()
|
||||
'-PT5H'
|
||||
>>> vDuration(timedelta(days=-1, hours=-5)).ical()
|
||||
>>> vDuration(timedelta(days=-1, hours=-5)).to_ical()
|
||||
'-P1DT5H'
|
||||
|
||||
How does the parsing work?
|
||||
|
@ -439,7 +426,7 @@ class vDuration:
|
|||
self.td = td
|
||||
self.params = Parameters()
|
||||
|
||||
def ical(self):
|
||||
def to_ical(self):
|
||||
sign = ""
|
||||
if self.td.days < 0:
|
||||
sign = "-"
|
||||
|
@ -482,8 +469,6 @@ class vDuration:
|
|||
raise ValueError('Invalid iCalendar duration: %s' % ical)
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
def __str__(self):
|
||||
return self.ical()
|
||||
|
||||
|
||||
|
||||
|
@ -491,11 +476,11 @@ class vFloat(float):
|
|||
"""
|
||||
Just a float.
|
||||
>>> f = vFloat(1.0)
|
||||
>>> f.ical()
|
||||
>>> f.to_ical()
|
||||
'1.0'
|
||||
>>> vFloat.from_ical('42')
|
||||
42.0
|
||||
>>> vFloat(42).ical()
|
||||
>>> vFloat(42).to_ical()
|
||||
'42.0'
|
||||
"""
|
||||
|
||||
|
@ -504,7 +489,7 @@ class vFloat(float):
|
|||
self.params = Parameters()
|
||||
return self
|
||||
|
||||
def ical(self):
|
||||
def to_ical(self):
|
||||
return str(self)
|
||||
|
||||
def from_ical(ical):
|
||||
|
@ -521,7 +506,7 @@ class vInt(int):
|
|||
"""
|
||||
Just an int.
|
||||
>>> f = vInt(42)
|
||||
>>> f.ical()
|
||||
>>> f.to_ical()
|
||||
'42'
|
||||
>>> vInt.from_ical('13')
|
||||
13
|
||||
|
@ -536,7 +521,7 @@ class vInt(int):
|
|||
self.params = Parameters()
|
||||
return self
|
||||
|
||||
def ical(self):
|
||||
def to_ical(self):
|
||||
return str(self)
|
||||
|
||||
def from_ical(ical):
|
||||
|
@ -593,14 +578,14 @@ class vDDDTypes:
|
|||
|
||||
self.dt = dt
|
||||
|
||||
def ical(self):
|
||||
def to_ical(self):
|
||||
dt = self.dt
|
||||
if isinstance(dt, datetime):
|
||||
return vDatetime(dt).ical()
|
||||
return vDatetime(dt).to_ical()
|
||||
elif isinstance(dt, date):
|
||||
return vDate(dt).ical()
|
||||
return vDate(dt).to_ical()
|
||||
elif isinstance(dt, timedelta):
|
||||
return vDuration(dt).ical()
|
||||
return vDuration(dt).to_ical()
|
||||
else:
|
||||
raise ValueError('Unknown date type')
|
||||
|
||||
|
@ -615,8 +600,6 @@ class vDDDTypes:
|
|||
return vDate.from_ical(ical)
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
def __str__(self):
|
||||
return self.ical()
|
||||
|
||||
|
||||
class vDDDLists:
|
||||
|
@ -671,11 +654,11 @@ class vDDDLists:
|
|||
vDDD.append(vDDDTypes(dt))
|
||||
self.dts = vDDD
|
||||
|
||||
def ical(self):
|
||||
def to_ical(self):
|
||||
'''
|
||||
Generates the text string in the iCalendar format.
|
||||
'''
|
||||
dts_ical = [dt.ical() for dt in self.dts]
|
||||
dts_ical = [dt.to_ical() for dt in self.dts]
|
||||
return ",".join(dts_ical)
|
||||
|
||||
def from_ical(ical):
|
||||
|
@ -690,8 +673,6 @@ class vDDDLists:
|
|||
return out
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
def __str__(self):
|
||||
return self.ical()
|
||||
|
||||
|
||||
class vPeriod:
|
||||
|
@ -777,7 +758,7 @@ class vPeriod:
|
|||
return True
|
||||
return False
|
||||
|
||||
def ical(self):
|
||||
def to_ical(self):
|
||||
if self.by_duration:
|
||||
return '%s/%s' % (vDatetime(self.start).ical(), vDuration(self.duration).ical())
|
||||
return '%s/%s' % (vDatetime(self.start).ical(), vDatetime(self.end).ical())
|
||||
|
@ -793,8 +774,6 @@ class vPeriod:
|
|||
raise ValueError, 'Expected period format, got: %s' % ical
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
def __str__(self):
|
||||
return self.ical()
|
||||
|
||||
def __repr__(self):
|
||||
if self.by_duration:
|
||||
|
@ -807,7 +786,7 @@ class vWeekday(str):
|
|||
"""
|
||||
This returns an unquoted weekday abbrevation
|
||||
>>> a = vWeekday('mo')
|
||||
>>> a.ical()
|
||||
>>> a.to_ical()
|
||||
'MO'
|
||||
|
||||
>>> a = vWeekday('erwer')
|
||||
|
@ -827,15 +806,15 @@ class vWeekday(str):
|
|||
ValueError: Expected weekday abbrevation, got: Saturday
|
||||
|
||||
>>> a = vWeekday('+mo')
|
||||
>>> a.ical()
|
||||
>>> a.to_ical()
|
||||
'+MO'
|
||||
|
||||
>>> a = vWeekday('+3mo')
|
||||
>>> a.ical()
|
||||
>>> a.to_ical()
|
||||
'+3MO'
|
||||
|
||||
>>> a = vWeekday('-tu')
|
||||
>>> a.ical()
|
||||
>>> a.to_ical()
|
||||
'-TU'
|
||||
"""
|
||||
|
||||
|
@ -857,7 +836,7 @@ class vWeekday(str):
|
|||
self.params = Parameters()
|
||||
return self
|
||||
|
||||
def ical(self):
|
||||
def to_ical(self):
|
||||
return self.upper()
|
||||
|
||||
def from_ical(ical):
|
||||
|
@ -868,8 +847,6 @@ class vWeekday(str):
|
|||
raise ValueError, 'Expected weekday abbrevation, got: %s' % ical
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
def __str__(self):
|
||||
return self.ical()
|
||||
|
||||
|
||||
|
||||
|
@ -880,7 +857,7 @@ class vFrequency(str):
|
|||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Expected frequency, got: BAD TEST
|
||||
>>> vFrequency('daily').ical()
|
||||
>>> vFrequency('daily').to_ical()
|
||||
'DAILY'
|
||||
>>> vFrequency('daily').from_ical('MONTHLY')
|
||||
'MONTHLY'
|
||||
|
@ -903,7 +880,7 @@ class vFrequency(str):
|
|||
self.params = Parameters()
|
||||
return self
|
||||
|
||||
def ical(self):
|
||||
def to_ical(self):
|
||||
return self.upper()
|
||||
|
||||
def from_ical(ical):
|
||||
|
@ -914,8 +891,6 @@ class vFrequency(str):
|
|||
raise ValueError, 'Expected weekday abbrevation, got: %s' % ical
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
def __str__(self):
|
||||
return self.ical()
|
||||
|
||||
|
||||
|
||||
|
@ -930,7 +905,7 @@ class vRecur(CaselessDict):
|
|||
>>> r['byhour'] = [8,9]
|
||||
>>> r['byminute'] = 30
|
||||
>>> r = vRecur(r)
|
||||
>>> r.ical()
|
||||
>>> r.to_ical()
|
||||
'FREQ=YEARLY;INTERVAL=2;BYMINUTE=30;BYHOUR=8,9;BYDAY=SU;BYMONTH=1'
|
||||
|
||||
>>> r = vRecur(FREQ='yearly', INTERVAL=2)
|
||||
|
@ -938,39 +913,39 @@ class vRecur(CaselessDict):
|
|||
>>> r['BYDAY'] = 'su'
|
||||
>>> r['BYHOUR'] = [8,9]
|
||||
>>> r['BYMINUTE'] = 30
|
||||
>>> r.ical()
|
||||
>>> r.to_ical()
|
||||
'FREQ=YEARLY;INTERVAL=2;BYMINUTE=30;BYHOUR=8,9;BYDAY=SU;BYMONTH=1'
|
||||
|
||||
>>> r = vRecur(freq='DAILY', count=10)
|
||||
>>> r['bysecond'] = [0, 15, 30, 45]
|
||||
>>> r.ical()
|
||||
>>> r.to_ical()
|
||||
'FREQ=DAILY;COUNT=10;BYSECOND=0,15,30,45'
|
||||
|
||||
>>> r = vRecur(freq='DAILY', until=datetime(2005,1,1,12,0,0))
|
||||
>>> r.ical()
|
||||
>>> r.to_ical()
|
||||
'FREQ=DAILY;UNTIL=20050101T120000'
|
||||
|
||||
How do we fare with regards to parsing?
|
||||
>>> r = vRecur.from_ical('FREQ=DAILY;INTERVAL=2;COUNT=10')
|
||||
>>> r
|
||||
{'COUNT': [10], 'FREQ': ['DAILY'], 'INTERVAL': [2]}
|
||||
>>> vRecur(r).ical()
|
||||
>>> vRecur(r).to_ical()
|
||||
'FREQ=DAILY;COUNT=10;INTERVAL=2'
|
||||
|
||||
>>> r = vRecur.from_ical('FREQ=YEARLY;INTERVAL=2;BYMONTH=1;BYDAY=-SU;BYHOUR=8,9;BYMINUTE=30')
|
||||
>>> r
|
||||
{'BYHOUR': [8, 9], 'BYDAY': ['-SU'], 'BYMINUTE': [30], 'BYMONTH': [1], 'FREQ': ['YEARLY'], 'INTERVAL': [2]}
|
||||
>>> vRecur(r).ical()
|
||||
>>> vRecur(r).to_ical()
|
||||
'FREQ=YEARLY;INTERVAL=2;BYMINUTE=30;BYHOUR=8,9;BYDAY=-SU;BYMONTH=1'
|
||||
|
||||
Some examples from the spec
|
||||
|
||||
>>> r = vRecur.from_ical('FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1')
|
||||
>>> vRecur(r).ical()
|
||||
>>> vRecur(r).to_ical()
|
||||
'FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1'
|
||||
|
||||
>>> r = vRecur.from_ical('FREQ=YEARLY;INTERVAL=2;BYMONTH=1;BYDAY=SU;BYHOUR=8,9;BYMINUTE=30')
|
||||
>>> vRecur(r).ical()
|
||||
>>> vRecur(r).to_ical()
|
||||
'FREQ=YEARLY;INTERVAL=2;BYMINUTE=30;BYHOUR=8,9;BYDAY=SU;BYMONTH=1'
|
||||
|
||||
and some errors
|
||||
|
@ -1008,14 +983,14 @@ class vRecur(CaselessDict):
|
|||
CaselessDict.__init__(self, *args, **kwargs)
|
||||
self.params = Parameters()
|
||||
|
||||
def ical(self):
|
||||
def to_ical(self):
|
||||
# SequenceTypes
|
||||
result = []
|
||||
for key, vals in self.sorted_items():
|
||||
typ = self.types[key]
|
||||
if not type(vals) in SequenceTypes:
|
||||
vals = [vals]
|
||||
vals = ','.join([typ(val).ical() for val in vals])
|
||||
vals = ','.join([typ(val).to_ical() for val in vals])
|
||||
result.append('%s=%s' % (key, vals))
|
||||
return ';'.join(result)
|
||||
|
||||
|
@ -1042,37 +1017,34 @@ class vRecur(CaselessDict):
|
|||
raise ValueError, 'Error in recurrence rule: %s' % ical
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
def __str__(self):
|
||||
return self.ical()
|
||||
|
||||
|
||||
|
||||
class vText(unicode):
|
||||
"""
|
||||
Simple text
|
||||
>>> t = vText(u'Simple text')
|
||||
>>> t.ical()
|
||||
>>> t.to_ical()
|
||||
'Simple text'
|
||||
|
||||
Escaped text
|
||||
>>> t = vText('Text ; with escaped, chars')
|
||||
>>> t.ical()
|
||||
>>> t.to_ical()
|
||||
'Text \\\\; with escaped\\\\, chars'
|
||||
|
||||
Escaped newlines
|
||||
>>> vText('Text with escaped\N chars').ical()
|
||||
>>> vText('Text with escaped\N chars').to_ical()
|
||||
'Text with escaped\\\\n chars'
|
||||
|
||||
If you pass a unicode object, it will be utf-8 encoded. As this is the
|
||||
(only) standard that RFC 2445 support.
|
||||
|
||||
>>> t = vText(u'international chars æøå ÆØÅ ü')
|
||||
>>> t.ical()
|
||||
>>> t.to_ical()
|
||||
'international chars \\xc3\\xa6\\xc3\\xb8\\xc3\\xa5 \\xc3\\x86\\xc3\\x98\\xc3\\x85 \\xc3\\xbc'
|
||||
|
||||
Unicode is converted to utf-8
|
||||
>>> t = vText(u'international æ ø å')
|
||||
>>> str(t)
|
||||
>>> t.to_ical()
|
||||
'international \\xc3\\xa6 \\xc3\\xb8 \\xc3\\xa5'
|
||||
|
||||
and parsing?
|
||||
|
@ -1115,7 +1087,7 @@ class vText(unicode):
|
|||
def __repr__(self):
|
||||
return u"vText(%s)" % unicode.__repr__(self)
|
||||
|
||||
def ical(self):
|
||||
def to_ical(self):
|
||||
return self.escape().encode(self.encoding)
|
||||
|
||||
def from_ical(ical):
|
||||
|
@ -1132,8 +1104,6 @@ class vText(unicode):
|
|||
raise ValueError, 'Expected ical text, got: %s' % ical
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
def __str__(self):
|
||||
return self.ical()
|
||||
|
||||
|
||||
|
||||
|
@ -1142,7 +1112,7 @@ class vTime(time):
|
|||
A subclass of datetime, that renders itself in the iCalendar time
|
||||
format.
|
||||
>>> dt = vTime(12, 30, 0)
|
||||
>>> dt.ical()
|
||||
>>> dt.to_ical()
|
||||
'123000'
|
||||
|
||||
>>> vTime.from_ical('123000')
|
||||
|
@ -1160,7 +1130,7 @@ class vTime(time):
|
|||
self.params = Parameters()
|
||||
return self
|
||||
|
||||
def ical(self):
|
||||
def to_ical(self):
|
||||
return self.strftime("%H%M%S")
|
||||
|
||||
def from_ical(ical):
|
||||
|
@ -1172,8 +1142,6 @@ class vTime(time):
|
|||
raise ValueError, 'Expected time, got: %s' % ical
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
def __str__(self):
|
||||
return self.ical()
|
||||
|
||||
|
||||
|
||||
|
@ -1181,7 +1149,7 @@ class vUri(str):
|
|||
"""
|
||||
Uniform resource identifier is basically just an unquoted string.
|
||||
>>> u = vUri('http://www.example.com/')
|
||||
>>> u.ical()
|
||||
>>> u.to_ical()
|
||||
'http://www.example.com/'
|
||||
>>> vUri.from_ical('http://www.example.com/') # doh!
|
||||
'http://www.example.com/'
|
||||
|
@ -1192,7 +1160,7 @@ class vUri(str):
|
|||
self.params = Parameters()
|
||||
return self
|
||||
|
||||
def ical(self):
|
||||
def to_ical(self):
|
||||
return str(self)
|
||||
|
||||
def from_ical(ical):
|
||||
|
@ -1203,8 +1171,6 @@ class vUri(str):
|
|||
raise ValueError, 'Expected , got: %s' % ical
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
def __str__(self):
|
||||
return str.__str__(self)
|
||||
|
||||
|
||||
|
||||
|
@ -1213,17 +1179,17 @@ class vGeo:
|
|||
A special type that is only indirectly defined in the rfc.
|
||||
|
||||
>>> g = vGeo((1.2, 3.0))
|
||||
>>> g.ical()
|
||||
>>> g.to_ical()
|
||||
'1.2;3.0'
|
||||
|
||||
>>> g = vGeo.from_ical('37.386013;-122.082932')
|
||||
>>> g == (float('37.386013'), float('-122.082932'))
|
||||
True
|
||||
|
||||
>>> vGeo(g).ical()
|
||||
>>> vGeo(g).to_ical()
|
||||
'37.386013;-122.082932'
|
||||
|
||||
>>> vGeo('g').ical()
|
||||
>>> vGeo('g').to_ical()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Input must be (float, float) for latitude and longitude
|
||||
|
@ -1240,7 +1206,7 @@ class vGeo:
|
|||
self.longitude = longitude
|
||||
self.params = Parameters()
|
||||
|
||||
def ical(self):
|
||||
def to_ical(self):
|
||||
return '%s;%s' % (self.latitude, self.longitude)
|
||||
|
||||
def from_ical(ical):
|
||||
|
@ -1252,8 +1218,6 @@ class vGeo:
|
|||
raise ValueError, "Expected 'float;float' , got: %s" % ical
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
def __str__(self):
|
||||
return self.ical()
|
||||
|
||||
|
||||
|
||||
|
@ -1262,27 +1226,27 @@ class vUTCOffset:
|
|||
Renders itself as a utc offset
|
||||
|
||||
>>> u = vUTCOffset(timedelta(hours=2))
|
||||
>>> u.ical()
|
||||
>>> u.to_ical()
|
||||
'+0200'
|
||||
|
||||
>>> u = vUTCOffset(timedelta(hours=-5))
|
||||
>>> u.ical()
|
||||
>>> u.to_ical()
|
||||
'-0500'
|
||||
|
||||
>>> u = vUTCOffset(timedelta())
|
||||
>>> u.ical()
|
||||
>>> u.to_ical()
|
||||
'+0000'
|
||||
|
||||
>>> u = vUTCOffset(timedelta(minutes=-30))
|
||||
>>> u.ical()
|
||||
>>> u.to_ical()
|
||||
'-0030'
|
||||
|
||||
>>> u = vUTCOffset(timedelta(hours=2, minutes=-30))
|
||||
>>> u.ical()
|
||||
->>> u = vUTCOffset(timedelta(hours=2, minutes=-30))
|
||||
>>> u.to_ical()
|
||||
'+0130'
|
||||
|
||||
>>> u = vUTCOffset(timedelta(hours=1, minutes=30))
|
||||
>>> u.ical()
|
||||
>>> u.to_ical()
|
||||
'+0130'
|
||||
|
||||
Parsing
|
||||
|
@ -1297,7 +1261,7 @@ class vUTCOffset:
|
|||
datetime.timedelta(0, 7200)
|
||||
|
||||
>>> o = vUTCOffset.from_ical('+0230')
|
||||
>>> vUTCOffset(o).ical()
|
||||
>>> vUTCOffset(o).to_ical()
|
||||
'+0230'
|
||||
|
||||
And a few failures
|
||||
|
@ -1318,7 +1282,7 @@ class vUTCOffset:
|
|||
self.td = td
|
||||
self.params = Parameters()
|
||||
|
||||
def ical(self):
|
||||
def to_ical(self):
|
||||
td = self.td
|
||||
day_in_minutes = (td.days * 24 * 60)
|
||||
seconds_in_minutes = td.seconds // 60
|
||||
|
@ -1348,8 +1312,6 @@ class vUTCOffset:
|
|||
return offset
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
def __str__(self):
|
||||
return self.ical()
|
||||
|
||||
|
||||
|
||||
|
@ -1376,15 +1338,13 @@ class vInline(str):
|
|||
self.obj = obj
|
||||
self.params = Parameters()
|
||||
|
||||
def ical(self):
|
||||
def to_ical(self):
|
||||
return str(self)
|
||||
|
||||
def from_ical(ical):
|
||||
return str(ical)
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.obj)
|
||||
|
||||
|
||||
class TypesFactory(CaselessDict):
|
||||
|
@ -1394,7 +1354,7 @@ class TypesFactory(CaselessDict):
|
|||
>>> factory = TypesFactory()
|
||||
>>> datetime_parser = factory['date-time']
|
||||
>>> dt = datetime_parser(datetime(2001, 1, 1))
|
||||
>>> dt.ical()
|
||||
>>> dt.to_ical()
|
||||
'20010101T000000'
|
||||
|
||||
A typical use is when the parser tries to find a content type and use text
|
||||
|
@ -1406,12 +1366,12 @@ class TypesFactory(CaselessDict):
|
|||
datetime.datetime(2005, 1, 1, 12, 30)
|
||||
|
||||
It can also be used to directly encode property and parameter values
|
||||
>>> comment = factory.ical('comment', u'by Rasmussen, Max Møller')
|
||||
>>> comment = factory.to_ical('comment', u'by Rasmussen, Max Møller')
|
||||
>>> str(comment)
|
||||
'by Rasmussen\\\\, Max M\\xc3\\xb8ller'
|
||||
>>> factory.ical('priority', 1)
|
||||
>>> factory.to_ical('priority', 1)
|
||||
'1'
|
||||
>>> factory.ical('cn', u'Rasmussen, Max Møller')
|
||||
>>> factory.to_ical('cn', u'Rasmussen, Max Møller')
|
||||
'Rasmussen\\\\, Max M\\xc3\\xb8ller'
|
||||
|
||||
>>> factory.from_ical('cn', 'Rasmussen\\\\, Max M\\xc3\\xb8ller')
|
||||
|
@ -1535,13 +1495,13 @@ class TypesFactory(CaselessDict):
|
|||
"Returns a the default type for a property or parameter"
|
||||
return self[self.types_map.get(name, 'text')]
|
||||
|
||||
def ical(self, name, value):
|
||||
def to_ical(self, name, value):
|
||||
"""
|
||||
Encodes a named value from a primitive python type to an
|
||||
icalendar encoded string.
|
||||
"""
|
||||
type_class = self.for_property(name)
|
||||
return type_class(value).ical()
|
||||
return type_class(value).to_ical()
|
||||
|
||||
def from_ical(self, name, value):
|
||||
"""
|
||||
|
|
|
@ -79,13 +79,9 @@ you do it like this. The calendar is a component::
|
|||
('DTSTART', '20050404T080000')
|
||||
('SUMMARY', 'Python meeting about calendaring')
|
||||
|
||||
You can generate a string for a file with the as_string() method. (Calling
|
||||
str(cal) does the same)::
|
||||
You can generate a string for a file with the to_ical() method::
|
||||
|
||||
>>> cal.as_string()
|
||||
'BEGIN:VCALENDAR\r\nDTSTART:20050404T080000\r\nSUMMARY:Python meeting about calendaring\r\nEND:VCALENDAR\r\n'
|
||||
|
||||
>>> str(cal)
|
||||
>>> cal.to_ical()
|
||||
'BEGIN:VCALENDAR\r\nDTSTART:20050404T080000\r\nSUMMARY:Python meeting about calendaring\r\nEND:VCALENDAR\r\n'
|
||||
|
||||
The rendered view is easier to read::
|
||||
|
@ -95,10 +91,10 @@ The rendered view is easier to read::
|
|||
SUMMARY:Python meeting about calendaring
|
||||
END:VCALENDAR
|
||||
|
||||
So, let's define a function so we can easily display to_string() output::
|
||||
So, let's define a function so we can easily display to_ical() output::
|
||||
|
||||
>>> def display(cal):
|
||||
... return cal.as_string().replace('\r\n', '\n').strip()
|
||||
... return cal.to_ical().replace('\r\n', '\n').strip()
|
||||
|
||||
You can set multiple properties like this::
|
||||
|
||||
|
@ -177,7 +173,7 @@ type defined in the spec::
|
|||
|
||||
>>> from datetime import datetime
|
||||
>>> cal.add('dtstart', datetime(2005,4,4,8,0,0))
|
||||
>>> str(cal['dtstart'])
|
||||
>>> cal['dtstart'].to_ical()
|
||||
'20050404T080000'
|
||||
|
||||
If that doesn't work satisfactorily for some reason, you can also do it
|
||||
|
@ -190,11 +186,11 @@ So if you want to do it manually::
|
|||
|
||||
>>> from icalendar import vDatetime
|
||||
>>> now = datetime(2005,4,4,8,0,0)
|
||||
>>> vDatetime(now).ical()
|
||||
>>> vDatetime(now).to_ical()
|
||||
'20050404T080000'
|
||||
|
||||
So the drill is to initialise the object with a python built in type,
|
||||
and then call the "ical()" method on the object. That will return an
|
||||
and then call the "to_ical()" method on the object. That will return an
|
||||
ical encoded string.
|
||||
|
||||
You can do it the other way around too. To parse an encoded string, just call
|
||||
|
@ -213,7 +209,7 @@ value directly::
|
|||
|
||||
>>> cal = Calendar()
|
||||
>>> cal.add('dtstart', datetime(2005,4,4,8,0,0))
|
||||
>>> str(cal['dtstart'])
|
||||
>>> cal['dtstart'].to_ical()
|
||||
'20050404T080000'
|
||||
>>> cal.decoded('dtstart')
|
||||
datetime.datetime(2005, 4, 4, 8, 0)
|
||||
|
@ -279,7 +275,7 @@ Write to disk::
|
|||
>>> import tempfile, os
|
||||
>>> directory = tempfile.mkdtemp()
|
||||
>>> f = open(os.path.join(directory, 'example.ics'), 'wb')
|
||||
>>> f.write(cal.as_string())
|
||||
>>> f.write(cal.to_ical())
|
||||
>>> f.close()
|
||||
|
||||
XXX We should check whether the write succeeded here..
|
||||
|
|
|
@ -3,7 +3,7 @@ An example from the RFC 2445 spec::
|
|||
>>> from icalendar import Calendar
|
||||
>>> import os
|
||||
>>> directory = os.path.dirname(__file__)
|
||||
>>> cal = Calendar.from_string(
|
||||
>>> cal = Calendar.from_ical(
|
||||
... open(os.path.join(directory, 'groupscheduled.ics'),'rb').read())
|
||||
>>> cal
|
||||
VCALENDAR({'VERSION': vText(u'2.0'), 'PRODID': vText(u'-//RDU Software//NONSGML HandCal//EN')})
|
||||
|
|
|
@ -3,7 +3,7 @@ A exmaple with multiple VCALENDAR components::
|
|||
>>> from icalendar import Calendar
|
||||
>>> import os
|
||||
>>> directory = os.path.dirname(__file__)
|
||||
>>> cals = Calendar.from_string(
|
||||
>>> cals = Calendar.from_ical(
|
||||
... open(os.path.join(directory, 'multiple.ics'),'rb').read(), multiple=True)
|
||||
|
||||
>>> for cal in cals:
|
||||
|
|
|
@ -3,7 +3,7 @@ Testing recurrence.
|
|||
>>> from icalendar import Calendar
|
||||
>>> import os
|
||||
>>> directory = os.path.dirname(__file__)
|
||||
>>> cal = Calendar.from_string(
|
||||
>>> cal = Calendar.from_ical(
|
||||
... open(os.path.join(directory, 'recurrence.ics'),'rb').read())
|
||||
>>> first_event = cal.walk('vevent')[0]
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ A small example::
|
|||
>>> from icalendar import Calendar
|
||||
>>> import os
|
||||
>>> directory = os.path.dirname(__file__)
|
||||
>>> cal = Calendar.from_string(
|
||||
>>> cal = Calendar.from_ical(
|
||||
... open(os.path.join(directory, 'small.ics'),'rb').read())
|
||||
>>> cal
|
||||
VCALENDAR({'VERSION': vText(u'2.0'), 'METHOD': vText(u'Request'), 'PRODID': vText(u'-//My product//mxm.dk/')})
|
||||
|
|
|
@ -6,14 +6,14 @@ class FuckYouTests(unittest.TestCase):
|
|||
from icalendar import Calendar
|
||||
c = Calendar()
|
||||
c['description']=u'Paragraph one\n\nParagraph two'
|
||||
output = c.as_string()
|
||||
output = c.to_ical()
|
||||
self.assertEqual(output,
|
||||
"BEGIN:VCALENDAR\r\nDESCRIPTION:Paragraph one\r\n \r\n Paragraph two\r\nEND:VCALENDAR\r\n")
|
||||
|
||||
def XtestTrailingNewline(self):
|
||||
from icalendar.parser import Contentlines, Contentline
|
||||
c = Contentlines([Contentline('BEGIN:VEVENT\\r\\n')])
|
||||
output = str(c)
|
||||
output = c.to_ical()
|
||||
self.assertEqual(output, 'BEGIN:VEVENT\\r\\n')
|
||||
|
||||
def XtestLongLine(self):
|
||||
|
@ -21,7 +21,7 @@ class FuckYouTests(unittest.TestCase):
|
|||
c = Contentlines([Contentline('BEGIN:VEVENT\\r\\n')])
|
||||
c.append(Contentline(''.join(['123456789 ']*10)+'\\r\\n'))
|
||||
import pdb ; pdb.set_trace()
|
||||
output = str(c)
|
||||
output = c.to_ical()
|
||||
self.assertEqual(output,
|
||||
"BEGIN:VEVENT\\r\\n\\r\\n123456789 123456789 123456789 123456789 123456789 123456789 123456789 1234\\r\\n 56789 123456789 123456789 \\r\\n")
|
||||
|
||||
|
@ -29,7 +29,7 @@ class FuckYouTests(unittest.TestCase):
|
|||
from icalendar.parser import Contentlines, Contentline
|
||||
c = Contentlines([Contentline('BEGIN:VEVENT\r\n')])
|
||||
c.append(Contentline(''.join(['123456789 ']*10)+'\r\n'))
|
||||
output = str(c)
|
||||
output = c.to_ical()
|
||||
self.assertEqual(output,
|
||||
'BEGIN:VEVENT\r\n\r\n123456789 123456789 123456789 123456789 123456789 123456789 123456789 1234\r\n 56789 123456789 123456789 \r\n')
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue