| from __future__ import unicode_literals |
| |
| import re |
| import string |
| |
| from datetime import date |
| from datetime import datetime |
| from datetime import time |
| from enum import Enum |
| from typing import Any |
| from typing import Dict |
| from typing import Generator |
| from typing import List |
| from typing import Optional |
| from typing import Union |
| |
| |
| from ._compat import PY2 |
| from ._compat import PY38 |
| from ._compat import decode |
| from ._compat import long |
| from ._compat import unicode |
| from ._utils import escape_string |
| |
| if PY2: |
| from functools32 import lru_cache |
| else: |
| from functools import lru_cache |
| |
| |
| def item(value, _parent=None): |
| from .container import Container |
| |
| if isinstance(value, Item): |
| return value |
| |
| if isinstance(value, bool): |
| return Bool(value, Trivia()) |
| elif isinstance(value, int): |
| return Integer(value, Trivia(), str(value)) |
| elif isinstance(value, float): |
| return Float(value, Trivia(), str(value)) |
| elif isinstance(value, dict): |
| val = Table(Container(), Trivia(), False) |
| for k, v in sorted(value.items(), key=lambda i: (isinstance(i[1], dict), i[0])): |
| val[k] = item(v, _parent=val) |
| |
| return val |
| elif isinstance(value, list): |
| if value and isinstance(value[0], dict): |
| a = AoT([]) |
| else: |
| a = Array([], Trivia()) |
| |
| for v in value: |
| if isinstance(v, dict): |
| table = Table(Container(), Trivia(), True) |
| |
| for k, _v in sorted( |
| v.items(), key=lambda i: (isinstance(i[1], dict), i[0]) |
| ): |
| i = item(_v) |
| if isinstance(table, InlineTable): |
| i.trivia.trail = "" |
| |
| table[k] = item(i) |
| |
| v = table |
| |
| a.append(v) |
| |
| return a |
| elif isinstance(value, (str, unicode)): |
| escaped = escape_string(value) |
| |
| return String(StringType.SLB, decode(value), escaped, Trivia()) |
| elif isinstance(value, datetime): |
| return DateTime( |
| value.year, |
| value.month, |
| value.day, |
| value.hour, |
| value.minute, |
| value.second, |
| value.microsecond, |
| value.tzinfo, |
| Trivia(), |
| value.isoformat().replace("+00:00", "Z"), |
| ) |
| elif isinstance(value, date): |
| return Date(value.year, value.month, value.day, Trivia(), value.isoformat()) |
| elif isinstance(value, time): |
| return Time( |
| value.hour, |
| value.minute, |
| value.second, |
| value.microsecond, |
| value.tzinfo, |
| Trivia(), |
| value.isoformat(), |
| ) |
| |
| raise ValueError("Invalid type {}".format(type(value))) |
| |
| |
| class StringType(Enum): |
| # Single Line Basic |
| SLB = '"' |
| # Multi Line Basic |
| MLB = '"""' |
| # Single Line Literal |
| SLL = "'" |
| # Multi Line Literal |
| MLL = "'''" |
| |
| @property |
| @lru_cache(maxsize=None) |
| def unit(self): # type: () -> str |
| return self.value[0] |
| |
| @lru_cache(maxsize=None) |
| def is_basic(self): # type: () -> bool |
| return self in {StringType.SLB, StringType.MLB} |
| |
| @lru_cache(maxsize=None) |
| def is_literal(self): # type: () -> bool |
| return self in {StringType.SLL, StringType.MLL} |
| |
| @lru_cache(maxsize=None) |
| def is_singleline(self): # type: () -> bool |
| return self in {StringType.SLB, StringType.SLL} |
| |
| @lru_cache(maxsize=None) |
| def is_multiline(self): # type: () -> bool |
| return self in {StringType.MLB, StringType.MLL} |
| |
| @lru_cache(maxsize=None) |
| def toggle(self): # type: () -> StringType |
| return { |
| StringType.SLB: StringType.MLB, |
| StringType.MLB: StringType.SLB, |
| StringType.SLL: StringType.MLL, |
| StringType.MLL: StringType.SLL, |
| }[self] |
| |
| |
| class BoolType(Enum): |
| TRUE = "true" |
| FALSE = "false" |
| |
| @lru_cache(maxsize=None) |
| def __bool__(self): |
| return {BoolType.TRUE: True, BoolType.FALSE: False}[self] |
| |
| if PY2: |
| __nonzero__ = __bool__ # for PY2 |
| |
| def __iter__(self): |
| return iter(self.value) |
| |
| def __len__(self): |
| return len(self.value) |
| |
| |
| class Trivia: |
| """ |
| Trivia information (aka metadata). |
| """ |
| |
| def __init__( |
| self, indent=None, comment_ws=None, comment=None, trail=None |
| ): # type: (str, str, str, str) -> None |
| # Whitespace before a value. |
| self.indent = indent or "" |
| # Whitespace after a value, but before a comment. |
| self.comment_ws = comment_ws or "" |
| # Comment, starting with # character, or empty string if no comment. |
| self.comment = comment or "" |
| # Trailing newline. |
| if trail is None: |
| trail = "\n" |
| |
| self.trail = trail |
| |
| |
| class KeyType(Enum): |
| """ |
| The type of a Key. |
| |
| Keys can be bare (unquoted), or quoted using basic ("), or literal (') |
| quotes following the same escaping rules as single-line StringType. |
| """ |
| |
| Bare = "" |
| Basic = '"' |
| Literal = "'" |
| |
| |
| class Key: |
| """ |
| A key value. |
| """ |
| |
| def __init__(self, k, t=None, sep=None, dotted=False): # type: (str) -> None |
| if t is None: |
| if any( |
| [c not in string.ascii_letters + string.digits + "-" + "_" for c in k] |
| ): |
| t = KeyType.Basic |
| else: |
| t = KeyType.Bare |
| |
| self.t = t |
| if sep is None: |
| sep = " = " |
| |
| self.sep = sep |
| self.key = k |
| self._dotted = dotted |
| |
| @property |
| def delimiter(self): # type: () -> str |
| return self.t.value |
| |
| def is_dotted(self): # type: () -> bool |
| return self._dotted |
| |
| def as_string(self): # type: () -> str |
| return "{}{}{}".format(self.delimiter, self.key, self.delimiter) |
| |
| def __hash__(self): # type: () -> int |
| return hash(self.key) |
| |
| def __eq__(self, other): # type: (Key) -> bool |
| if isinstance(other, Key): |
| return self.key == other.key |
| |
| return self.key == other |
| |
| def __str__(self): # type: () -> str |
| return self.as_string() |
| |
| def __repr__(self): # type: () -> str |
| return "<Key {}>".format(self.as_string()) |
| |
| |
| class Item(object): |
| """ |
| An item within a TOML document. |
| """ |
| |
| def __init__(self, trivia): # type: (Trivia) -> None |
| self._trivia = trivia |
| |
| @property |
| def trivia(self): # type: () -> Trivia |
| return self._trivia |
| |
| @property |
| def discriminant(self): # type: () -> int |
| raise NotImplementedError() |
| |
| def as_string(self): # type: () -> str |
| raise NotImplementedError() |
| |
| # Helpers |
| |
| def comment(self, comment): # type: (str) -> Item |
| if not comment.strip().startswith("#"): |
| comment = "# " + comment |
| |
| self._trivia.comment_ws = " " |
| self._trivia.comment = comment |
| |
| return self |
| |
| def indent(self, indent): # type: (int) -> Item |
| if self._trivia.indent.startswith("\n"): |
| self._trivia.indent = "\n" + " " * indent |
| else: |
| self._trivia.indent = " " * indent |
| |
| return self |
| |
| def is_boolean(self): # type: () -> bool |
| return isinstance(self, Bool) |
| |
| def is_table(self): # type: () -> bool |
| return isinstance(self, Table) |
| |
| def is_inline_table(self): # type: () -> bool |
| return isinstance(self, InlineTable) |
| |
| def _getstate(self, protocol=3): |
| return (self._trivia,) |
| |
| def __reduce__(self): |
| return self.__reduce_ex__(2) |
| |
| def __reduce_ex__(self, protocol): |
| return self.__class__, self._getstate(protocol) |
| |
| |
| class Whitespace(Item): |
| """ |
| A whitespace literal. |
| """ |
| |
| def __init__(self, s, fixed=False): # type: (str, bool) -> None |
| self._s = s |
| self._fixed = fixed |
| |
| @property |
| def s(self): # type: () -> str |
| return self._s |
| |
| @property |
| def value(self): # type: () -> str |
| return self._s |
| |
| @property |
| def trivia(self): # type: () -> Trivia |
| raise RuntimeError("Called trivia on a Whitespace variant.") |
| |
| @property |
| def discriminant(self): # type: () -> int |
| return 0 |
| |
| def is_fixed(self): # type: () -> bool |
| return self._fixed |
| |
| def as_string(self): # type: () -> str |
| return self._s |
| |
| def __repr__(self): # type: () -> str |
| return "<{} {}>".format(self.__class__.__name__, repr(self._s)) |
| |
| def _getstate(self, protocol=3): |
| return self._s, self._fixed |
| |
| |
| class Comment(Item): |
| """ |
| A comment literal. |
| """ |
| |
| @property |
| def discriminant(self): # type: () -> int |
| return 1 |
| |
| def as_string(self): # type: () -> str |
| return "{}{}{}".format( |
| self._trivia.indent, decode(self._trivia.comment), self._trivia.trail |
| ) |
| |
| def __str__(self): # type: () -> str |
| return "{}{}".format(self._trivia.indent, decode(self._trivia.comment)) |
| |
| |
| class Integer(long, Item): |
| """ |
| An integer literal. |
| """ |
| |
| def __new__(cls, value, trivia, raw): # type: (int, Trivia, str) -> Integer |
| return super(Integer, cls).__new__(cls, value) |
| |
| def __init__(self, _, trivia, raw): # type: (int, Trivia, str) -> None |
| super(Integer, self).__init__(trivia) |
| |
| self._raw = raw |
| self._sign = False |
| |
| if re.match(r"^[+\-]\d+$", raw): |
| self._sign = True |
| |
| @property |
| def discriminant(self): # type: () -> int |
| return 2 |
| |
| @property |
| def value(self): # type: () -> int |
| return self |
| |
| def as_string(self): # type: () -> str |
| return self._raw |
| |
| def __add__(self, other): |
| result = super(Integer, self).__add__(other) |
| |
| return self._new(result) |
| |
| def __radd__(self, other): |
| result = super(Integer, self).__radd__(other) |
| |
| if isinstance(other, Integer): |
| return self._new(result) |
| |
| return result |
| |
| def __sub__(self, other): |
| result = super(Integer, self).__sub__(other) |
| |
| return self._new(result) |
| |
| def __rsub__(self, other): |
| result = super(Integer, self).__rsub__(other) |
| |
| if isinstance(other, Integer): |
| return self._new(result) |
| |
| return result |
| |
| def _new(self, result): |
| raw = str(result) |
| |
| if self._sign: |
| sign = "+" if result >= 0 else "-" |
| raw = sign + raw |
| |
| return Integer(result, self._trivia, raw) |
| |
| def _getstate(self, protocol=3): |
| return int(self), self._trivia, self._raw |
| |
| |
| class Float(float, Item): |
| """ |
| A float literal. |
| """ |
| |
| def __new__(cls, value, trivia, raw): # type: (float, Trivia, str) -> Integer |
| return super(Float, cls).__new__(cls, value) |
| |
| def __init__(self, _, trivia, raw): # type: (float, Trivia, str) -> None |
| super(Float, self).__init__(trivia) |
| |
| self._raw = raw |
| self._sign = False |
| |
| if re.match(r"^[+\-].+$", raw): |
| self._sign = True |
| |
| @property |
| def discriminant(self): # type: () -> int |
| return 3 |
| |
| @property |
| def value(self): # type: () -> float |
| return self |
| |
| def as_string(self): # type: () -> str |
| return self._raw |
| |
| def __add__(self, other): |
| result = super(Float, self).__add__(other) |
| |
| return self._new(result) |
| |
| def __radd__(self, other): |
| result = super(Float, self).__radd__(other) |
| |
| if isinstance(other, Float): |
| return self._new(result) |
| |
| return result |
| |
| def __sub__(self, other): |
| result = super(Float, self).__sub__(other) |
| |
| return self._new(result) |
| |
| def __rsub__(self, other): |
| result = super(Float, self).__rsub__(other) |
| |
| if isinstance(other, Float): |
| return self._new(result) |
| |
| return result |
| |
| def _new(self, result): |
| raw = str(result) |
| |
| if self._sign: |
| sign = "+" if result >= 0 else "-" |
| raw = sign + raw |
| |
| return Float(result, self._trivia, raw) |
| |
| def _getstate(self, protocol=3): |
| return float(self), self._trivia, self._raw |
| |
| |
| class Bool(Item): |
| """ |
| A boolean literal. |
| """ |
| |
| def __init__(self, t, trivia): # type: (float, Trivia) -> None |
| super(Bool, self).__init__(trivia) |
| |
| self._value = bool(t) |
| |
| @property |
| def discriminant(self): # type: () -> int |
| return 4 |
| |
| @property |
| def value(self): # type: () -> bool |
| return self._value |
| |
| def as_string(self): # type: () -> str |
| return str(self._value).lower() |
| |
| def _getstate(self, protocol=3): |
| return self._value, self._trivia |
| |
| |
| class DateTime(Item, datetime): |
| """ |
| A datetime literal. |
| """ |
| |
| def __new__( |
| cls, |
| year, |
| month, |
| day, |
| hour, |
| minute, |
| second, |
| microsecond, |
| tzinfo, |
| trivia, |
| raw, |
| **kwargs |
| ): # type: (int, int, int, int, int, int, int, ..., Trivia, ...) -> datetime |
| return datetime.__new__( |
| cls, |
| year, |
| month, |
| day, |
| hour, |
| minute, |
| second, |
| microsecond, |
| tzinfo=tzinfo, |
| **kwargs |
| ) |
| |
| def __init__( |
| self, year, month, day, hour, minute, second, microsecond, tzinfo, trivia, raw |
| ): # type: (int, int, int, int, int, int, int, ..., Trivia) -> None |
| super(DateTime, self).__init__(trivia) |
| |
| self._raw = raw |
| |
| @property |
| def discriminant(self): # type: () -> int |
| return 5 |
| |
| @property |
| def value(self): # type: () -> datetime |
| return self |
| |
| def as_string(self): # type: () -> str |
| return self._raw |
| |
| def __add__(self, other): |
| if PY38: |
| result = datetime( |
| self.year, |
| self.month, |
| self.day, |
| self.hour, |
| self.minute, |
| self.second, |
| self.microsecond, |
| self.tzinfo, |
| ).__add__(other) |
| else: |
| result = super(DateTime, self).__add__(other) |
| |
| return self._new(result) |
| |
| def __sub__(self, other): |
| if PY38: |
| result = datetime( |
| self.year, |
| self.month, |
| self.day, |
| self.hour, |
| self.minute, |
| self.second, |
| self.microsecond, |
| self.tzinfo, |
| ).__sub__(other) |
| else: |
| result = super(DateTime, self).__sub__(other) |
| |
| if isinstance(result, datetime): |
| result = self._new(result) |
| |
| return result |
| |
| def _new(self, result): |
| raw = result.isoformat() |
| |
| return DateTime( |
| result.year, |
| result.month, |
| result.day, |
| result.hour, |
| result.minute, |
| result.second, |
| result.microsecond, |
| result.tzinfo, |
| self._trivia, |
| raw, |
| ) |
| |
| def _getstate(self, protocol=3): |
| return ( |
| self.year, |
| self.month, |
| self.day, |
| self.hour, |
| self.minute, |
| self.second, |
| self.microsecond, |
| self.tzinfo, |
| self._trivia, |
| self._raw, |
| ) |
| |
| |
| class Date(Item, date): |
| """ |
| A date literal. |
| """ |
| |
| def __new__(cls, year, month, day, *_): # type: (int, int, int, ...) -> date |
| return date.__new__(cls, year, month, day) |
| |
| def __init__( |
| self, year, month, day, trivia, raw |
| ): # type: (int, int, int, Trivia, str) -> None |
| super(Date, self).__init__(trivia) |
| |
| self._raw = raw |
| |
| @property |
| def discriminant(self): # type: () -> int |
| return 6 |
| |
| @property |
| def value(self): # type: () -> date |
| return self |
| |
| def as_string(self): # type: () -> str |
| return self._raw |
| |
| def __add__(self, other): |
| if PY38: |
| result = date(self.year, self.month, self.day).__add__(other) |
| else: |
| result = super(Date, self).__add__(other) |
| |
| return self._new(result) |
| |
| def __sub__(self, other): |
| if PY38: |
| result = date(self.year, self.month, self.day).__sub__(other) |
| else: |
| result = super(Date, self).__sub__(other) |
| |
| return self._new(result) |
| |
| def _new(self, result): |
| raw = result.isoformat() |
| |
| return Date(result.year, result.month, result.day, self._trivia, raw) |
| |
| def _getstate(self, protocol=3): |
| return (self.year, self.month, self.day, self._trivia, self._raw) |
| |
| |
| class Time(Item, time): |
| """ |
| A time literal. |
| """ |
| |
| def __new__( |
| cls, hour, minute, second, microsecond, tzinfo, *_ |
| ): # type: (int, int, int, int, ...) -> time |
| return time.__new__(cls, hour, minute, second, microsecond, tzinfo) |
| |
| def __init__( |
| self, hour, minute, second, microsecond, tzinfo, trivia, raw |
| ): # type: (int, int, int, int, Trivia, str) -> None |
| super(Time, self).__init__(trivia) |
| |
| self._raw = raw |
| |
| @property |
| def discriminant(self): # type: () -> int |
| return 7 |
| |
| @property |
| def value(self): # type: () -> time |
| return self |
| |
| def as_string(self): # type: () -> str |
| return self._raw |
| |
| def _getstate(self, protocol=3): |
| return ( |
| self.hour, |
| self.minute, |
| self.second, |
| self.microsecond, |
| self.tzinfo, |
| self._trivia, |
| self._raw, |
| ) |
| |
| |
| class Array(Item, list): |
| """ |
| An array literal |
| """ |
| |
| def __init__(self, value, trivia): # type: (list, Trivia) -> None |
| super(Array, self).__init__(trivia) |
| |
| list.__init__( |
| self, [v.value for v in value if not isinstance(v, (Whitespace, Comment))] |
| ) |
| |
| self._value = value |
| |
| @property |
| def discriminant(self): # type: () -> int |
| return 8 |
| |
| @property |
| def value(self): # type: () -> list |
| return self |
| |
| def is_homogeneous(self): # type: () -> bool |
| if not self: |
| return True |
| |
| discriminants = [ |
| i.discriminant |
| for i in self._value |
| if not isinstance(i, (Whitespace, Comment)) |
| ] |
| |
| return len(set(discriminants)) == 1 |
| |
| def as_string(self): # type: () -> str |
| return "[{}]".format("".join(v.as_string() for v in self._value)) |
| |
| def append(self, _item): # type: () -> None |
| if self._value: |
| self._value.append(Whitespace(", ")) |
| |
| it = item(_item) |
| super(Array, self).append(it.value) |
| |
| self._value.append(it) |
| |
| if not self.is_homogeneous(): |
| raise ValueError("Array has mixed types elements") |
| |
| if not PY2: |
| |
| def clear(self): |
| super(Array, self).clear() |
| |
| self._value.clear() |
| |
| def __iadd__(self, other): # type: (list) -> Array |
| if not isinstance(other, list): |
| return NotImplemented |
| |
| for v in other: |
| self.append(v) |
| |
| return self |
| |
| def __delitem__(self, key): |
| super(Array, self).__delitem__(key) |
| |
| j = 0 if key >= 0 else -1 |
| for i, v in enumerate(self._value if key >= 0 else reversed(self._value)): |
| if key < 0: |
| i = -i - 1 |
| |
| if isinstance(v, (Comment, Whitespace)): |
| continue |
| |
| if j == key: |
| del self._value[i] |
| |
| if i < 0 and abs(i) > len(self._value): |
| i += 1 |
| |
| if i < len(self._value) - 1 and isinstance(self._value[i], Whitespace): |
| del self._value[i] |
| |
| break |
| |
| j += 1 if key >= 0 else -1 |
| |
| def __str__(self): |
| return str( |
| [v.value for v in self._value if not isinstance(v, (Whitespace, Comment))] |
| ) |
| |
| def __repr__(self): |
| return str(self) |
| |
| def _getstate(self, protocol=3): |
| return self._value, self._trivia |
| |
| |
| class Table(Item, dict): |
| """ |
| A table literal. |
| """ |
| |
| def __init__( |
| self, |
| value, |
| trivia, |
| is_aot_element, |
| is_super_table=False, |
| name=None, |
| display_name=None, |
| ): # type: (tomlkit.container.Container, Trivia, bool, ...) -> None |
| super(Table, self).__init__(trivia) |
| |
| self.name = name |
| self.display_name = display_name |
| self._value = value |
| self._is_aot_element = is_aot_element |
| self._is_super_table = is_super_table |
| |
| for k, v in self._value.body: |
| if k is not None: |
| super(Table, self).__setitem__(k.key, v) |
| |
| @property |
| def value(self): # type: () -> tomlkit.container.Container |
| return self._value |
| |
| @property |
| def discriminant(self): # type: () -> int |
| return 9 |
| |
| def add(self, key, item=None): # type: (Union[Key, Item, str], Any) -> Item |
| if item is None: |
| if not isinstance(key, (Comment, Whitespace)): |
| raise ValueError( |
| "Non comment/whitespace items must have an associated key" |
| ) |
| |
| key, item = None, key |
| |
| return self.append(key, item) |
| |
| def append(self, key, _item): # type: (Union[Key, str], Any) -> Table |
| """ |
| Appends a (key, item) to the table. |
| """ |
| if not isinstance(_item, Item): |
| _item = item(_item) |
| |
| self._value.append(key, _item) |
| |
| if isinstance(key, Key): |
| key = key.key |
| |
| if key is not None: |
| super(Table, self).__setitem__(key, _item) |
| |
| m = re.match("(?s)^[^ ]*([ ]+).*$", self._trivia.indent) |
| if not m: |
| return self |
| |
| indent = m.group(1) |
| |
| if not isinstance(_item, Whitespace): |
| m = re.match("(?s)^([^ ]*)(.*)$", _item.trivia.indent) |
| if not m: |
| _item.trivia.indent = indent |
| else: |
| _item.trivia.indent = m.group(1) + indent + m.group(2) |
| |
| return self |
| |
| def raw_append(self, key, _item): # type: (Union[Key, str], Any) -> Table |
| if not isinstance(_item, Item): |
| _item = item(_item) |
| |
| self._value.append(key, _item) |
| |
| if isinstance(key, Key): |
| key = key.key |
| |
| if key is not None: |
| super(Table, self).__setitem__(key, _item) |
| |
| return self |
| |
| def remove(self, key): # type: (Union[Key, str]) -> Table |
| self._value.remove(key) |
| |
| if isinstance(key, Key): |
| key = key.key |
| |
| if key is not None: |
| super(Table, self).__delitem__(key) |
| |
| return self |
| |
| def is_aot_element(self): # type: () -> bool |
| return self._is_aot_element |
| |
| def is_super_table(self): # type: () -> bool |
| return self._is_super_table |
| |
| def as_string(self, prefix=None): # type: () -> str |
| return self._value.as_string(prefix=prefix) |
| |
| # Helpers |
| |
| def indent(self, indent): # type: (int) -> Table |
| super(Table, self).indent(indent) |
| |
| m = re.match("(?s)^[^ ]*([ ]+).*$", self._trivia.indent) |
| if not m: |
| indent = "" |
| else: |
| indent = m.group(1) |
| |
| for k, item in self._value.body: |
| if not isinstance(item, Whitespace): |
| item.trivia.indent = indent + item.trivia.indent |
| |
| return self |
| |
| def keys(self): # type: () -> Generator[str] |
| for k in self._value.keys(): |
| yield k |
| |
| def values(self): # type: () -> Generator[Item] |
| for v in self._value.values(): |
| yield v |
| |
| def items(self): # type: () -> Generator[Item] |
| for k, v in self._value.items(): |
| yield k, v |
| |
| def update(self, other): # type: (Dict) -> None |
| for k, v in other.items(): |
| self[k] = v |
| |
| def __contains__(self, key): # type: (Union[Key, str]) -> bool |
| return key in self._value |
| |
| def __getitem__(self, key): # type: (Union[Key, str]) -> Item |
| return self._value[key] |
| |
| def __setitem__(self, key, value): # type: (Union[Key, str], Any) -> None |
| if not isinstance(value, Item): |
| value = item(value) |
| |
| self._value[key] = value |
| |
| if key is not None: |
| super(Table, self).__setitem__(key, value) |
| |
| m = re.match("(?s)^[^ ]*([ ]+).*$", self._trivia.indent) |
| if not m: |
| return |
| |
| indent = m.group(1) |
| |
| if not isinstance(value, Whitespace): |
| m = re.match("(?s)^([^ ]*)(.*)$", value.trivia.indent) |
| if not m: |
| value.trivia.indent = indent |
| else: |
| value.trivia.indent = m.group(1) + indent + m.group(2) |
| |
| def __delitem__(self, key): # type: (Union[Key, str]) -> None |
| self.remove(key) |
| |
| def __repr__(self): |
| return super(Table, self).__repr__() |
| |
| def __str__(self): |
| return str(self.value) |
| |
| def _getstate(self, protocol=3): |
| return ( |
| self._value, |
| self._trivia, |
| self._is_aot_element, |
| self._is_super_table, |
| self.name, |
| self.display_name, |
| ) |
| |
| |
| class InlineTable(Item, dict): |
| """ |
| An inline table literal. |
| """ |
| |
| def __init__( |
| self, value, trivia, new=False |
| ): # type: (tomlkit.container.Container, Trivia, bool) -> None |
| super(InlineTable, self).__init__(trivia) |
| |
| self._value = value |
| self._new = new |
| |
| for k, v in self._value.body: |
| if k is not None: |
| super(InlineTable, self).__setitem__(k.key, v) |
| |
| @property |
| def discriminant(self): # type: () -> int |
| return 10 |
| |
| @property |
| def value(self): # type: () -> Dict |
| return self._value |
| |
| def append(self, key, _item): # type: (Union[Key, str], Any) -> InlineTable |
| """ |
| Appends a (key, item) to the table. |
| """ |
| if not isinstance(_item, Item): |
| _item = item(_item) |
| |
| if not isinstance(_item, (Whitespace, Comment)): |
| if not _item.trivia.indent and len(self._value) > 0: |
| _item.trivia.indent = " " |
| if _item.trivia.comment: |
| _item.trivia.comment = "" |
| |
| self._value.append(key, _item) |
| |
| if isinstance(key, Key): |
| key = key.key |
| |
| if key is not None: |
| super(InlineTable, self).__setitem__(key, _item) |
| |
| return self |
| |
| def remove(self, key): # type: (Union[Key, str]) -> InlineTable |
| self._value.remove(key) |
| |
| if isinstance(key, Key): |
| key = key.key |
| |
| if key is not None: |
| super(InlineTable, self).__delitem__(key) |
| |
| return self |
| |
| def as_string(self): # type: () -> str |
| buf = "{" |
| for i, (k, v) in enumerate(self._value.body): |
| if k is None: |
| if i == len(self._value.body) - 1: |
| buf = buf.rstrip(",") |
| |
| buf += v.as_string() |
| |
| continue |
| |
| buf += "{}{}{}{}{}{}".format( |
| v.trivia.indent, |
| k.as_string(), |
| k.sep, |
| v.as_string(), |
| v.trivia.comment, |
| v.trivia.trail.replace("\n", ""), |
| ) |
| |
| if i != len(self._value.body) - 1: |
| buf += "," |
| if self._new: |
| buf += " " |
| |
| buf += "}" |
| |
| return buf |
| |
| def keys(self): # type: () -> Generator[str] |
| for k in self._value.keys(): |
| yield k |
| |
| def values(self): # type: () -> Generator[Item] |
| for v in self._value.values(): |
| yield v |
| |
| def items(self): # type: () -> Generator[Item] |
| for k, v in self._value.items(): |
| yield k, v |
| |
| def update(self, other): # type: (Dict) -> None |
| for k, v in other.items(): |
| self[k] = v |
| |
| def __contains__(self, key): # type: (Union[Key, str]) -> bool |
| return key in self._value |
| |
| def __getitem__(self, key): # type: (Union[Key, str]) -> Item |
| return self._value[key] |
| |
| def __setitem__(self, key, value): # type: (Union[Key, str], Any) -> None |
| if not isinstance(value, Item): |
| value = item(value) |
| |
| self._value[key] = value |
| |
| if key is not None: |
| super(InlineTable, self).__setitem__(key, value) |
| if value.trivia.comment: |
| value.trivia.comment = "" |
| |
| m = re.match("(?s)^[^ ]*([ ]+).*$", self._trivia.indent) |
| if not m: |
| return |
| |
| indent = m.group(1) |
| |
| if not isinstance(value, Whitespace): |
| m = re.match("(?s)^([^ ]*)(.*)$", value.trivia.indent) |
| if not m: |
| value.trivia.indent = indent |
| else: |
| value.trivia.indent = m.group(1) + indent + m.group(2) |
| |
| def __delitem__(self, key): # type: (Union[Key, str]) -> None |
| self.remove(key) |
| |
| def __repr__(self): |
| return super(InlineTable, self).__repr__() |
| |
| def _getstate(self, protocol=3): |
| return (self._value, self._trivia) |
| |
| |
| class String(unicode, Item): |
| """ |
| A string literal. |
| """ |
| |
| def __new__(cls, t, value, original, trivia): |
| return super(String, cls).__new__(cls, value) |
| |
| def __init__( |
| self, t, _, original, trivia |
| ): # type: (StringType, str, original, Trivia) -> None |
| super(String, self).__init__(trivia) |
| |
| self._t = t |
| self._original = original |
| |
| @property |
| def discriminant(self): # type: () -> int |
| return 11 |
| |
| @property |
| def value(self): # type: () -> str |
| return self |
| |
| def as_string(self): # type: () -> str |
| return "{}{}{}".format(self._t.value, decode(self._original), self._t.value) |
| |
| def __add__(self, other): |
| result = super(String, self).__add__(other) |
| |
| return self._new(result) |
| |
| def __sub__(self, other): |
| result = super(String, self).__sub__(other) |
| |
| return self._new(result) |
| |
| def _new(self, result): |
| return String(self._t, result, result, self._trivia) |
| |
| def _getstate(self, protocol=3): |
| return self._t, unicode(self), self._original, self._trivia |
| |
| |
| class AoT(Item, list): |
| """ |
| An array of table literal |
| """ |
| |
| def __init__( |
| self, body, name=None, parsed=False |
| ): # type: (List[Table], Optional[str]) -> None |
| self.name = name |
| self._body = [] |
| self._parsed = parsed |
| |
| super(AoT, self).__init__(Trivia(trail="")) |
| |
| for table in body: |
| self.append(table) |
| |
| @property |
| def body(self): # type: () -> List[Table] |
| return self._body |
| |
| @property |
| def discriminant(self): # type: () -> int |
| return 12 |
| |
| @property |
| def value(self): # type: () -> List[Dict[Any, Any]] |
| return [v.value for v in self._body] |
| |
| def append(self, table): # type: (Table) -> Table |
| m = re.match("(?s)^[^ ]*([ ]+).*$", self._trivia.indent) |
| if m: |
| indent = m.group(1) |
| |
| m = re.match("(?s)^([^ ]*)(.*)$", table.trivia.indent) |
| if not m: |
| table.trivia.indent = indent |
| else: |
| table.trivia.indent = m.group(1) + indent + m.group(2) |
| |
| if not self._parsed and "\n" not in table.trivia.indent and self._body: |
| table.trivia.indent = "\n" + table.trivia.indent |
| |
| self._body.append(table) |
| |
| super(AoT, self).append(table) |
| |
| return table |
| |
| def as_string(self): # type: () -> str |
| b = "" |
| for table in self._body: |
| b += table.as_string(prefix=self.name) |
| |
| return b |
| |
| def __repr__(self): # type: () -> str |
| return "<AoT {}>".format(self.value) |
| |
| def _getstate(self, protocol=3): |
| return self._body, self.name, self._parsed |
| |
| |
| class Null(Item): |
| """ |
| A null item. |
| """ |
| |
| def __init__(self): # type: () -> None |
| pass |
| |
| @property |
| def discriminant(self): # type: () -> int |
| return -1 |
| |
| @property |
| def value(self): # type: () -> None |
| return None |
| |
| def as_string(self): # type: () -> str |
| return "" |
| |
| def _getstate(self, protocol=3): |
| return tuple() |