| import io |
| import json |
| import os |
| |
| from datetime import date |
| from datetime import datetime |
| from datetime import time |
| from types import MappingProxyType |
| |
| import pytest |
| |
| import tomlkit |
| |
| from tomlkit import dump |
| from tomlkit import dumps |
| from tomlkit import load |
| from tomlkit import loads |
| from tomlkit import parse |
| from tomlkit.exceptions import InvalidCharInStringError |
| from tomlkit.exceptions import InvalidControlChar |
| from tomlkit.exceptions import InvalidDateError |
| from tomlkit.exceptions import InvalidDateTimeError |
| from tomlkit.exceptions import InvalidNumberError |
| from tomlkit.exceptions import InvalidStringError |
| from tomlkit.exceptions import InvalidTimeError |
| from tomlkit.exceptions import UnexpectedCharError |
| from tomlkit.items import AoT |
| from tomlkit.items import Array |
| from tomlkit.items import Bool |
| 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 Key |
| from tomlkit.items import Table |
| from tomlkit.items import Time |
| from tomlkit.toml_document import TOMLDocument |
| |
| |
| def json_serial(obj): |
| """JSON serializer for objects not serializable by default json code""" |
| if isinstance(obj, (datetime, date, time)): |
| return obj.isoformat() |
| |
| raise TypeError(f"Type {type(obj)} not serializable") |
| |
| |
| @pytest.mark.parametrize( |
| "example_name", |
| [ |
| "example", |
| "fruit", |
| "hard", |
| "sections_with_same_start", |
| "pyproject", |
| "0.5.0", |
| "test", |
| "newline_in_strings", |
| "preserve_quotes_in_string", |
| "string_slash_whitespace_newline", |
| "table_names", |
| ], |
| ) |
| def test_parse_can_parse_valid_toml_files(example, example_name): |
| assert isinstance(parse(example(example_name)), TOMLDocument) |
| assert isinstance(loads(example(example_name)), TOMLDocument) |
| |
| |
| @pytest.mark.parametrize( |
| "example_name", |
| [ |
| "example", |
| "fruit", |
| "hard", |
| "sections_with_same_start", |
| "pyproject", |
| "0.5.0", |
| "test", |
| "newline_in_strings", |
| "preserve_quotes_in_string", |
| "string_slash_whitespace_newline", |
| "table_names", |
| ], |
| ) |
| def test_load_from_file_object(example_name): |
| with open( |
| os.path.join(os.path.dirname(__file__), "examples", example_name + ".toml"), |
| encoding="utf-8", |
| ) as fp: |
| assert isinstance(load(fp), TOMLDocument) |
| |
| |
| @pytest.mark.parametrize("example_name", ["0.5.0", "pyproject", "table_names"]) |
| def test_parsed_document_are_properly_json_representable( |
| example, json_example, example_name |
| ): |
| doc = json.loads(json.dumps(parse(example(example_name)), default=json_serial)) |
| json_doc = json.loads(json_example(example_name)) |
| |
| assert doc == json_doc |
| |
| |
| @pytest.mark.parametrize( |
| "example_name,error", |
| [ |
| ("section_with_trailing_characters", UnexpectedCharError), |
| ("key_value_with_trailing_chars", UnexpectedCharError), |
| ("array_with_invalid_chars", UnexpectedCharError), |
| ("invalid_number", InvalidNumberError), |
| ("invalid_date", InvalidDateError), |
| ("invalid_time", InvalidTimeError), |
| ("invalid_datetime", InvalidDateTimeError), |
| ("trailing_comma", UnexpectedCharError), |
| ("newline_in_singleline_string", InvalidControlChar), |
| ("string_slash_whitespace_char", InvalidCharInStringError), |
| ("array_no_comma", UnexpectedCharError), |
| ("array_duplicate_comma", UnexpectedCharError), |
| ("array_leading_comma", UnexpectedCharError), |
| ("inline_table_no_comma", UnexpectedCharError), |
| ("inline_table_duplicate_comma", UnexpectedCharError), |
| ("inline_table_leading_comma", UnexpectedCharError), |
| ("inline_table_trailing_comma", UnexpectedCharError), |
| ], |
| ) |
| def test_parse_raises_errors_for_invalid_toml_files( |
| invalid_example, error, example_name |
| ): |
| with pytest.raises(error): |
| parse(invalid_example(example_name)) |
| |
| |
| @pytest.mark.parametrize( |
| "example_name", |
| [ |
| "example", |
| "fruit", |
| "hard", |
| "sections_with_same_start", |
| "pyproject", |
| "0.5.0", |
| "test", |
| "table_names", |
| ], |
| ) |
| def test_original_string_and_dumped_string_are_equal(example, example_name): |
| content = example(example_name) |
| parsed = parse(content) |
| |
| assert content == dumps(parsed) |
| |
| |
| def test_a_raw_dict_can_be_dumped(): |
| s = dumps({"foo": "bar"}) |
| |
| assert s == 'foo = "bar"\n' |
| |
| |
| def test_mapping_types_can_be_dumped(): |
| x = MappingProxyType({"foo": "bar"}) |
| assert dumps(x) == 'foo = "bar"\n' |
| |
| |
| def test_dumps_weird_object(): |
| with pytest.raises(TypeError): |
| dumps(object()) |
| |
| |
| def test_dump_tuple_value_as_array(): |
| x = {"foo": (1, 2)} |
| assert dumps(x) == "foo = [1, 2]\n" |
| |
| x = {"foo": ({"a": 1}, {"a": 2})} |
| assert dumps(x) == "[[foo]]\na = 1\n\n[[foo]]\na = 2\n" |
| |
| |
| def test_dump_to_file_object(): |
| doc = {"foo": "bar"} |
| fp = io.StringIO() |
| dump(doc, fp) |
| assert fp.getvalue() == 'foo = "bar"\n' |
| |
| |
| def test_integer(): |
| i = tomlkit.integer("34") |
| |
| assert isinstance(i, Integer) |
| |
| |
| def test_float(): |
| i = tomlkit.float_("34.56") |
| |
| assert isinstance(i, Float) |
| |
| |
| def test_boolean(): |
| i = tomlkit.boolean("true") |
| |
| assert isinstance(i, Bool) |
| |
| |
| def test_date(): |
| dt = tomlkit.date("1979-05-13") |
| |
| assert isinstance(dt, Date) |
| |
| with pytest.raises(ValueError): |
| tomlkit.date("12:34:56") |
| |
| |
| def test_time(): |
| dt = tomlkit.time("12:34:56") |
| |
| assert isinstance(dt, Time) |
| |
| with pytest.raises(ValueError): |
| tomlkit.time("1979-05-13") |
| |
| |
| def test_datetime(): |
| dt = tomlkit.datetime("1979-05-13T12:34:56") |
| |
| assert isinstance(dt, DateTime) |
| |
| with pytest.raises(ValueError): |
| tomlkit.time("1979-05-13") |
| |
| |
| def test_array(): |
| a = tomlkit.array() |
| |
| assert isinstance(a, Array) |
| |
| a = tomlkit.array("[1,2, 3]") |
| |
| assert isinstance(a, Array) |
| |
| |
| def test_table(): |
| t = tomlkit.table() |
| |
| assert isinstance(t, Table) |
| |
| |
| def test_inline_table(): |
| t = tomlkit.inline_table() |
| |
| assert isinstance(t, InlineTable) |
| |
| |
| def test_aot(): |
| t = tomlkit.aot() |
| |
| assert isinstance(t, AoT) |
| |
| |
| def test_key(): |
| k = tomlkit.key("foo") |
| |
| assert isinstance(k, Key) |
| |
| |
| def test_key_value(): |
| k, i = tomlkit.key_value("foo = 12") |
| |
| assert isinstance(k, Key) |
| assert isinstance(i, Integer) |
| |
| |
| def test_string(): |
| s = tomlkit.string('foo "') |
| |
| assert s.value == 'foo "' |
| assert s.as_string() == '"foo \\""' |
| |
| |
| def test_item_dict_to_table(): |
| t = tomlkit.item({"foo": {"bar": "baz"}}) |
| |
| assert t.value == {"foo": {"bar": "baz"}} |
| assert ( |
| t.as_string() |
| == """[foo] |
| bar = "baz" |
| """ |
| ) |
| |
| |
| def test_item_mixed_aray(): |
| example = [{"a": 3}, "b", 42] |
| expected = '[{a = 3}, "b", 42]' |
| t = tomlkit.item(example) |
| assert t.as_string().strip() == expected |
| assert dumps({"x": {"y": example}}).strip() == "[x]\ny = " + expected |
| |
| |
| def test_build_super_table(): |
| doc = tomlkit.document() |
| table = tomlkit.table(True) |
| table.add("bar", {"x": 1}) |
| doc.add("foo", table) |
| assert doc.as_string() == "[foo.bar]\nx = 1\n" |
| |
| |
| def test_add_dotted_key(): |
| doc = tomlkit.document() |
| doc.add(tomlkit.key(["foo", "bar"]), 1) |
| assert doc.as_string() == "foo.bar = 1\n" |
| |
| table = tomlkit.table() |
| table.add(tomlkit.key(["foo", "bar"]), 1) |
| assert table.as_string() == "foo.bar = 1\n" |
| |
| |
| @pytest.mark.parametrize( |
| ("raw", "expected"), |
| [ |
| ("true", True), |
| ("false", False), |
| ], |
| ) |
| def test_value_parses_boolean(raw, expected): |
| parsed = tomlkit.value(raw) |
| assert parsed == expected |
| |
| |
| @pytest.mark.parametrize( |
| "raw", ["t", "f", "tru", "fals", "test", "friend", "truthy", "falsify"] |
| ) |
| def test_value_rejects_values_looking_like_bool_at_start(raw): |
| """Reproduces https://github.com/sdispater/tomlkit/issues/165""" |
| with pytest.raises(tomlkit.exceptions.ParseError): |
| tomlkit.value(raw) |
| |
| |
| @pytest.mark.parametrize( |
| "raw", |
| [ |
| "truee", |
| "truely", |
| "true-thoughts", |
| "true_hip_hop", |
| ], |
| ) |
| def test_value_rejects_values_having_true_prefix(raw): |
| """Values that have ``true`` or ``false`` as prefix but then have additional chars are rejected.""" |
| with pytest.raises(tomlkit.exceptions.ParseError): |
| tomlkit.value(raw) |
| |
| |
| @pytest.mark.parametrize( |
| "raw", |
| [ |
| "falsee", |
| "falsely", |
| "false-ideas", |
| "false_prophet", |
| ], |
| ) |
| def test_value_rejects_values_having_false_prefix(raw): |
| """Values that have ``true`` or ``false`` as prefix but then have additional chars are rejected.""" |
| with pytest.raises(tomlkit.exceptions.ParseError): |
| tomlkit.value(raw) |
| |
| |
| @pytest.mark.parametrize( |
| "raw", |
| [ |
| '"foo"1.2', |
| "truefalse", |
| "1.0false", |
| "100true", |
| "truetrue", |
| "falsefalse", |
| "1.2.3.4", |
| "[][]", |
| "{a=[][]}[]", |
| "true[]", |
| "false{a=1}", |
| ], |
| ) |
| def test_value_rejects_values_with_appendage(raw): |
| """Values that appear valid at the beginning but leave chars unparsed are rejected.""" |
| with pytest.raises(tomlkit.exceptions.ParseError): |
| tomlkit.value(raw) |
| |
| |
| def test_create_super_table_with_table(): |
| data = {"foo": {"bar": {"a": 1}}} |
| assert dumps(data) == "[foo.bar]\na = 1\n" |
| |
| |
| def test_create_super_table_with_aot(): |
| data = {"foo": {"bar": [{"a": 1}]}} |
| assert dumps(data) == "[[foo.bar]]\na = 1\n" |
| |
| |
| @pytest.mark.parametrize( |
| "kwargs, example, expected", |
| [ |
| ({}, "My\nString", '"My\\nString"'), |
| ({"escape": False}, "My String\t", '"My String\t"'), |
| ({"literal": True}, "My String\t", "'My String\t'"), |
| ({"escape": True, "literal": True}, "My String\t", "'My String\t'"), |
| ({}, "My String\u0001", '"My String\\u0001"'), |
| ({}, "My String\u000b", '"My String\\u000b"'), |
| ({}, "My String\x08", '"My String\\b"'), |
| ({}, "My String\x0c", '"My String\\f"'), |
| ({}, "My String\x01", '"My String\\u0001"'), |
| ({}, "My String\x06", '"My String\\u0006"'), |
| ({}, "My String\x12", '"My String\\u0012"'), |
| ({}, "My String\x7f", '"My String\\u007f"'), |
| ({"escape": False}, "My String\u0001", '"My String\u0001"'), |
| ({"multiline": True}, "\nMy\nString\n", '"""\nMy\nString\n"""'), |
| ({"multiline": True}, 'My"String', '"""My"String"""'), |
| ({"multiline": True}, 'My""String', '"""My""String"""'), |
| ({"multiline": True}, 'My"""String', '"""My""\\"String"""'), |
| ({"multiline": True}, 'My""""String', '"""My""\\""String"""'), |
| ( |
| {"multiline": True}, |
| '"""My"""Str"""ing"""', |
| '"""""\\"My""\\"Str""\\"ing""\\""""', |
| ), |
| ({"multiline": True, "literal": True}, "My\nString", "'''My\nString'''"), |
| ({"multiline": True, "literal": True}, "My'String", "'''My'String'''"), |
| ({"multiline": True, "literal": True}, "My\r\nString", "'''My\r\nString'''"), |
| ( |
| {"literal": True}, |
| r"C:\Users\nodejs\templates", |
| r"'C:\Users\nodejs\templates'", |
| ), |
| ({"literal": True}, r"<\i\c*\s*>", r"'<\i\c*\s*>'"), |
| ( |
| {"multiline": True, "literal": True}, |
| r"I [dw]on't need \d{2} apples", |
| r"'''I [dw]on't need \d{2} apples'''", |
| ), |
| ], |
| ) |
| def test_create_string(kwargs, example, expected): |
| value = tomlkit.string(example, **kwargs) |
| assert value.as_string() == expected |
| |
| |
| @pytest.mark.parametrize( |
| "kwargs, example", |
| [ |
| ({"literal": True}, "My'String"), |
| ({"literal": True}, "My\nString"), |
| ({"literal": True}, "My\r\nString"), |
| ({"literal": True}, "My\bString"), |
| ({"literal": True}, "My\x08String"), |
| ({"literal": True}, "My\x0cString"), |
| ({"literal": True}, "My\x7fString"), |
| ({"multiline": True, "literal": True}, "My'''String"), |
| ], |
| ) |
| def test_create_string_with_invalid_characters(kwargs, example): |
| with pytest.raises(InvalidStringError): |
| tomlkit.string(example, **kwargs) |
| |
| |
| def test_parse_empty_quoted_table_name(): |
| content = "['']\nx = 1\n" |
| parsed = loads(content) |
| assert parsed == {"": {"x": 1}} |
| assert dumps(parsed) == content |