cctool

A tool for managing contacts and calendars.
git clone https://git.ce9e.org/cctool.git

commit
29525d5bc74b58588bf9a1042ffcd2715256ef8d
parent
1ba29f54a7d3ffff8cb69b7d6e39f64307ad0efe
Author
Tobias Bengfort <tobias.bengfort@gmx.net>
Date
2014-04-20 20:34
multidict

Diffstat

M cctool.py 75 +++++++++++++++++++++++++++++++++++++++++++++++++------------

1 files changed, 61 insertions, 14 deletions


diff --git a/cctool.py b/cctool.py

@@ -25,7 +25,6 @@
   25    25 # -	filter/convert for valid fields
   26    26 # -	doc
   27    27 # -	tests
   28    -1 # -	multidicts
   29    28 # -	merge
   30    29 # -	sort
   31    30 # -	filter
@@ -50,6 +49,47 @@ except ImportError as e:
   50    49 	vobject = e
   51    50 
   52    51 
   -1    52 NOTSET = object()
   -1    53 
   -1    54 
   -1    55 class MultiDict(dict):
   -1    56 	"""Dict subclass with multiple values for each key.
   -1    57 
   -1    58 	>>> d = MultiDict()
   -1    59 	>>> d['foo'] = []
   -1    60 	>>> 'foo' in d
   -1    61 	False
   -1    62 	>>> d['foo'] = [1, 2, 3]
   -1    63 	>>> 'foo' in d
   -1    64 	True
   -1    65 	>>> d['foo']
   -1    66 	[1, 2, 3]
   -1    67 	>>> d.first('foo')
   -1    68 	1
   -1    69 	"""
   -1    70 
   -1    71 	def __contains__(self, key):
   -1    72 		return super(MultiDict, self).__contains__(key) and self[key] != []
   -1    73 
   -1    74 	def first(self, key, default=NOTSET):
   -1    75 		if key in self:
   -1    76 			return self[key][0]
   -1    77 		elif default is not NOTSET :
   -1    78 			return default
   -1    79 		else:
   -1    80 			raise KeyError
   -1    81 
   -1    82 	def join(self, key, default=NOTSET, sep=u','):
   -1    83 		if key in self and len(self[key]) == 1:
   -1    84 			return self[key][0]
   -1    85 		elif key in self:
   -1    86 			return sep.join(self[key])
   -1    87 		elif default is not NOTSET :
   -1    88 			return default
   -1    89 		else:
   -1    90 			raise KeyError
   -1    91 
   -1    92 
   53    93 class Format(object):
   54    94 	@classmethod
   55    95 	def load(cls, fh):
@@ -75,9 +115,9 @@ class BSDCal(Format):
   75   115 	def dump(cls, data, fh):
   76   116 		for item in data:
   77   117 			if u'dtstart' in item and u'summary' in item:
   78    -1 				fh.write('%s\t%s\n' % (item['dtstart'], item['summary']))
   -1   118 				fh.write('%s\t%s\n' % (item.first('dtstart'), item.join('summary')))
   79   119 			if u'bday' in item and u'name' in item:
   80    -1 				fh.write('%s\t%s\n' % (item['bday'], item['name']))
   -1   120 				fh.write('%s\t%s\n' % (item.first('bday'), item.join('name')))
   81   121 
   82   122 
   83   123 class ICal(Format):
@@ -88,7 +128,10 @@ class ICal(Format):
   88   128 
   89   129 		for calendar in vobject.readComponents(fh):
   90   130 			for event in calendar.vevent_list:
   91    -1 				yield {k: v[0].value for (k, v) in event.contents.iteritems()}
   -1   131 				d = MultiDict()
   -1   132 				for key, value in event.contents.iteritems():
   -1   133 					d[key] = [i.value for i in value]
   -1   134 				yield d
   92   135 
   93   136 	@classmethod
   94   137 	def dump(cls, data, fh):
@@ -98,8 +141,8 @@ class ICal(Format):
   98   141 		ical = vobject.iCalendar()
   99   142 		for event in data:
  100   143 			vevent = ical.add('vevent')
  101    -1 			for key, value in event.iteritems():
  102    -1 				vevent.add(key).value = value
   -1   144 			for key in event:
   -1   145 				vevent.add(key).value = event.join(key)
  103   146 		ical.serialize(fh)
  104   147 
  105   148 
@@ -112,7 +155,7 @@ class ABook(Format):
  112   155 		cp.readfp(fh)
  113   156 		for section in cp.sections():
  114   157 			if section != u'format':
  115    -1 				yield dict(cp.items(section))
   -1   158 				yield MultiDict({k: [v] for (k, v) in cp.items(section)})
  116   159 
  117   160 	@classmethod
  118   161 	def dump(cls, data, fh):
@@ -121,8 +164,8 @@ class ABook(Format):
  121   164 		for item in data:
  122   165 			section = unicode(i)
  123   166 			cp.add_section(section)
  124    -1 			for key, value in item.iteritems():
  125    -1 				cp.set(section, key, unicode(value))
   -1   167 			for key in item:
   -1   168 				cp.set(section, key, item.join(key))
  126   169 			i += 1
  127   170 		cp.write(fh)
  128   171 
@@ -146,7 +189,8 @@ class LDIF(Format):
  146   189 			parser.parse()
  147   190 		except ValueError:
  148   191 			log.warning("ValueError after reading %i records" % parser.records_read)
  149    -1 		return parser.entries.itervalues()
   -1   192 		for entry in parser.entries.itervalues():
   -1   193 			yield MultiDict(entry)
  150   194 
  151   195 	@classmethod
  152   196 	def dump(cls, fh):
@@ -162,7 +206,10 @@ class VCard(Format):
  162   206 			raise vobject
  163   207 
  164   208 		for vcard in vobject.readComponents(fh):
  165    -1 			yield {k: v[0].value for (k, v) in vcard.contents.iteritems()}
   -1   209 			d = MultiDict()
   -1   210 			for key, value in vcard.contents.iteritems():
   -1   211 				d[key] = [i.value for i in value]
   -1   212 			yield d
  166   213 
  167   214 	@classmethod
  168   215 	def dump(cls, data, fh):
@@ -171,15 +218,15 @@ class VCard(Format):
  171   218 
  172   219 		for item in data:
  173   220 			vcard = vobject.vCard()
  174    -1 			for key, value in item.iteritems():
  175    -1 				vcard.add(key).value = value
   -1   221 			for key in item:
   -1   222 				vcard.add(key).value = item.join(key)
  176   223 			vcard.serialize(fh)
  177   224 
  178   225 
  179   226 class JSON(Format):
  180   227 	@classmethod
  181   228 	def load(cls, fh):
  182    -1 		return json.load(fh)
   -1   229 		return [MultiDict(i) for i in json.load(fh)]
  183   230 
  184   231 	@classmethod
  185   232 	def dump(cls, data, fh):