summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuido Guenther <agx@sigxcpu.org>2006-09-23 23:25:37 +0200
committerGuido Guenther <agx@bogon.sigxcpu.org>2006-09-23 23:25:37 +0200
commit83cca3541c1171102bcda16aa5aab732f5a9097f (patch)
tree8482a7de9a4c9daa636796d9e9f2638aa13e88d9
parent0f963fa4c3d05e0f8b297aeb20aa5d719f7ab31d (diff)
Imported python-vobject-0.0.svn155
into Git repository
-rw-r--r--ez_setup.py50
-rwxr-xr-xsetup.py12
-rw-r--r--src/vobject/base.py34
-rw-r--r--src/vobject/icalendar.py28
-rw-r--r--tests/tests.py4
5 files changed, 74 insertions, 54 deletions
diff --git a/ez_setup.py b/ez_setup.py
index 4789e37..3367510 100644
--- a/ez_setup.py
+++ b/ez_setup.py
@@ -14,30 +14,20 @@ the appropriate options to ``use_setuptools()``.
This file can also be run as a script to install or upgrade setuptools.
"""
import sys
-DEFAULT_VERSION = "0.6a9"
+DEFAULT_VERSION = "0.6c1"
DEFAULT_URL = "http://cheeseshop.python.org/packages/%s/s/setuptools/" % sys.version[:3]
md5_data = {
- 'setuptools-0.5a13-py2.3.egg': '85edcf0ef39bab66e130d3f38f578c86',
- 'setuptools-0.5a13-py2.4.egg': 'ede4be600e3890e06d4ee5e0148e092a',
- 'setuptools-0.6a1-py2.3.egg': 'ee819a13b924d9696b0d6ca6d1c5833d',
- 'setuptools-0.6a1-py2.4.egg': '8256b5f1cd9e348ea6877b5ddd56257d',
- 'setuptools-0.6a2-py2.3.egg': 'b98da449da411267c37a738f0ab625ba',
- 'setuptools-0.6a2-py2.4.egg': 'be5b88bc30aed63fdefd2683be135c3b',
- 'setuptools-0.6a3-py2.3.egg': 'ee0e325de78f23aab79d33106dc2a8c8',
- 'setuptools-0.6a3-py2.4.egg': 'd95453d525a456d6c23e7a5eea89a063',
- 'setuptools-0.6a4-py2.3.egg': 'e958cbed4623bbf47dd1f268b99d7784',
- 'setuptools-0.6a4-py2.4.egg': '7f33c3ac2ef1296f0ab4fac1de4767d8',
- 'setuptools-0.6a5-py2.3.egg': '748408389c49bcd2d84f6ae0b01695b1',
- 'setuptools-0.6a5-py2.4.egg': '999bacde623f4284bfb3ea77941d2627',
- 'setuptools-0.6a6-py2.3.egg': '7858139f06ed0600b0d9383f36aca24c',
- 'setuptools-0.6a6-py2.4.egg': 'c10d20d29acebce0dc76219dc578d058',
- 'setuptools-0.6a7-py2.3.egg': 'cfc4125ddb95c07f9500adc5d6abef6f',
- 'setuptools-0.6a7-py2.4.egg': 'c6d62dab4461f71aed943caea89e6f20',
- 'setuptools-0.6a8-py2.3.egg': '2f18eaaa3f544f5543ead4a68f3b2e1a',
- 'setuptools-0.6a8-py2.4.egg': '799018f2894f14c9f8bcb2b34e69b391',
- 'setuptools-0.6a9-py2.3.egg': '8e438ad70438b07b0d8f82cae42b278f',
- 'setuptools-0.6a9-py2.4.egg': '8f6e01fc12fb1cd006dc0d6c04327ec1',
+ 'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',
+ 'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb',
+ 'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b',
+ 'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a',
+ 'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618',
+ 'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac',
+ 'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5',
+ 'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4',
+ 'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c',
+ 'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b',
}
import sys, os
@@ -52,7 +42,7 @@ def _validate_md5(egg_name, data):
% egg_name
)
sys.exit(2)
- return data
+ return data
def use_setuptools(
@@ -68,7 +58,7 @@ def use_setuptools(
be the number of seconds that will be paused before initiating a download,
should one be required. If an older version of setuptools is installed,
this routine will print a message to ``sys.stderr`` and raise SystemExit in
- an attempt to abort the calling script.
+ an attempt to abort the calling script.
"""
try:
import setuptools
@@ -123,8 +113,14 @@ help). I will attempt to download it for you (from
%s), but
you may need to enable firewall access for this script first.
I will start the download in %d seconds.
+
+(Note: if this machine does not have network access, please obtain the file
+
+ %s
+
+and place it in this directory before rerunning this script.)
---------------------------------------------------------------------------""",
- version, download_base, delay
+ version, download_base, delay, url
); from time import sleep; sleep(delay)
log.warn("Downloading %s", url)
src = urllib2.urlopen(url)
@@ -149,7 +145,7 @@ def main(argv, version=DEFAULT_VERSION):
egg = download_setuptools(version, to_dir=tmpdir, delay=0)
sys.path.insert(0,egg)
from setuptools.command.easy_install import main
- main(list(argv)+[egg])
+ return main(list(argv)+[egg]) # we're done here
finally:
shutil.rmtree(tmpdir)
else:
@@ -177,7 +173,7 @@ def main(argv, version=DEFAULT_VERSION):
print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
-
+
def update_md5(filenames):
"""Update our built-in md5 registry"""
@@ -186,7 +182,7 @@ def update_md5(filenames):
for name in filenames:
base = os.path.basename(name)
- f = open(name,'rb')
+ f = open(name,'rb')
md5_data[base] = md5(f.read()).hexdigest()
f.close()
diff --git a/setup.py b/setup.py
index fd44be0..3f79027 100755
--- a/setup.py
+++ b/setup.py
@@ -7,16 +7,16 @@ Requires dateutil (https://moin.conectiva.com.br/DateUtil) 0.9 or later.
"""
# not using setuptools until Chandler's ready for eggs
-# from ez_setup import use_setuptools
-# use_setuptools()
+from ez_setup import use_setuptools
+use_setuptools()
-# from setuptools import setup, find_packages
+from setuptools import setup, find_packages
-from distutils.core import setup
+#from distutils.core import setup
# Metadata
PACKAGE_NAME = "vobject"
-PACKAGE_VERSION = "0.3.0"
+PACKAGE_VERSION = "0.4.2"
ALL_EXTS = ['*.py', '*.ics', '*.txt']
@@ -28,7 +28,7 @@ setup(name = "vobject",
version = PACKAGE_VERSION,
author = "Jeffrey Harris",
author_email = "jeffrey@osafoundation.org",
- license = "BSD",
+ license = "Apache",
zip_safe = True,
url = "http://vobject.skyhouseconsulting.com",
diff --git a/src/vobject/base.py b/src/vobject/base.py
index 102e38f..e68f366 100644
--- a/src/vobject/base.py
+++ b/src/vobject/base.py
@@ -611,6 +611,8 @@ 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)
+begin_re = re.compile('BEGIN', re.IGNORECASE)
+
def parseParams(string):
"""
@@ -687,7 +689,7 @@ Line 1;encoding=quoted-printable:this is an evil=
Line 2 is a new line, it does not start with whitespace.
"""
-def getLogicalLines(fp, allowQP=True):
+def getLogicalLines(fp, allowQP=True, findBegin=False):
"""Iterate through a stream, yielding one logical line at a time.
Because many applications still use vCard 2.1, we have to deal with the
@@ -710,13 +712,26 @@ def getLogicalLines(fp, allowQP=True):
"""
if not allowQP:
- val = fp.read(-1)
+ bytes = fp.read(-1)
+ if type(bytes[0]) == unicode:
+ val = bytes
+ elif not findBegin:
+ val = bytes.decode('utf-8')
+ else:
+ for encoding in 'utf-8', 'utf-16-LE', 'utf-16-BE':
+ try:
+ val = bytes.decode(encoding)
+ if begin_re.search(val) is not None:
+ break
+ except UnicodeDecodeError:
+ pass
+ else:
+ raise ParseError, 'Could not find BEGIN when trying to determine encoding'
+
lineNumber = 1
for match in logical_lines_re.finditer(val):
line, n = wrap_re.subn('', match.group())
if line != '':
- if type(line[0]) != unicode:
- line = line.decode('utf-8')
yield line, lineNumber
lineNumber += n
@@ -731,8 +746,6 @@ def getLogicalLines(fp, allowQP=True):
if line == '':
break
else:
- if type(line[0]) != unicode:
- line = line.decode('utf-8')
line = line.rstrip(CRLF)
lineNumber += 1
if line.rstrip() == '':
@@ -771,6 +784,7 @@ def getLogicalLines(fp, allowQP=True):
def textLineToContentLine(text, n=None):
return ContentLine(*parseLine(text, n), **{'encoded':True, 'lineNumber' : n})
+
def dquoteEscape(param):
"""Return param, or "param" if ',' or ';' or ':' is in param."""
@@ -857,7 +871,7 @@ class Stack:
def push(self, obj): self.stack.append(obj)
def pop(self): return self.stack.pop()
-def readComponents(streamOrString, validate=False, transform=True):
+def readComponents(streamOrString, validate=False, transform=True, findBegin=True):
"""Generate one Component at a time from a stream.
>>> import StringIO
@@ -876,7 +890,7 @@ def readComponents(streamOrString, validate=False, transform=True):
stack = Stack()
versionLine = None
n = 0
- for line, n in getLogicalLines(stream, False): # not allowing vCard 2.1
+ for line, n in getLogicalLines(stream, False, findBegin):
vline = textLineToContentLine(line, n)
if vline.name == "VERSION":
versionLine = vline
@@ -912,9 +926,9 @@ def readComponents(streamOrString, validate=False, transform=True):
yield stack.pop()
-def readOne(stream, validate=False, transform=True):
+def readOne(stream, validate=False, transform=True, findBegin=True):
"""Return the first component from stream."""
- return readComponents(stream, validate, transform).next()
+ return readComponents(stream, validate, transform, findBegin).next()
#--------------------------- version registry ----------------------------------
__behaviorRegistry={}
diff --git a/src/vobject/icalendar.py b/src/vobject/icalendar.py
index 9350131..728afb0 100644
--- a/src/vobject/icalendar.py
+++ b/src/vobject/icalendar.py
@@ -84,6 +84,9 @@ class TimezoneComponent(Component):
good_lines = ('rdate', 'rrule', 'dtstart', 'tzname', 'tzoffsetfrom',
'tzoffsetto', 'tzid')
buffer = StringIO.StringIO()
+ # allow empty VTIMEZONEs
+ if len(self.contents) == 0:
+ return None
def customSerialize(obj):
if isinstance(obj, Component):
foldOneLine(buffer, u"BEGIN:" + obj.name)
@@ -380,7 +383,9 @@ class RecurringComponent(Component):
rule = dateutil.rrule.rrulestr(str(line.value),
dtstart=dtstart)
until = rule._until
- if until is not None and until.tzinfo != dtstart.tzinfo:
+ if until is not None and \
+ isinstance(dtstart, datetime.datetime) and \
+ (until.tzinfo != dtstart.tzinfo):
# dateutil converts the UNTIL date to a datetime,
# check to see if the UNTIL parameter value was a date
vals = dict(pair.split('=') for pair in
@@ -482,9 +487,11 @@ class RecurringComponent(Component):
values['BYMONTHDAY'] = [str(n) for n in rule._bymonthday]
if rule._bymonth is not None and len(rule._bymonth) > 0:
- if not (rule._freq == dateutil.rrule.YEARLY and
- len(rule._bymonth) == 1 and
- rule._bymonth[0] == rule._dtstart.month):
+ if (rule._byweekday is not None or
+ len(rrule._bynweekday or ()) > 0 or
+ not (rule._freq == dateutil.rrule.YEARLY and
+ len(rule._bymonth) == 1 and
+ rule._bymonth[0] == rule._dtstart.month)):
# ignore bymonth if it's generated by dateutil
values['BYMONTH'] = [str(n) for n in rule._bymonth]
@@ -657,8 +664,7 @@ class MultiDateBehavior(behavior.Behavior):
appropriate strings.
"""
- # Fixme: obj.value should be a list, so this test should never succeed
- if type(obj.value) == datetime.date:
+ if obj.value and type(obj.value[0]) == datetime.date:
obj.isNative = False
obj.value_param = 'DATE'
obj.value = ','.join([dateToString(val) for val in obj.value])
@@ -791,8 +797,8 @@ class VCalendar2_0(behavior.Behavior):
findTzids(obj, tzidsUsed)
oldtzids = [x.tzid.value for x in getattr(obj, 'vtimezone_list', [])]
for tzid in tzidsUsed.keys():
- if tzid == 'UTC' or tzid in oldtzids: continue
- obj.add(TimezoneComponent(tzinfo=getTzid(tzid)))
+ if tzid != 'UTC' and tzid not in oldtzids:
+ obj.add(TimezoneComponent(tzinfo=getTzid(tzid)))
registerBehavior(VCalendar2_0)
class VTimezone(behavior.Behavior):
@@ -811,7 +817,11 @@ class VTimezone(behavior.Behavior):
@classmethod
def validate(cls, obj, raiseException, *args):
- return True #TODO: FIXME
+ if not hasattr(obj, 'tzid') or obj.tzid.value is None:
+ if raiseException:
+ m = "VTIMEZONE components must contain a valid TZID"
+ raise ValidateError(m)
+ return False
if obj.contents.has_key('standard') or obj.contents.has_key('daylight'):
return super(VTimezone, cls).validate(obj, raiseException, *args)
else:
diff --git a/tests/tests.py b/tests/tests.py
index 16ef0c2..9432cd9 100644
--- a/tests/tests.py
+++ b/tests/tests.py
@@ -274,7 +274,7 @@ END:VTIMEZONE
__test__ = { "Test readOne" :
r"""
- >>> silly = base.readOne(testSilly)
+ >>> silly = base.readOne(testSilly, findBegin=False)
>>> silly
<SILLYPROFILE| [<MORESTUFF{}this line is not folded, but in practice probably ought to be, as it is exceptionally long, and moreover demonstratively stupid>, <SILLYNAME{}name>, <STUFF{}foldedline>]>
>>> silly.stuff
@@ -285,7 +285,7 @@ __test__ = { "Test readOne" :
>>> silly2.serialize()==original
True
>>> s3 = StringIO.StringIO('cn:Babs Jensen\r\ncn:Barbara J Jensen\r\nsn:Jensen\r\nemail:babs@umich.edu\r\nphone:+1 313 747-4454\r\nx-id:1234567890\r\n')
- >>> ex1 = base.readOne(s3)
+ >>> ex1 = base.readOne(s3, findBegin=False)
>>> ex1
<*unnamed*| [<CN{}Babs Jensen>, <CN{}Barbara J Jensen>, <EMAIL{}babs@umich.edu>, <PHONE{}+1 313 747-4454>, <SN{}Jensen>, <X-ID{}1234567890>]>
>>> ex1.serialize()