- commit
- b329a7613a15efa3cbe9c6f8538b639e801ea889
- parent
- 7ec7ea7190d2fde6f8ddbc1f8d8eeb60d63d711d
- Author
- Tobias Bengfort <tobias.bengfort@gmx.net>
- Date
- 2015-05-08 19:42
implement own ldif parser incompatible but actually works better on my data than the 3rd party one. Should be turned into a full implementation of rfc2849.
Diffstat
| M | cctool.py | 58 | ++++++++++++++++++++++++++++++---------------------------- |
| M | setup.py | 1 | - |
| M | tests.py | 8 | +++++--- |
3 files changed, 35 insertions, 32 deletions
diff --git a/cctool.py b/cctool.py
@@ -40,9 +40,9 @@ from datetime import date 40 40 from datetime import datetime 41 41 from io import BytesIO 42 42 import argparse -1 43 import base64 43 44 import codecs 44 45 import json45 -1 import logging as log46 46 import os 47 47 import pickle 48 48 import re @@ -54,11 +54,6 @@ except ImportError: 54 54 from configparser import RawConfigParser as ConfigParser 55 55 56 56 try:57 -1 import ldif58 -1 except ImportError as err:59 -1 ldif = err60 -161 -1 try:62 57 import icalendar 63 58 except ImportError as err: 64 59 icalendar = err @@ -87,6 +82,7 @@ def formats(): 87 82 'abook': ABook, 88 83 'json': JSON, 89 84 'pickle': Pickle, -1 85 'ldif': LDIF, 90 86 } 91 87 outformats = { 92 88 'bsdcal': BSDCal, @@ -97,8 +93,6 @@ def formats(): 97 93 if not isinstance(icalendar, Exception): 98 94 informats['ics'] = ICal 99 95 outformats['ics'] = ICal100 -1 if not isinstance(ldif, Exception):101 -1 informats['ldif'] = LDIF102 96 if not isinstance(yaml, Exception): 103 97 informats['yml'] = YAML 104 98 outformats['yml'] = YAML @@ -402,16 +396,6 @@ class ABook(Format): 402 396 cp.write(_fh) 403 397 404 398405 -1 if not isinstance(ldif, Exception):406 -1 class LDIFParser(ldif.LDIFParser):407 -1 def __init__(self, fh):408 -1 ldif.LDIFParser.__init__(self, fh)409 -1 self.entries = {}410 -1411 -1 def handle(self, dn, entry):412 -1 self.entries[dn] = entry413 -1414 -1415 399 class LDIF(Format): 416 400 fields = { 417 401 'cn': 'name', @@ -419,17 +403,35 @@ class LDIF(Format): 419 403 } 420 404 421 405 @classmethod -1 406 def get_blocks(cls, fh): -1 407 block = [] -1 408 for _line in fh: -1 409 line = _line.rstrip() -1 410 if not line: -1 411 yield block -1 412 block = [] -1 413 elif line.startswith(b'#'): -1 414 continue -1 415 elif line.startswith(b' '): -1 416 block[-1] += line[1:] -1 417 else: -1 418 block.append(line) -1 419 if block: -1 420 yield block -1 421 -1 422 @classmethod 422 423 def load(cls, fh):423 -1 if isinstance(ldif, Exception):424 -1 raise ldif425 -1 parser = LDIFParser(fh)426 -1 try:427 -1 parser.parse()428 -1 except ValueError as err:429 -1 log.warning("ValueError after reading %i records: %s",430 -1 parser.records_read, err)431 -1 for entry in parser.entries.values():432 -1 yield map_keys(MultiDict(entry), cls.fields)-1 424 for block in cls.get_blocks(fh): -1 425 item = MultiDict() -1 426 for line in block: -1 427 m = re.match(b'([^:]*):(:?) *(.*)', line) -1 428 if m: -1 429 key, b64, value = m.groups() -1 430 if b64 == b':': -1 431 value = base64.decodestring(value) -1 432 item.append(key.decode('utf8'), [value.decode('utf8')]) -1 433 if item: -1 434 yield map_keys(item, cls.fields) 433 435 434 436 435 437 class DateTimeJSONEncoder(json.JSONEncoder):
diff --git a/setup.py b/setup.py
@@ -11,7 +11,6 @@ setup( 11 11 platforms='any', 12 12 py_modules=['cctool'], 13 13 extras_require={14 -1 'ldif': ['python-ldap'],15 14 'ical': ['icaledar'], 16 15 'yaml': ['PyYAML'], 17 16 },
diff --git a/tests.py b/tests.py
@@ -112,12 +112,14 @@ class TestABook(_TestFormat): 112 112 self.text = b'[0]\nname = foo\nbday = 1970-01-01\n\n' 113 113 114 114115 -1 @unittest.skipIf(isinstance(cctool.ldif, Exception), 'ldif not available')116 115 class TestLDIF(_TestFormat): 117 116 def setUp(self): 118 117 self.format = cctool.LDIF()119 -1 self.data = [cctool.MultiDict({'dn': ['foo']})]120 -1 self.text = b'[0]\ndn = foo\n\n'-1 118 self.data = [cctool.MultiDict([ -1 119 ('name', ['foo']), -1 120 ('email', ['foo@example.com']), -1 121 ])] -1 122 self.text = b'cn: foo\nmail:: Zm9vQGV4YW1wbGUuY29t' 121 123 122 124 def test_dump(self): 123 125 pass