Removed the Requirement to Install Python and NodeJS (Now Bundled with Borealis)

This commit is contained in:
2025-04-24 00:42:19 -06:00
parent 785265d3e7
commit 9c68cdea84
7786 changed files with 2386458 additions and 217 deletions

View File

@ -0,0 +1,15 @@
# SPDX-License-Identifier: MIT
# SPDX-FileCopyrightText: 2021 Taneli Hukkinen
# Licensed to PSF under a Contributor Agreement.
__all__ = ("tomllib",)
# By changing this one line, we can run the tests against
# a different module name.
import tomllib
import os
from test.support import load_package_tests
def load_tests(*args):
return load_package_tests(os.path.dirname(__file__), *args)

View File

@ -0,0 +1,6 @@
import unittest
from . import load_tests
unittest.main()

View File

@ -0,0 +1,120 @@
# SPDX-License-Identifier: MIT
# SPDX-FileCopyrightText: 2021 Taneli Hukkinen
# Licensed to PSF under a Contributor Agreement.
"""Utilities for tests that are in the "burntsushi" format."""
import datetime
from typing import Any
# Aliases for converting TOML compliance format [1] to BurntSushi format [2]
# [1] https://github.com/toml-lang/compliance/blob/db7c3211fda30ff9ddb10292f4aeda7e2e10abc4/docs/json-encoding.md # noqa: E501
# [2] https://github.com/BurntSushi/toml-test/blob/4634fdf3a6ecd6aaea5f4cdcd98b2733c2694993/README.md # noqa: E501
_aliases = {
"boolean": "bool",
"offset datetime": "datetime",
"local datetime": "datetime-local",
"local date": "date-local",
"local time": "time-local",
}
def convert(obj): # noqa: C901
if isinstance(obj, str):
return {"type": "string", "value": obj}
elif isinstance(obj, bool):
return {"type": "bool", "value": str(obj).lower()}
elif isinstance(obj, int):
return {"type": "integer", "value": str(obj)}
elif isinstance(obj, float):
return {"type": "float", "value": _normalize_float_str(str(obj))}
elif isinstance(obj, datetime.datetime):
val = _normalize_datetime_str(obj.isoformat())
if obj.tzinfo:
return {"type": "datetime", "value": val}
return {"type": "datetime-local", "value": val}
elif isinstance(obj, datetime.time):
return {
"type": "time-local",
"value": _normalize_localtime_str(str(obj)),
}
elif isinstance(obj, datetime.date):
return {
"type": "date-local",
"value": str(obj),
}
elif isinstance(obj, list):
return [convert(i) for i in obj]
elif isinstance(obj, dict):
return {k: convert(v) for k, v in obj.items()}
raise Exception("unsupported type")
def normalize(obj: Any) -> Any:
"""Normalize test objects.
This normalizes primitive values (e.g. floats), and also converts from
TOML compliance format [1] to BurntSushi format [2].
[1] https://github.com/toml-lang/compliance/blob/db7c3211fda30ff9ddb10292f4aeda7e2e10abc4/docs/json-encoding.md # noqa: E501
[2] https://github.com/BurntSushi/toml-test/blob/4634fdf3a6ecd6aaea5f4cdcd98b2733c2694993/README.md # noqa: E501
"""
if isinstance(obj, list):
return [normalize(item) for item in obj]
if isinstance(obj, dict):
if "type" in obj and "value" in obj:
type_ = obj["type"]
norm_type = _aliases.get(type_, type_)
value = obj["value"]
if norm_type == "float":
norm_value = _normalize_float_str(value)
elif norm_type in {"datetime", "datetime-local"}:
norm_value = _normalize_datetime_str(value)
elif norm_type == "time-local":
norm_value = _normalize_localtime_str(value)
else:
norm_value = value
if norm_type == "array":
return [normalize(item) for item in value]
return {"type": norm_type, "value": norm_value}
return {k: normalize(v) for k, v in obj.items()}
raise AssertionError("Burntsushi fixtures should be dicts/lists only")
def _normalize_datetime_str(dt_str: str) -> str:
if dt_str[-1].lower() == "z":
dt_str = dt_str[:-1] + "+00:00"
date = dt_str[:10]
rest = dt_str[11:]
if "+" in rest:
sign = "+"
elif "-" in rest:
sign = "-"
else:
sign = ""
if sign:
time, _, offset = rest.partition(sign)
else:
time = rest
offset = ""
time = time.rstrip("0") if "." in time else time
return date + "T" + time + sign + offset
def _normalize_localtime_str(lt_str: str) -> str:
return lt_str.rstrip("0") if "." in lt_str else lt_str
def _normalize_float_str(float_str: str) -> str:
as_float = float(float_str)
# Normalize "-0.0" and "+0.0"
if as_float == 0:
return "0"
return str(as_float)

View File

@ -0,0 +1 @@
arrr = [true false]

View File

@ -0,0 +1,4 @@
[[parent-table.arr]]
[parent-table]
not-arr = 1
arr = 2

View File

@ -0,0 +1 @@
"backslash is the last char\

View File

@ -0,0 +1 @@
val=falsE

View File

@ -0,0 +1 @@
val=trUe

View File

@ -0,0 +1 @@
"only 28 or 29 days in february" = 1988-02-30

View File

@ -0,0 +1,2 @@
a = false
a.b = true

View File

@ -0,0 +1,3 @@
[[tab.arr]]
[tab]
arr.val1=1

View File

@ -0,0 +1,4 @@
[a.b.c.d]
z = 9
[a]
b.c.d.k.t = 8

View File

@ -0,0 +1,4 @@
[a.b.c]
z = 9
[a]
b.c.t = 9

View File

@ -0,0 +1 @@
arrr = { comma-missing = true valid-toml = false }

View File

@ -0,0 +1 @@
table1 = { table2.dupe = 1, table2.dupe = 2 }

View File

@ -0,0 +1 @@
table = { dupe = 1, dupe = 2 }

View File

@ -0,0 +1,2 @@
a = { b = 1 }
a.b = 2

View File

@ -0,0 +1,5 @@
[tab.nested]
inline-t = { nest = {} }
[tab]
nested.inline-t.nest = 2

View File

@ -0,0 +1,3 @@
inline-t = { nest = {} }
[[inline-t.nest]]

View File

@ -0,0 +1,3 @@
inline-t = { nest = {} }
[inline-t.nest]

View File

@ -0,0 +1 @@
a = { b = 1, b.c = 2 }

View File

@ -0,0 +1 @@
tab = { inner.table = [{}], inner.table.val = "bad" }

View File

@ -0,0 +1 @@
tab = { inner = { dog = "best" }, inner.cat = "worst" }

View File

@ -0,0 +1 @@
# form feed ( ) not allowed in comments

View File

@ -0,0 +1 @@
escaped-unicode = "\uabag"

View File

@ -0,0 +1 @@
hex = 0xgabba00f1

View File

@ -0,0 +1 @@
why-no-value=

View File

@ -0,0 +1 @@
unclosed='dwdd

View File

@ -0,0 +1,2 @@
[[closing-bracket.missing]
blaa=2

View File

@ -0,0 +1,2 @@
[closing-bracket.missingö
blaa=2

View File

@ -0,0 +1,2 @@
s="""cr is not an allowed line ending
but we just tried to use it

View File

@ -0,0 +1 @@
bee = """\"""

View File

@ -0,0 +1,4 @@
bee = """
hee \
gee \ """

View File

@ -0,0 +1,3 @@
bee = '''
hee
gee ''

View File

@ -0,0 +1 @@
a="\ud800"

View File

@ -0,0 +1,3 @@
[t1]
t2.t3.v = 0
[t1.t2]

View File

@ -0,0 +1,3 @@
[t1]
t2.t3.v = 0
[t1.t2.t3]

View File

@ -0,0 +1,4 @@
not-closed= """
diibaa
blibae ete
eteta

View File

@ -0,0 +1 @@
"a-string".must-be = "closed

View File

@ -0,0 +1 @@
{"this-str-has-apostrophes": {"type": "string", "value": "' there's one already\n'' two more\n''"}}

View File

@ -0,0 +1,3 @@
this-str-has-apostrophes='''' there's one already
'' two more
'''''

View File

@ -0,0 +1,11 @@
{"arr":
{"type":"array","value":
[
{"subtab":
{"val": {"type":"integer","value":"1"}
}
},
{"subtab": {"val": {"type":"integer","value":"2"}}}
]
}
}

View File

@ -0,0 +1,7 @@
[[arr]]
[arr.subtab]
val=1
[[arr]]
[arr.subtab]
val=2

View File

@ -0,0 +1,6 @@
{
"parent-table": {
"arr": {"type":"array","value":[{},{}]},
"not-arr": {"type":"integer","value":"1"}
}
}

View File

@ -0,0 +1,4 @@
[[parent-table.arr]]
[[parent-table.arr]]
[parent-table]
not-arr = 1

View File

@ -0,0 +1,4 @@
{
"a": {"type":"bool","value":"true"},
"b": {"type":"bool","value":"false"}
}

View File

@ -0,0 +1,2 @@
'a'=true
"b"=false

View File

@ -0,0 +1,4 @@
{
"local-dt": {"type":"datetime-local","value":"1988-10-27t01:01:01"},
"zulu-dt": {"type":"datetime","value":"1988-10-27t01:01:01z"}
}

View File

@ -0,0 +1,2 @@
local-dt=1988-10-27t01:01:01
zulu-dt=1988-10-27t01:01:01z

View File

@ -0,0 +1,2 @@
{"t":
{"type":"time-local","value":"00:00:00.999999"}}

View File

@ -0,0 +1 @@
t=00:00:00.99999999999999

View File

@ -0,0 +1 @@
{"empty": {}}

View File

@ -0,0 +1 @@
empty ={ }#nothing here

View File

@ -0,0 +1,4 @@
{
"five-quotes": {"type":"string","value":"Closing with five quotes\n\"\""},
"four-quotes": {"type":"string","value":"Closing with four quotes\n\""}
}

View File

@ -0,0 +1,6 @@
five-quotes = """
Closing with five quotes
"""""
four-quotes = """
Closing with four quotes
""""

View File

@ -0,0 +1,5 @@
{
"a": {"type":"string","value":"a"},
"b": {"type":"string","value":"b"},
"c": {"type":"string","value":"c"}
}

View File

@ -0,0 +1,3 @@
a="\u0061"
b="\u0062"
c="\U00000063"

View File

@ -0,0 +1 @@
{"beee": {"type": "string", "value": "heeee\ngeeee"}}

View File

@ -0,0 +1,6 @@
beee = """
heeee
geeee\
"""

View File

@ -0,0 +1 @@
{}

View File

@ -0,0 +1 @@
#no newlines at all here

View File

@ -0,0 +1,7 @@
{"arr":
{"type":"array","value":
[
{"type":"integer","value":"1"}
]
}
}

View File

@ -0,0 +1 @@
arr=[1,]

View File

@ -0,0 +1,64 @@
# SPDX-License-Identifier: MIT
# SPDX-FileCopyrightText: 2021 Taneli Hukkinen
# Licensed to PSF under a Contributor Agreement.
import json
from pathlib import Path
import unittest
from . import burntsushi, tomllib
class MissingFile:
def __init__(self, path: Path):
self.path = path
DATA_DIR = Path(__file__).parent / "data"
VALID_FILES = tuple((DATA_DIR / "valid").glob("**/*.toml"))
assert VALID_FILES, "Valid TOML test files not found"
_expected_files = []
for p in VALID_FILES:
json_path = p.with_suffix(".json")
try:
text = json.loads(json_path.read_bytes().decode())
except FileNotFoundError:
text = MissingFile(json_path)
_expected_files.append(text)
VALID_FILES_EXPECTED = tuple(_expected_files)
INVALID_FILES = tuple((DATA_DIR / "invalid").glob("**/*.toml"))
assert INVALID_FILES, "Invalid TOML test files not found"
class TestData(unittest.TestCase):
def test_invalid(self):
for invalid in INVALID_FILES:
with self.subTest(msg=invalid.stem):
toml_bytes = invalid.read_bytes()
try:
toml_str = toml_bytes.decode()
except UnicodeDecodeError:
# Some BurntSushi tests are not valid UTF-8. Skip those.
continue
with self.assertRaises(tomllib.TOMLDecodeError):
tomllib.loads(toml_str)
def test_valid(self):
for valid, expected in zip(VALID_FILES, VALID_FILES_EXPECTED):
with self.subTest(msg=valid.stem):
if isinstance(expected, MissingFile):
# For a poor man's xfail, assert that this is one of the
# test cases where expected data is known to be missing.
assert valid.stem in {
"qa-array-inline-nested-1000",
"qa-table-inline-nested-1000",
}
continue
toml_str = valid.read_bytes().decode()
actual = tomllib.loads(toml_str)
actual = burntsushi.convert(actual)
expected = burntsushi.normalize(expected)
self.assertEqual(actual, expected)

View File

@ -0,0 +1,57 @@
# SPDX-License-Identifier: MIT
# SPDX-FileCopyrightText: 2021 Taneli Hukkinen
# Licensed to PSF under a Contributor Agreement.
import unittest
from . import tomllib
class TestError(unittest.TestCase):
def test_line_and_col(self):
with self.assertRaises(tomllib.TOMLDecodeError) as exc_info:
tomllib.loads("val=.")
self.assertEqual(str(exc_info.exception), "Invalid value (at line 1, column 5)")
with self.assertRaises(tomllib.TOMLDecodeError) as exc_info:
tomllib.loads(".")
self.assertEqual(
str(exc_info.exception), "Invalid statement (at line 1, column 1)"
)
with self.assertRaises(tomllib.TOMLDecodeError) as exc_info:
tomllib.loads("\n\nval=.")
self.assertEqual(str(exc_info.exception), "Invalid value (at line 3, column 5)")
with self.assertRaises(tomllib.TOMLDecodeError) as exc_info:
tomllib.loads("\n\n.")
self.assertEqual(
str(exc_info.exception), "Invalid statement (at line 3, column 1)"
)
def test_missing_value(self):
with self.assertRaises(tomllib.TOMLDecodeError) as exc_info:
tomllib.loads("\n\nfwfw=")
self.assertEqual(str(exc_info.exception), "Invalid value (at end of document)")
def test_invalid_char_quotes(self):
with self.assertRaises(tomllib.TOMLDecodeError) as exc_info:
tomllib.loads("v = '\n'")
self.assertTrue(" '\\n' " in str(exc_info.exception))
def test_module_name(self):
self.assertEqual(tomllib.TOMLDecodeError().__module__, tomllib.__name__)
def test_invalid_parse_float(self):
def dict_returner(s: str) -> dict:
return {}
def list_returner(s: str) -> list:
return []
for invalid_parse_float in (dict_returner, list_returner):
with self.assertRaises(ValueError) as exc_info:
tomllib.loads("f=0.1", parse_float=invalid_parse_float)
self.assertEqual(
str(exc_info.exception), "parse_float must not return dicts or lists"
)

View File

@ -0,0 +1,115 @@
# SPDX-License-Identifier: MIT
# SPDX-FileCopyrightText: 2021 Taneli Hukkinen
# Licensed to PSF under a Contributor Agreement.
import copy
import datetime
from decimal import Decimal as D
from pathlib import Path
import sys
import tempfile
import unittest
from test import support
from . import tomllib
class TestMiscellaneous(unittest.TestCase):
def test_load(self):
content = "one=1 \n two='two' \n arr=[]"
expected = {"one": 1, "two": "two", "arr": []}
with tempfile.TemporaryDirectory() as tmp_dir_path:
file_path = Path(tmp_dir_path) / "test.toml"
file_path.write_text(content)
with open(file_path, "rb") as bin_f:
actual = tomllib.load(bin_f)
self.assertEqual(actual, expected)
def test_incorrect_load(self):
content = "one=1"
with tempfile.TemporaryDirectory() as tmp_dir_path:
file_path = Path(tmp_dir_path) / "test.toml"
file_path.write_text(content)
with open(file_path, "r") as txt_f:
with self.assertRaises(TypeError):
tomllib.load(txt_f) # type: ignore[arg-type]
def test_parse_float(self):
doc = """
val=0.1
biggest1=inf
biggest2=+inf
smallest=-inf
notnum1=nan
notnum2=-nan
notnum3=+nan
"""
obj = tomllib.loads(doc, parse_float=D)
expected = {
"val": D("0.1"),
"biggest1": D("inf"),
"biggest2": D("inf"),
"smallest": D("-inf"),
"notnum1": D("nan"),
"notnum2": D("-nan"),
"notnum3": D("nan"),
}
for k, expected_val in expected.items():
actual_val = obj[k]
self.assertIsInstance(actual_val, D)
if actual_val.is_nan():
self.assertTrue(expected_val.is_nan())
else:
self.assertEqual(actual_val, expected_val)
def test_deepcopy(self):
doc = """
[bliibaa.diibaa]
offsettime=[1979-05-27T00:32:00.999999-07:00]
"""
obj = tomllib.loads(doc)
obj_copy = copy.deepcopy(obj)
self.assertEqual(obj_copy, obj)
expected_obj = {
"bliibaa": {
"diibaa": {
"offsettime": [
datetime.datetime(
1979,
5,
27,
0,
32,
0,
999999,
tzinfo=datetime.timezone(datetime.timedelta(hours=-7)),
)
]
}
}
}
self.assertEqual(obj_copy, expected_obj)
def test_inline_array_recursion_limit(self):
with support.infinite_recursion(max_depth=100):
available = support.get_recursion_available()
nest_count = (available // 2) - 2
# Add details if the test fails
with self.subTest(limit=sys.getrecursionlimit(),
available=available,
nest_count=nest_count):
recursive_array_toml = "arr = " + nest_count * "[" + nest_count * "]"
tomllib.loads(recursive_array_toml)
def test_inline_table_recursion_limit(self):
with support.infinite_recursion(max_depth=100):
available = support.get_recursion_available()
nest_count = (available // 3) - 1
# Add details if the test fails
with self.subTest(limit=sys.getrecursionlimit(),
available=available,
nest_count=nest_count):
recursive_table_toml = nest_count * "key = {" + nest_count * "}"
tomllib.loads(recursive_table_toml)