summaryrefslogtreecommitdiff
path: root/setuptools/_vendor
diff options
context:
space:
mode:
authorAnderson Bravalheri <andersonbravalheri@gmail.com>2022-02-08 11:39:25 +0000
committerAnderson Bravalheri <andersonbravalheri@gmail.com>2022-03-05 09:58:49 +0000
commite0d61d45eaf94b55a57a68c6cd65b3e508aee5a9 (patch)
tree110828190a062fd7fc84b557752fefc13db018b0 /setuptools/_vendor
parentccd2f073171065ad8fe65215ff837644689c6d85 (diff)
downloadpython-setuptools-git-e0d61d45eaf94b55a57a68c6cd65b3e508aee5a9.tar.gz
Update vendored tomli to 2.0.1
Enforcing local imports is no longer needed.
Diffstat (limited to 'setuptools/_vendor')
-rw-r--r--setuptools/_vendor/_validate_pyproject/fastjsonschema_validations.py2
-rw-r--r--setuptools/_vendor/tomli-2.0.1.dist-info/INSTALLER1
-rw-r--r--setuptools/_vendor/tomli-2.0.1.dist-info/LICENSE (renamed from setuptools/_vendor/tomli/LICENSE)0
-rw-r--r--setuptools/_vendor/tomli-2.0.1.dist-info/METADATA206
-rw-r--r--setuptools/_vendor/tomli-2.0.1.dist-info/RECORD15
-rw-r--r--setuptools/_vendor/tomli-2.0.1.dist-info/REQUESTED0
-rw-r--r--setuptools/_vendor/tomli-2.0.1.dist-info/WHEEL4
-rw-r--r--setuptools/_vendor/tomli/__init__.py8
-rw-r--r--setuptools/_vendor/tomli/_parser.py190
-rw-r--r--setuptools/_vendor/tomli/_re.py18
-rw-r--r--setuptools/_vendor/tomli/_types.py4
-rw-r--r--setuptools/_vendor/vendored.txt2
12 files changed, 358 insertions, 92 deletions
diff --git a/setuptools/_vendor/_validate_pyproject/fastjsonschema_validations.py b/setuptools/_vendor/_validate_pyproject/fastjsonschema_validations.py
index d409b2a5..8bfd8809 100644
--- a/setuptools/_vendor/_validate_pyproject/fastjsonschema_validations.py
+++ b/setuptools/_vendor/_validate_pyproject/fastjsonschema_validations.py
@@ -10,7 +10,7 @@
# *** PLEASE DO NOT MODIFY DIRECTLY: Automatically generated code ***
-VERSION = "2.15.2"
+VERSION = "2.15.3"
import re
from .fastjsonschema_exceptions import JsonSchemaValueException
diff --git a/setuptools/_vendor/tomli-2.0.1.dist-info/INSTALLER b/setuptools/_vendor/tomli-2.0.1.dist-info/INSTALLER
new file mode 100644
index 00000000..a1b589e3
--- /dev/null
+++ b/setuptools/_vendor/tomli-2.0.1.dist-info/INSTALLER
@@ -0,0 +1 @@
+pip
diff --git a/setuptools/_vendor/tomli/LICENSE b/setuptools/_vendor/tomli-2.0.1.dist-info/LICENSE
index e859590f..e859590f 100644
--- a/setuptools/_vendor/tomli/LICENSE
+++ b/setuptools/_vendor/tomli-2.0.1.dist-info/LICENSE
diff --git a/setuptools/_vendor/tomli-2.0.1.dist-info/METADATA b/setuptools/_vendor/tomli-2.0.1.dist-info/METADATA
new file mode 100644
index 00000000..efd87ecc
--- /dev/null
+++ b/setuptools/_vendor/tomli-2.0.1.dist-info/METADATA
@@ -0,0 +1,206 @@
+Metadata-Version: 2.1
+Name: tomli
+Version: 2.0.1
+Summary: A lil' TOML parser
+Keywords: toml
+Author-email: Taneli Hukkinen <hukkin@users.noreply.github.com>
+Requires-Python: >=3.7
+Description-Content-Type: text/markdown
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Operating System :: MacOS
+Classifier: Operating System :: Microsoft :: Windows
+Classifier: Operating System :: POSIX :: Linux
+Classifier: Programming Language :: Python :: 3 :: Only
+Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: Implementation :: CPython
+Classifier: Programming Language :: Python :: Implementation :: PyPy
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Classifier: Typing :: Typed
+Project-URL: Changelog, https://github.com/hukkin/tomli/blob/master/CHANGELOG.md
+Project-URL: Homepage, https://github.com/hukkin/tomli
+
+[![Build Status](https://github.com/hukkin/tomli/workflows/Tests/badge.svg?branch=master)](https://github.com/hukkin/tomli/actions?query=workflow%3ATests+branch%3Amaster+event%3Apush)
+[![codecov.io](https://codecov.io/gh/hukkin/tomli/branch/master/graph/badge.svg)](https://codecov.io/gh/hukkin/tomli)
+[![PyPI version](https://img.shields.io/pypi/v/tomli)](https://pypi.org/project/tomli)
+
+# Tomli
+
+> A lil' TOML parser
+
+**Table of Contents** *generated with [mdformat-toc](https://github.com/hukkin/mdformat-toc)*
+
+<!-- mdformat-toc start --slug=github --maxlevel=6 --minlevel=2 -->
+
+- [Intro](#intro)
+- [Installation](#installation)
+- [Usage](#usage)
+ - [Parse a TOML string](#parse-a-toml-string)
+ - [Parse a TOML file](#parse-a-toml-file)
+ - [Handle invalid TOML](#handle-invalid-toml)
+ - [Construct `decimal.Decimal`s from TOML floats](#construct-decimaldecimals-from-toml-floats)
+- [FAQ](#faq)
+ - [Why this parser?](#why-this-parser)
+ - [Is comment preserving round-trip parsing supported?](#is-comment-preserving-round-trip-parsing-supported)
+ - [Is there a `dumps`, `write` or `encode` function?](#is-there-a-dumps-write-or-encode-function)
+ - [How do TOML types map into Python types?](#how-do-toml-types-map-into-python-types)
+- [Performance](#performance)
+
+<!-- mdformat-toc end -->
+
+## Intro<a name="intro"></a>
+
+Tomli is a Python library for parsing [TOML](https://toml.io).
+Tomli is fully compatible with [TOML v1.0.0](https://toml.io/en/v1.0.0).
+
+## Installation<a name="installation"></a>
+
+```bash
+pip install tomli
+```
+
+## Usage<a name="usage"></a>
+
+### Parse a TOML string<a name="parse-a-toml-string"></a>
+
+```python
+import tomli
+
+toml_str = """
+ gretzky = 99
+
+ [kurri]
+ jari = 17
+ """
+
+toml_dict = tomli.loads(toml_str)
+assert toml_dict == {"gretzky": 99, "kurri": {"jari": 17}}
+```
+
+### Parse a TOML file<a name="parse-a-toml-file"></a>
+
+```python
+import tomli
+
+with open("path_to_file/conf.toml", "rb") as f:
+ toml_dict = tomli.load(f)
+```
+
+The file must be opened in binary mode (with the `"rb"` flag).
+Binary mode will enforce decoding the file as UTF-8 with universal newlines disabled,
+both of which are required to correctly parse TOML.
+
+### Handle invalid TOML<a name="handle-invalid-toml"></a>
+
+```python
+import tomli
+
+try:
+ toml_dict = tomli.loads("]] this is invalid TOML [[")
+except tomli.TOMLDecodeError:
+ print("Yep, definitely not valid.")
+```
+
+Note that error messages are considered informational only.
+They should not be assumed to stay constant across Tomli versions.
+
+### Construct `decimal.Decimal`s from TOML floats<a name="construct-decimaldecimals-from-toml-floats"></a>
+
+```python
+from decimal import Decimal
+import tomli
+
+toml_dict = tomli.loads("precision-matters = 0.982492", parse_float=Decimal)
+assert toml_dict["precision-matters"] == Decimal("0.982492")
+```
+
+Note that `decimal.Decimal` can be replaced with another callable that converts a TOML float from string to a Python type.
+The `decimal.Decimal` is, however, a practical choice for use cases where float inaccuracies can not be tolerated.
+
+Illegal types are `dict` and `list`, and their subtypes.
+A `ValueError` will be raised if `parse_float` produces illegal types.
+
+## FAQ<a name="faq"></a>
+
+### Why this parser?<a name="why-this-parser"></a>
+
+- it's lil'
+- pure Python with zero dependencies
+- the fastest pure Python parser [\*](#performance):
+ 15x as fast as [tomlkit](https://pypi.org/project/tomlkit/),
+ 2.4x as fast as [toml](https://pypi.org/project/toml/)
+- outputs [basic data types](#how-do-toml-types-map-into-python-types) only
+- 100% spec compliant: passes all tests in
+ [a test set](https://github.com/toml-lang/compliance/pull/8)
+ soon to be merged to the official
+ [compliance tests for TOML](https://github.com/toml-lang/compliance)
+ repository
+- thoroughly tested: 100% branch coverage
+
+### Is comment preserving round-trip parsing supported?<a name="is-comment-preserving-round-trip-parsing-supported"></a>
+
+No.
+
+The `tomli.loads` function returns a plain `dict` that is populated with builtin types and types from the standard library only.
+Preserving comments requires a custom type to be returned so will not be supported,
+at least not by the `tomli.loads` and `tomli.load` functions.
+
+Look into [TOML Kit](https://github.com/sdispater/tomlkit) if preservation of style is what you need.
+
+### Is there a `dumps`, `write` or `encode` function?<a name="is-there-a-dumps-write-or-encode-function"></a>
+
+[Tomli-W](https://github.com/hukkin/tomli-w) is the write-only counterpart of Tomli, providing `dump` and `dumps` functions.
+
+The core library does not include write capability, as most TOML use cases are read-only, and Tomli intends to be minimal.
+
+### How do TOML types map into Python types?<a name="how-do-toml-types-map-into-python-types"></a>
+
+| TOML type | Python type | Details |
+| ---------------- | ------------------- | ------------------------------------------------------------ |
+| Document Root | `dict` | |
+| Key | `str` | |
+| String | `str` | |
+| Integer | `int` | |
+| Float | `float` | |
+| Boolean | `bool` | |
+| Offset Date-Time | `datetime.datetime` | `tzinfo` attribute set to an instance of `datetime.timezone` |
+| Local Date-Time | `datetime.datetime` | `tzinfo` attribute set to `None` |
+| Local Date | `datetime.date` | |
+| Local Time | `datetime.time` | |
+| Array | `list` | |
+| Table | `dict` | |
+| Inline Table | `dict` | |
+
+## Performance<a name="performance"></a>
+
+The `benchmark/` folder in this repository contains a performance benchmark for comparing the various Python TOML parsers.
+The benchmark can be run with `tox -e benchmark-pypi`.
+Running the benchmark on my personal computer output the following:
+
+```console
+foo@bar:~/dev/tomli$ tox -e benchmark-pypi
+benchmark-pypi installed: attrs==19.3.0,click==7.1.2,pytomlpp==1.0.2,qtoml==0.3.0,rtoml==0.7.0,toml==0.10.2,tomli==1.1.0,tomlkit==0.7.2
+benchmark-pypi run-test-pre: PYTHONHASHSEED='2658546909'
+benchmark-pypi run-test: commands[0] | python -c 'import datetime; print(datetime.date.today())'
+2021-07-23
+benchmark-pypi run-test: commands[1] | python --version
+Python 3.8.10
+benchmark-pypi run-test: commands[2] | python benchmark/run.py
+Parsing data.toml 5000 times:
+------------------------------------------------------
+ parser | exec time | performance (more is better)
+-----------+------------+-----------------------------
+ rtoml | 0.901 s | baseline (100%)
+ pytomlpp | 1.08 s | 83.15%
+ tomli | 3.89 s | 23.15%
+ toml | 9.36 s | 9.63%
+ qtoml | 11.5 s | 7.82%
+ tomlkit | 56.8 s | 1.59%
+```
+
+The parsers are ordered from fastest to slowest, using the fastest parser as baseline.
+Tomli performed the best out of all pure Python TOML parsers,
+losing only to pytomlpp (wraps C++) and rtoml (wraps Rust).
+
diff --git a/setuptools/_vendor/tomli-2.0.1.dist-info/RECORD b/setuptools/_vendor/tomli-2.0.1.dist-info/RECORD
new file mode 100644
index 00000000..2d93fa2c
--- /dev/null
+++ b/setuptools/_vendor/tomli-2.0.1.dist-info/RECORD
@@ -0,0 +1,15 @@
+tomli-2.0.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+tomli-2.0.1.dist-info/LICENSE,sha256=uAgWsNUwuKzLTCIReDeQmEpuO2GSLCte6S8zcqsnQv4,1072
+tomli-2.0.1.dist-info/METADATA,sha256=zPDceKmPwJGLWtZykrHixL7WVXWmJGzZ1jyRT5lCoPI,8875
+tomli-2.0.1.dist-info/RECORD,,
+tomli-2.0.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+tomli-2.0.1.dist-info/WHEEL,sha256=jPMR_Dzkc4X4icQtmz81lnNY_kAsfog7ry7qoRvYLXw,81
+tomli/__init__.py,sha256=JhUwV66DB1g4Hvt1UQCVMdfCu-IgAV8FXmvDU9onxd4,396
+tomli/__pycache__/__init__.cpython-38.pyc,,
+tomli/__pycache__/_parser.cpython-38.pyc,,
+tomli/__pycache__/_re.cpython-38.pyc,,
+tomli/__pycache__/_types.cpython-38.pyc,,
+tomli/_parser.py,sha256=g9-ENaALS-B8dokYpCuzUFalWlog7T-SIYMjLZSWrtM,22633
+tomli/_re.py,sha256=dbjg5ChZT23Ka9z9DHOXfdtSpPwUfdgMXnj8NOoly-w,2943
+tomli/_types.py,sha256=-GTG2VUqkpxwMqzmVO4F7ybKddIbAnuAHXfmWQcTi3Q,254
+tomli/py.typed,sha256=8PjyZ1aVoQpRVvt71muvuq5qE-jTFZkK-GLHkhdebmc,26
diff --git a/setuptools/_vendor/tomli-2.0.1.dist-info/REQUESTED b/setuptools/_vendor/tomli-2.0.1.dist-info/REQUESTED
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/setuptools/_vendor/tomli-2.0.1.dist-info/REQUESTED
diff --git a/setuptools/_vendor/tomli-2.0.1.dist-info/WHEEL b/setuptools/_vendor/tomli-2.0.1.dist-info/WHEEL
new file mode 100644
index 00000000..c727d148
--- /dev/null
+++ b/setuptools/_vendor/tomli-2.0.1.dist-info/WHEEL
@@ -0,0 +1,4 @@
+Wheel-Version: 1.0
+Generator: flit 3.6.0
+Root-Is-Purelib: true
+Tag: py3-none-any
diff --git a/setuptools/_vendor/tomli/__init__.py b/setuptools/_vendor/tomli/__init__.py
index 0ac89c82..4c6ec97e 100644
--- a/setuptools/_vendor/tomli/__init__.py
+++ b/setuptools/_vendor/tomli/__init__.py
@@ -1,9 +1,11 @@
-"""A lil' TOML parser."""
+# SPDX-License-Identifier: MIT
+# SPDX-FileCopyrightText: 2021 Taneli Hukkinen
+# Licensed to PSF under a Contributor Agreement.
__all__ = ("loads", "load", "TOMLDecodeError")
-__version__ = "1.2.3" # DO NOT EDIT THIS LINE MANUALLY. LET bump2version UTILITY DO IT
+__version__ = "2.0.1" # DO NOT EDIT THIS LINE MANUALLY. LET bump2version UTILITY DO IT
from ._parser import TOMLDecodeError, load, loads
# Pretend this exception was created here.
-TOMLDecodeError.__module__ = "setuptools.extern.tomli"
+TOMLDecodeError.__module__ = __name__
diff --git a/setuptools/_vendor/tomli/_parser.py b/setuptools/_vendor/tomli/_parser.py
index 093afe50..f1bb0aa1 100644
--- a/setuptools/_vendor/tomli/_parser.py
+++ b/setuptools/_vendor/tomli/_parser.py
@@ -1,7 +1,13 @@
+# SPDX-License-Identifier: MIT
+# SPDX-FileCopyrightText: 2021 Taneli Hukkinen
+# Licensed to PSF under a Contributor Agreement.
+
+from __future__ import annotations
+
+from collections.abc import Iterable
import string
from types import MappingProxyType
-from typing import Any, BinaryIO, Dict, FrozenSet, Iterable, NamedTuple, Optional, Tuple
-import warnings
+from typing import Any, BinaryIO, NamedTuple
from ._re import (
RE_DATETIME,
@@ -48,31 +54,28 @@ class TOMLDecodeError(ValueError):
"""An error raised if a document is not valid TOML."""
-def load(fp: BinaryIO, *, parse_float: ParseFloat = float) -> Dict[str, Any]:
+def load(__fp: BinaryIO, *, parse_float: ParseFloat = float) -> dict[str, Any]:
"""Parse TOML from a binary file object."""
- s_bytes = fp.read()
+ b = __fp.read()
try:
- s = s_bytes.decode()
+ s = b.decode()
except AttributeError:
- warnings.warn(
- "Text file object support is deprecated in favor of binary file objects."
- ' Use `open("foo.toml", "rb")` to open the file in binary mode.',
- DeprecationWarning,
- stacklevel=2,
- )
- s = s_bytes # type: ignore[assignment]
+ raise TypeError(
+ "File must be opened in binary mode, e.g. use `open('foo.toml', 'rb')`"
+ ) from None
return loads(s, parse_float=parse_float)
-def loads(s: str, *, parse_float: ParseFloat = float) -> Dict[str, Any]: # noqa: C901
+def loads(__s: str, *, parse_float: ParseFloat = float) -> dict[str, Any]: # noqa: C901
"""Parse TOML from a string."""
# The spec allows converting "\r\n" to "\n", even in string
# literals. Let's do so to simplify parsing.
- src = s.replace("\r\n", "\n")
+ src = __s.replace("\r\n", "\n")
pos = 0
out = Output(NestedDict(), Flags())
header: Key = ()
+ parse_float = make_safe_parse_float(parse_float)
# Parse one statement at a time
# (typically means one line in TOML source)
@@ -100,9 +103,10 @@ def loads(s: str, *, parse_float: ParseFloat = float) -> Dict[str, Any]: # noqa
pos = skip_chars(src, pos, TOML_WS)
elif char == "[":
try:
- second_char: Optional[str] = src[pos + 1]
+ second_char: str | None = src[pos + 1]
except IndexError:
second_char = None
+ out.flags.finalize_pending()
if second_char == "[":
pos, header = create_list_rule(src, pos, out)
else:
@@ -138,7 +142,16 @@ class Flags:
EXPLICIT_NEST = 1
def __init__(self) -> None:
- self._flags: Dict[str, dict] = {}
+ self._flags: dict[str, dict] = {}
+ self._pending_flags: set[tuple[Key, int]] = set()
+
+ def add_pending(self, key: Key, flag: int) -> None:
+ self._pending_flags.add((key, flag))
+
+ def finalize_pending(self) -> None:
+ for key, flag in self._pending_flags:
+ self.set(key, flag, recursive=False)
+ self._pending_flags.clear()
def unset_all(self, key: Key) -> None:
cont = self._flags
@@ -148,19 +161,6 @@ class Flags:
cont = cont[k]["nested"]
cont.pop(key[-1], None)
- def set_for_relative_key(self, head_key: Key, rel_key: Key, flag: int) -> None:
- cont = self._flags
- for k in head_key:
- if k not in cont:
- cont[k] = {"flags": set(), "recursive_flags": set(), "nested": {}}
- cont = cont[k]["nested"]
- for k in rel_key:
- if k in cont:
- cont[k]["flags"].add(flag)
- else:
- cont[k] = {"flags": {flag}, "recursive_flags": set(), "nested": {}}
- cont = cont[k]["nested"]
-
def set(self, key: Key, flag: int, *, recursive: bool) -> None: # noqa: A003
cont = self._flags
key_parent, key_stem = key[:-1], key[-1]
@@ -193,7 +193,7 @@ class Flags:
class NestedDict:
def __init__(self) -> None:
# The parsed content of the TOML document
- self.dict: Dict[str, Any] = {}
+ self.dict: dict[str, Any] = {}
def get_or_create_nest(
self,
@@ -217,10 +217,9 @@ class NestedDict:
last_key = key[-1]
if last_key in cont:
list_ = cont[last_key]
- try:
- list_.append({})
- except AttributeError:
+ if not isinstance(list_, list):
raise KeyError("An object other than list found behind this key")
+ list_.append({})
else:
cont[last_key] = [{}]
@@ -244,7 +243,7 @@ def skip_until(
pos: Pos,
expect: str,
*,
- error_on: FrozenSet[str],
+ error_on: frozenset[str],
error_on_eof: bool,
) -> Pos:
try:
@@ -263,7 +262,7 @@ def skip_until(
def skip_comment(src: str, pos: Pos) -> Pos:
try:
- char: Optional[str] = src[pos]
+ char: str | None = src[pos]
except IndexError:
char = None
if char == "#":
@@ -282,31 +281,31 @@ def skip_comments_and_array_ws(src: str, pos: Pos) -> Pos:
return pos
-def create_dict_rule(src: str, pos: Pos, out: Output) -> Tuple[Pos, Key]:
+def create_dict_rule(src: str, pos: Pos, out: Output) -> tuple[Pos, Key]:
pos += 1 # Skip "["
pos = skip_chars(src, pos, TOML_WS)
pos, key = parse_key(src, pos)
if out.flags.is_(key, Flags.EXPLICIT_NEST) or out.flags.is_(key, Flags.FROZEN):
- raise suffixed_err(src, pos, f"Can not declare {key} twice")
+ raise suffixed_err(src, pos, f"Cannot declare {key} twice")
out.flags.set(key, Flags.EXPLICIT_NEST, recursive=False)
try:
out.data.get_or_create_nest(key)
except KeyError:
- raise suffixed_err(src, pos, "Can not overwrite a value") from None
+ raise suffixed_err(src, pos, "Cannot overwrite a value") from None
if not src.startswith("]", pos):
- raise suffixed_err(src, pos, 'Expected "]" at the end of a table declaration')
+ raise suffixed_err(src, pos, "Expected ']' at the end of a table declaration")
return pos + 1, key
-def create_list_rule(src: str, pos: Pos, out: Output) -> Tuple[Pos, Key]:
+def create_list_rule(src: str, pos: Pos, out: Output) -> tuple[Pos, Key]:
pos += 2 # Skip "[["
pos = skip_chars(src, pos, TOML_WS)
pos, key = parse_key(src, pos)
if out.flags.is_(key, Flags.FROZEN):
- raise suffixed_err(src, pos, f"Can not mutate immutable namespace {key}")
+ raise suffixed_err(src, pos, f"Cannot mutate immutable namespace {key}")
# Free the namespace now that it points to another empty list item...
out.flags.unset_all(key)
# ...but this key precisely is still prohibited from table declaration
@@ -314,10 +313,10 @@ def create_list_rule(src: str, pos: Pos, out: Output) -> Tuple[Pos, Key]:
try:
out.data.append_nest_to_list(key)
except KeyError:
- raise suffixed_err(src, pos, "Can not overwrite a value") from None
+ raise suffixed_err(src, pos, "Cannot overwrite a value") from None
if not src.startswith("]]", pos):
- raise suffixed_err(src, pos, 'Expected "]]" at the end of an array declaration')
+ raise suffixed_err(src, pos, "Expected ']]' at the end of an array declaration")
return pos + 2, key
@@ -328,18 +327,26 @@ def key_value_rule(
key_parent, key_stem = key[:-1], key[-1]
abs_key_parent = header + key_parent
+ relative_path_cont_keys = (header + key[:i] for i in range(1, len(key)))
+ for cont_key in relative_path_cont_keys:
+ # Check that dotted key syntax does not redefine an existing table
+ if out.flags.is_(cont_key, Flags.EXPLICIT_NEST):
+ raise suffixed_err(src, pos, f"Cannot redefine namespace {cont_key}")
+ # Containers in the relative path can't be opened with the table syntax or
+ # dotted key/value syntax in following table sections.
+ out.flags.add_pending(cont_key, Flags.EXPLICIT_NEST)
+
if out.flags.is_(abs_key_parent, Flags.FROZEN):
raise suffixed_err(
- src, pos, f"Can not mutate immutable namespace {abs_key_parent}"
+ src, pos, f"Cannot mutate immutable namespace {abs_key_parent}"
)
- # Containers in the relative path can't be opened with the table syntax after this
- out.flags.set_for_relative_key(header, key, Flags.EXPLICIT_NEST)
+
try:
nest = out.data.get_or_create_nest(abs_key_parent)
except KeyError:
- raise suffixed_err(src, pos, "Can not overwrite a value") from None
+ raise suffixed_err(src, pos, "Cannot overwrite a value") from None
if key_stem in nest:
- raise suffixed_err(src, pos, "Can not overwrite a value")
+ raise suffixed_err(src, pos, "Cannot overwrite a value")
# Mark inline table and array namespaces recursively immutable
if isinstance(value, (dict, list)):
out.flags.set(header + key, Flags.FROZEN, recursive=True)
@@ -349,27 +356,27 @@ def key_value_rule(
def parse_key_value_pair(
src: str, pos: Pos, parse_float: ParseFloat
-) -> Tuple[Pos, Key, Any]:
+) -> tuple[Pos, Key, Any]:
pos, key = parse_key(src, pos)
try:
- char: Optional[str] = src[pos]
+ char: str | None = src[pos]
except IndexError:
char = None
if char != "=":
- raise suffixed_err(src, pos, 'Expected "=" after a key in a key/value pair')
+ raise suffixed_err(src, pos, "Expected '=' after a key in a key/value pair")
pos += 1
pos = skip_chars(src, pos, TOML_WS)
pos, value = parse_value(src, pos, parse_float)
return pos, key, value
-def parse_key(src: str, pos: Pos) -> Tuple[Pos, Key]:
+def parse_key(src: str, pos: Pos) -> tuple[Pos, Key]:
pos, key_part = parse_key_part(src, pos)
key: Key = (key_part,)
pos = skip_chars(src, pos, TOML_WS)
while True:
try:
- char: Optional[str] = src[pos]
+ char: str | None = src[pos]
except IndexError:
char = None
if char != ".":
@@ -381,9 +388,9 @@ def parse_key(src: str, pos: Pos) -> Tuple[Pos, Key]:
pos = skip_chars(src, pos, TOML_WS)
-def parse_key_part(src: str, pos: Pos) -> Tuple[Pos, str]:
+def parse_key_part(src: str, pos: Pos) -> tuple[Pos, str]:
try:
- char: Optional[str] = src[pos]
+ char: str | None = src[pos]
except IndexError:
char = None
if char in BARE_KEY_CHARS:
@@ -397,12 +404,12 @@ def parse_key_part(src: str, pos: Pos) -> Tuple[Pos, str]:
raise suffixed_err(src, pos, "Invalid initial character for a key part")
-def parse_one_line_basic_str(src: str, pos: Pos) -> Tuple[Pos, str]:
+def parse_one_line_basic_str(src: str, pos: Pos) -> tuple[Pos, str]:
pos += 1
return parse_basic_str(src, pos, multiline=False)
-def parse_array(src: str, pos: Pos, parse_float: ParseFloat) -> Tuple[Pos, list]:
+def parse_array(src: str, pos: Pos, parse_float: ParseFloat) -> tuple[Pos, list]:
pos += 1
array: list = []
@@ -426,7 +433,7 @@ def parse_array(src: str, pos: Pos, parse_float: ParseFloat) -> Tuple[Pos, list]
return pos + 1, array
-def parse_inline_table(src: str, pos: Pos, parse_float: ParseFloat) -> Tuple[Pos, dict]:
+def parse_inline_table(src: str, pos: Pos, parse_float: ParseFloat) -> tuple[Pos, dict]:
pos += 1
nested_dict = NestedDict()
flags = Flags()
@@ -438,11 +445,11 @@ def parse_inline_table(src: str, pos: Pos, parse_float: ParseFloat) -> Tuple[Pos
pos, key, value = parse_key_value_pair(src, pos, parse_float)
key_parent, key_stem = key[:-1], key[-1]
if flags.is_(key, Flags.FROZEN):
- raise suffixed_err(src, pos, f"Can not mutate immutable namespace {key}")
+ raise suffixed_err(src, pos, f"Cannot mutate immutable namespace {key}")
try:
nest = nested_dict.get_or_create_nest(key_parent, access_lists=False)
except KeyError:
- raise suffixed_err(src, pos, "Can not overwrite a value") from None
+ raise suffixed_err(src, pos, "Cannot overwrite a value") from None
if key_stem in nest:
raise suffixed_err(src, pos, f"Duplicate inline table key {key_stem!r}")
nest[key_stem] = value
@@ -458,9 +465,9 @@ def parse_inline_table(src: str, pos: Pos, parse_float: ParseFloat) -> Tuple[Pos
pos = skip_chars(src, pos, TOML_WS)
-def parse_basic_str_escape( # noqa: C901
+def parse_basic_str_escape(
src: str, pos: Pos, *, multiline: bool = False
-) -> Tuple[Pos, str]:
+) -> tuple[Pos, str]:
escape_id = src[pos : pos + 2]
pos += 2
if multiline and escape_id in {"\\ ", "\\\t", "\\\n"}:
@@ -473,7 +480,7 @@ def parse_basic_str_escape( # noqa: C901
except IndexError:
return pos, ""
if char != "\n":
- raise suffixed_err(src, pos, 'Unescaped "\\" in a string')
+ raise suffixed_err(src, pos, "Unescaped '\\' in a string")
pos += 1
pos = skip_chars(src, pos, TOML_WS_AND_NEWLINE)
return pos, ""
@@ -484,16 +491,14 @@ def parse_basic_str_escape( # noqa: C901
try:
return pos, BASIC_STR_ESCAPE_REPLACEMENTS[escape_id]
except KeyError:
- if len(escape_id) != 2:
- raise suffixed_err(src, pos, "Unterminated string") from None
- raise suffixed_err(src, pos, 'Unescaped "\\" in a string') from None
+ raise suffixed_err(src, pos, "Unescaped '\\' in a string") from None
-def parse_basic_str_escape_multiline(src: str, pos: Pos) -> Tuple[Pos, str]:
+def parse_basic_str_escape_multiline(src: str, pos: Pos) -> tuple[Pos, str]:
return parse_basic_str_escape(src, pos, multiline=True)
-def parse_hex_char(src: str, pos: Pos, hex_len: int) -> Tuple[Pos, str]:
+def parse_hex_char(src: str, pos: Pos, hex_len: int) -> tuple[Pos, str]:
hex_str = src[pos : pos + hex_len]
if len(hex_str) != hex_len or not HEXDIGIT_CHARS.issuperset(hex_str):
raise suffixed_err(src, pos, "Invalid hex value")
@@ -504,7 +509,7 @@ def parse_hex_char(src: str, pos: Pos, hex_len: int) -> Tuple[Pos, str]:
return pos, chr(hex_int)
-def parse_literal_str(src: str, pos: Pos) -> Tuple[Pos, str]:
+def parse_literal_str(src: str, pos: Pos) -> tuple[Pos, str]:
pos += 1 # Skip starting apostrophe
start_pos = pos
pos = skip_until(
@@ -513,7 +518,7 @@ def parse_literal_str(src: str, pos: Pos) -> Tuple[Pos, str]:
return pos + 1, src[start_pos:pos] # Skip ending apostrophe
-def parse_multiline_str(src: str, pos: Pos, *, literal: bool) -> Tuple[Pos, str]:
+def parse_multiline_str(src: str, pos: Pos, *, literal: bool) -> tuple[Pos, str]:
pos += 3
if src.startswith("\n", pos):
pos += 1
@@ -544,7 +549,7 @@ def parse_multiline_str(src: str, pos: Pos, *, literal: bool) -> Tuple[Pos, str]
return pos, result + (delim * 2)
-def parse_basic_str(src: str, pos: Pos, *, multiline: bool) -> Tuple[Pos, str]:
+def parse_basic_str(src: str, pos: Pos, *, multiline: bool) -> tuple[Pos, str]:
if multiline:
error_on = ILLEGAL_MULTILINE_BASIC_STR_CHARS
parse_escapes = parse_basic_str_escape_multiline
@@ -578,12 +583,14 @@ def parse_basic_str(src: str, pos: Pos, *, multiline: bool) -> Tuple[Pos, str]:
def parse_value( # noqa: C901
src: str, pos: Pos, parse_float: ParseFloat
-) -> Tuple[Pos, Any]:
+) -> tuple[Pos, Any]:
try:
- char: Optional[str] = src[pos]
+ char: str | None = src[pos]
except IndexError:
char = None
+ # IMPORTANT: order conditions based on speed of checking and likelihood
+
# Basic strings
if char == '"':
if src.startswith('"""', pos):
@@ -604,6 +611,14 @@ def parse_value( # noqa: C901
if src.startswith("false", pos):
return pos + 5, False
+ # Arrays
+ if char == "[":
+ return parse_array(src, pos, parse_float)
+
+ # Inline tables
+ if char == "{":
+ return parse_inline_table(src, pos, parse_float)
+
# Dates and times
datetime_match = RE_DATETIME.match(src, pos)
if datetime_match:
@@ -623,14 +638,6 @@ def parse_value( # noqa: C901
if number_match:
return number_match.end(), match_to_number(number_match, parse_float)
- # Arrays
- if char == "[":
- return parse_array(src, pos, parse_float)
-
- # Inline tables
- if char == "{":
- return parse_inline_table(src, pos, parse_float)
-
# Special floats
first_three = src[pos : pos + 3]
if first_three in {"inf", "nan"}:
@@ -661,3 +668,24 @@ def suffixed_err(src: str, pos: Pos, msg: str) -> TOMLDecodeError:
def is_unicode_scalar_value(codepoint: int) -> bool:
return (0 <= codepoint <= 55295) or (57344 <= codepoint <= 1114111)
+
+
+def make_safe_parse_float(parse_float: ParseFloat) -> ParseFloat:
+ """A decorator to make `parse_float` safe.
+
+ `parse_float` must not return dicts or lists, because these types
+ would be mixed with parsed TOML tables and arrays, thus confusing
+ the parser. The returned decorated callable raises `ValueError`
+ instead of returning illegal types.
+ """
+ # The default `float` callable never returns illegal types. Optimize it.
+ if parse_float is float: # type: ignore[comparison-overlap]
+ return float
+
+ def safe_parse_float(float_str: str) -> Any:
+ float_value = parse_float(float_str)
+ if isinstance(float_value, (dict, list)):
+ raise ValueError("parse_float must not return dicts or lists")
+ return float_value
+
+ return safe_parse_float
diff --git a/setuptools/_vendor/tomli/_re.py b/setuptools/_vendor/tomli/_re.py
index 45e17e2c..994bb749 100644
--- a/setuptools/_vendor/tomli/_re.py
+++ b/setuptools/_vendor/tomli/_re.py
@@ -1,7 +1,13 @@
+# SPDX-License-Identifier: MIT
+# SPDX-FileCopyrightText: 2021 Taneli Hukkinen
+# Licensed to PSF under a Contributor Agreement.
+
+from __future__ import annotations
+
from datetime import date, datetime, time, timedelta, timezone, tzinfo
from functools import lru_cache
import re
-from typing import Any, Optional, Union
+from typing import Any
from ._types import ParseFloat
@@ -31,7 +37,7 @@ RE_NUMBER = re.compile(
)
RE_LOCALTIME = re.compile(_TIME_RE_STR)
RE_DATETIME = re.compile(
- fr"""
+ rf"""
([0-9]{{4}})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01]) # date, e.g. 1988-10-27
(?:
[Tt ]
@@ -43,7 +49,7 @@ RE_DATETIME = re.compile(
)
-def match_to_datetime(match: "re.Match") -> Union[datetime, date]:
+def match_to_datetime(match: re.Match) -> datetime | date:
"""Convert a `RE_DATETIME` match to `datetime.datetime` or `datetime.date`.
Raises ValueError if the match does not correspond to a valid date
@@ -68,7 +74,7 @@ def match_to_datetime(match: "re.Match") -> Union[datetime, date]:
hour, minute, sec = int(hour_str), int(minute_str), int(sec_str)
micros = int(micros_str.ljust(6, "0")) if micros_str else 0
if offset_sign_str:
- tz: Optional[tzinfo] = cached_tz(
+ tz: tzinfo | None = cached_tz(
offset_hour_str, offset_minute_str, offset_sign_str
)
elif zulu_time:
@@ -89,13 +95,13 @@ def cached_tz(hour_str: str, minute_str: str, sign_str: str) -> timezone:
)
-def match_to_localtime(match: "re.Match") -> time:
+def match_to_localtime(match: re.Match) -> time:
hour_str, minute_str, sec_str, micros_str = match.groups()
micros = int(micros_str.ljust(6, "0")) if micros_str else 0
return time(int(hour_str), int(minute_str), int(sec_str), micros)
-def match_to_number(match: "re.Match", parse_float: "ParseFloat") -> Any:
+def match_to_number(match: re.Match, parse_float: ParseFloat) -> Any:
if match.group("floatpart"):
return parse_float(match.group())
return int(match.group(), 0)
diff --git a/setuptools/_vendor/tomli/_types.py b/setuptools/_vendor/tomli/_types.py
index e37cc808..d949412e 100644
--- a/setuptools/_vendor/tomli/_types.py
+++ b/setuptools/_vendor/tomli/_types.py
@@ -1,3 +1,7 @@
+# SPDX-License-Identifier: MIT
+# SPDX-FileCopyrightText: 2021 Taneli Hukkinen
+# Licensed to PSF under a Contributor Agreement.
+
from typing import Any, Callable, Tuple
# Type annotations
diff --git a/setuptools/_vendor/vendored.txt b/setuptools/_vendor/vendored.txt
index fe05dc1a..38d1f70f 100644
--- a/setuptools/_vendor/vendored.txt
+++ b/setuptools/_vendor/vendored.txt
@@ -9,5 +9,5 @@ importlib_metadata==4.11.1
typing_extensions==4.0.1
# required for importlib_resources and _metadata on older Pythons
zipp==3.7.0
-tomli==1.2.3
+tomli==2.0.1
# validate-pyproject[all]==0.3.2 # Special handling in tools/vendored, don't uncomment or remove