[Vobject] Mac OS X AddressBook and vobject

Lars Immisch lars at ibp.de
Tue Jan 17 17:43:06 CST 2006


Dear Jeffrey,

I got as far as bubbling up the group info to ContentLine (without 
breaking any doctests after adjustments).

So: another patch. This time as attachment.

The longer I think about RFC 2426 groups, the more am I convinced that 
it's a classical standards bug: Not a bad idea in itself, but 
underspecified and subsequently abused.

That being said, groups are in the standard, and I am strongly in favour 
of including it into vobject, my peripheral doubts in RFC 2425 and RFC 
2526 notwithstanding.

You'll probably see worse once Chandler becomes reality.

- Lars

P.S:

I do like the example in RFC 2425, section 8.3. Someone was in love with 
Görlitz (and so am I):

begin:vcard
source:ldap://cn=Meister%20Berger,o=Universitaet%20Goerlitz,c=DE
name:Meister Berger
fn:Meister Berger
n:Berger;Meister
bday;value=date:1963-09-21
o:Universit=E6t G=F6rlitz
title:Mayor
title;language=de;value=text:Burgermeister
note:The Mayor of the great city of
   Goerlitz in the great country of Germany.
email;internet:mb at goerlitz.de
home.tel;type=fax,voice,msg:+49 3581 123456
home.label:Hufenshlagel 1234\n
  02828 Goerlitz\n
  Deutschland
end:vcard

-------------- next part --------------
Index: vobject.py
===================================================================
--- vobject.py	(revision 104)
+++ vobject.py	(working copy)
@@ -177,6 +177,8 @@
         be empty for empty parameters).
     @ivar value:
         The value of the contentline.
+    @ivar group:
+        The optional group prefix, used for provate purposes of the generator.
     @ivar singletonparams:
         A list of parameters for which it's unclear if the string represents the
         parameter name or the parameter value. In vCard 2.1, "The value string
@@ -193,12 +195,14 @@
     @ivar lineNumber:
         An optional line number associated with the contentline.
     """
-    def __init__(self, name, params, value, encoded=False, corruption=None,
-                            isNative=False, lineNumber = None, *args, **kwds):
+    def __init__(self, name, params, value, group = None,
+                 encoded=False, corruption=None,
+                 isNative=False, lineNumber = None, *args, **kwds):
         """Take output from parseLine, convert params list to dictionary."""
         super(ContentLine, self).__init__(*args, **kwds)
         self.name        = name.upper()
         self.value       = value
+        self.group       = group
         self.corruption  = corruption
         self.encoded     = encoded
         self.params      = {}
@@ -307,12 +311,14 @@
         else:
             object.__setattr__(self, name, value)
 
-    def add(self, objOrName):
+    def add(self, objOrName, group = None):
         """Add objOrName to contents, set behavior if it can be inferred.
         
         If objOrName is a string, create an empty component or line based on
         behavior. If no behavior is found for the object, add a ContentLine.
-        
+
+        group is an optional prefix to the name of the object (see
+        RFC 2425).
         """
         if isinstance(objOrName, VBase):
             obj = objOrName
@@ -327,12 +333,12 @@
                 if behavior.isComponent:
                     obj = Component(name)
                 else:
-                    obj = ContentLine(name, [], '')
+                    obj = ContentLine(name, [], '', group)
                 obj.parentBehavior = self.behavior
                 obj.behavior = behavior
                 obj = obj.transformToNative()     
             except (KeyError, AttributeError):
-                obj = ContentLine(objOrName, [], '') 
+                obj = ContentLine(objOrName, [], '', group)
         self.contents.setdefault(obj.name.lower(), []).append(obj)
         return obj
 
@@ -464,11 +470,11 @@
 )?
 """ % patterns
 
-# get a full content line, break it up into name, parameters, and value
+# get a full content line, break it up into group, name, parameters, and value
 patterns['line'] = r"""
-^ (?P<name> %(name)s )               # name group
-  (?P<params> (?: %(param)s )* )     # params group (may be empty)
-: (?P<value> .* )$                   # value group
+^ ((?P<group> %(name)s)\.)?(?P<name> %(name)s) # name group
+  (?P<params> (?: %(param)s )* )               # params group (may be empty)
+: (?P<value> .* )$                             # value group
 """ % patterns
 
 ' "%(qsafe_char)s*" | %(safe_char)s* '
@@ -503,15 +509,17 @@
 def parseLine(line):
     """
     >>> parseLine("BLAH:")
-    ('BLAH', [], '')
+    ('BLAH', [], '', None)
     >>> parseLine("RDATE:VALUE=DATE:19970304,19970504,19970704,19970904")
-    ('RDATE', [], 'VALUE=DATE:19970304,19970504,19970704,19970904')
+    ('RDATE', [], 'VALUE=DATE:19970304,19970504,19970704,19970904', None)
     >>> parseLine('DESCRIPTION;ALTREP="http://www.wiz.org":The Fall 98 Wild Wizards Conference - - Las Vegas, NV, USA')
-    ('DESCRIPTION', [['ALTREP', 'http://www.wiz.org']], 'The Fall 98 Wild Wizards Conference - - Las Vegas, NV, USA')
+    ('DESCRIPTION', [['ALTREP', 'http://www.wiz.org']], 'The Fall 98 Wild Wizards Conference - - Las Vegas, NV, USA', None)
     >>> parseLine("EMAIL;PREF;INTERNET:john at nowhere.com")
-    ('EMAIL', [['PREF'], ['INTERNET']], 'john at nowhere.com')
+    ('EMAIL', [['PREF'], ['INTERNET']], 'john at nowhere.com', None)
     >>> parseLine('EMAIL;TYPE="blah",hah;INTERNET="DIGI",DERIDOO:john at nowhere.com')
-    ('EMAIL', [['TYPE', 'blah', 'hah'], ['INTERNET', 'DIGI', 'DERIDOO']], 'john at nowhere.com')
+    ('EMAIL', [['TYPE', 'blah', 'hah'], ['INTERNET', 'DIGI', 'DERIDOO']], 'john at nowhere.com', None)
+    >>> parseLine('item1.ADR;type=HOME;type=pref:;;Reeperbahn 116;Hamburg;;20359;')
+    ('ADR', [['type', 'HOME'], ['type', 'pref']], ';;Reeperbahn 116;Hamburg;;20359;', 'item1')
     >>> parseLine(":")
     Traceback (most recent call last):
     ...
@@ -523,7 +531,7 @@
         raise ParseError("Failed to parse line: %s" % line)
     return (match.group('name'), 
             parseParams(match.group('params')),
-            match.group('value'))
+            match.group('value'), match.group('group'))
 
 # logical line regular expressions
 
@@ -814,4 +822,4 @@
 #------------------- Testing and running functions -----------------------------
 if __name__ == '__main__':
     import tests
-    tests._test()
\ No newline at end of file
+    tests._test()   


More information about the VObject mailing list