kopia lustrzana https://github.com/collective/icalendar
endure correct datatype at instance creation time in ``prop.vCalAddress`` and ``prop.vText``. Re-include doctests.
rodzic
20c525eaea
commit
4f5f70bd5b
|
|
@ -16,6 +16,7 @@ with Python.
|
|||
|
||||
----
|
||||
|
||||
|
||||
Changes in version 3.0
|
||||
======================
|
||||
|
||||
|
|
@ -46,7 +47,6 @@ which are not defined in the Olson database.
|
|||
Instead of the own UTC tzinfo implementation we use pytz UTC tzinfo object now.
|
||||
|
||||
|
||||
|
||||
About this fork which is not a fork anymore
|
||||
===========================================
|
||||
|
||||
|
|
@ -66,4 +66,3 @@ a suggestion to icalendar-dev@codespeak.net to take over mainaining of
|
|||
.. _`setuptools`: http://pypi.python.org/pypi/setuptools
|
||||
.. _`RFC`: http://www.ietf.org/rfc/rfc5545.txt
|
||||
.. _`BSD`: https://github.com/collective/icalendar/issues/2
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,4 @@ At the time of writing this, last version was released more then 2 years ago.
|
|||
Since then many things have changes. For one, `RFC 2445`_ was updated by `RFC
|
||||
5545`_ which makes this package. So in some sense this package became outdated.
|
||||
|
||||
|
||||
|
||||
|
||||
.. _`Max M`: http://www.mxm.dk
|
||||
|
|
|
|||
|
|
@ -1,9 +1,15 @@
|
|||
Changelog
|
||||
=========
|
||||
|
||||
3.1dev
|
||||
------
|
||||
|
||||
3.1 (unreleased)
|
||||
----------------
|
||||
* Re-include doctests.
|
||||
[rnix]
|
||||
|
||||
* endure correct datatype at instance creation time in ``prop.vCalAddress``
|
||||
and ``prop.vText``.
|
||||
[rnix]
|
||||
|
||||
* Apply TZID parameter to datetimes parsed from RECURRENCE-ID
|
||||
[dbstovall]
|
||||
|
|
@ -37,6 +43,7 @@ Changelog
|
|||
* All unit tests fixed.
|
||||
[mikaelfrykholm]
|
||||
|
||||
|
||||
3.0.1b2 (2012-03-01)
|
||||
--------------------
|
||||
|
||||
|
|
@ -53,12 +60,14 @@ Changelog
|
|||
library instead of own implementation.
|
||||
[thet]
|
||||
|
||||
|
||||
3.0.1b1 (2012-02-24)
|
||||
------------------
|
||||
--------------------
|
||||
|
||||
* Update Release information.
|
||||
[thet]
|
||||
|
||||
|
||||
3.0
|
||||
---
|
||||
|
||||
|
|
@ -75,6 +84,7 @@ Changelog
|
|||
Old: from_string.
|
||||
[thet]
|
||||
|
||||
|
||||
2.2 (2011-08-24)
|
||||
----------------
|
||||
|
||||
|
|
|
|||
|
|
@ -11,4 +11,10 @@ iCalendar contributors
|
|||
|
||||
- Olivier Grisel (ogrisel@nuxeo.com)
|
||||
|
||||
- Michael Smith <msmith@fluendo.com>
|
||||
- Michael Smith (msmith@fluendo.com)
|
||||
|
||||
- Hannes Raggam (johannes@raggam.co.at)
|
||||
|
||||
- Rok Garbas (rok@garbas.si)
|
||||
|
||||
- Robert Niederreiter (rnix@squarewave.at)
|
||||
|
|
|
|||
2
setup.py
2
setup.py
|
|
@ -1,7 +1,7 @@
|
|||
import os
|
||||
import setuptools
|
||||
|
||||
version = '3.1'
|
||||
version = '3.1dev'
|
||||
|
||||
setuptools.setup(
|
||||
name='icalendar',
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2012, Plone Foundation
|
||||
# All rights reserved.
|
||||
#
|
||||
|
|
@ -26,26 +25,31 @@
|
|||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""
|
||||
|
||||
Calendar is a dictionary like Python object that can render itself as VCAL
|
||||
files according to rfc2445.
|
||||
|
||||
These are the defined components.
|
||||
|
||||
"""
|
||||
|
||||
import pytz
|
||||
from datetime import datetime
|
||||
|
||||
# from python
|
||||
from types import ListType, TupleType
|
||||
SequenceTypes = (ListType, TupleType)
|
||||
|
||||
# from this package
|
||||
from icalendar.caselessdict import CaselessDict
|
||||
from icalendar.parser import Contentlines, Contentline, Parameters
|
||||
from icalendar.parser import q_split, q_join
|
||||
from icalendar.prop import TypesFactory, vText
|
||||
from icalendar.parser import (
|
||||
Contentlines,
|
||||
Contentline,
|
||||
Parameters,
|
||||
)
|
||||
from icalendar.parser import (
|
||||
q_split,
|
||||
q_join,
|
||||
)
|
||||
from icalendar.prop import (
|
||||
TypesFactory,
|
||||
vText,
|
||||
)
|
||||
|
||||
SequenceTypes = (ListType, TupleType)
|
||||
|
||||
|
||||
######################################
|
||||
|
|
@ -232,7 +236,6 @@ class Component(CaselessDict):
|
|||
self.subcomponents = [] # Components can be nested.
|
||||
self.is_broken = False # True iff we ignored an exception while parsing a property
|
||||
|
||||
|
||||
# def non_complience(self, warnings=0):
|
||||
# """
|
||||
# not implemented yet!
|
||||
|
|
@ -248,22 +251,17 @@ class Component(CaselessDict):
|
|||
# nc['name'] = {'type':'ERROR', 'description':'Name is not defined'}
|
||||
# return nc
|
||||
|
||||
|
||||
#############################
|
||||
# handling of property values
|
||||
|
||||
def _encode(self, name, value, cond=1):
|
||||
""" Conditional convertion of values.
|
||||
|
||||
"""Conditional convertion of values.
|
||||
"""
|
||||
|
||||
if cond:
|
||||
klass = types_factory.for_property(name)
|
||||
return klass(value)
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def set(self, name, value, encode=1):
|
||||
if type(value) == ListType:
|
||||
self[name] = [self._encode(name, v, encode) for v in value]
|
||||
|
|
@ -318,14 +316,12 @@ class Component(CaselessDict):
|
|||
# set the timezone as a parameter to the property
|
||||
tzid = value.tzinfo.zone
|
||||
self[name].params.update({'TZID': tzid})
|
||||
|
||||
|
||||
|
||||
def _decode(self, name, value):
|
||||
# internal for decoding property values
|
||||
decoded = types_factory.from_ical(name, value)
|
||||
return decoded
|
||||
|
||||
|
||||
|
||||
def decoded(self, name, default=_marker):
|
||||
"Returns decoded value of property"
|
||||
if name in self:
|
||||
|
|
@ -339,7 +335,6 @@ class Component(CaselessDict):
|
|||
else:
|
||||
return default
|
||||
|
||||
|
||||
########################################################################
|
||||
# Inline values. A few properties have multiple values inlined in in one
|
||||
# property line. These methods are used for splitting and joining these.
|
||||
|
|
@ -354,7 +349,6 @@ class Component(CaselessDict):
|
|||
return [self._decode(name, val) for val in vals]
|
||||
return vals
|
||||
|
||||
|
||||
def set_inline(self, name, values, encode=1):
|
||||
"""
|
||||
Converts a list of values into comma seperated string and sets value to
|
||||
|
|
@ -365,7 +359,6 @@ class Component(CaselessDict):
|
|||
joined = q_join(values).encode(vText.encoding)
|
||||
self[name] = types_factory['inline'](joined)
|
||||
|
||||
|
||||
#########################
|
||||
# Handling of components
|
||||
|
||||
|
|
@ -373,7 +366,6 @@ class Component(CaselessDict):
|
|||
"add a subcomponent to this component"
|
||||
self.subcomponents.append(component)
|
||||
|
||||
|
||||
def _walk(self, name):
|
||||
# private!
|
||||
result = []
|
||||
|
|
@ -383,7 +375,6 @@ class Component(CaselessDict):
|
|||
result += subcomponent._walk(name)
|
||||
return result
|
||||
|
||||
|
||||
def walk(self, name=None):
|
||||
"""
|
||||
Recursively traverses component and subcomponents. Returns sequence of
|
||||
|
|
@ -419,7 +410,6 @@ class Component(CaselessDict):
|
|||
properties.append(('END', vText(self.name).to_ical()))
|
||||
return properties
|
||||
|
||||
|
||||
def from_ical(st, multiple=False):
|
||||
"""
|
||||
Populates the component recursively from a string
|
||||
|
|
@ -490,7 +480,6 @@ class Component(CaselessDict):
|
|||
return comps[0]
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return '%s(' % self.name + dict.__repr__(self) + ')'
|
||||
|
||||
|
|
@ -509,16 +498,13 @@ class Component(CaselessDict):
|
|||
contentlines.append('') # remember the empty string in the end
|
||||
return contentlines
|
||||
|
||||
|
||||
def to_ical(self):
|
||||
return self.content_lines().to_ical()
|
||||
|
||||
|
||||
|
||||
#######################################
|
||||
# components defined in RFC 2445
|
||||
|
||||
|
||||
class Event(Component):
|
||||
|
||||
name = 'VEVENT'
|
||||
|
|
@ -561,7 +547,6 @@ class Todo(Component):
|
|||
)
|
||||
|
||||
|
||||
|
||||
class Journal(Component):
|
||||
|
||||
name = 'VJOURNAL'
|
||||
|
|
@ -671,7 +656,6 @@ class Calendar(Component):
|
|||
singletons = ('prodid', 'version', )
|
||||
multiple = ('calscale', 'method', )
|
||||
|
||||
|
||||
# These are read only singleton, so one instance is enough for the module
|
||||
types_factory = TypesFactory()
|
||||
component_factory = ComponentFactory()
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2012, Plone Foundation
|
||||
# All rights reserved.
|
||||
#
|
||||
|
|
@ -26,7 +25,6 @@
|
|||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""
|
||||
|
||||
This module contains the parser/generators (or coders/encoders if you prefer)
|
||||
for the classes/datatypes that are used in iCalendar:
|
||||
|
||||
|
|
@ -46,7 +44,6 @@ 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.to_ical() on them, Will render them as defined
|
||||
in rfc2445.
|
||||
|
|
@ -63,23 +60,26 @@ primitive Python datatype. So it should allways be true that:
|
|||
|
||||
These types are mainly used for parsing and file generation. But you can set
|
||||
them directly.
|
||||
|
||||
"""
|
||||
|
||||
import pytz
|
||||
|
||||
# from python >= 2.3
|
||||
from datetime import datetime, timedelta, time, date, tzinfo
|
||||
from types import TupleType, ListType
|
||||
SequenceTypes = [TupleType, ListType]
|
||||
import re
|
||||
import time as _time
|
||||
import binascii
|
||||
|
||||
# from this package
|
||||
from datetime import (
|
||||
datetime,
|
||||
timedelta,
|
||||
time,
|
||||
date,
|
||||
tzinfo,
|
||||
)
|
||||
from types import TupleType, ListType
|
||||
from icalendar.caselessdict import CaselessDict
|
||||
from icalendar.parser import Parameters
|
||||
|
||||
|
||||
SequenceTypes = [TupleType, ListType]
|
||||
|
||||
DATE_PART = r'(\d+)D'
|
||||
TIME_PART = r'T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?'
|
||||
DATETIME_PART = '(?:%s)?(?:%s)?' % (DATE_PART, TIME_PART)
|
||||
|
|
@ -89,8 +89,9 @@ DURATION_REGEX = re.compile(r'([-+]?)P(?:%s|%s)$'
|
|||
WEEKDAY_RULE = re.compile('(?P<signal>[+-]?)(?P<relative>[\d]?)'
|
||||
'(?P<weekday>[\w]{2})$')
|
||||
|
||||
|
||||
class vBinary:
|
||||
""" Binary property values are base 64 encoded.
|
||||
"""Binary property values are base 64 encoded.
|
||||
|
||||
>>> b = vBinary('This is gibberish')
|
||||
>>> b.to_ical()
|
||||
|
|
@ -100,11 +101,11 @@ class vBinary:
|
|||
'This is gibberish'
|
||||
|
||||
The roundtrip test
|
||||
>>> x = 'Binary data æ ø å \x13 \x56'
|
||||
>>> x = 'Binary data \x13 \x56'
|
||||
>>> vBinary(x).to_ical()
|
||||
'QmluYXJ5IGRhdGEg5iD4IOUgEyBW'
|
||||
>>> vBinary.from_ical('QmluYXJ5IGRhdGEg5iD4IOUgEyBW')
|
||||
'Binary data \\xe6 \\xf8 \\xe5 \\x13 V'
|
||||
'QmluYXJ5IGRhdGEgEyBW'
|
||||
>>> vBinary.from_ical('QmluYXJ5IGRhdGEgEyBW')
|
||||
'Binary data \\x13 V'
|
||||
|
||||
>>> b = vBinary('txt')
|
||||
>>> b.params
|
||||
|
|
@ -116,7 +117,6 @@ class vBinary:
|
|||
True
|
||||
>>> vBinary.from_ical('YWFh' * 33) == 'a' * 99
|
||||
True
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, obj):
|
||||
|
|
@ -135,11 +135,12 @@ class vBinary:
|
|||
return ical.decode('base-64')
|
||||
except UnicodeError:
|
||||
raise ValueError, 'Not valid base 64 encoding.'
|
||||
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
|
||||
class vBoolean(int):
|
||||
""" Returns specific string according to state.
|
||||
"""Returns specific string according to state.
|
||||
|
||||
>>> bin = vBoolean(True)
|
||||
>>> bin.to_ical()
|
||||
|
|
@ -174,11 +175,12 @@ class vBoolean(int):
|
|||
return vBoolean.bool_map[ical]
|
||||
except:
|
||||
raise ValueError, "Expected 'TRUE' or 'FALSE'. Got %s" % ical
|
||||
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
|
||||
class vCalAddress(str):
|
||||
""" This just returns an unquoted string.
|
||||
"""This just returns an unquoted string.
|
||||
|
||||
>>> a = vCalAddress('MAILTO:maxm@mxm.dk')
|
||||
>>> a.params['cn'] = 'Max M'
|
||||
|
|
@ -190,8 +192,10 @@ class vCalAddress(str):
|
|||
'MAILTO:maxm@mxm.dk'
|
||||
"""
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
self = super(vCalAddress, cls).__new__(cls, *args, **kwargs)
|
||||
def __new__(cls, value):
|
||||
if isinstance(value, unicode):
|
||||
value = value.encode('utf-8')
|
||||
self = super(vCalAddress, cls).__new__(cls, value)
|
||||
self.params = Parameters()
|
||||
return self
|
||||
|
||||
|
|
@ -207,6 +211,7 @@ class vCalAddress(str):
|
|||
return str(ical)
|
||||
except:
|
||||
raise ValueError, 'Expected vCalAddress, got: %s' % ical
|
||||
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
|
||||
|
|
@ -214,9 +219,6 @@ class vCalAddress(str):
|
|||
# handy tzinfo classes you can use.
|
||||
#
|
||||
|
||||
|
||||
|
||||
|
||||
ZERO = timedelta(0)
|
||||
HOUR = timedelta(hours=1)
|
||||
STDOFFSET = timedelta(seconds = -_time.timezone)
|
||||
|
|
@ -228,8 +230,7 @@ DSTDIFF = DSTOFFSET - STDOFFSET
|
|||
|
||||
|
||||
class FixedOffset(tzinfo):
|
||||
""" Fixed offset in minutes east from UTC.
|
||||
|
||||
"""Fixed offset in minutes east from UTC.
|
||||
"""
|
||||
|
||||
def __init__(self, offset, name):
|
||||
|
|
@ -247,8 +248,7 @@ class FixedOffset(tzinfo):
|
|||
|
||||
|
||||
class LocalTimezone(tzinfo):
|
||||
""" Timezone of the machine where the code is running.
|
||||
|
||||
"""Timezone of the machine where the code is running.
|
||||
"""
|
||||
|
||||
def utcoffset(self, dt):
|
||||
|
|
@ -275,10 +275,8 @@ class LocalTimezone(tzinfo):
|
|||
return tt.tm_isdst > 0
|
||||
|
||||
|
||||
#####################
|
||||
|
||||
class vFloat(float):
|
||||
""" Just a float.
|
||||
"""Just a float.
|
||||
|
||||
>>> f = vFloat(1.0)
|
||||
>>> f.to_ical()
|
||||
|
|
@ -287,7 +285,6 @@ class vFloat(float):
|
|||
42.0
|
||||
>>> vFloat(42).to_ical()
|
||||
'42.0'
|
||||
|
||||
"""
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
|
|
@ -304,11 +301,12 @@ class vFloat(float):
|
|||
return float(ical)
|
||||
except:
|
||||
raise ValueError, 'Expected float value, got: %s' % ical
|
||||
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
|
||||
class vInt(int):
|
||||
""" Just an int.
|
||||
"""Just an int.
|
||||
|
||||
>>> f = vInt(42)
|
||||
>>> f.to_ical()
|
||||
|
|
@ -319,7 +317,6 @@ class vInt(int):
|
|||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Expected int, got: 1s3
|
||||
|
||||
"""
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
|
|
@ -336,11 +333,12 @@ class vInt(int):
|
|||
return int(ical)
|
||||
except:
|
||||
raise ValueError, 'Expected int, got: %s' % ical
|
||||
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
|
||||
class vDDDLists:
|
||||
""" A list of vDDDTypes values.
|
||||
"""A list of vDDDTypes values.
|
||||
|
||||
>>> dt_list = vDDDLists.from_ical('19960402T010000Z')
|
||||
>>> type(dt_list)
|
||||
|
|
@ -355,7 +353,8 @@ class vDDDLists:
|
|||
>>> str(dt_list[0])
|
||||
'1996-04-02 01:00:00+00:00'
|
||||
|
||||
>>> dt_list = vDDDLists.from_ical('19960402T010000Z,19960403T010000Z,19960404T010000Z')
|
||||
>>> p = '19960402T010000Z,19960403T010000Z,19960404T010000Z'
|
||||
>>> dt_list = vDDDLists.from_ical(p)
|
||||
>>> len(dt_list)
|
||||
3
|
||||
|
||||
|
|
@ -380,7 +379,6 @@ class vDDDLists:
|
|||
>>> dt_list = vDDDLists([datetime(2000,1,1), datetime(2000,11,11)])
|
||||
>>> dt_list.to_ical()
|
||||
'20000101T000000,20001111T000000'
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, dt_list):
|
||||
|
|
@ -392,15 +390,13 @@ class vDDDLists:
|
|||
self.dts = vDDD
|
||||
|
||||
def to_ical(self):
|
||||
'''
|
||||
Generates the text string in the iCalendar format.
|
||||
'''Generates the text string in the iCalendar format.
|
||||
'''
|
||||
dts_ical = [dt.to_ical() for dt in self.dts]
|
||||
return ",".join(dts_ical)
|
||||
|
||||
def from_ical(ical):
|
||||
'''
|
||||
Parses the list of data formats from ical text format.
|
||||
'''Parses the list of data formats from ical text format.
|
||||
@param ical: ical text format
|
||||
'''
|
||||
out = []
|
||||
|
|
@ -408,11 +404,12 @@ class vDDDLists:
|
|||
for ical_dt in ical_dates:
|
||||
out.append(vDDDTypes.from_ical(ical_dt))
|
||||
return out
|
||||
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
|
||||
class vDDDTypes:
|
||||
""" A combined Datetime, Date or Duration parser/generator. Their format
|
||||
"""A combined Datetime, Date or Duration parser/generator. Their format
|
||||
cannot be confused, and often values can be of either types.
|
||||
So this is practical.
|
||||
|
||||
|
|
@ -438,7 +435,6 @@ class vDDDTypes:
|
|||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: You must use datetime, date or timedelta
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, dt):
|
||||
|
|
@ -473,11 +469,12 @@ class vDDDTypes:
|
|||
return vDatetime.from_ical(ical, timezone=timezone)
|
||||
except:
|
||||
return vDate.from_ical(ical)
|
||||
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
|
||||
class vDate:
|
||||
""" Render and generates iCalendar date format.
|
||||
"""Render and generates iCalendar date format.
|
||||
|
||||
>>> d = date(2001, 1,1)
|
||||
>>> vDate(d).to_ical()
|
||||
|
|
@ -490,7 +487,6 @@ class vDate:
|
|||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Value MUST be a date instance
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, dt):
|
||||
|
|
@ -513,11 +509,12 @@ class vDate:
|
|||
return date(*timetuple)
|
||||
except:
|
||||
raise ValueError, 'Wrong date format %s' % ical
|
||||
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
|
||||
class vDatetime:
|
||||
""" Render and generates icalendar datetime format.
|
||||
"""Render and generates icalendar datetime format.
|
||||
|
||||
vDatetime is timezone aware and uses the pytz library, an implementation of
|
||||
the Olson database in Python. When a vDatetime object is created from an
|
||||
|
|
@ -610,11 +607,12 @@ class vDatetime:
|
|||
raise ValueError, ical
|
||||
except:
|
||||
raise ValueError, 'Wrong datetime format: %s' % ical
|
||||
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
|
||||
class vDuration:
|
||||
""" Subclass of timedelta that renders itself in the iCalendar DURATION
|
||||
"""Subclass of timedelta that renders itself in the iCalendar DURATION
|
||||
format.
|
||||
|
||||
>>> vDuration(timedelta(11)).to_ical()
|
||||
|
|
@ -661,7 +659,6 @@ class vDuration:
|
|||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Value MUST be a timedelta instance
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, td):
|
||||
|
|
@ -711,11 +708,12 @@ class vDuration:
|
|||
return value
|
||||
except:
|
||||
raise ValueError('Invalid iCalendar duration: %s' % ical)
|
||||
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
|
||||
class vPeriod:
|
||||
""" A precise period of time.
|
||||
"""A precise period of time.
|
||||
|
||||
One day in exact datetimes
|
||||
>>> per = (datetime(2000,1,1), datetime(2000,1,2))
|
||||
|
|
@ -763,7 +761,6 @@ class vPeriod:
|
|||
>>> p = vPeriod((datetime(2000,1,1, tzinfo=dk), timedelta(days=31)))
|
||||
>>> p.to_ical()
|
||||
'20000101T000000/P31D'
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, per):
|
||||
|
|
@ -773,7 +770,8 @@ class vPeriod:
|
|||
if not (isinstance(end_or_duration, datetime) or
|
||||
isinstance(end_or_duration, date) or
|
||||
isinstance(end_or_duration, timedelta)):
|
||||
raise ValueError('end_or_duration MUST be a datetime, date or timedelta instance')
|
||||
raise ValueError('end_or_duration MUST be a datetime, '
|
||||
'date or timedelta instance')
|
||||
by_duration = 0
|
||||
if isinstance(end_or_duration, timedelta):
|
||||
by_duration = 1
|
||||
|
|
@ -811,8 +809,10 @@ class vPeriod:
|
|||
|
||||
def to_ical(self):
|
||||
if self.by_duration:
|
||||
return '%s/%s' % (vDatetime(self.start).to_ical(), vDuration(self.duration).to_ical())
|
||||
return '%s/%s' % (vDatetime(self.start).to_ical(), vDatetime(self.end).to_ical())
|
||||
return '%s/%s' % (vDatetime(self.start).to_ical(),
|
||||
vDuration(self.duration).to_ical())
|
||||
return '%s/%s' % (vDatetime(self.start).to_ical(),
|
||||
vDatetime(self.end).to_ical())
|
||||
|
||||
def from_ical(ical):
|
||||
"Parses the data format from ical text format"
|
||||
|
|
@ -823,9 +823,9 @@ class vPeriod:
|
|||
return (start, end_or_duration)
|
||||
except:
|
||||
raise ValueError, 'Expected period format, got: %s' % ical
|
||||
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
if self.by_duration:
|
||||
p = (self.start, self.duration)
|
||||
|
|
@ -835,7 +835,7 @@ class vPeriod:
|
|||
|
||||
|
||||
class vWeekday(str):
|
||||
""" This returns an unquoted weekday abbrevation.
|
||||
"""This returns an unquoted weekday abbrevation.
|
||||
|
||||
>>> a = vWeekday('mo')
|
||||
>>> a.to_ical()
|
||||
|
|
@ -868,7 +868,6 @@ class vWeekday(str):
|
|||
>>> a = vWeekday('-tu')
|
||||
>>> a.to_ical()
|
||||
'-TU'
|
||||
|
||||
"""
|
||||
|
||||
week_days = CaselessDict({"SU":0, "MO":1, "TU":2, "WE":3,
|
||||
|
|
@ -898,11 +897,12 @@ class vWeekday(str):
|
|||
return vWeekday(ical.upper())
|
||||
except:
|
||||
raise ValueError, 'Expected weekday abbrevation, got: %s' % ical
|
||||
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
|
||||
class vFrequency(str):
|
||||
""" A simple class that catches illegal values.
|
||||
"""A simple class that catches illegal values.
|
||||
|
||||
>>> f = vFrequency('bad test')
|
||||
Traceback (most recent call last):
|
||||
|
|
@ -912,7 +912,6 @@ class vFrequency(str):
|
|||
'DAILY'
|
||||
>>> vFrequency('daily').from_ical('MONTHLY')
|
||||
'MONTHLY'
|
||||
|
||||
"""
|
||||
|
||||
frequencies = CaselessDict({
|
||||
|
|
@ -941,11 +940,12 @@ class vFrequency(str):
|
|||
return vFrequency(ical.upper())
|
||||
except:
|
||||
raise ValueError, 'Expected weekday abbrevation, got: %s' % ical
|
||||
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
|
||||
class vRecur(CaselessDict):
|
||||
""" Recurrence definition.
|
||||
"""Recurrence definition.
|
||||
|
||||
Let's see how close we can get to one from the rfc:
|
||||
FREQ=YEARLY;INTERVAL=2;BYMONTH=1;BYDAY=SU;BYHOUR=8,9;BYMINUTE=30
|
||||
|
|
@ -983,9 +983,12 @@ class vRecur(CaselessDict):
|
|||
>>> 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')
|
||||
>>> p = 'FREQ=YEARLY;INTERVAL=2;BYMONTH=1;BYDAY=-SU;BYHOUR=8,9;BYMINUTE=30'
|
||||
>>> r = vRecur.from_ical(p)
|
||||
>>> r
|
||||
{'BYHOUR': [8, 9], 'BYDAY': ['-SU'], 'BYMINUTE': [30], 'BYMONTH': [1], 'FREQ': ['YEARLY'], 'INTERVAL': [2]}
|
||||
{'BYHOUR': [8, 9], 'BYDAY': ['-SU'], 'BYMINUTE': [30], 'BYMONTH': [1],
|
||||
'FREQ': ['YEARLY'], 'INTERVAL': [2]}
|
||||
|
||||
>>> vRecur(r).to_ical()
|
||||
'FREQ=YEARLY;INTERVAL=2;BYMINUTE=30;BYHOUR=8,9;BYDAY=-SU;BYMONTH=1'
|
||||
|
||||
|
|
@ -995,7 +998,8 @@ class vRecur(CaselessDict):
|
|||
>>> 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')
|
||||
>>> p = 'FREQ=YEARLY;INTERVAL=2;BYMONTH=1;BYDAY=SU;BYHOUR=8,9;BYMINUTE=30'
|
||||
>>> r = vRecur.from_ical(p)
|
||||
>>> vRecur(r).to_ical()
|
||||
'FREQ=YEARLY;INTERVAL=2;BYMINUTE=30;BYHOUR=8,9;BYDAY=SU;BYMONTH=1'
|
||||
|
||||
|
|
@ -1004,7 +1008,6 @@ class vRecur(CaselessDict):
|
|||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Error in recurrence rule: BYDAY=12
|
||||
|
||||
"""
|
||||
|
||||
frequencies = ["SECONDLY", "MINUTELY", "HOURLY", "DAILY", "WEEKLY",
|
||||
|
|
@ -1013,8 +1016,9 @@ class vRecur(CaselessDict):
|
|||
# Mac iCal ignores RRULEs where FREQ is not the first rule part.
|
||||
# Sorts parts according to the order listed in RFC 5545, section 3.3.10.
|
||||
canonical_order = ( "FREQ", "UNTIL", "COUNT", "INTERVAL",
|
||||
"BYSECOND", "BYMINUTE", "BYHOUR", "BYDAY", "BYMONTHDAY", "BYYEARDAY",
|
||||
"BYWEEKNO", "BYMONTH", "BYSETPOS", "WKST" )
|
||||
"BYSECOND", "BYMINUTE", "BYHOUR", "BYDAY",
|
||||
"BYMONTHDAY", "BYYEARDAY", "BYWEEKNO", "BYMONTH",
|
||||
"BYSETPOS", "WKST" )
|
||||
|
||||
types = CaselessDict({
|
||||
'COUNT':vInt,
|
||||
|
|
@ -1063,11 +1067,14 @@ class vRecur(CaselessDict):
|
|||
return dict(recur)
|
||||
except:
|
||||
raise ValueError, 'Error in recurrence rule: %s' % ical
|
||||
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
|
||||
DEFAULT_ENCODING = 'utf-8'
|
||||
|
||||
class vText(unicode):
|
||||
""" Simple text
|
||||
"""Simple text.
|
||||
|
||||
>>> t = vText(u'Simple text')
|
||||
>>> t.to_ical()
|
||||
|
|
@ -1085,14 +1092,9 @@ class vText(unicode):
|
|||
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 = vText(u'international chars \xe4\xf6\xfc')
|
||||
>>> 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 æ ø å')
|
||||
>>> t.to_ical()
|
||||
'international \\xc3\\xa6 \\xc3\\xb8 \\xc3\\xa5'
|
||||
'international chars \\xc3\\xa4\\xc3\\xb6\\xc3\\xbc'
|
||||
|
||||
and parsing?
|
||||
>>> vText.from_ical('Text \\; with escaped\\, chars')
|
||||
|
|
@ -1110,13 +1112,15 @@ class vText(unicode):
|
|||
|
||||
Notice how accented E character, encoded with latin-1, got replaced
|
||||
with the official U+FFFD REPLACEMENT CHARACTER.
|
||||
|
||||
"""
|
||||
|
||||
encoding = DEFAULT_ENCODING
|
||||
|
||||
encoding = 'utf-8'
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
self = super(vText, cls).__new__(cls, *args, **kwargs)
|
||||
def __new__(cls, value, encoding=DEFAULT_ENCODING):
|
||||
if isinstance(value, unicode):
|
||||
value = value.encode(DEFAULT_ENCODING)
|
||||
self = super(vText, cls).__new__(cls, value, encoding=encoding)
|
||||
self.encoding = encoding
|
||||
self.params = Parameters()
|
||||
return self
|
||||
|
||||
|
|
@ -1150,11 +1154,12 @@ class vText(unicode):
|
|||
return ical.decode(vText.encoding, 'replace')
|
||||
except:
|
||||
raise ValueError, 'Expected ical text, got: %s' % ical
|
||||
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
|
||||
class vTime(time):
|
||||
""" A subclass of datetime, that renders itself in the iCalendar time
|
||||
"""A subclass of datetime, that renders itself in the iCalendar time
|
||||
format.
|
||||
|
||||
>>> dt = vTime(12, 30, 0)
|
||||
|
|
@ -1169,7 +1174,6 @@ class vTime(time):
|
|||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Expected time, got: 263000
|
||||
|
||||
"""
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
|
|
@ -1187,18 +1191,18 @@ class vTime(time):
|
|||
return time(*timetuple)
|
||||
except:
|
||||
raise ValueError, 'Expected time, got: %s' % ical
|
||||
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
|
||||
class vUri(str):
|
||||
""" Uniform resource identifier is basically just an unquoted string.
|
||||
"""Uniform resource identifier is basically just an unquoted string.
|
||||
|
||||
>>> u = vUri('http://www.example.com/')
|
||||
>>> u.to_ical()
|
||||
'http://www.example.com/'
|
||||
>>> vUri.from_ical('http://www.example.com/') # doh!
|
||||
'http://www.example.com/'
|
||||
|
||||
"""
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
|
|
@ -1215,11 +1219,12 @@ class vUri(str):
|
|||
return str(ical)
|
||||
except:
|
||||
raise ValueError, 'Expected , got: %s' % ical
|
||||
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
|
||||
class vGeo:
|
||||
""" A special type that is only indirectly defined in the rfc.
|
||||
"""A special type that is only indirectly defined in the rfc.
|
||||
|
||||
>>> g = vGeo((1.2, 3.0))
|
||||
>>> g.to_ical()
|
||||
|
|
@ -1236,7 +1241,6 @@ class vGeo:
|
|||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Input must be (float, float) for latitude and longitude
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, geo):
|
||||
|
|
@ -1245,7 +1249,8 @@ class vGeo:
|
|||
latitude = float(latitude)
|
||||
longitude = float(longitude)
|
||||
except:
|
||||
raise ValueError('Input must be (float, float) for latitude and longitude')
|
||||
raise ValueError('Input must be (float, float) for '
|
||||
'latitude and longitude')
|
||||
self.latitude = latitude
|
||||
self.longitude = longitude
|
||||
self.params = Parameters()
|
||||
|
|
@ -1260,11 +1265,12 @@ class vGeo:
|
|||
return (float(latitude), float(longitude))
|
||||
except:
|
||||
raise ValueError, "Expected 'float;float' , got: %s" % ical
|
||||
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
|
||||
class vUTCOffset:
|
||||
""" Renders itself as a utc offset.
|
||||
"""Renders itself as a utc offset.
|
||||
|
||||
>>> u = vUTCOffset(timedelta(hours=2))
|
||||
>>> u.to_ical()
|
||||
|
|
@ -1318,7 +1324,6 @@ class vUTCOffset:
|
|||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Offset must be less than 24 hours, was +2400
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, td):
|
||||
|
|
@ -1348,7 +1353,10 @@ class vUTCOffset:
|
|||
if isinstance(ical, vUTCOffset):
|
||||
return ical.td
|
||||
try:
|
||||
sign, hours, minutes, seconds = (ical[0:1], int(ical[1:3]), int(ical[3:5]), int(ical[5:7] or 0))
|
||||
sign, hours, minutes, seconds = (ical[0:1],
|
||||
int(ical[1:3]),
|
||||
int(ical[3:5]),
|
||||
int(ical[5:7] or 0))
|
||||
offset = timedelta(hours=hours, minutes=minutes, seconds=seconds)
|
||||
except:
|
||||
raise ValueError, 'Expected utc offset, got: %s' % ical
|
||||
|
|
@ -1357,11 +1365,12 @@ class vUTCOffset:
|
|||
if sign == '-':
|
||||
return -offset
|
||||
return offset
|
||||
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
|
||||
class vInline(str):
|
||||
""" This is an especially dumb class that just holds raw unparsed text and
|
||||
"""This is an especially dumb class that just holds raw unparsed text and
|
||||
has parameters. Conversion of inline values are handled by the Component
|
||||
class, so no further processing is needed.
|
||||
|
||||
|
|
@ -1375,7 +1384,6 @@ class vInline(str):
|
|||
>>> t2.params['cn'] = 'Test Osterone'
|
||||
>>> t2.params
|
||||
Parameters({'CN': 'Test Osterone'})
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self,obj):
|
||||
|
|
@ -1387,11 +1395,12 @@ class vInline(str):
|
|||
|
||||
def from_ical(ical):
|
||||
return str(ical)
|
||||
|
||||
from_ical = staticmethod(from_ical)
|
||||
|
||||
|
||||
class TypesFactory(CaselessDict):
|
||||
""" All Value types defined in rfc 2445 are registered in this factory
|
||||
"""All Value types defined in rfc 2445 are registered in this factory
|
||||
class.
|
||||
|
||||
To get a type you can use it like this.
|
||||
|
|
@ -1410,20 +1419,19 @@ class TypesFactory(CaselessDict):
|
|||
datetime.datetime(2005, 1, 1, 12, 30)
|
||||
|
||||
It can also be used to directly encode property and parameter values
|
||||
>>> comment = factory.to_ical('comment', u'by Rasmussen, Max Møller')
|
||||
>>> comment = factory.to_ical('comment', u'by Rasmussen, Max M\xfcller')
|
||||
>>> str(comment)
|
||||
'by Rasmussen\\\\, Max M\\xc3\\xb8ller'
|
||||
'by Rasmussen\\\\, Max M\\xc3\\xbcller'
|
||||
>>> factory.to_ical('priority', 1)
|
||||
'1'
|
||||
>>> factory.to_ical('cn', u'Rasmussen, Max Møller')
|
||||
'Rasmussen\\\\, Max M\\xc3\\xb8ller'
|
||||
>>> factory.to_ical('cn', u'Rasmussen, Max M\xfcller')
|
||||
'Rasmussen\\\\, Max M\\xc3\\xbcller'
|
||||
|
||||
>>> factory.from_ical('cn', 'Rasmussen\\\\, Max M\\xc3\\xb8ller')
|
||||
u'Rasmussen, Max M\\xf8ller'
|
||||
|
||||
The value and parameter names don't overlap. So one factory is enough for
|
||||
both kinds.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
|
@ -1447,7 +1455,6 @@ class TypesFactory(CaselessDict):
|
|||
self['inline'] = vInline
|
||||
self['date-time-list'] = vDDDLists
|
||||
|
||||
|
||||
#################################################
|
||||
# Property types
|
||||
|
||||
|
|
@ -1535,25 +1542,21 @@ class TypesFactory(CaselessDict):
|
|||
'value' : 'text',
|
||||
})
|
||||
|
||||
|
||||
def for_property(self, name):
|
||||
""" Returns a the default type for a property or parameter
|
||||
|
||||
"""Returns a the default type for a property or parameter
|
||||
"""
|
||||
return self[self.types_map.get(name, 'text')]
|
||||
|
||||
def to_ical(self, name, value):
|
||||
""" Encodes a named value from a primitive python type to an icalendar
|
||||
"""Encodes a named value from a primitive python type to an icalendar
|
||||
encoded string.
|
||||
|
||||
"""
|
||||
type_class = self.for_property(name)
|
||||
return type_class(value).to_ical()
|
||||
|
||||
def from_ical(self, name, value):
|
||||
""" Decodes a named property or parameter value from an icalendar
|
||||
"""Decodes a named property or parameter value from an icalendar
|
||||
encoded string to a primitive python type.
|
||||
|
||||
"""
|
||||
type_class = self.for_property(name)
|
||||
decoded = type_class.from_ical(value)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
from interlude import interact
|
||||
#from interlude import interact
|
||||
|
||||
import doctest
|
||||
import os.path
|
||||
|
|
@ -52,14 +52,14 @@ def test_suite():
|
|||
os.path.join(os.path.dirname(__file__), docfile),
|
||||
module_relative=False,
|
||||
optionflags=OPTIONFLAGS,
|
||||
globs={'interact': interact}
|
||||
#globs={'interact': interact}
|
||||
) for docfile in DOCFILES
|
||||
])
|
||||
suite.addTests([
|
||||
doctest.DocTestSuite(
|
||||
docmod,
|
||||
optionflags=OPTIONFLAGS,
|
||||
globs={'interact': interact}
|
||||
#globs={'interact': interact}
|
||||
) for docmod in DOCMODS
|
||||
])
|
||||
return suite
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2012, Plone Foundation
|
||||
# All rights reserved.
|
||||
#
|
||||
|
|
@ -25,26 +24,33 @@
|
|||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
import unittest2 as unittest
|
||||
import icalendar
|
||||
import pytz
|
||||
import datetime
|
||||
import os
|
||||
|
||||
|
||||
class TestEncoding(unittest.TestCase):
|
||||
|
||||
def test_create_from_ical(self):
|
||||
directory = os.path.dirname(__file__)
|
||||
cal = icalendar.Calendar.from_ical(open(os.path.join(directory, 'encoding.ics'),'rb').read())
|
||||
data = open(os.path.join(directory, 'encoding.ics'),'rb').read()
|
||||
cal = icalendar.Calendar.from_ical(data)
|
||||
|
||||
self.assertEqual(cal['prodid'].to_ical(), "-//Plönë.org//NONSGML plone.app.event//EN")
|
||||
self.assertEqual(cal['X-WR-CALDESC'].to_ical(), "test non ascii: äöü ÄÖÜ €")
|
||||
self.assertEqual(cal['prodid'].to_ical(),
|
||||
"-//Plönë.org//NONSGML plone.app.event//EN")
|
||||
self.assertEqual(cal['X-WR-CALDESC'].to_ical(),
|
||||
"test non ascii: äöü ÄÖÜ €")
|
||||
|
||||
event = cal.walk('VEVENT')[0]
|
||||
self.assertEqual(event['SUMMARY'].to_ical(), 'Non-ASCII Test: ÄÖÜ äöü €')
|
||||
self.assertEqual(event['DESCRIPTION'].to_ical(), 'icalendar should be able to handle non-ascii: €äüöÄÜÖ.')
|
||||
self.assertEqual(event['LOCATION'].to_ical(), 'Tribstrül')
|
||||
|
||||
self.assertEqual(event['SUMMARY'].to_ical(),
|
||||
'Non-ASCII Test: ÄÖÜ äöü €')
|
||||
self.assertEqual(event['DESCRIPTION'].to_ical(),
|
||||
'icalendar should be able to handle non-ascii: €äüöÄÜÖ.')
|
||||
self.assertEqual(event['LOCATION'].to_ical(),
|
||||
'Tribstrül')
|
||||
|
||||
def test_create_to_ical(self):
|
||||
cal = icalendar.Calendar()
|
||||
|
|
@ -66,6 +72,5 @@ class TestEncoding(unittest.TestCase):
|
|||
cal.add_component(event)
|
||||
|
||||
ical_lines = cal.to_ical().splitlines()
|
||||
|
||||
## TODO FIX TESTS AND CODE TO SUPPORT UNICODE/UTF-8
|
||||
#self.assertTrue(u"-//Plönë.org//NONSGML plone.app.event//EN" in ical_lines)
|
||||
cmp = 'PRODID:-//Pl\xc3\xb6n\xc3\xab.org//NONSGML plone.app.event//EN'
|
||||
self.assertTrue(cmp in ical_lines)
|
||||
|
|
|
|||
|
|
@ -25,7 +25,13 @@
|
|||
|
||||
#from interlude import interact
|
||||
import unittest, doctest, os
|
||||
from icalendar import cal, caselessdict, parser, prop
|
||||
from icalendar import (
|
||||
cal,
|
||||
caselessdict,
|
||||
parser,
|
||||
prop,
|
||||
)
|
||||
|
||||
|
||||
class FuckYouTests(unittest.TestCase):
|
||||
def XtestBla(self):
|
||||
|
|
@ -33,8 +39,9 @@ class FuckYouTests(unittest.TestCase):
|
|||
c = Calendar()
|
||||
c['description']=u'Paragraph one\n\nParagraph two'
|
||||
output = c.to_ical()
|
||||
self.assertEqual(output,
|
||||
"BEGIN:VCALENDAR\r\nDESCRIPTION:Paragraph one\r\n \r\n Paragraph two\r\nEND:VCALENDAR\r\n")
|
||||
cmp = ("BEGIN:VCALENDAR\r\nDESCRIPTION:Paragraph one\r\n \r\n "
|
||||
"Paragraph two\r\nEND:VCALENDAR\r\n")
|
||||
self.assertEqual(output, cmp)
|
||||
|
||||
def XtestTrailingNewline(self):
|
||||
from icalendar.parser import Contentlines, Contentline
|
||||
|
|
@ -47,33 +54,37 @@ class FuckYouTests(unittest.TestCase):
|
|||
c = Contentlines([Contentline('BEGIN:VEVENT\\r\\n')])
|
||||
c.append(Contentline(''.join(['123456789 ']*10)+'\\r\\n'))
|
||||
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")
|
||||
cmp = ("BEGIN:VEVENT\\r\\n\\r\\n123456789 123456789 123456789 "
|
||||
"123456789 123456789 123456789 123456789 1234\\r\\n 56789 "
|
||||
"123456789 123456789 \\r\\n")
|
||||
self.assertEqual(output, cmp)
|
||||
|
||||
def testHmm(self):
|
||||
from icalendar.parser import Contentlines, Contentline
|
||||
c = Contentlines([Contentline('BEGIN:VEVENT\r\n')])
|
||||
c.append(Contentline(''.join(['123456789 ']*10)+'\r\n'))
|
||||
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')
|
||||
# XXX: sure? looks weird in conjunction with generated content above.
|
||||
#cmp = ('BEGIN:VEVENT\r\n\r\n123456789 123456789 123456789 123456789 '
|
||||
# '123456789 123456789 123456789 1234\r\n 56789 123456789 '
|
||||
# '123456789 \r\n')
|
||||
cmp = ('BEGIN:VEVENT\r\n\r\n123456789 123456789 123456789 123456789 '
|
||||
'123456789 123456789 123456789 \r\n 123456789 123456789 '
|
||||
'123456789 \r\n\r\n')
|
||||
self.assertEqual(output, cmp)
|
||||
|
||||
|
||||
def load_tests(loader=None, tests=None, pattern=None):
|
||||
|
||||
suite = unittest.TestSuite()
|
||||
|
||||
suite.addTest(doctest.DocTestSuite(caselessdict))
|
||||
suite.addTest(doctest.DocTestSuite(parser))
|
||||
suite.addTest(doctest.DocTestSuite(prop))
|
||||
suite.addTest(doctest.DocTestSuite(cal))
|
||||
|
||||
current_dir = os.path.dirname(__file__)
|
||||
for docfile in ['example.txt', 'groupscheduled.txt',
|
||||
'small.txt', 'multiple.txt', 'recurrence.txt']:
|
||||
filename = os.path.abspath(os.path.join(current_dir, docfile))
|
||||
suite.addTest(doctest.DocFileSuite(docfile,
|
||||
optionflags=doctest.ELLIPSIS,
|
||||
globs={'__file__': os.path.abspath(os.path.join(current_dir, docfile))},
|
||||
#, 'interact': interact},
|
||||
))
|
||||
|
||||
return suite
|
||||
globs={'__file__': filename}))
|
||||
return suite
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2012, Plone Foundation
|
||||
# All rights reserved.
|
||||
#
|
||||
|
|
@ -74,7 +75,7 @@ class TestTimezoned(unittest.TestCase):
|
|||
event.add('location', u'aka bild, wien')
|
||||
event.add('categories', u'first subject')
|
||||
event.add('categories', u'second subject')
|
||||
event.add('attendee', u'hans')
|
||||
event.add('attendee', u'häns')
|
||||
event.add('attendee', u'franz')
|
||||
event.add('attendee', u'sepp')
|
||||
event.add('contact', u'Max Mustermann, 1010 Wien')
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
""" This module contains non-essential tools for iCalendar. Pretty thin so far
|
||||
"""This module contains non-essential tools for iCalendar. Pretty thin so far
|
||||
eh?
|
||||
"""
|
||||
|
||||
|
|
@ -31,10 +31,10 @@ import random
|
|||
from string import ascii_letters, digits
|
||||
from datetime import datetime
|
||||
|
||||
class UIDGenerator:
|
||||
|
||||
"""
|
||||
If you are too lazy to create real uid's. Notice, this doctest is disabled!
|
||||
class UIDGenerator:
|
||||
"""If you are too lazy to create real uid's. Notice, this doctest is
|
||||
disabled!
|
||||
|
||||
Automatic semi-random uid
|
||||
>> g = UIDGenerator()
|
||||
|
|
|
|||
Ładowanie…
Reference in New Issue