From 0fd2c8e6a2f7c2d524b56c47a5de4f665898f753 Mon Sep 17 00:00:00 2001 From: Matt Bogosian Date: Wed, 22 Dec 2021 16:57:58 -0600 Subject: [PATCH] Allows for exclude as a multiline basic string in TOML files Multiple regexes are expressed as a sequence. Fixes #11825. --- docs/source/config_file.rst | 35 +++++++++++++++++++++ mypy/config_parser.py | 7 +++++ test-data/unit/cmdline.pyproject.test | 45 +++++++++++++++++++++++++++ 3 files changed, 87 insertions(+) diff --git a/docs/source/config_file.rst b/docs/source/config_file.rst index c34f23d9e169a..b8e7342c617de 100644 --- a/docs/source/config_file.rst +++ b/docs/source/config_file.rst @@ -214,6 +214,35 @@ section of the command line docs. This option may only be set in the global section (``[mypy]``). + .. note:: + + Note that the TOML equivalent differs slightly. It can be either a single string + (including a multi-line string) -- which is treated as a single regular + expression -- or an array of such strings. The following TOML examples are + equivalent to the above INI example. + + Array of strings: + + .. code-block:: toml + + [tool.mypy] + exclude = [ + '^file1\.py$', # literal (no escaping) + "^file2\\.py$", # basic (backslash needs escaping) + ] + + A single, multi-line string: + + .. code-block:: toml + + [tool.mypy] + exclude = '''(?x)( + ^file1\.py$ + |^file2\.py$", + )''' + + See :ref:`using-a-pyproject-toml`. + .. confval:: namespace_packages :type: boolean @@ -907,6 +936,8 @@ These options may only be set in the global section (``[mypy]``). Controls how much debug output will be generated. Higher numbers are more verbose. +.. _using-a-pyproject-toml: + Using a pyproject.toml file *************************** @@ -965,6 +996,10 @@ of your repo (or append it to the end of an existing ``pyproject.toml`` file) an python_version = "2.7" warn_return_any = true warn_unused_configs = true + exclude = [ + '^file1\.py$', # literal (no escaping) + "^file2\\.py$", # basic (backslash needs escaping) + ] # mypy per-module options: diff --git a/mypy/config_parser.py b/mypy/config_parser.py index 24e61df0441c0..2af679f4dd202 100644 --- a/mypy/config_parser.py +++ b/mypy/config_parser.py @@ -57,6 +57,12 @@ def expand_path(path: str) -> str: return os.path.expandvars(os.path.expanduser(path)) +def str_or_seq_of_strs_as_list_of_strs(v: Union[str, Sequence[str]]) -> List[str]: + if isinstance(v, str): + return [v.strip()] if v.strip() else [] + return [p.strip() for p in v if p.strip()] + + def split_and_match_files_list(paths: Sequence[str]) -> List[str]: """Take a list of files/directories (with support for globbing through the glob library). @@ -143,6 +149,7 @@ def check_follow_imports(choice: str) -> str: 'disable_error_code': try_split, 'enable_error_code': try_split, 'package_root': try_split, + 'exclude': str_or_seq_of_strs_as_list_of_strs, }) diff --git a/test-data/unit/cmdline.pyproject.test b/test-data/unit/cmdline.pyproject.test index 83f4745d07867..ea561ed164e75 100644 --- a/test-data/unit/cmdline.pyproject.test +++ b/test-data/unit/cmdline.pyproject.test @@ -80,3 +80,48 @@ def g(a: int) -> int: [out] pyproject.toml: toml config file contains [[tool.mypy.overrides]] sections with conflicting values. Module 'x' has two different values for 'disallow_untyped_defs' == Return code: 0 + +[case testMultilineLiteralExcludePyprojectTOML] +# cmd: mypy x +[file pyproject.toml] +\[tool.mypy] +exclude = '''(?x)( + (^|/)[^/]*skipme_\.py$ + |(^|/)_skipme[^/]*\.py$ +)''' +[file x/__init__.py] +i: int = 0 +[file x/_skipme_please.py] +This isn't even syntatically valid! +[file x/please_skipme_.py] +Neither is this! + +[case testMultilineBasicExcludePyprojectTOML] +# cmd: mypy x +[file pyproject.toml] +\[tool.mypy] +exclude = """(?x)( + (^|/)[^/]*skipme_\\.py$ + |(^|/)_skipme[^/]*\\.py$ +)""" +[file x/__init__.py] +i: int = 0 +[file x/_skipme_please.py] +This isn't even syntatically valid! +[file x/please_skipme_.py] +Neither is this! + +[case testSequenceExcludePyprojectTOML] +# cmd: mypy x +[file pyproject.toml] +\[tool.mypy] +exclude = [ + '(^|/)[^/]*skipme_\.py$', # literal (no escaping) + "(^|/)_skipme[^/]*\\.py$", # basic (backslash needs escaping) +] +[file x/__init__.py] +i: int = 0 +[file x/_skipme_please.py] +This isn't even syntatically valid! +[file x/please_skipme_.py] +Neither is this!