- commit
- e820676a8df7d07f7bcc31385ec39a074b575e72
- parent
- e300f902ea7cb7d0a0ffd3868e423a64be03fa46
- Author
- Tobias Bengfort <tobias.bengfort@gmx.net>
- Date
- 2015-05-08 13:14
strict encoding
Diffstat
| M | cctool.py | 40 | ++++++++++++++++++++++------------------ |
| M | tests.py | 24 | ++++++++++++++++++------ |
2 files changed, 40 insertions, 24 deletions
diff --git a/cctool.py b/cctool.py
@@ -35,11 +35,8 @@ from collections import OrderedDict 35 35 import json 36 36 from datetime import datetime 37 37 import pickle38 -139 -1 try:40 -1 from StringIO import StringIO41 -1 except ImportError:42 -1 from io import StringIO-1 38 import codecs -1 39 from io import BytesIO 43 40 44 41 try: 45 42 from ConfigParser import RawConfigParser as ConfigParser @@ -155,7 +152,11 @@ def merged(data, key): 155 152 156 153 157 154 class Format(object):158 -1 """Baseclass with an API similar to the marshal, pickle and json modules."""-1 155 """Baseclass with an API similar to the marshal, pickle and json modules. -1 156 -1 157 :py:meth:`load` takes a bytes stream and returns a :py:class:`MultiDict`. -1 158 :py:meth:`dump` does the reverse. -1 159 """ 159 160 160 161 @classmethod 161 162 def load(cls, fh): @@ -163,7 +164,7 @@ class Format(object): 163 164 164 165 @classmethod 165 166 def loads(cls, s):166 -1 return cls.load(StringIO(s))-1 167 return cls.load(BytesIO(s)) 167 168 168 169 @classmethod 169 170 def dump(cls, data, fh): @@ -171,7 +172,7 @@ class Format(object): 171 172 172 173 @classmethod 173 174 def dumps(cls, data):174 -1 fh = StringIO()-1 175 fh = BytesIO() 175 176 cls.dump(data, fh) 176 177 return fh.getvalue() 177 178 @@ -179,14 +180,15 @@ class Format(object): 179 180 class BSDCal(Format): 180 181 @classmethod 181 182 def dump(cls, data, fh): -1 183 _fh = codecs.getwriter('utf8')(fh) 182 184 for item in data: 183 185 if u'dtstart' in item and u'summary' in item: 184 186 dt = item.first('dtstart') 185 187 if dt.year == datetime.today().year:186 -1 fh.write('%s\t%s\n' % (dt.strftime('%m/%d'), item.join('summary')))-1 188 _fh.write('%s\t%s\n' % (dt.strftime('%m/%d'), item.join('summary'))) 187 189 if u'bday' in item and u'name' in item: 188 190 dt = item.first('bday')189 -1 fh.write('%s\t%s\n' % (dt.strftime('%m/%d*'), item.join('name')))-1 191 _fh.write('%s\t%s\n' % (dt.strftime('%m/%d*'), item.join('name'))) 190 192 191 193 192 194 class ICal(Format): @@ -270,8 +272,9 @@ class ABook(Format): 270 272 271 273 @classmethod 272 274 def load(cls, fh): -1 275 _fh = codecs.getreader('utf8')(fh) 273 276 config_parser = ConfigParser()274 -1 config_parser.readfp(fh)-1 277 config_parser.readfp(_fh) 275 278 for section in config_parser.sections(): 276 279 if section != u'format': 277 280 d = MultiDict() @@ -286,6 +289,7 @@ class ABook(Format): 286 289 287 290 @classmethod 288 291 def dump(cls, data, fh): -1 292 _fh = codecs.getwriter('utf8')(fh) 289 293 cp = ConfigParser() 290 294 i = 0 291 295 for item in data: @@ -306,7 +310,7 @@ class ABook(Format): 306 310 elif key in ['cn']: 307 311 cp.set(section, 'name', item.join(key)) 308 312 i += 1309 -1 cp.write(fh)-1 313 cp.write(_fh) 310 314 311 315 312 316 if not isinstance(ldif, Exception): @@ -354,11 +358,13 @@ class DateTimeJSONEncoder(json.JSONEncoder): 354 358 class JSON(Format): 355 359 @classmethod 356 360 def load(cls, fh):357 -1 return [MultiDict(i) for i in json.load(fh)]-1 361 _fh = codecs.getreader('utf8')(fh) -1 362 return [MultiDict(i) for i in json.load(_fh)] 358 363 359 364 @classmethod 360 365 def dump(cls, data, fh):361 -1 json.dump(list(data), fh, indent=4, cls=DateTimeJSONEncoder)-1 366 _fh = codecs.getwriter('utf8')(fh) -1 367 json.dump(list(data), _fh, indent=4, cls=DateTimeJSONEncoder) 362 368 363 369 364 370 class Pickle(Format): @@ -417,8 +423,6 @@ def main(): 417 423 informats, outformats = formats() 418 424 args = parse_args() 419 425420 -1 sys.setdefaultencoding('utf-8')421 -1422 426 outformat = get_outformat(args) 423 427 424 428 data = [] @@ -428,7 +432,7 @@ def main(): 428 432 else: 429 433 informat = get_informat(filename) 430 434431 -1 infile = sys.stdin if filename == '-' else open(filename)-1 435 infile = sys.stdin if filename == '-' else open(filename, 'rb') 432 436 try: 433 437 data += informats[informat]().load(infile) 434 438 except Exception as err: @@ -443,7 +447,7 @@ def main(): 443 447 if args.sort is not None: 444 448 data = sorted(data, key=lambda x: x[args.sort]) 445 449446 -1 outfile = sys.stdout if args.output is None else open(args.output, 'w')-1 450 outfile = sys.stdout if args.output is None else open(args.output, 'wb') 447 451 try: 448 452 outformats[outformat]().dump(data, outfile) 449 453 except Exception as err:
diff --git a/tests.py b/tests.py
@@ -84,7 +84,7 @@ class TestBSDCal(_TestFormat): 84 84 cctool.MultiDict({'dtstart': [dt], 'summary': ['foo']}), 85 85 cctool.MultiDict({'bday': [dt], 'name': ['bar']}), 86 86 ]87 -1 self.text = '01/01\tfoo\n01/01*\tbar\n'-1 87 self.text = b'01/01\tfoo\n01/01*\tbar\n' 88 88 89 89 def test_load(self): 90 90 pass @@ -95,7 +95,7 @@ class TestICal(_TestFormat): 95 95 def setUp(self): 96 96 self.format = cctool.ICal() 97 97 self.data = [cctool.MultiDict({u'uid': [u'20140519T210153Z-13022@tobias-eee']})]98 -1 self.text = 'BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//XI//NONSGML CCTOOL//\r\nBEGIN:VEVENT\r\nUID:20140519T210153Z-13022@tobias-eee\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n'-1 98 self.text = b'BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//XI//NONSGML CCTOOL//\r\nBEGIN:VEVENT\r\nUID:20140519T210153Z-13022@tobias-eee\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n' 99 99 100 100 101 101 class TestABook(_TestFormat): @@ -105,7 +105,7 @@ class TestABook(_TestFormat): 105 105 ('name', ['foo']), 106 106 ('bday', [datetime(1970, 1, 1)]), 107 107 ])]108 -1 self.text = '[0]\nname = foo\nbday = 1970-01-01\n\n'-1 108 self.text = b'[0]\nname = foo\nbday = 1970-01-01\n\n' 109 109 110 110 111 111 @unittest.skipIf(isinstance(cctool.ldif, Exception), 'ldif not available') @@ -113,7 +113,7 @@ class TestLDIF(_TestFormat): 113 113 def setUp(self): 114 114 self.format = cctool.LDIF() 115 115 self.data = [cctool.MultiDict({'dn': ['foo']})]116 -1 self.text = '[0]\ndn = foo\n\n'-1 116 self.text = b'[0]\ndn = foo\n\n' 117 117 118 118 def test_dump(self): 119 119 pass @@ -122,13 +122,25 @@ class TestLDIF(_TestFormat): 122 122 class TestJSON(_TestFormat): 123 123 def setUp(self): 124 124 self.format = cctool.JSON()125 -1 self.text = '[\n {\n "name": [\n "foo"\n ]\n }\n]'-1 125 self.text = b'[\n {\n "name": [\n "foo"\n ]\n }\n]' 126 126 127 127 128 128 class TestPickle(_TestFormat): 129 129 def setUp(self): 130 130 self.format = cctool.Pickle()131 -1 self.text = '(lp0\nccctool\nMultiDict\np1\n((lp2\n(lp3\nS\'name\'\np4\na(lp5\nS\'foo\'\np6\naaatp7\nRp8\na.'-1 131 -1 132 # the serialization is different in py3, even with same protocol. -1 133 # so we only test that the data is not changes by encode/decode. -1 134 def test_combined(self): -1 135 tmp = self.format.dumps(self.data) -1 136 actual = self.format.loads(tmp) -1 137 self.assertEqual(list(actual), self.data) -1 138 -1 139 def test_dump(self): -1 140 pass -1 141 -1 142 def test_load(self): -1 143 pass 132 144 133 145 134 146 class TestArgs(unittest.TestCase):