diff options
author | Guido Guenther <agx@sigxcpu.org> | 2008-06-20 09:11:43 +0200 |
---|---|---|
committer | Guido Guenther <agx@sigxcpu.org> | 2008-06-20 09:11:43 +0200 |
commit | d31aba9e4d61f2dd4cb3ccf75ae351002350bca1 (patch) | |
tree | e1d97e887159b62a97e725c027680f22cfc314e7 | |
parent | 0177b888475caf0af323a9aa66e11b463fb14612 (diff) | |
parent | bd308fbf5f91cd2d9f86f9ea437bcf54a120a09c (diff) |
Merge branch 'upstream'
-rw-r--r-- | PKG-INFO | 28 | ||||
-rwxr-xr-x | setup.py | 44 | ||||
-rw-r--r-- | src/vobject.egg-info/PKG-INFO | 27 | ||||
-rw-r--r-- | src/vobject.egg-info/SOURCES.txt | 25 | ||||
-rw-r--r-- | test_files/more_tests.txt | 62 | ||||
-rw-r--r-- | test_files/recurrence.ics (renamed from tests/recurrence.ics) | 0 | ||||
-rw-r--r-- | test_files/tzid_8bit.ics | 23 | ||||
-rw-r--r-- | test_files/utf8_test.ics (renamed from tests/utf8_test.ics) | 0 | ||||
-rw-r--r-- | test_vobject.py (renamed from tests/tests.py) | 56 | ||||
-rw-r--r-- | tests/more_tests.txt | 35 | ||||
-rw-r--r-- | vobject.egg-info/PKG-INFO | 43 | ||||
-rw-r--r-- | vobject.egg-info/SOURCES.txt | 26 | ||||
-rw-r--r-- | vobject.egg-info/dependency_links.txt (renamed from src/vobject.egg-info/dependency_links.txt) | 0 | ||||
-rw-r--r-- | vobject.egg-info/entry_points.txt (renamed from src/vobject.egg-info/entry_points.txt) | 0 | ||||
-rw-r--r-- | vobject.egg-info/requires.txt (renamed from src/vobject.egg-info/requires.txt) | 0 | ||||
-rw-r--r-- | vobject.egg-info/top_level.txt (renamed from src/vobject.egg-info/top_level.txt) | 0 | ||||
-rw-r--r-- | vobject.egg-info/zip-safe (renamed from src/vobject.egg-info/zip-safe) | 0 | ||||
-rw-r--r-- | vobject/__init__.py (renamed from src/vobject/__init__.py) | 0 | ||||
-rw-r--r-- | vobject/base.py (renamed from src/vobject/base.py) | 58 | ||||
-rw-r--r-- | vobject/behavior.py (renamed from src/vobject/behavior.py) | 0 | ||||
-rw-r--r-- | vobject/hcalendar.py (renamed from src/vobject/hcalendar.py) | 0 | ||||
-rw-r--r-- | vobject/icalendar.py (renamed from src/vobject/icalendar.py) | 45 | ||||
-rw-r--r-- | vobject/ics_diff.py (renamed from src/vobject/ics_diff.py) | 0 | ||||
-rw-r--r-- | vobject/vcard.py (renamed from src/vobject/vcard.py) | 0 | ||||
-rw-r--r-- | vobject/win32tz.py (renamed from src/vobject/win32tz.py) | 0 |
25 files changed, 291 insertions, 181 deletions
@@ -1,20 +1,36 @@ Metadata-Version: 1.0 Name: vobject -Version: 0.6.0 +Version: 0.6.6 Summary: VObject: module for reading vCard and vCalendar files Home-page: http://vobject.skyhouseconsulting.com Author: Jeffrey Harris Author-email: jeffrey@osafoundation.org License: Apache -Description: Parses iCalendar and vCard files into Python data structures, decoding the relevant encodings. Also serializes vobject data structures to iCalendar, vCard, or (expirementally) hCalendar unicode strings. +Description: Description + ----------- + + Parses iCalendar and vCard files into Python data structures, decoding the relevant encodings. Also serializes vobject data structures to iCalendar, vCard, or (expirementally) hCalendar unicode strings. + + Requirements + ------------ Requires python 2.4 or later, dateutil (http://labix.org/python-dateutil) 1.1 or later. - Recent changes: - - Added VAVAILABILITY support - - Improved wrapping of unicode lines, serialize encodes unicode as utf-8 by default + Recent changes + -------------- + + * Allow unicode names for TZIDs + * Worked around Lotus Notes use of underscores in names by just silently replacing + with dashes + * When allowing quoted-printable data, honor CHARSET for each line, defaulting to + iso-8859-1 + * Simplified directory layout, unit tests are now available via setup.py test + * Added VAVAILABILITY support + * Improved wrapping of unicode lines, serialize encodes unicode as utf-8 by default - For older changes, see http://vobject.skyhouseconsulting.com/history.html or http://websvn.osafoundation.org/listing.php?repname=vobject&path=/trunk/ + For older changes, see + * http://vobject.skyhouseconsulting.com/history.html or + * http://websvn.osafoundation.org/listing.php?repname=vobject&path=/trunk/ Platform: any Classifier: Development Status :: 4 - Beta @@ -1,14 +1,30 @@ """VObject: module for reading vCard and vCalendar files
+Description
+-----------
+
Parses iCalendar and vCard files into Python data structures, decoding the relevant encodings. Also serializes vobject data structures to iCalendar, vCard, or (expirementally) hCalendar unicode strings.
+Requirements
+------------
+
Requires python 2.4 or later, dateutil (http://labix.org/python-dateutil) 1.1 or later.
-Recent changes:
-- Added VAVAILABILITY support
-- Improved wrapping of unicode lines, serialize encodes unicode as utf-8 by default
+Recent changes
+--------------
-For older changes, see http://vobject.skyhouseconsulting.com/history.html or http://websvn.osafoundation.org/listing.php?repname=vobject&path=/trunk/
+ * Allow unicode names for TZIDs
+ * Worked around Lotus Notes use of underscores in names by just silently replacing
+ with dashes
+ * When allowing quoted-printable data, honor CHARSET for each line, defaulting to
+ iso-8859-1
+ * Simplified directory layout, unit tests are now available via setup.py test
+ * Added VAVAILABILITY support
+ * Improved wrapping of unicode lines, serialize encodes unicode as utf-8 by default
+
+For older changes, see
+ * http://vobject.skyhouseconsulting.com/history.html or
+ * http://websvn.osafoundation.org/listing.php?repname=vobject&path=/trunk/
"""
@@ -17,33 +33,23 @@ use_setuptools() from setuptools import setup, find_packages
-#from distutils.core import setup
-
-# Metadata
-PACKAGE_NAME = "vobject"
-PACKAGE_VERSION = "0.6.0"
-
-ALL_EXTS = ['*.py', '*.ics', '*.txt']
-
-packages = ['vobject']
-
doclines = __doc__.splitlines()
setup(name = "vobject",
- version = PACKAGE_VERSION,
+ version = "0.6.6",
author = "Jeffrey Harris",
author_email = "jeffrey@osafoundation.org",
license = "Apache",
zip_safe = True,
url = "http://vobject.skyhouseconsulting.com",
entry_points = { 'console_scripts': ['ics_diff = vobject.ics_diff:main'] },
- package_dir = {'':'src'},
- package_data = {'': ALL_EXTS},
+ include_package_data = True,
+ test_suite = "test_vobject",
install_requires = ['python-dateutil >= 1.1'],
-
+
platforms = ["any"],
- packages = ["vobject"],
+ packages = find_packages(),
description = doclines[0],
long_description = "\n".join(doclines[2:]),
classifiers = """
diff --git a/src/vobject.egg-info/PKG-INFO b/src/vobject.egg-info/PKG-INFO deleted file mode 100644 index 6ecafcc..0000000 --- a/src/vobject.egg-info/PKG-INFO +++ /dev/null @@ -1,27 +0,0 @@ -Metadata-Version: 1.0 -Name: vobject -Version: 0.6.0 -Summary: VObject: module for reading vCard and vCalendar files -Home-page: http://vobject.skyhouseconsulting.com -Author: Jeffrey Harris -Author-email: jeffrey@osafoundation.org -License: Apache -Description: Parses iCalendar and vCard files into Python data structures, decoding the relevant encodings. Also serializes vobject data structures to iCalendar, vCard, or (expirementally) hCalendar unicode strings. - - Requires python 2.4 or later, dateutil (http://labix.org/python-dateutil) 1.1 or later. - - Recent changes: - - Added VAVAILABILITY support - - Improved wrapping of unicode lines, serialize encodes unicode as utf-8 by default - - For older changes, see http://vobject.skyhouseconsulting.com/history.html or http://websvn.osafoundation.org/listing.php?repname=vobject&path=/trunk/ - -Platform: any -Classifier: Development Status :: 4 - Beta -Classifier: Environment :: Console -Classifier: License :: OSI Approved :: BSD License -Classifier: Intended Audience :: Developers -Classifier: Natural Language :: English -Classifier: Programming Language :: Python -Classifier: Operating System :: OS Independent -Classifier: Topic :: Text Processing diff --git a/src/vobject.egg-info/SOURCES.txt b/src/vobject.egg-info/SOURCES.txt deleted file mode 100644 index 8e378ac..0000000 --- a/src/vobject.egg-info/SOURCES.txt +++ /dev/null @@ -1,25 +0,0 @@ -ACKNOWLEDGEMENTS.txt -LICENSE.txt -README.txt -setup.py -ez_setup/README.txt -ez_setup/__init__.py -src/vobject/__init__.py -src/vobject/base.py -src/vobject/behavior.py -src/vobject/hcalendar.py -src/vobject/icalendar.py -src/vobject/ics_diff.py -src/vobject/vcard.py -src/vobject/win32tz.py -src/vobject.egg-info/PKG-INFO -src/vobject.egg-info/SOURCES.txt -src/vobject.egg-info/dependency_links.txt -src/vobject.egg-info/entry_points.txt -src/vobject.egg-info/requires.txt -src/vobject.egg-info/top_level.txt -src/vobject.egg-info/zip-safe -tests/more_tests.txt -tests/recurrence.ics -tests/tests.py -tests/utf8_test.ics
\ No newline at end of file diff --git a/test_files/more_tests.txt b/test_files/more_tests.txt new file mode 100644 index 0000000..8f4ec9a --- /dev/null +++ b/test_files/more_tests.txt @@ -0,0 +1,62 @@ + +Unicode in vCards +................. + +>>> import vobject +>>> card = vobject.vCard() +>>> card.add('fn').value = u'Hello\u1234 World!' +>>> card.add('n').value = vobject.vcard.Name('World', u'Hello\u1234') +>>> card.add('adr').value = vobject.vcard.Address(u'5\u1234 Nowhere, Apt 1', 'Berkeley', 'CA', '94704', 'USA') +>>> card +<VCARD| [<ADR{}5? Nowhere, Apt 1\nBerkeley, CA 94704\nUSA>, <FN{}Hello? World!>, <N{} Hello? World >]> +>>> card.serialize().decode("utf-8") +u'BEGIN:VCARD\r\nVERSION:3.0\r\nADR:;;5\u1234 Nowhere\\, Apt 1;Berkeley;CA;94704;USA\r\nFN:Hello\u1234 World!\r\nN:World;Hello\u1234;;;\r\nEND:VCARD\r\n' +>>> print card.serialize() +BEGIN:VCARD +VERSION:3.0 +ADR:;;5ሴ Nowhere\, Apt 1;Berkeley;CA;94704;USA +FN:Helloሴ World! +N:World;Helloሴ;;; +END:VCARD + +Unicode in TZID +............... + +>>> from pkg_resources import resource_stream +>>> f = resource_stream(__name__, 'test_files/tzid_8bit.ics') +>>> cal = vobject.readOne(f) +>>> print cal.vevent.dtstart.value +2008-05-30 15:00:00+06:00 +>>> print cal.vevent.dtstart.serialize() +DTSTART;TZID=Екатеринбург:20080530T150000 + +Equality in vCards +.................. + +>>> card.adr.value == vobject.vcard.Address('Just a street') +False +>>> card.adr.value == vobject.vcard.Address(u'5\u1234 Nowhere, Apt 1', 'Berkeley', 'CA', '94704', 'USA') +True + +Organization (org) +.................. + +>>> card.add('org').value = ["Company, Inc.", "main unit", "sub-unit"] +>>> print card.org.serialize() +ORG:Company\, Inc.;main unit;sub-unit + + +quoted-printable +................ + +>>> vcf = 'BEGIN:VCARD\nVERSION:2.1\nN;ENCODING=QUOTED-PRINTABLE:;=E9\nFN;ENCODING=QUOTED-PRINTABLE:=E9\nTEL;HOME:0111111111\nEND:VCARD\n\n' +>>> vcf = vobject.readOne(vcf) +>>> vcf.n.value +u';\xe9' +>>> vcf.serialize() +'BEGIN:VCARD\r\nFN:\xc3\xa9\r\nN:;\xc3\xa9\r\nTEL:0111111111\r\nVERSION:2.1\r\nEND:VCARD\r\n' + +>>> vcs = 'BEGIN:VCALENDAR\r\nPRODID:-//OpenSync//NONSGML OpenSync vformat 0.3//EN\r\nVERSION:1.0\r\nBEGIN:VEVENT\r\nDESCRIPTION;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:foo =C3=A5=0Abar =C3=A4=\r\n=0Abaz =C3=B6\r\nUID:20080406T152030Z-7822\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n' +>>> vcs = vobject.readOne(vcs, allowQP = True) +>>> vcs.serialize() +'BEGIN:VCALENDAR\r\nPRODID:-//OpenSync//NONSGML OpenSync vformat 0.3//EN\r\nVERSION:1.0\r\nBEGIN:VEVENT\r\nDESCRIPTION:foo \xc3\xa5\nbar \xc3\xa4\nbaz \xc3\xb6\r\nUID:20080406T152030Z-7822\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n' diff --git a/tests/recurrence.ics b/test_files/recurrence.ics index f592234..f592234 100644 --- a/tests/recurrence.ics +++ b/test_files/recurrence.ics diff --git a/test_files/tzid_8bit.ics b/test_files/tzid_8bit.ics new file mode 100644 index 0000000..91d35d2 --- /dev/null +++ b/test_files/tzid_8bit.ics @@ -0,0 +1,23 @@ +BEGIN:VCALENDAR +PRODID:-//Microsoft Corporation//Outlook 12.0 MIMEDIR//EN +VERSION:2.0 +BEGIN:VTIMEZONE +TZID:Екатеринбург +BEGIN:STANDARD +DTSTART:16011028T030000 +RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10 +TZOFFSETFROM:+0600 +TZOFFSETTO:+0500 +END:STANDARD +BEGIN:DAYLIGHT +DTSTART:16010325T020000 +RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=3 +TZOFFSETFROM:+0500 +TZOFFSETTO:+0600 +END:DAYLIGHT +END:VTIMEZONE +BEGIN:VEVENT +UID:CyrillicTest +DTSTART;TZID=Екатеринбург:20080530T150000 +END:VEVENT +END:VCALENDAR diff --git a/tests/utf8_test.ics b/test_files/utf8_test.ics index fbb9ada..fbb9ada 100644 --- a/tests/utf8_test.ics +++ b/test_files/utf8_test.ics diff --git a/tests/tests.py b/test_vobject.py index b36793b..1ed3858 100644 --- a/tests/tests.py +++ b/test_vobject.py @@ -1,31 +1,32 @@ """Long or boring tests for vobjects."""
-# add source directory to front of sys path
-import sys, os
-basepath = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-sys.path.insert( 0, os.path.join( basepath, 'src', 'vobject' ) )
-
-import base, icalendar, behavior, vcard, hcalendar
+import vobject
+from vobject import base, icalendar, behavior, vcard, hcalendar
import StringIO, re, dateutil.tz, datetime
+import doctest, test_vobject, unittest
+
+from pkg_resources import resource_stream
+
base.logger.setLevel(base.logging.FATAL)
#------------------- Testing and running functions -----------------------------
-def _test():
- import doctest, base, tests, icalendar, __init__, re
+# named additional_tests for setuptools
+def additional_tests():
+
flags = doctest.NORMALIZE_WHITESPACE | doctest.REPORT_ONLY_FIRST_FAILURE
- for mod in base, tests, icalendar, __init__, vcard:
- doctest.testmod(mod, verbose=0, optionflags=flags)
- doctest.testfile('more_tests.txt', optionflags=flags)
- try:
- sys.path.pop()
- sys.path.insert( 0, os.path.join( basepath, 'src' ) )
- doctest.testfile('../README.txt', optionflags=flags)
- except IOError: #allow this test to fail if we can't find README.txt
- pass
-
+ suite = unittest.TestSuite()
+ for module in base, test_vobject, icalendar, vobject, vcard:
+ suite.addTest(doctest.DocTestSuite(module, optionflags=flags))
+
+ suite.addTest(doctest.DocFileSuite(
+ 'README.txt', 'test_files/more_tests.txt',
+ package='__main__', optionflags=flags
+ ))
+ return suite
if __name__ == '__main__':
- _test()
+ runner = unittest.TextTestRunner()
+ runner.run(additional_tests())
testSilly="""
@@ -95,6 +96,7 @@ METHOD:PUBLISH VERSION:2.0
BEGIN:VEVENT
DTSTART:19870405T020000
+X-BAD/SLASH:TRUE
X-BAD_UNDERSCORE:TRUE
UID:EC9439B1-FF65-11D6-9973-003065F99D04
END:VEVENT
@@ -360,12 +362,14 @@ __test__ = { "Test readOne" : >>> cal = base.readOne(badLineTest)
Traceback (most recent call last):
...
- ParseError: At line 6: Failed to parse line: X-BAD_UNDERSCORE:TRUE
+ ParseError: At line 6: Failed to parse line: X-BAD/SLASH:TRUE
>>> cal = base.readOne(badLineTest, ignoreUnreadable=True)
- >>> cal.x_bad_underscore
+ >>> cal.vevent.x_bad_slash
Traceback (most recent call last):
...
- AttributeError: x_bad_underscore
+ AttributeError: x_bad_slash
+ >>> cal.vevent.x_bad_underscore
+ <X-BAD-UNDERSCORE{}TRUE>
""",
"ical trigger workaround" :
@@ -380,7 +384,7 @@ __test__ = { "Test readOne" : "unicode test" :
r"""
- >>> f = open(os.path.join(basepath, 'tests', 'utf8_test.ics'))
+ >>> f = resource_stream(__name__, 'test_files/utf8_test.ics')
>>> vevent = base.readOne(f).vevent
>>> vevent.summary.value
u'The title \u3053\u3093\u306b\u3061\u306f\u30ad\u30c6\u30a3'
@@ -392,7 +396,7 @@ __test__ = { "Test readOne" : # and include that day (12/28 in this test)
"recurrence test" :
r"""
- >>> f = file(os.path.join(basepath, 'tests', 'recurrence.ics'))
+ >>> f = resource_stream(__name__, 'test_files/recurrence.ics')
>>> cal = base.readOne(f)
>>> dates = list(cal.vevent.rruleset)
>>> dates[0]
@@ -638,7 +642,7 @@ __test__ = { "Test readOne" : """
>>> cal = base.newFromBehavior('hcalendar')
>>> cal.behavior
- <class 'hcalendar.HCalendar'>
+ <class 'vobject.hcalendar.HCalendar'>
>>> pacific = dateutil.tz.tzical(StringIO.StringIO(timezones)).get('US/Pacific')
>>> cal.add('vevent')
<VEVENT| []>
@@ -760,7 +764,7 @@ __test__ = { "Test readOne" : >>> base.getBehavior('note') == None
True
>>> card.note.behavior
- <class 'vcard.VCardTextBehavior'>
+ <class 'vobject.vcard.VCardTextBehavior'>
>>> print card.note.value
The Mayor of the great city of Goerlitz in the great country of Germany.
Next line.
diff --git a/tests/more_tests.txt b/tests/more_tests.txt deleted file mode 100644 index 628b091..0000000 --- a/tests/more_tests.txt +++ /dev/null @@ -1,35 +0,0 @@ -Unicode in vCards -................. - ->>> import vobject ->>> card = vobject.vCard() ->>> card.add('fn').value = u'Hello\u1234 World!' ->>> card.add('n').value = vobject.vcard.Name('World', u'Hello\u1234') ->>> card.add('adr').value = vobject.vcard.Address(u'5\u1234 Nowhere, Apt 1', 'Berkeley', 'CA', '94704', 'USA') ->>> card -<VCARD| [<ADR{}5? Nowhere, Apt 1\nBerkeley, CA 94704\nUSA>, <FN{}Hello? World!>, <N{} Hello? World >]> ->>> card.serialize().decode("utf-8") -u'BEGIN:VCARD\r\nVERSION:3.0\r\nADR:;;5\u1234 Nowhere\\, Apt 1;Berkeley;CA;94704;USA\r\nFN:Hello\u1234 World!\r\nN:World;Hello\u1234;;;\r\nEND:VCARD\r\n' ->>> print card.serialize().decode("utf-8").encode('ascii', 'replace') -BEGIN:VCARD -VERSION:3.0 -ADR:;;5? Nowhere\, Apt 1;Berkeley;CA;94704;USA -FN:Hello? World! -N:World;Hello?;;; -END:VCARD - - -Equality in vCards -.................. - ->>> card.adr.value == vobject.vcard.Address('Just a street') -False ->>> card.adr.value == vobject.vcard.Address(u'5\u1234 Nowhere, Apt 1', 'Berkeley', 'CA', '94704', 'USA') -True - -Organization (org) -.................. - ->>> card.add('org').value = ["Company, Inc.", "main unit", "sub-unit"] ->>> print card.org.serialize() -ORG:Company\, Inc.;main unit;sub-unit
\ No newline at end of file diff --git a/vobject.egg-info/PKG-INFO b/vobject.egg-info/PKG-INFO new file mode 100644 index 0000000..3353477 --- /dev/null +++ b/vobject.egg-info/PKG-INFO @@ -0,0 +1,43 @@ +Metadata-Version: 1.0 +Name: vobject +Version: 0.6.6 +Summary: VObject: module for reading vCard and vCalendar files +Home-page: http://vobject.skyhouseconsulting.com +Author: Jeffrey Harris +Author-email: jeffrey@osafoundation.org +License: Apache +Description: Description + ----------- + + Parses iCalendar and vCard files into Python data structures, decoding the relevant encodings. Also serializes vobject data structures to iCalendar, vCard, or (expirementally) hCalendar unicode strings. + + Requirements + ------------ + + Requires python 2.4 or later, dateutil (http://labix.org/python-dateutil) 1.1 or later. + + Recent changes + -------------- + + * Allow unicode names for TZIDs + * Worked around Lotus Notes use of underscores in names by just silently replacing + with dashes + * When allowing quoted-printable data, honor CHARSET for each line, defaulting to + iso-8859-1 + * Simplified directory layout, unit tests are now available via setup.py test + * Added VAVAILABILITY support + * Improved wrapping of unicode lines, serialize encodes unicode as utf-8 by default + + For older changes, see + * http://vobject.skyhouseconsulting.com/history.html or + * http://websvn.osafoundation.org/listing.php?repname=vobject&path=/trunk/ + +Platform: any +Classifier: Development Status :: 4 - Beta +Classifier: Environment :: Console +Classifier: License :: OSI Approved :: BSD License +Classifier: Intended Audience :: Developers +Classifier: Natural Language :: English +Classifier: Programming Language :: Python +Classifier: Operating System :: OS Independent +Classifier: Topic :: Text Processing diff --git a/vobject.egg-info/SOURCES.txt b/vobject.egg-info/SOURCES.txt new file mode 100644 index 0000000..721a609 --- /dev/null +++ b/vobject.egg-info/SOURCES.txt @@ -0,0 +1,26 @@ +ACKNOWLEDGEMENTS.txt +LICENSE.txt +README.txt +setup.py +test_vobject.py +ez_setup/README.txt +ez_setup/__init__.py +test_files/more_tests.txt +test_files/recurrence.ics +test_files/tzid_8bit.ics +test_files/utf8_test.ics +vobject/__init__.py +vobject/base.py +vobject/behavior.py +vobject/hcalendar.py +vobject/icalendar.py +vobject/ics_diff.py +vobject/vcard.py +vobject/win32tz.py +vobject.egg-info/PKG-INFO +vobject.egg-info/SOURCES.txt +vobject.egg-info/dependency_links.txt +vobject.egg-info/entry_points.txt +vobject.egg-info/requires.txt +vobject.egg-info/top_level.txt +vobject.egg-info/zip-safe
\ No newline at end of file diff --git a/src/vobject.egg-info/dependency_links.txt b/vobject.egg-info/dependency_links.txt index 8b13789..8b13789 100644 --- a/src/vobject.egg-info/dependency_links.txt +++ b/vobject.egg-info/dependency_links.txt diff --git a/src/vobject.egg-info/entry_points.txt b/vobject.egg-info/entry_points.txt index 405bd65..405bd65 100644 --- a/src/vobject.egg-info/entry_points.txt +++ b/vobject.egg-info/entry_points.txt diff --git a/src/vobject.egg-info/requires.txt b/vobject.egg-info/requires.txt index 21aa035..21aa035 100644 --- a/src/vobject.egg-info/requires.txt +++ b/vobject.egg-info/requires.txt diff --git a/src/vobject.egg-info/top_level.txt b/vobject.egg-info/top_level.txt index 52a5040..52a5040 100644 --- a/src/vobject.egg-info/top_level.txt +++ b/vobject.egg-info/top_level.txt diff --git a/src/vobject.egg-info/zip-safe b/vobject.egg-info/zip-safe index 8b13789..8b13789 100644 --- a/src/vobject.egg-info/zip-safe +++ b/vobject.egg-info/zip-safe diff --git a/src/vobject/__init__.py b/vobject/__init__.py index d5daf30..d5daf30 100644 --- a/src/vobject/__init__.py +++ b/vobject/__init__.py diff --git a/src/vobject/base.py b/vobject/base.py index abb6a9e..107e71c 100644 --- a/src/vobject/base.py +++ b/vobject/base.py @@ -4,7 +4,7 @@ import copy import re import sys import logging -import StringIO +import StringIO, cStringIO import string import exceptions import codecs @@ -19,11 +19,11 @@ if not logging.getLogger().handlers: logger.setLevel(logging.ERROR) # Log errors DEBUG = False # Don't waste time on debug calls #----------------------------------- Constants --------------------------------- -CR = unichr(13) -LF = unichr(10) +CR = '\r' +LF = '\n' CRLF = CR + LF -SPACE = unichr(32) -TAB = unichr(9) +SPACE = ' ' +TAB = '\t' SPACEORTAB = SPACE + TAB #-------------------------------- Useful modules ------------------------------- # use doctest, it kills two birds with one stone and docstrings often become @@ -261,6 +261,17 @@ class ContentLine(VBase): if qp: self.value = str(self.value).decode('quoted-printable') + # self.value should be unicode for iCalendar, but if quoted-printable + # is used, or if the quoted-printable state machine is used, text may be + # encoded + if type(self.value) is str: + charset = 'iso-8859-1' + if 'CHARSET' in self.params: + charsets = self.params.pop('CHARSET') + if charsets: + charset = charsets[0] + self.value = unicode(self.value, charset) + @classmethod def duplicate(clz, copyit): newcopy = clz('', {}, '') @@ -613,7 +624,9 @@ class NativeError(VObjectError): patterns = {} -patterns['name'] = '[a-zA-Z0-9\-]+' +# Note that underscore is not legal for names, it's included because +# Lotus Notes uses it +patterns['name'] = '[a-zA-Z0-9\-_]+' patterns['safe_char'] = '[^";:,]' patterns['qsafe_char'] = '[^"]' @@ -662,7 +675,7 @@ patterns['line'] = r""" param_values_re = re.compile(patterns['param_value_grouped'], re.VERBOSE) params_re = re.compile(patterns['params_grouped'], re.VERBOSE) -line_re = re.compile(patterns['line'], re.VERBOSE) +line_re = re.compile(patterns['line'], re.DOTALL | re.VERBOSE) begin_re = re.compile('BEGIN', re.IGNORECASE) @@ -712,7 +725,8 @@ def parseLine(line, lineNumber = None): match = line_re.match(line) if match is None: raise ParseError("Failed to parse line: %s" % line, lineNumber) - return (match.group('name'), + # Underscores are replaced with dash to work around Lotus Notes + return (match.group('name').replace('_','-'), parseParams(match.group('params')), match.group('value'), match.group('group')) @@ -888,7 +902,7 @@ def foldOneLine(outbuf, input, lineLength = 75): def defaultSerialize(obj, buf, lineLength): """Encode and fold obj and its children, write to buf or return a string.""" - outbuf = buf or StringIO.StringIO() + outbuf = buf or cStringIO.StringIO() if isinstance(obj, Component): if obj.group is None: @@ -902,26 +916,19 @@ def defaultSerialize(obj, buf, lineLength): child.serialize(outbuf, lineLength, validate=False) if obj.useBegin: foldOneLine(outbuf, str(groupString + u"END:" + obj.name), lineLength) - if DEBUG: logger.debug("Finished %s" % obj.name.upper()) elif isinstance(obj, ContentLine): startedEncoded = obj.encoded if obj.behavior and not startedEncoded: obj.behavior.encode(obj) - s=StringIO.StringIO() #unfolded buffer + s=codecs.getwriter('utf-8')(cStringIO.StringIO()) #unfolded buffer if obj.group is not None: - s.write(str(obj.group + '.')) - if DEBUG: logger.debug("Serializing line" + str(obj)) - s.write(str(obj.name.upper())) + s.write(obj.group + '.') + s.write(obj.name.upper()) for key, paramvals in obj.params.iteritems(): - s.write(';' + str(key) + '=' + ','.join(map(dquoteEscape, paramvals)).encode("utf-8")) - if isinstance(obj.value, unicode): - strout = obj.value.encode("utf-8") - else: - strout = obj.value - s.write(':' + strout) + s.write(';' + key + '=' + ','.join(dquoteEscape(p) for p in paramvals)) + s.write(':' + obj.value) if obj.behavior and not startedEncoded: obj.behavior.decode(obj) foldOneLine(outbuf, s.getvalue(), lineLength) - if DEBUG: logger.debug("Finished %s line" % obj.name.upper()) return buf or outbuf.getvalue() @@ -957,7 +964,8 @@ class Stack: def readComponents(streamOrString, validate=False, transform=True, - findBegin=True, ignoreUnreadable=False): + findBegin=True, ignoreUnreadable=False, + allowQP=False): """Generate one Component at a time from a stream. >>> import StringIO @@ -978,7 +986,7 @@ def readComponents(streamOrString, validate=False, transform=True, stack = Stack() versionLine = None n = 0 - for line, n in getLogicalLines(stream, False, findBegin): + for line, n in getLogicalLines(stream, allowQP, findBegin): if ignoreUnreadable: try: vline = textLineToContentLine(line, n) @@ -1031,10 +1039,10 @@ def readComponents(streamOrString, validate=False, transform=True, def readOne(stream, validate=False, transform=True, findBegin=True, - ignoreUnreadable=False): + ignoreUnreadable=False, allowQP=False): """Return the first component from stream.""" return readComponents(stream, validate, transform, findBegin, - ignoreUnreadable).next() + ignoreUnreadable, allowQP).next() #--------------------------- version registry ---------------------------------- __behaviorRegistry={} diff --git a/src/vobject/behavior.py b/vobject/behavior.py index 226c0cc..226c0cc 100644 --- a/src/vobject/behavior.py +++ b/vobject/behavior.py diff --git a/src/vobject/hcalendar.py b/vobject/hcalendar.py index 93614ab..93614ab 100644 --- a/src/vobject/hcalendar.py +++ b/vobject/hcalendar.py diff --git a/src/vobject/icalendar.py b/vobject/icalendar.py index fd18910..09862c1 100644 --- a/src/vobject/icalendar.py +++ b/vobject/icalendar.py @@ -4,15 +4,15 @@ import string import behavior import dateutil.rrule import dateutil.tz -import StringIO +import StringIO, cStringIO import datetime import socket, random #for generating a UID import itertools -from base import VObjectError, NativeError, ValidateError, ParseError, \ - VBase, Component, ContentLine, logger, defaultSerialize, \ - registerBehavior, backslashEscape, foldOneLine, \ - newFromBehavior, CRLF, LF +from base import (VObjectError, NativeError, ValidateError, ParseError, + VBase, Component, ContentLine, logger, defaultSerialize, + registerBehavior, backslashEscape, foldOneLine, + newFromBehavior, CRLF, LF, ascii) #------------------------------- Constants ------------------------------------- DATENAMES = ("rdate", "exdate") @@ -30,13 +30,19 @@ twoHours = datetime.timedelta(hours=2) #---------------------------- TZID registry ------------------------------------ __tzidMap={} +def toUnicode(s): + """Take a string or unicode, turn it into unicode, decoding as utf-8""" + if isinstance(s, str): + s = s.decode('utf-8') + return s + def registerTzid(tzid, tzinfo): """Register a tzid -> tzinfo mapping.""" - __tzidMap[tzid]=tzinfo + __tzidMap[toUnicode(tzid)]=tzinfo def getTzid(tzid): """Return the tzid if it exists, or None.""" - return __tzidMap.get(tzid, None) + return __tzidMap.get(toUnicode(tzid), None) utc = dateutil.tz.tzutc() registerTzid("UTC", utc) @@ -83,7 +89,8 @@ class TimezoneComponent(Component): # workaround for dateutil failing to parse some experimental properties good_lines = ('rdate', 'rrule', 'dtstart', 'tzname', 'tzoffsetfrom', 'tzoffsetto', 'tzid') - buffer = StringIO.StringIO() + # serialize encodes as utf-8, cStringIO will leave utf-8 alone + buffer = cStringIO.StringIO() # allow empty VTIMEZONEs if len(self.contents) == 0: return None @@ -97,7 +104,8 @@ class TimezoneComponent(Component): customSerialize(comp) foldOneLine(buffer, u"END:" + obj.name) customSerialize(self) - return dateutil.tz.tzical(StringIO.StringIO(str(buffer.getvalue()))).get() + buffer.seek(0) # tzical wants to read a stream + return dateutil.tz.tzical(buffer).get() def settzinfo(self, tzinfo, start=2000, end=2030): """Create appropriate objects in self to represent tzinfo. @@ -269,22 +277,22 @@ class TimezoneComponent(Component): return None # try PyICU's tzid key if hasattr(tzinfo, 'tzid'): - return tzinfo.tzid + return toUnicode(tzinfo.tzid) # try pytz zone key if hasattr(tzinfo, 'zone'): - return tzinfo.zone + return toUnicode(tzinfo.zone) # try tzical's tzid key elif hasattr(tzinfo, '_tzid'): - return tzinfo._tzid + return toUnicode(tzinfo._tzid) else: # return tzname for standard (non-DST) time notDST = datetime.timedelta(0) for month in xrange(1,13): dt = datetime.datetime(2000, month, 1) if tzinfo.dst(dt) == notDST: - return tzinfo.tzname(dt) + return toUnicode(tzinfo.tzname(dt)) # there was no standard time in 2000! raise VObjectError("Unable to guess TZID for tzinfo %s" % str(tzinfo)) @@ -646,7 +654,7 @@ class DateTimeBehavior(behavior.Behavior): obj.params['X-VOBJ-FLOATINGTIME-ALLOWED'] = ['TRUE'] if obj.params.get('TZID'): # Keep a copy of the original TZID around - obj.params['X-VOBJ-ORIGINAL-TZID'] = obj.params['TZID'] + obj.params['X-VOBJ-ORIGINAL-TZID'] = [obj.params['TZID']] del obj.params['TZID'] return obj @@ -661,7 +669,7 @@ class DateTimeBehavior(behavior.Behavior): obj.tzid_param = tzid if obj.params.get('X-VOBJ-ORIGINAL-TZID'): if not hasattr(obj, 'tzid_param'): - obj.tzid_param = obj.params['X-VOBJ-ORIGINAL-TZID'] + obj.tzid_param = obj.x_vobj_original_tzid_param del obj.params['X-VOBJ-ORIGINAL-TZID'] return obj @@ -685,7 +693,7 @@ class DateOrDateTimeBehavior(behavior.Behavior): if getattr(obj, 'value_param', 'DATE-TIME').upper() == 'DATE-TIME': if hasattr(obj, 'tzid_param'): # Keep a copy of the original TZID around - obj.params['X-VOBJ-ORIGINAL-TZID'] = obj.tzid_param + obj.params['X-VOBJ-ORIGINAL-TZID'] = [obj.tzid_param] del obj.tzid_param return obj @@ -838,9 +846,10 @@ class VCalendar2_0(VCalendarComponentBehavior): findTzids(child, table) findTzids(obj, tzidsUsed) - oldtzids = [x.tzid.value for x in getattr(obj, 'vtimezone_list', [])] + oldtzids = [toUnicode(x.tzid.value) for x in getattr(obj, 'vtimezone_list', [])] for tzid in tzidsUsed.keys(): - if tzid != 'UTC' and tzid not in oldtzids: + tzid = toUnicode(tzid) + if tzid != u'UTC' and tzid not in oldtzids: obj.add(TimezoneComponent(tzinfo=getTzid(tzid))) registerBehavior(VCalendar2_0) diff --git a/src/vobject/ics_diff.py b/vobject/ics_diff.py index 4aaaef9..4aaaef9 100644 --- a/src/vobject/ics_diff.py +++ b/vobject/ics_diff.py diff --git a/src/vobject/vcard.py b/vobject/vcard.py index 01d1d42..01d1d42 100644 --- a/src/vobject/vcard.py +++ b/vobject/vcard.py diff --git a/src/vobject/win32tz.py b/vobject/win32tz.py index 35f997b..35f997b 100644 --- a/src/vobject/win32tz.py +++ b/vobject/win32tz.py |