Repository: koxudaxi/datamodel-code-generator

Issue:
Support black 22.1.0
**Is your feature request related to a problem? Please describe.**
`black` released a new version 22.1.0 https://github.com/psf/black/releases/tag/22.1.0

**Describe the solution you'd like**
Being able to use `black` 22.1.0 and the latest `datamodel-code-generator` in the same project

**Describe alternatives you've considered**
Pin black to an earlier for now

**Additional context**
In particular, this new version changed `find_project_root ` return value used by `datamodel-code-generator` package.
* 22.1.0 https://github.com/psf/black/blob/d038a24ca200da9dacc1dcb05090c9e5b45b7869/src/black/files.py#L34
* 21.12b0 https://github.com/psf/black/blob/f1d4e742c91dd5179d742b0db9293c4472b765f8/src/black/files.py#L34
Using `black` 22.1.0 with `datamodel-code-generator` 0.11.17 causes this kind of error:
```
  File "/opt/hostedtoolcache/Python/3.8.12/x64/lib/python3.8/site-packages/datamodel_code_generator/format.py", line 44, in __init__
    path = root / "pyproject.toml"
TypeError: unsupported operand type(s) for /: 'tuple' and 'str'
```


Discussion:

Resolving patch:
diff --git a/datamodel_code_generator/__main__.py b/datamodel_code_generator/__main__.py
--- a/datamodel_code_generator/__main__.py
+++ b/datamodel_code_generator/__main__.py
@@ -41,7 +41,11 @@
     enable_debug_message,
     generate,
 )
-from datamodel_code_generator.format import PythonVersion, is_supported_in_black
+from datamodel_code_generator.format import (
+    PythonVersion,
+    black_find_project_root,
+    is_supported_in_black,
+)
 from datamodel_code_generator.parser import LiteralType
 from datamodel_code_generator.reference import is_url
 from datamodel_code_generator.types import StrictTypes
@@ -435,7 +439,7 @@ def main(args: Optional[Sequence[str]] = None) -> Exit:
         print(version)
         exit(0)
 
-    root = black.find_project_root((Path().resolve(),))
+    root = black_find_project_root((Path().resolve(),))
     pyproject_toml_path = root / "pyproject.toml"
     if pyproject_toml_path.is_file():
         pyproject_toml: Dict[str, Any] = {
diff --git a/datamodel_code_generator/format.py b/datamodel_code_generator/format.py
--- a/datamodel_code_generator/format.py
+++ b/datamodel_code_generator/format.py
@@ -1,6 +1,6 @@
 from enum import Enum
 from pathlib import Path
-from typing import TYPE_CHECKING, Any, Dict, Optional
+from typing import TYPE_CHECKING, Any, Dict, Optional, Sequence
 from warnings import warn
 
 import black
@@ -19,17 +19,42 @@ def has_literal_type(self) -> bool:
         return self.value >= self.PY_38.value  # type: ignore
 
 
-BLACK_PYTHON_VERSION: Dict[PythonVersion, black.TargetVersion] = {
-    v: getattr(black.TargetVersion, f'PY{v.name.split("_")[-1]}')
-    for v in PythonVersion
-    if hasattr(black.TargetVersion, f'PY{v.name.split("_")[-1]}')
-}
+if TYPE_CHECKING:
+
+    class _TargetVersion(Enum):
+        ...
+
+    BLACK_PYTHON_VERSION: Dict[PythonVersion, _TargetVersion]
+else:
+    BLACK_PYTHON_VERSION: Dict[PythonVersion, black.TargetVersion] = {
+        v: getattr(black.TargetVersion, f'PY{v.name.split("_")[-1]}')
+        for v in PythonVersion
+        if hasattr(black.TargetVersion, f'PY{v.name.split("_")[-1]}')
+    }
 
 
 def is_supported_in_black(python_version: PythonVersion) -> bool:  # pragma: no cover
     return python_version in BLACK_PYTHON_VERSION
 
 
+def black_find_project_root(sources: Sequence[Path]) -> Path:
+    if TYPE_CHECKING:
+        from typing import Iterable, Tuple, Union
+
+        def _find_project_root(
+            srcs: Union[Sequence[str], Iterable[str]]
+        ) -> Union[Tuple[Path, str], Path]:
+            ...
+
+    else:
+        from black import find_project_root as _find_project_root
+    project_root = _find_project_root(tuple(str(s) for s in sources))
+    if isinstance(project_root, tuple):
+        return project_root[0]
+    else:
+        return project_root
+
+
 class CodeFormatter:
     def __init__(
         self,
@@ -40,7 +65,7 @@ def __init__(
         if not settings_path:
             settings_path = Path().resolve()
 
-        root = black.find_project_root((settings_path,))
+        root = black_find_project_root((settings_path,))
         path = root / "pyproject.toml"
         if path.is_file():
             value = str(path)


Test patch:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -13,6 +13,7 @@ jobs:
         python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"]
         os: [ubuntu-latest, windows-latest, macos-latest]
         isort-version: [4.3.21, 5.6.4]
+        black-version: [22.1.0, defualt]
         pydantic-version: [1.5.1, default]
     defaults:
       run:
@@ -50,6 +51,10 @@ jobs:
       if: matrix.pydantic-version == '1.5.1' && matrix.python-version != '3.9'  && matrix.python-version != '3.10'
       run: |
          poetry run pip install pydantic=="1.5.1"
+    - name: Install Black 22.1.0
+      if: matrix.black-version == '22.1.0'
+      run: |
+         poetry run pip install black=="22.1.0"
     - name: Lint
       run: |
         source $VENV