kopia lustrzana https://github.com/collective/icalendar
Don't let Component.add re-encode already encoded values. This simplifies
the API, since there is no need explicitly pass encode=False. Fixes #82.pull/98/merge
rodzic
2f53d1f180
commit
71da2fa8ea
|
@ -5,6 +5,10 @@ Changelog
|
|||
3.4dev (unreleased)
|
||||
-------------------
|
||||
|
||||
- Don't let ``Component.add`` re-encode already encoded values. This simplifies
|
||||
the API, since there is no need explicitly pass ``encode=False``. Fixes #82.
|
||||
[thet]
|
||||
|
||||
- Switch to unicode internally.
|
||||
[thet]
|
||||
|
||||
|
|
|
@ -103,6 +103,9 @@ class Component(CaselessDict):
|
|||
"""
|
||||
if not cond:
|
||||
return value
|
||||
if type(value) in types_factory.all_types:
|
||||
# Don't encode already encoded values.
|
||||
return value
|
||||
klass = types_factory.for_property(name)
|
||||
obj = klass(value)
|
||||
if hasattr(value, 'params') and len(value.params.keys()) > 0:
|
||||
|
|
|
@ -68,6 +68,64 @@ WEEKDAY_RULE = re.compile('(?P<signal>[+-]?)(?P<relative>[\d]?)'
|
|||
'(?P<weekday>[\w]{2})$')
|
||||
|
||||
|
||||
####################################################
|
||||
# handy tzinfo classes you can use.
|
||||
#
|
||||
|
||||
ZERO = timedelta(0)
|
||||
HOUR = timedelta(hours=1)
|
||||
STDOFFSET = timedelta(seconds=-_time.timezone)
|
||||
if _time.daylight:
|
||||
DSTOFFSET = timedelta(seconds=-_time.altzone)
|
||||
else:
|
||||
DSTOFFSET = STDOFFSET
|
||||
DSTDIFF = DSTOFFSET - STDOFFSET
|
||||
|
||||
|
||||
class FixedOffset(tzinfo):
|
||||
"""Fixed offset in minutes east from UTC.
|
||||
"""
|
||||
def __init__(self, offset, name):
|
||||
self.__offset = timedelta(minutes=offset)
|
||||
self.__name = name
|
||||
|
||||
def utcoffset(self, dt):
|
||||
return self.__offset
|
||||
|
||||
def tzname(self, dt):
|
||||
return self.__name
|
||||
|
||||
def dst(self, dt):
|
||||
return ZERO
|
||||
|
||||
|
||||
class LocalTimezone(tzinfo):
|
||||
"""Timezone of the machine where the code is running.
|
||||
"""
|
||||
def utcoffset(self, dt):
|
||||
if self._isdst(dt):
|
||||
return DSTOFFSET
|
||||
else:
|
||||
return STDOFFSET
|
||||
|
||||
def dst(self, dt):
|
||||
if self._isdst(dt):
|
||||
return DSTDIFF
|
||||
else:
|
||||
return ZERO
|
||||
|
||||
def tzname(self, dt):
|
||||
return _time.tzname[self._isdst(dt)]
|
||||
|
||||
def _isdst(self, dt):
|
||||
tt = (dt.year, dt.month, dt.day,
|
||||
dt.hour, dt.minute, dt.second,
|
||||
dt.weekday(), 0, -1)
|
||||
stamp = _time.mktime(tt)
|
||||
tt = _time.localtime(stamp)
|
||||
return tt.tm_isdst > 0
|
||||
|
||||
|
||||
class vBinary(object):
|
||||
"""Binary property values are base 64 encoded.
|
||||
|
||||
|
@ -139,63 +197,6 @@ class vCalAddress(unicode):
|
|||
raise ValueError(u'Expected vCalAddress, got: %s' % ical)
|
||||
|
||||
|
||||
####################################################
|
||||
# handy tzinfo classes you can use.
|
||||
#
|
||||
|
||||
ZERO = timedelta(0)
|
||||
HOUR = timedelta(hours=1)
|
||||
STDOFFSET = timedelta(seconds=-_time.timezone)
|
||||
if _time.daylight:
|
||||
DSTOFFSET = timedelta(seconds=-_time.altzone)
|
||||
else:
|
||||
DSTOFFSET = STDOFFSET
|
||||
DSTDIFF = DSTOFFSET - STDOFFSET
|
||||
|
||||
|
||||
class FixedOffset(tzinfo):
|
||||
"""Fixed offset in minutes east from UTC.
|
||||
"""
|
||||
def __init__(self, offset, name):
|
||||
self.__offset = timedelta(minutes=offset)
|
||||
self.__name = name
|
||||
|
||||
def utcoffset(self, dt):
|
||||
return self.__offset
|
||||
|
||||
def tzname(self, dt):
|
||||
return self.__name
|
||||
|
||||
def dst(self, dt):
|
||||
return ZERO
|
||||
|
||||
|
||||
class LocalTimezone(tzinfo):
|
||||
"""Timezone of the machine where the code is running.
|
||||
"""
|
||||
def utcoffset(self, dt):
|
||||
if self._isdst(dt):
|
||||
return DSTOFFSET
|
||||
else:
|
||||
return STDOFFSET
|
||||
|
||||
def dst(self, dt):
|
||||
if self._isdst(dt):
|
||||
return DSTDIFF
|
||||
else:
|
||||
return ZERO
|
||||
|
||||
def tzname(self, dt):
|
||||
return _time.tzname[self._isdst(dt)]
|
||||
|
||||
def _isdst(self, dt):
|
||||
tt = (dt.year, dt.month, dt.day,
|
||||
dt.hour, dt.minute, dt.second,
|
||||
dt.weekday(), 0, -1)
|
||||
stamp = _time.mktime(tt)
|
||||
tt = _time.localtime(stamp)
|
||||
return tt.tm_isdst > 0
|
||||
|
||||
|
||||
class vFloat(float):
|
||||
"""Just a float.
|
||||
|
@ -855,6 +856,28 @@ class TypesFactory(CaselessDict):
|
|||
def __init__(self, *args, **kwargs):
|
||||
"Set keys to upper for initial dict"
|
||||
CaselessDict.__init__(self, *args, **kwargs)
|
||||
self.all_types = [
|
||||
vBinary,
|
||||
vBoolean,
|
||||
vCalAddress,
|
||||
vDDDLists,
|
||||
vDDDTypes,
|
||||
vDate,
|
||||
vDatetime,
|
||||
vDuration,
|
||||
vFloat,
|
||||
vFrequency,
|
||||
vGeo,
|
||||
vInline,
|
||||
vInt,
|
||||
vPeriod,
|
||||
vRecur,
|
||||
vText,
|
||||
vTime,
|
||||
vUTCOffset,
|
||||
vUri,
|
||||
vWeekday,
|
||||
]
|
||||
self['binary'] = vBinary
|
||||
self['boolean'] = vBoolean
|
||||
self['cal-address'] = vCalAddress
|
||||
|
|
|
@ -169,6 +169,19 @@ class TestCalComponent(unittest.TestCase):
|
|||
self.assertTrue(
|
||||
"LAST-MODIFIED;VALUE=DATE-TIME:20101010T160000Z" in lines)
|
||||
|
||||
def test_cal_Component_add_no_reencode(self):
|
||||
"""Already encoded values should not be re-encoded.
|
||||
"""
|
||||
from icalendar import cal, prop
|
||||
comp = cal.Component()
|
||||
comp.add('ATTACH', 'me')
|
||||
|
||||
comp.add('ATTACH', 'you', encode=False)
|
||||
binary = prop.vBinary('us')
|
||||
comp.add('ATTACH', binary)
|
||||
|
||||
self.assertEqual(comp['ATTACH'], [u'me', 'you', binary])
|
||||
|
||||
def test_cal_Component_from_ical(self):
|
||||
# RecurrenceIDs may contain a TZID parameter, if so, they should create
|
||||
# a tz localized datetime, otherwise, create a naive datetime
|
||||
|
|
|
@ -3,10 +3,10 @@ from . import unittest
|
|||
import icalendar
|
||||
import os
|
||||
|
||||
class TestCases(unittest.TestCase):
|
||||
class TestIssues(unittest.TestCase):
|
||||
|
||||
def test_case_meetup(self):
|
||||
# broken description
|
||||
def test_issue_53(self):
|
||||
# parsing failure on some descriptions?
|
||||
# see: https://github.com/collective/icalendar/issues/53
|
||||
directory = os.path.dirname(__file__)
|
||||
ics = open(os.path.join(directory, 'case_meetup.ics'), 'rb')
|
||||
|
@ -21,3 +21,16 @@ class TestCases(unittest.TestCase):
|
|||
self.assertEqual(len(timezones), 1)
|
||||
tz = timezones[0]
|
||||
self.assertEqual(tz['tzid'].to_ical(), "America/New_York")
|
||||
|
||||
def test_issue_82(self):
|
||||
# vBinary __repr__ called rather than to_ical from container types
|
||||
# https://github.com/collective/icalendar/issues/82
|
||||
b = icalendar.vBinary('text')
|
||||
b.params['FMTTYPE'] = 'text/plain'
|
||||
self.assertEqual(b.to_ical(), 'dGV4dA==')
|
||||
e = icalendar.Event()
|
||||
e.add('ATTACH', b)
|
||||
self.assertEqual(e.to_ical(),
|
||||
"BEGIN:VEVENT\r\nATTACH;ENCODING=BASE64;FMTTYPE=text/plain;"
|
||||
"VALUE=BINARY:dGV4dA==\r\nEND:VEVENT\r\n"
|
||||
)
|
Ładowanie…
Reference in New Issue