Skip to content

Commit

Permalink
Add unwrap method to recursive convert to plain old python objects (#187
Browse files Browse the repository at this point in the history
)

* add as_ppo method for elementary types

* rename as_popo to unwrap; add recursive arg

* add unwrap methods to collection types + Null

* remove dangling 'def'

* Container loops through items() instead of _body

* add Integer and Item unit tests

* added passing tests for everything up to Array

* remove recursive option

* remove unused is_ppo function

* refactor Container unwrap to reuse code

* add AbstractTable test

* add string, null, and aot tests

* add test for Container

* type(..) to isinstance(..) in Container unwrap

* try/catch ensure v has unwrap in Container.unwrap

* replace 'type' with 'isinstance' in test_items.py

* refactor assert_is_ppo to pass only ppo type

* refactory test_document_is_a_dict to not call 'type'

* remove elementary_fail function

* minor change in Container unwrap method

* use isinstance not is_tomlkit in AoT.unwrap

* run pre-commit
  • Loading branch information
syntapy committed May 22, 2022
1 parent 721acca commit deac74d
Show file tree
Hide file tree
Showing 6 changed files with 290 additions and 0 deletions.
104 changes: 104 additions & 0 deletions tests/test_items.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,32 @@

from tomlkit import api
from tomlkit import parse
from tomlkit.check import is_tomlkit
from tomlkit.exceptions import NonExistentKey
from tomlkit.items import AoT
from tomlkit.items import Array
from tomlkit.items import Bool
from tomlkit.items import Comment
from tomlkit.items import Date
from tomlkit.items import DateTime
from tomlkit.items import Float
from tomlkit.items import InlineTable
from tomlkit.items import Integer
from tomlkit.items import Item
from tomlkit.items import KeyType
from tomlkit.items import Null
from tomlkit.items import SingleKey as Key
from tomlkit.items import String
from tomlkit.items import StringType
from tomlkit.items import Table
from tomlkit.items import Time
from tomlkit.items import Trivia
from tomlkit.items import item
from tomlkit.parser import Parser

from .util import assert_is_ppo
from .util import elementary_test


@pytest.fixture()
def tz_pst():
Expand Down Expand Up @@ -69,6 +81,98 @@ def dst(self, dt):
return UTC()


def test_item_base_has_no_unwrap():
trivia = Trivia(indent="\t", comment_ws=" ", comment="For unit test")
item = Item(trivia)
try:
item.unwrap()
except NotImplementedError:
pass
else:
raise AssertionError("`items.Item` should not implement `unwrap`")


def test_integer_unwrap():
elementary_test(item(666), int)


def test_float_unwrap():
elementary_test(item(2.78), float)


def test_false_unwrap():
elementary_test(item(False), bool)


def test_true_unwrap():
elementary_test(item(True), bool)


def test_datetime_unwrap():
dt = datetime.utcnow()
elementary_test(item(dt), datetime)


def test_string_unwrap():
elementary_test(item("hello"), str)


def test_null_unwrap():
n = Null()
elementary_test(n, type(None))


def test_aot_unwrap():
d = item([{"a": "A"}, {"b": "B"}])
assert is_tomlkit(d)
unwrapped = d.unwrap()
assert_is_ppo(unwrapped, list)
for du, dw in zip(unwrapped, d):
assert_is_ppo(du, dict)
for ku in du:
vu = du[ku]
assert_is_ppo(ku, str)
assert_is_ppo(vu, str)


def test_time_unwrap():
t = time(3, 8, 14)
elementary_test(item(t), time)


def test_date_unwrap():
d = date.today()
elementary_test(item(d), date)


def test_array_unwrap():
trivia = Trivia(indent="\t", comment_ws=" ", comment="For unit test")
i = item(666)
f = item(2.78)
b = item(False)
a = Array([i, f, b], trivia)
a_unwrapped = a.unwrap()
assert_is_ppo(a_unwrapped, list)
assert_is_ppo(a_unwrapped[0], int)
assert_is_ppo(a_unwrapped[1], float)
assert_is_ppo(a_unwrapped[2], bool)


def test_abstract_table_unwrap():
table = item({"foo": "bar"})
super_table = item({"table": table, "baz": "borg"})
assert is_tomlkit(super_table["table"])

table_unwrapped = super_table.unwrap()
sub_table = table_unwrapped["table"]
assert_is_ppo(table_unwrapped, dict)
assert_is_ppo(sub_table, dict)
for ku in sub_table:
vu = sub_table[ku]
assert_is_ppo(ku, str)
assert_is_ppo(vu, str)


def test_key_comparison():
k = Key("foo")

Expand Down
18 changes: 18 additions & 0 deletions tests/test_toml_document.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
from tomlkit._utils import _utc
from tomlkit.api import document
from tomlkit.exceptions import NonExistentKey
from tomlkit.toml_document import TOMLDocument

from .util import assert_is_ppo
from .util import elementary_test


def test_document_is_a_dict(example):
Expand Down Expand Up @@ -154,6 +158,20 @@ def test_toml_document_without_super_tables():
assert "tool" in d


def test_toml_document_unwrap():
content = """[tool.poetry]
name = "foo"
"""

doc = parse(content)
unwrapped = doc.unwrap()
assert_is_ppo(unwrapped, dict)
assert_is_ppo(list(unwrapped.keys())[0], str)
assert_is_ppo(unwrapped["tool"], dict)
assert_is_ppo(list(unwrapped["tool"].keys())[0], str)
assert_is_ppo(unwrapped["tool"]["poetry"]["name"], str)


def test_toml_document_with_dotted_keys(example):
content = example("0.5.0")

Expand Down
57 changes: 57 additions & 0 deletions tests/util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
from tomlkit.items import AoT
from tomlkit.items import Array
from tomlkit.items import Bool
from tomlkit.items import Comment
from tomlkit.items import Date
from tomlkit.items import DateTime
from tomlkit.items import Float
from tomlkit.items import InlineTable
from tomlkit.items import Integer
from tomlkit.items import Item
from tomlkit.items import KeyType
from tomlkit.items import Null
from tomlkit.items import SingleKey as Key
from tomlkit.items import String
from tomlkit.items import StringType
from tomlkit.items import Table
from tomlkit.items import Time
from tomlkit.items import Trivia
from tomlkit.toml_document import TOMLDocument


TOMLKIT_TYPES = [
Bool,
Comment,
InlineTable,
Integer,
Float,
DateTime,
Date,
Time,
Array,
KeyType,
Key,
String,
StringType,
Table,
Trivia,
Item,
AoT,
Null,
TOMLDocument,
]


def assert_not_tomlkit_type(v):
for i, T in enumerate(TOMLKIT_TYPES):
assert not isinstance(v, T)


def assert_is_ppo(v_unwrapped, unwrappedType):
assert_not_tomlkit_type(v_unwrapped)
assert isinstance(v_unwrapped, unwrappedType)


def elementary_test(v, unwrappedType):
v_unwrapped = v.unwrap()
assert_is_ppo(v_unwrapped, unwrappedType)
12 changes: 12 additions & 0 deletions tomlkit/check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
def is_tomlkit(v):
from .container import Container
from .container import OutOfOrderTableProxy
from .items import Item as _Item

if isinstance(v, _Item):
return True
if isinstance(v, Container):
return True
if isinstance(v, OutOfOrderTableProxy):
return True
return False
23 changes: 23 additions & 0 deletions tomlkit/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

from ._compat import decode
from ._utils import merge_dicts
from .check import is_tomlkit
from .exceptions import KeyAlreadyPresent
from .exceptions import NonExistentKey
from .exceptions import TOMLKitError
Expand Down Expand Up @@ -46,6 +47,25 @@ def __init__(self, parsed: bool = False) -> None:
def body(self) -> List[Tuple[Optional[Key], Item]]:
return self._body

def unwrap(self) -> str:
unwrapped = {}
for k, v in self.items():
if k is None:
continue

if not isinstance(k, str):
k = k.key

if isinstance(v, Item):
v = v.unwrap()

if k in unwrapped:
merge_dicts(unwrapped[k], v)
else:
unwrapped[k] = v

return unwrapped

@property
def value(self) -> Dict[Any, Any]:
d = {}
Expand Down Expand Up @@ -796,6 +816,9 @@ def __init__(self, container: Container, indices: Tuple[int]) -> None:
if k is not None:
dict.__setitem__(self, k.key, v)

def unwrap(self) -> str:
return self._internal_container.unwrap()

@property
def value(self):
return self._internal_container.value
Expand Down
Loading

0 comments on commit deac74d

Please sign in to comment.