Repository: psf/black

Issue:
Valid toml syntax causes black to crash
**Describe the bug**

I have a pyproject.toml for configuring various other tools (not black), which includes a list with mixed type contents, as explicitly support by the v1.0.0 of the toml spec.

When I run black it crashes with a cryptic traceback from inside the toml library.

**To Reproduce**

```bash
mkdir new_project
cat <<EOT > ./new_project/pyproject.toml
# this example is from the toml spec
contributors = [
  "Foo Bar <foo@example.com>",
  { name = "Baz Qux", email = "bazqux@example.com", url = "https://example.com/bazqux" }
]
EOT
cd new_project
black .
```

**Expected behavior**

It shouldn't crash.

**Environment (please complete the following information):**

- Version: black, version 21.5b1
- OS and Python version: MacOs Python 3.8.8

---

Since the presently used "toml" library explicitly only supports up to version 0.5.0 of the spec (from about two years ago), I'd suggest switching to [tomlkit](https://github.com/sdispater/tomlkit), which supports the current toml spec (officially up to 1.0.0rc1 but nothing has materially changed since then).

I'd be happy to put together a PR if this approach is deemed acceptable in principle.


Discussion:
Seems reasonable. It looks like pip itself still uses `toml` though, and in practice compatibility with other Python tools that use pyproject.toml is probably more important for us than compatibility with the toml standard. There's some related discussion in https://discuss.python.org/t/adopting-recommending-a-toml-parser/4068.
[tomli](https://github.com/hukkinj1/tomli) looks promising. Hope it can get into the stdlib so toml can become "real" in python as a low level config file format. Thanks for raising this interesting issue. For now tho I think you're stuck using `0.5.0` toml for pyproject.toml as I'd like us to follow what `pip` does too.
I see, yes it seems pip has the same issue. I'd argue there's still value in supporting the latest toml syntax, even if pip does not yet. In principle it should be a non breaking change, though I guess the bottom line is that any divergence presents a risk of unexpected consequences?
I made an issue in pip issue tracker about this: https://github.com/pypa/pip/issues/10034

Let's see if they have willingness to upgrade to a TOML v1.0.0 compatible parser.

Edit: This also led to a [proposal](https://discuss.python.org/t/should-pep-518-specify-toml-spec-version-for-pyproject-toml/9031) to change PEP 518 so that it includes a TOML spec version for pyproject.toml.

Resolving patch:
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -74,7 +74,7 @@ def get_long_description() -> str:
     install_requires=[
         "click>=7.1.2",
         "appdirs",
-        "toml>=0.10.1",
+        "tomli>=0.2.6,<2.0.0",
         "typed-ast>=1.4.2; python_version < '3.8'",
         "regex>=2020.1.8",
         "pathspec>=0.8.1, <1",
diff --git a/src/black/files.py b/src/black/files.py
--- a/src/black/files.py
+++ b/src/black/files.py
@@ -18,7 +18,7 @@
 )
 
 from pathspec import PathSpec
-import toml
+import tomli
 
 from black.output import err
 from black.report import Report
@@ -89,9 +89,10 @@ def find_pyproject_toml(path_search_start: Tuple[str, ...]) -> Optional[str]:
 def parse_pyproject_toml(path_config: str) -> Dict[str, Any]:
     """Parse a pyproject toml file, pulling out relevant parts for Black
 
-    If parsing fails, will raise a toml.TomlDecodeError
+    If parsing fails, will raise a tomli.TOMLDecodeError
     """
-    pyproject_toml = toml.load(path_config)
+    with open(path_config, encoding="utf8") as f:
+        pyproject_toml = tomli.load(f)
     config = pyproject_toml.get("tool", {}).get("black", {})
     return {k.replace("--", "").replace("-", "_"): v for k, v in config.items()}
 


Test patch:
diff --git a/tests/test.toml b/tests/test.toml
--- a/tests/test.toml
+++ b/tests/test.toml
@@ -7,3 +7,10 @@ line-length = 79
 target-version = ["py36", "py37", "py38"]
 exclude='\.pyi?$'
 include='\.py?$'
+
+[v1.0.0-syntax]
+# This shouldn't break Black.
+contributors = [
+  "Foo Bar <foo@example.com>",
+  { name = "Baz Qux", email = "bazqux@example.com", url = "https://example.com/bazqux" }
+]