pytoml-0.1.21/0000777000000000000000000000000013515123661011254 5ustar 00000000000000pytoml-0.1.21/LICENSE0000666000000000000000000000160112501140764012254 0ustar 00000000000000No-notice MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. pytoml-0.1.21/MANIFEST.in0000666000000000000000000000004413334326174013013 0ustar 00000000000000include LICENSE include README.md pytoml-0.1.21/PKG-INFO0000666000000000000000000000461413515123661012356 0ustar 00000000000000Metadata-Version: 2.1 Name: pytoml Version: 0.1.21 Summary: A parser for TOML-0.4.0 Home-page: https://github.com/avakar/pytoml Author: Martin Vejnár Author-email: vejnar.martin@gmail.com License: MIT Description: [![PyPI](https://img.shields.io/pypi/v/pytoml.svg)](https://pypi.python.org/pypi/pytoml) [![Build Status](https://travis-ci.org/avakar/pytoml.svg?branch=master)](https://travis-ci.org/avakar/pytoml) # Deprecated The pytoml project is no longer being actively maintained. Consider using the [toml](https://github.com/uiri/toml) package instead. # pytoml This project aims at being a specs-conforming and strict parser and writer for [TOML][1] files. The library currently supports [version 0.4.0][2] of the specs and runs with Python 2.7+ and 3.5+. Install: pip install pytoml The interface is the same as for the standard `json` package. >>> import pytoml as toml >>> toml.loads('a = 1') {'a': 1} >>> with open('file.toml', 'rb') as fin: ... obj = toml.load(fin) >>> obj {'a': 1} The `loads` function accepts either a bytes object (that gets decoded as UTF-8 with no BOM allowed), or a unicode object. Use `dump` or `dumps` to serialize a dict into TOML. >>> print toml.dumps(obj) a = 1 ## tests To run the tests update the `toml-test` submodule: git submodule update --init --recursive Then run the tests: python test/test.py [1]: https://github.com/toml-lang/toml [2]: https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md Platform: UNKNOWN Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: License :: OSI Approved :: MIT License Classifier: Topic :: Software Development :: Libraries Description-Content-Type: text/markdown pytoml-0.1.21/README.md0000666000000000000000000000252513515113575012542 0ustar 00000000000000[![PyPI](https://img.shields.io/pypi/v/pytoml.svg)](https://pypi.python.org/pypi/pytoml) [![Build Status](https://travis-ci.org/avakar/pytoml.svg?branch=master)](https://travis-ci.org/avakar/pytoml) # Deprecated The pytoml project is no longer being actively maintained. Consider using the [toml](https://github.com/uiri/toml) package instead. # pytoml This project aims at being a specs-conforming and strict parser and writer for [TOML][1] files. The library currently supports [version 0.4.0][2] of the specs and runs with Python 2.7+ and 3.5+. Install: pip install pytoml The interface is the same as for the standard `json` package. >>> import pytoml as toml >>> toml.loads('a = 1') {'a': 1} >>> with open('file.toml', 'rb') as fin: ... obj = toml.load(fin) >>> obj {'a': 1} The `loads` function accepts either a bytes object (that gets decoded as UTF-8 with no BOM allowed), or a unicode object. Use `dump` or `dumps` to serialize a dict into TOML. >>> print toml.dumps(obj) a = 1 ## tests To run the tests update the `toml-test` submodule: git submodule update --init --recursive Then run the tests: python test/test.py [1]: https://github.com/toml-lang/toml [2]: https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md pytoml-0.1.21/pytoml/0000777000000000000000000000000013515123661012600 5ustar 00000000000000pytoml-0.1.21/pytoml/__init__.py0000666000000000000000000000020213515113575014706 0ustar 00000000000000from .core import TomlError from .parser import load, loads from .test import translate_to_test from .writer import dump, dumpspytoml-0.1.21/pytoml/core.py0000666000000000000000000000101212501641241014065 0ustar 00000000000000class TomlError(RuntimeError): def __init__(self, message, line, col, filename): RuntimeError.__init__(self, message, line, col, filename) self.message = message self.line = line self.col = col self.filename = filename def __str__(self): return '{}({}, {}): {}'.format(self.filename, self.line, self.col, self.message) def __repr__(self): return 'TomlError({!r}, {!r}, {!r}, {!r})'.format(self.message, self.line, self.col, self.filename) pytoml-0.1.21/pytoml/parser.py0000666000000000000000000002463313515122612014451 0ustar 00000000000000import re, sys from .core import TomlError from .utils import rfc3339_re, parse_rfc3339_re if sys.version_info[0] == 2: _chr = unichr else: _chr = chr def load(fin, translate=lambda t, x, v: v, object_pairs_hook=dict): return loads(fin.read(), translate=translate, object_pairs_hook=object_pairs_hook, filename=getattr(fin, 'name', repr(fin))) def loads(s, filename='', translate=lambda t, x, v: v, object_pairs_hook=dict): if isinstance(s, bytes): s = s.decode('utf-8') s = s.replace('\r\n', '\n') root = object_pairs_hook() tables = object_pairs_hook() scope = root src = _Source(s, filename=filename) ast = _p_toml(src, object_pairs_hook=object_pairs_hook) def error(msg): raise TomlError(msg, pos[0], pos[1], filename) def process_value(v, object_pairs_hook): kind, text, value, pos = v if kind == 'array': if value and any(k != value[0][0] for k, t, v, p in value[1:]): error('array-type-mismatch') value = [process_value(item, object_pairs_hook=object_pairs_hook) for item in value] elif kind == 'table': value = object_pairs_hook([(k, process_value(value[k], object_pairs_hook=object_pairs_hook)) for k in value]) return translate(kind, text, value) for kind, value, pos in ast: if kind == 'kv': k, v = value if k in scope: error('duplicate_keys. Key "{0}" was used more than once.'.format(k)) scope[k] = process_value(v, object_pairs_hook=object_pairs_hook) else: is_table_array = (kind == 'table_array') cur = tables for name in value[:-1]: if isinstance(cur.get(name), list): d, cur = cur[name][-1] else: d, cur = cur.setdefault(name, (None, object_pairs_hook())) scope = object_pairs_hook() name = value[-1] if name not in cur: if is_table_array: cur[name] = [(scope, object_pairs_hook())] else: cur[name] = (scope, object_pairs_hook()) elif isinstance(cur[name], list): if not is_table_array: error('table_type_mismatch') cur[name].append((scope, object_pairs_hook())) else: if is_table_array: error('table_type_mismatch') old_scope, next_table = cur[name] if old_scope is not None: error('duplicate_tables') cur[name] = (scope, next_table) def merge_tables(scope, tables): if scope is None: scope = object_pairs_hook() for k in tables: if k in scope: error('key_table_conflict') v = tables[k] if isinstance(v, list): scope[k] = [merge_tables(sc, tbl) for sc, tbl in v] else: scope[k] = merge_tables(v[0], v[1]) return scope return merge_tables(root, tables) class _Source: def __init__(self, s, filename=None): self.s = s self._pos = (1, 1) self._last = None self._filename = filename self.backtrack_stack = [] def last(self): return self._last def pos(self): return self._pos def fail(self): return self._expect(None) def consume_dot(self): if self.s: self._last = self.s[0] self.s = self[1:] self._advance(self._last) return self._last return None def expect_dot(self): return self._expect(self.consume_dot()) def consume_eof(self): if not self.s: self._last = '' return True return False def expect_eof(self): return self._expect(self.consume_eof()) def consume(self, s): if self.s.startswith(s): self.s = self.s[len(s):] self._last = s self._advance(s) return True return False def expect(self, s): return self._expect(self.consume(s)) def consume_re(self, re): m = re.match(self.s) if m: self.s = self.s[len(m.group(0)):] self._last = m self._advance(m.group(0)) return m return None def expect_re(self, re): return self._expect(self.consume_re(re)) def __enter__(self): self.backtrack_stack.append((self.s, self._pos)) def __exit__(self, type, value, traceback): if type is None: self.backtrack_stack.pop() else: self.s, self._pos = self.backtrack_stack.pop() return type == TomlError def commit(self): self.backtrack_stack[-1] = (self.s, self._pos) def _expect(self, r): if not r: raise TomlError('msg', self._pos[0], self._pos[1], self._filename) return r def _advance(self, s): suffix_pos = s.rfind('\n') if suffix_pos == -1: self._pos = (self._pos[0], self._pos[1] + len(s)) else: self._pos = (self._pos[0] + s.count('\n'), len(s) - suffix_pos) _ews_re = re.compile(r'(?:[ \t]|#[^\n]*\n|#[^\n]*\Z|\n)*') def _p_ews(s): s.expect_re(_ews_re) _ws_re = re.compile(r'[ \t]*') def _p_ws(s): s.expect_re(_ws_re) _escapes = { 'b': '\b', 'n': '\n', 'r': '\r', 't': '\t', '"': '"', '\\': '\\', 'f': '\f' } _basicstr_re = re.compile(r'[^"\\\000-\037]*') _short_uni_re = re.compile(r'u([0-9a-fA-F]{4})') _long_uni_re = re.compile(r'U([0-9a-fA-F]{8})') _escapes_re = re.compile(r'[btnfr\"\\]') _newline_esc_re = re.compile('\n[ \t\n]*') def _p_basicstr_content(s, content=_basicstr_re): res = [] while True: res.append(s.expect_re(content).group(0)) if not s.consume('\\'): break if s.consume_re(_newline_esc_re): pass elif s.consume_re(_short_uni_re) or s.consume_re(_long_uni_re): v = int(s.last().group(1), 16) if 0xd800 <= v < 0xe000: s.fail() res.append(_chr(v)) else: s.expect_re(_escapes_re) res.append(_escapes[s.last().group(0)]) return ''.join(res) _key_re = re.compile(r'[0-9a-zA-Z-_]+') def _p_key(s): with s: s.expect('"') r = _p_basicstr_content(s, _basicstr_re) s.expect('"') return r if s.consume('\''): if s.consume('\'\''): s.consume('\n') r = s.expect_re(_litstr_ml_re).group(0) s.expect('\'\'\'') else: r = s.expect_re(_litstr_re).group(0) s.expect('\'') return r return s.expect_re(_key_re).group(0) _float_re = re.compile(r'[+-]?(?:0|[1-9](?:_?\d)*)(?:\.\d(?:_?\d)*)?(?:[eE][+-]?(?:\d(?:_?\d)*))?') _basicstr_ml_re = re.compile(r'(?:""?(?!")|[^"\\\000-\011\013-\037])*') _litstr_re = re.compile(r"[^'\000\010\012-\037]*") _litstr_ml_re = re.compile(r"(?:(?:|'|'')(?:[^'\000-\010\013-\037]))*") def _p_value(s, object_pairs_hook): pos = s.pos() if s.consume('true'): return 'bool', s.last(), True, pos if s.consume('false'): return 'bool', s.last(), False, pos if s.consume('"'): if s.consume('""'): s.consume('\n') r = _p_basicstr_content(s, _basicstr_ml_re) s.expect('"""') else: r = _p_basicstr_content(s, _basicstr_re) s.expect('"') return 'str', r, r, pos if s.consume('\''): if s.consume('\'\''): s.consume('\n') r = s.expect_re(_litstr_ml_re).group(0) s.expect('\'\'\'') else: r = s.expect_re(_litstr_re).group(0) s.expect('\'') return 'str', r, r, pos if s.consume_re(rfc3339_re): m = s.last() return 'datetime', m.group(0), parse_rfc3339_re(m), pos if s.consume_re(_float_re): m = s.last().group(0) r = m.replace('_','') if '.' in m or 'e' in m or 'E' in m: return 'float', m, float(r), pos else: return 'int', m, int(r, 10), pos if s.consume('['): items = [] with s: while True: _p_ews(s) items.append(_p_value(s, object_pairs_hook=object_pairs_hook)) s.commit() _p_ews(s) s.expect(',') s.commit() _p_ews(s) s.expect(']') return 'array', None, items, pos if s.consume('{'): _p_ws(s) items = object_pairs_hook() if not s.consume('}'): k = _p_key(s) _p_ws(s) s.expect('=') _p_ws(s) items[k] = _p_value(s, object_pairs_hook=object_pairs_hook) _p_ws(s) while s.consume(','): _p_ws(s) k = _p_key(s) _p_ws(s) s.expect('=') _p_ws(s) items[k] = _p_value(s, object_pairs_hook=object_pairs_hook) _p_ws(s) s.expect('}') return 'table', None, items, pos s.fail() def _p_stmt(s, object_pairs_hook): pos = s.pos() if s.consume( '['): is_array = s.consume('[') _p_ws(s) keys = [_p_key(s)] _p_ws(s) while s.consume('.'): _p_ws(s) keys.append(_p_key(s)) _p_ws(s) s.expect(']') if is_array: s.expect(']') return 'table_array' if is_array else 'table', keys, pos key = _p_key(s) _p_ws(s) s.expect('=') _p_ws(s) value = _p_value(s, object_pairs_hook=object_pairs_hook) return 'kv', (key, value), pos _stmtsep_re = re.compile(r'(?:[ \t]*(?:#[^\n]*)?\n)+[ \t]*') def _p_toml(s, object_pairs_hook): stmts = [] _p_ews(s) with s: stmts.append(_p_stmt(s, object_pairs_hook=object_pairs_hook)) while True: s.commit() s.expect_re(_stmtsep_re) stmts.append(_p_stmt(s, object_pairs_hook=object_pairs_hook)) _p_ews(s) s.expect_eof() return stmts pytoml-0.1.21/pytoml/test.py0000666000000000000000000000203313515113575014132 0ustar 00000000000000import datetime from .utils import format_rfc3339 try: _string_types = (str, unicode) _int_types = (int, long) except NameError: _string_types = str _int_types = int def translate_to_test(v): if isinstance(v, dict): return { k: translate_to_test(v) for k, v in v.items() } if isinstance(v, list): a = [translate_to_test(x) for x in v] if v and isinstance(v[0], dict): return a else: return {'type': 'array', 'value': a} if isinstance(v, datetime.datetime): return {'type': 'datetime', 'value': format_rfc3339(v)} if isinstance(v, bool): return {'type': 'bool', 'value': 'true' if v else 'false'} if isinstance(v, _int_types): return {'type': 'integer', 'value': str(v)} if isinstance(v, float): return {'type': 'float', 'value': '{:.17}'.format(v)} if isinstance(v, _string_types): return {'type': 'string', 'value': v} raise RuntimeError('unexpected value: {!r}'.format(v)) pytoml-0.1.21/pytoml/utils.py0000666000000000000000000000330413515113575014315 0ustar 00000000000000import datetime import re rfc3339_re = re.compile(r'(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(\.\d+)?(?:Z|([+-]\d{2}):(\d{2}))') def parse_rfc3339(v): m = rfc3339_re.match(v) if not m or m.group(0) != v: return None return parse_rfc3339_re(m) def parse_rfc3339_re(m): r = map(int, m.groups()[:6]) if m.group(7): micro = float(m.group(7)) else: micro = 0 if m.group(8): g = int(m.group(8), 10) * 60 + int(m.group(9), 10) tz = _TimeZone(datetime.timedelta(0, g * 60)) else: tz = _TimeZone(datetime.timedelta(0, 0)) y, m, d, H, M, S = r return datetime.datetime(y, m, d, H, M, S, int(micro * 1000000), tz) def format_rfc3339(v): offs = v.utcoffset() offs = int(offs.total_seconds()) // 60 if offs is not None else 0 if offs == 0: suffix = 'Z' else: if offs > 0: suffix = '+' else: suffix = '-' offs = -offs suffix = '{0}{1:02}:{2:02}'.format(suffix, offs // 60, offs % 60) if v.microsecond: return v.strftime('%Y-%m-%dT%H:%M:%S.%f') + suffix else: return v.strftime('%Y-%m-%dT%H:%M:%S') + suffix class _TimeZone(datetime.tzinfo): def __init__(self, offset): self._offset = offset def utcoffset(self, dt): return self._offset def dst(self, dt): return None def tzname(self, dt): m = self._offset.total_seconds() // 60 if m < 0: res = '-' m = -m else: res = '+' h = m // 60 m = m - h * 60 return '{}{:.02}{:.02}'.format(res, h, m) pytoml-0.1.21/pytoml/writer.py0000666000000000000000000000663313515113575014501 0ustar 00000000000000from __future__ import unicode_literals import io, datetime, math, string, sys from .utils import format_rfc3339 try: from pathlib import PurePath as _path_types except ImportError: _path_types = () if sys.version_info[0] == 3: long = int unicode = str def dumps(obj, sort_keys=False): fout = io.StringIO() dump(obj, fout, sort_keys=sort_keys) return fout.getvalue() _escapes = {'\n': 'n', '\r': 'r', '\\': '\\', '\t': 't', '\b': 'b', '\f': 'f', '"': '"'} def _escape_string(s): res = [] start = 0 def flush(): if start != i: res.append(s[start:i]) return i + 1 i = 0 while i < len(s): c = s[i] if c in '"\\\n\r\t\b\f': start = flush() res.append('\\' + _escapes[c]) elif ord(c) < 0x20: start = flush() res.append('\\u%04x' % ord(c)) i += 1 flush() return '"' + ''.join(res) + '"' _key_chars = string.digits + string.ascii_letters + '-_' def _escape_id(s): if any(c not in _key_chars for c in s): return _escape_string(s) return s def _format_value(v): if isinstance(v, bool): return 'true' if v else 'false' if isinstance(v, int) or isinstance(v, long): return unicode(v) if isinstance(v, float): if math.isnan(v) or math.isinf(v): raise ValueError("{0} is not a valid TOML value".format(v)) else: return repr(v) elif isinstance(v, unicode) or isinstance(v, bytes): return _escape_string(v) elif isinstance(v, datetime.datetime): return format_rfc3339(v) elif isinstance(v, list): return '[{0}]'.format(', '.join(_format_value(obj) for obj in v)) elif isinstance(v, dict): return '{{{0}}}'.format(', '.join('{} = {}'.format(_escape_id(k), _format_value(obj)) for k, obj in v.items())) elif isinstance(v, _path_types): return _escape_string(str(v)) else: raise RuntimeError(v) def dump(obj, fout, sort_keys=False): tables = [((), obj, False)] while tables: name, table, is_array = tables.pop() if name: section_name = '.'.join(_escape_id(c) for c in name) if is_array: fout.write('[[{0}]]\n'.format(section_name)) else: fout.write('[{0}]\n'.format(section_name)) table_keys = sorted(table.keys()) if sort_keys else table.keys() new_tables = [] has_kv = False for k in table_keys: v = table[k] if isinstance(v, dict): new_tables.append((name + (k,), v, False)) elif isinstance(v, list) and v and all(isinstance(o, dict) for o in v): new_tables.extend((name + (k,), d, True) for d in v) elif v is None: # based on mojombo's comment: https://github.com/toml-lang/toml/issues/146#issuecomment-25019344 fout.write( '#{} = null # To use: uncomment and replace null with value\n'.format(_escape_id(k))) has_kv = True else: fout.write('{0} = {1}\n'.format(_escape_id(k), _format_value(v))) has_kv = True tables.extend(reversed(new_tables)) if (name or has_kv) and tables: fout.write('\n') pytoml-0.1.21/pytoml.egg-info/0000777000000000000000000000000013515123661014272 5ustar 00000000000000pytoml-0.1.21/pytoml.egg-info/PKG-INFO0000666000000000000000000000461413515123661015374 0ustar 00000000000000Metadata-Version: 2.1 Name: pytoml Version: 0.1.21 Summary: A parser for TOML-0.4.0 Home-page: https://github.com/avakar/pytoml Author: Martin Vejnár Author-email: vejnar.martin@gmail.com License: MIT Description: [![PyPI](https://img.shields.io/pypi/v/pytoml.svg)](https://pypi.python.org/pypi/pytoml) [![Build Status](https://travis-ci.org/avakar/pytoml.svg?branch=master)](https://travis-ci.org/avakar/pytoml) # Deprecated The pytoml project is no longer being actively maintained. Consider using the [toml](https://github.com/uiri/toml) package instead. # pytoml This project aims at being a specs-conforming and strict parser and writer for [TOML][1] files. The library currently supports [version 0.4.0][2] of the specs and runs with Python 2.7+ and 3.5+. Install: pip install pytoml The interface is the same as for the standard `json` package. >>> import pytoml as toml >>> toml.loads('a = 1') {'a': 1} >>> with open('file.toml', 'rb') as fin: ... obj = toml.load(fin) >>> obj {'a': 1} The `loads` function accepts either a bytes object (that gets decoded as UTF-8 with no BOM allowed), or a unicode object. Use `dump` or `dumps` to serialize a dict into TOML. >>> print toml.dumps(obj) a = 1 ## tests To run the tests update the `toml-test` submodule: git submodule update --init --recursive Then run the tests: python test/test.py [1]: https://github.com/toml-lang/toml [2]: https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md Platform: UNKNOWN Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: License :: OSI Approved :: MIT License Classifier: Topic :: Software Development :: Libraries Description-Content-Type: text/markdown pytoml-0.1.21/pytoml.egg-info/SOURCES.txt0000666000000000000000000000050013515123661016151 0ustar 00000000000000LICENSE MANIFEST.in README.md setup.cfg setup.py pytoml/__init__.py pytoml/core.py pytoml/parser.py pytoml/test.py pytoml/utils.py pytoml/writer.py pytoml.egg-info/PKG-INFO pytoml.egg-info/SOURCES.txt pytoml.egg-info/dependency_links.txt pytoml.egg-info/top_level.txt test/test.py test/test_parser.py test/test_writer.pypytoml-0.1.21/pytoml.egg-info/dependency_links.txt0000666000000000000000000000000113515123661020340 0ustar 00000000000000 pytoml-0.1.21/pytoml.egg-info/top_level.txt0000666000000000000000000000000713515123661017021 0ustar 00000000000000pytoml pytoml-0.1.21/setup.cfg0000666000000000000000000000016013515123661013072 0ustar 00000000000000[bdist_wheel] universal = 1 [metadata] license_file = LICENSE [egg_info] tag_build = tag_date = 0 pytoml-0.1.21/setup.py0000666000000000000000000000176613515123234012774 0ustar 00000000000000#!/usr/bin/env python # coding: utf-8 from setuptools import setup with open('README.md', 'r') as fin: long_description = fin.read() setup( name='pytoml', version='0.1.21', description='A parser for TOML-0.4.0', long_description=long_description, long_description_content_type='text/markdown', author='Martin Vejnár', author_email='vejnar.martin@gmail.com', url='https://github.com/avakar/pytoml', license='MIT', packages=['pytoml'], classifiers=[ # Supported python versions 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', # License 'License :: OSI Approved :: MIT License', # Topics 'Topic :: Software Development :: Libraries', ] ) pytoml-0.1.21/test/0000777000000000000000000000000013515123661012233 5ustar 00000000000000pytoml-0.1.21/test/test.py0000666000000000000000000000723613515113575013577 0ustar 00000000000000import os, json, sys, io, traceback, argparse import pytoml as toml from pytoml.utils import parse_rfc3339 def is_bench_equal(a, b): if isinstance(a, dict): if 'type' in a: if b.get('type') != a['type']: return False if a['type'] == 'float': return float(a['value']) == float(b['value']) if a['type'] == 'datetime': x = parse_rfc3339(a['value']) y = parse_rfc3339(b['value']) return x == y if a['type'] == 'array': return is_bench_equal(a['value'], b['value']) return a['value'] == b['value'] return (isinstance(b, dict) and len(a) == len(b) and all(k in b and is_bench_equal(a[k], b[k]) for k in a)) if isinstance(a, list): return (isinstance(b, list) and len(a) == len(b) and all(is_bench_equal(x, y) for x, y in zip(a, b))) raise RuntimeError('Invalid data in the bench JSON') def _main(): ap = argparse.ArgumentParser() ap.add_argument('-d', '--dir', action='append') ap.add_argument('testcase', nargs='*') args = ap.parse_args() if not args.dir: args.dir = [os.path.join(os.path.split(__file__)[0], 'toml-test/tests')] succeeded = [] failed = [] for path in args.dir: if not os.path.isdir(path): print('error: not a dir: {0}'.format(path)) return 2 for top, dirnames, fnames in os.walk(path): for fname in fnames: if not fname.endswith('.toml'): continue if args.testcase and not any(arg in fname for arg in args.testcase): continue parse_error = None try: with open(os.path.join(top, fname), 'rb') as fin: parsed = toml.load(fin) except toml.TomlError: parsed = None parse_error = sys.exc_info() else: dumped = toml.dumps(parsed, sort_keys=False) dumped_sorted = toml.dumps(parsed, sort_keys=True) parsed2 = toml.loads(dumped) parsed2_sorted = toml.loads(dumped_sorted) if parsed != parsed2 or parsed != parsed2_sorted: failed.append((fname, parsed, [parsed2, parsed2_sorted], None)) continue with open(os.path.join(top, fname), 'rb') as fin: parsed = toml.load(fin) parsed = toml.translate_to_test(parsed) try: with io.open(os.path.join(top, fname[:-5] + '.json'), 'rt', encoding='utf-8') as fin: bench = json.load(fin) except IOError: bench = None if (parsed is None) != (bench is None) or (parsed is not None and not is_bench_equal(parsed, bench)): failed.append((fname, parsed, bench, parse_error)) else: succeeded.append(fname) for f, parsed, bench, e in failed: try: print('failed: {}\n{}\n{}'.format(f, json.dumps(parsed, indent=4), json.dumps(bench, indent=4))) except TypeError: print('failed: {}\n{}\n{}'.format(f, parsed, bench)) if e: traceback.print_exception(*e) print('succeeded: {0}'.format(len(succeeded))) return 1 if failed or not succeeded else 0 if __name__ == '__main__': r = _main() if r: sys.exit(r) pytoml-0.1.21/test/test_parser.py0000666000000000000000000000171013334326174015142 0ustar 00000000000000from __future__ import unicode_literals import collections import sys if sys.version_info < (2, 7): from StringIO import StringIO else: from io import StringIO import pytest import pytoml as toml def test_name_of_fileobj_is_used_in_errors(): source = StringIO("[") source.name = "" error = pytest.raises(toml.TomlError, lambda: toml.load(source)) assert error.value.filename == "" def test_when_fileobj_has_no_name_attr_then_repr_of_fileobj_is_used_in_errors(): source = StringIO("[") error = pytest.raises(toml.TomlError, lambda: toml.load(source)) assert error.value.filename == repr(source) def test_object_pairs_hook(): source = StringIO(u"""\ [x.a] [x.b] [x.c] """) d = toml.load(source, object_pairs_hook=collections.defaultdict) assert isinstance(d, collections.defaultdict) assert isinstance(d['x'], collections.defaultdict) pytoml-0.1.21/test/test_writer.py0000666000000000000000000000215313515113575015164 0ustar 00000000000000from __future__ import unicode_literals import pytest import pytoml as toml @pytest.mark.parametrize("value", [ float("NaN"), float("Inf"), -float("Inf"), ]) def test_attempting_to_write_non_number_floats_raises_error(value): error = pytest.raises(ValueError, lambda: toml.dumps({"value": value})) assert str(error.value) == "{0} is not a valid TOML value".format(value) def test_pathlib_path_objects_are_written_as_strings(): pathlib = pytest.importorskip("pathlib") path_value = toml.dumps({"value": pathlib.Path("test-path")}) assert path_value == 'value = "test-path"\n' def test_pathlib_purepath_objects_are_written_as_strings(): pathlib = pytest.importorskip("pathlib") path_value = toml.dumps({"value": pathlib.PurePath("test-path")}) assert path_value == 'value = "test-path"\n' def test_pathlib_purepath_objects_contents_are_escaped(): pathlib = pytest.importorskip("pathlib") path_value = toml.dumps({"value": pathlib.PurePath('C:\\Escape\"this string"')}) assert path_value == 'value = "C:\\\\Escape\\"this string\\""\n'