diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d324a03..12b7a34 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,43 +1,57 @@ +default_language_version: + python: python3.11 + repos: -- repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.3.0 - hooks: - - id: trailing-whitespace - - id: end-of-file-fixer - - id: check-yaml - - id: debug-statements - - id: requirements-txt-fixer -- repo: https://github.com/asottile/reorder_python_imports - rev: v3.8.5 - hooks: - - id: reorder-python-imports - args: - - --py37-plus - - --application-directories - - .:example:src - - --add-import - - 'from __future__ import annotations' -- repo: https://github.com/asottile/add-trailing-comma - rev: v2.3.0 - hooks: - - id: add-trailing-comma - args: [--py36-plus] -- repo: https://github.com/asottile/pyupgrade - rev: v3.1.0 - hooks: - - id: pyupgrade - args: [--py37-plus] -- repo: https://github.com/pre-commit/mirrors-autopep8 - rev: v1.7.0 - hooks: - - id: autopep8 -- repo: https://github.com/PyCQA/flake8 - rev: 5.0.4 - hooks: - - id: flake8 -- repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.982 - hooks: - - id: mypy - additional_dependencies: - - black==22.12.0 +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + - id: check-added-large-files + - id: check-case-conflict + - id: check-json + - id: check-merge-conflict + - id: check-symlinks + - id: check-toml + - id: end-of-file-fixer + - id: trailing-whitespace +- repo: https://github.com/asottile/pyupgrade + rev: v3.3.1 + hooks: + - id: pyupgrade + args: [--py37-plus] +- repo: https://github.com/psf/black + rev: 22.12.0 + hooks: + - id: black +- repo: https://github.com/asottile/blacken-docs + rev: v1.12.1 + hooks: + - id: blacken-docs + additional_dependencies: + - black==22.10.0 + files: '\.rst$' +- repo: https://github.com/asottile/reorder_python_imports + rev: v3.9.0 + hooks: + - id: reorder-python-imports + args: + - --py37-plus + - --application-directories + - .:example:src + - --add-import + - 'from __future__ import annotations' +- repo: https://github.com/PyCQA/flake8 + rev: 6.0.0 + hooks: + - id: flake8 + additional_dependencies: + - flake8-bugbear + - flake8-comprehensions + - flake8-tidy-imports + - flake8-typing-imports +- repo: https://github.com/pre-commit/mirrors-mypy + rev: v0.991 + hooks: + - id: mypy + additional_dependencies: + - black==22.12.0 + - pytest==7.1.2 diff --git a/src/blacken_docs/__init__.py b/src/blacken_docs/__init__.py index 4487a3f..153828e 100644 --- a/src/blacken_docs/__init__.py +++ b/src/blacken_docs/__init__.py @@ -15,77 +15,77 @@ MD_RE = re.compile( - r'(?P^(?P *)```\s*python\n)' - r'(?P.*?)' - r'(?P^(?P=indent)```\s*$)', + r"(?P^(?P *)```\s*python\n)" + r"(?P.*?)" + r"(?P^(?P=indent)```\s*$)", re.DOTALL | re.MULTILINE, ) MD_PYCON_RE = re.compile( - r'(?P^(?P *)```\s*pycon\n)' - r'(?P.*?)' - r'(?P^(?P=indent)```.*$)', + r"(?P^(?P *)```\s*pycon\n)" + r"(?P.*?)" + r"(?P^(?P=indent)```.*$)", re.DOTALL | re.MULTILINE, ) -RST_PY_LANGS = frozenset(('python', 'py', 'sage', 'python3', 'py3', 'numpy')) -BLOCK_TYPES = '(code|code-block|sourcecode|ipython)' -DOCTEST_TYPES = '(testsetup|testcleanup|testcode)' +RST_PY_LANGS = frozenset(("python", "py", "sage", "python3", "py3", "numpy")) +BLOCK_TYPES = "(code|code-block|sourcecode|ipython)" +DOCTEST_TYPES = "(testsetup|testcleanup|testcode)" RST_RE = re.compile( - rf'(?P' - rf'^(?P *)\.\. (' - rf'jupyter-execute::|' - rf'{BLOCK_TYPES}:: (?P\w+)|' - rf'{DOCTEST_TYPES}::.*' - rf')\n' - rf'((?P=indent) +:.*\n)*' - rf'\n*' - rf')' - rf'(?P(^((?P=indent) +.*)?\n)+)', + rf"(?P" + rf"^(?P *)\.\. (" + rf"jupyter-execute::|" + rf"{BLOCK_TYPES}:: (?P\w+)|" + rf"{DOCTEST_TYPES}::.*" + rf")\n" + rf"((?P=indent) +:.*\n)*" + rf"\n*" + rf")" + rf"(?P(^((?P=indent) +.*)?\n)+)", re.MULTILINE, ) RST_LITERAL_BLOCKS_RE = re.compile( - r'(?P' - r'^(?! *\.\. )(?P *).*::\n' - r'((?P=indent) +:.*\n)*' - r'\n*' - r')' - r'(?P(^((?P=indent) +.*)?\n)+)', + r"(?P" + r"^(?! *\.\. )(?P *).*::\n" + r"((?P=indent) +:.*\n)*" + r"\n*" + r")" + r"(?P(^((?P=indent) +.*)?\n)+)", re.MULTILINE, ) RST_PYCON_RE = re.compile( - r'(?P' - r'(?P *)\.\. ((code|code-block):: pycon|doctest::.*)\n' - r'((?P=indent) +:.*\n)*' - r'\n*' - r')' - r'(?P(^((?P=indent) +.*)?(\n|$))+)', + r"(?P" + r"(?P *)\.\. ((code|code-block):: pycon|doctest::.*)\n" + r"((?P=indent) +:.*\n)*" + r"\n*" + r")" + r"(?P(^((?P=indent) +.*)?(\n|$))+)", re.MULTILINE, ) -PYCON_PREFIX = '>>> ' -PYCON_CONTINUATION_PREFIX = '...' +PYCON_PREFIX = ">>> " +PYCON_CONTINUATION_PREFIX = "..." PYCON_CONTINUATION_RE = re.compile( - rf'^{re.escape(PYCON_CONTINUATION_PREFIX)}( |$)', + rf"^{re.escape(PYCON_CONTINUATION_PREFIX)}( |$)", ) LATEX_RE = re.compile( - r'(?P^(?P *)\\begin{minted}{python}\n)' - r'(?P.*?)' - r'(?P^(?P=indent)\\end{minted}\s*$)', + r"(?P^(?P *)\\begin{minted}{python}\n)" + r"(?P.*?)" + r"(?P^(?P=indent)\\end{minted}\s*$)", re.DOTALL | re.MULTILINE, ) LATEX_PYCON_RE = re.compile( - r'(?P^(?P *)\\begin{minted}{pycon}\n)' - r'(?P.*?)' - r'(?P^(?P=indent)\\end{minted}\s*$)', + r"(?P^(?P *)\\begin{minted}{pycon}\n)" + r"(?P.*?)" + r"(?P^(?P=indent)\\end{minted}\s*$)", re.DOTALL | re.MULTILINE, ) -PYTHONTEX_LANG = r'(?Ppyblock|pycode|pyconsole|pyverbatim)' +PYTHONTEX_LANG = r"(?Ppyblock|pycode|pyconsole|pyverbatim)" PYTHONTEX_RE = re.compile( - rf'(?P^(?P *)\\begin{{{PYTHONTEX_LANG}}}\n)' - rf'(?P.*?)' - rf'(?P^(?P=indent)\\end{{(?P=lang)}}\s*$)', + rf"(?P^(?P *)\\begin{{{PYTHONTEX_LANG}}}\n)" + rf"(?P.*?)" + rf"(?P^(?P=indent)\\end{{(?P=lang)}}\s*$)", re.DOTALL | re.MULTILINE, ) -INDENT_RE = re.compile('^ +(?=[^ ])', re.MULTILINE) -TRAILING_NL_RE = re.compile(r'\n+\Z', re.MULTILINE) +INDENT_RE = re.compile("^ +(?=[^ ])", re.MULTILINE) +TRAILING_NL_RE = re.compile(r"\n+\Z", re.MULTILINE) class CodeBlockError(NamedTuple): @@ -94,10 +94,10 @@ class CodeBlockError(NamedTuple): def format_str( - src: str, - black_mode: black.FileMode, - *, - rst_literal_blocks: bool = False, + src: str, + black_mode: black.FileMode, + *, + rst_literal_blocks: bool = False, ) -> tuple[str, Sequence[CodeBlockError]]: errors: list[CodeBlockError] = [] @@ -109,41 +109,41 @@ def _collect_error(match: Match[str]) -> Generator[None, None, None]: errors.append(CodeBlockError(match.start(), e)) def _md_match(match: Match[str]) -> str: - code = textwrap.dedent(match['code']) + code = textwrap.dedent(match["code"]) with _collect_error(match): code = black.format_str(code, mode=black_mode) - code = textwrap.indent(code, match['indent']) + code = textwrap.indent(code, match["indent"]) return f'{match["before"]}{code}{match["after"]}' def _rst_match(match: Match[str]) -> str: - lang = match['lang'] + lang = match["lang"] if lang is not None and lang not in RST_PY_LANGS: return match[0] - min_indent = min(INDENT_RE.findall(match['code'])) - trailing_ws_match = TRAILING_NL_RE.search(match['code']) + min_indent = min(INDENT_RE.findall(match["code"])) + trailing_ws_match = TRAILING_NL_RE.search(match["code"]) assert trailing_ws_match trailing_ws = trailing_ws_match.group() - code = textwrap.dedent(match['code']) + code = textwrap.dedent(match["code"]) with _collect_error(match): code = black.format_str(code, mode=black_mode) code = textwrap.indent(code, min_indent) return f'{match["before"]}{code.rstrip()}{trailing_ws}' def _rst_literal_blocks_match(match: Match[str]) -> str: - if not match['code'].strip(): + if not match["code"].strip(): return match[0] - min_indent = min(INDENT_RE.findall(match['code'])) - trailing_ws_match = TRAILING_NL_RE.search(match['code']) + min_indent = min(INDENT_RE.findall(match["code"])) + trailing_ws_match = TRAILING_NL_RE.search(match["code"]) assert trailing_ws_match trailing_ws = trailing_ws_match.group() - code = textwrap.dedent(match['code']) + code = textwrap.dedent(match["code"]) with _collect_error(match): code = black.format_str(code, mode=black_mode) code = textwrap.indent(code, min_indent) return f'{match["before"]}{code.rstrip()}{trailing_ws}' def _pycon_match(match: Match[str]) -> str: - code = '' + code = "" fragment: str | None = None def finish_fragment() -> None: @@ -154,7 +154,7 @@ def finish_fragment() -> None: with _collect_error(match): fragment = black.format_str(fragment, mode=black_mode) fragment_lines = fragment.splitlines() - code += f'{PYCON_PREFIX}{fragment_lines[0]}\n' + code += f"{PYCON_PREFIX}{fragment_lines[0]}\n" for line in fragment_lines[1:]: # Skip blank lines to handle Black adding a blank above # functions within blocks. A blank line would end the REPL @@ -165,49 +165,49 @@ def finish_fragment() -> None: # ... pass # ... if line: - code += f'{PYCON_CONTINUATION_PREFIX} {line}\n' - if fragment_lines[-1].startswith(' '): - code += f'{PYCON_CONTINUATION_PREFIX}\n' + code += f"{PYCON_CONTINUATION_PREFIX} {line}\n" + if fragment_lines[-1].startswith(" "): + code += f"{PYCON_CONTINUATION_PREFIX}\n" fragment = None indentation = None - for line in match['code'].splitlines(): + for line in match["code"].splitlines(): orig_line, line = line, line.lstrip() if indentation is None and line: indentation = len(orig_line) - len(line) continuation_match = PYCON_CONTINUATION_RE.match(line) if continuation_match and fragment is not None: - fragment += line[continuation_match.end():] + '\n' + fragment += line[continuation_match.end() :] + "\n" else: finish_fragment() if line.startswith(PYCON_PREFIX): - fragment = line[len(PYCON_PREFIX):] + '\n' + fragment = line[len(PYCON_PREFIX) :] + "\n" else: - code += orig_line[indentation:] + '\n' + code += orig_line[indentation:] + "\n" finish_fragment() return code def _md_pycon_match(match: Match[str]) -> str: code = _pycon_match(match) - code = textwrap.indent(code, match['indent']) + code = textwrap.indent(code, match["indent"]) return f'{match["before"]}{code}{match["after"]}' def _rst_pycon_match(match: Match[str]) -> str: code = _pycon_match(match) - min_indent = min(INDENT_RE.findall(match['code'])) + min_indent = min(INDENT_RE.findall(match["code"])) code = textwrap.indent(code, min_indent) return f'{match["before"]}{code}' def _latex_match(match: Match[str]) -> str: - code = textwrap.dedent(match['code']) + code = textwrap.dedent(match["code"]) with _collect_error(match): code = black.format_str(code, mode=black_mode) - code = textwrap.indent(code, match['indent']) + code = textwrap.indent(code, match["indent"]) return f'{match["before"]}{code}{match["after"]}' def _latex_pycon_match(match: Match[str]) -> str: code = _pycon_match(match) - code = textwrap.indent(code, match['indent']) + code = textwrap.indent(code, match["indent"]) return f'{match["before"]}{code}{match["after"]}' src = MD_RE.sub(_md_match, src) @@ -226,12 +226,12 @@ def _latex_pycon_match(match: Match[str]) -> str: def format_file( - filename: str, - black_mode: black.FileMode, - skip_errors: bool, - rst_literal_blocks: bool, + filename: str, + black_mode: black.FileMode, + skip_errors: bool, + rst_literal_blocks: bool, ) -> int: - with open(filename, encoding='UTF-8') as f: + with open(filename, encoding="UTF-8") as f: contents = f.read() new_contents, errors = format_str( contents, @@ -239,13 +239,13 @@ def format_file( rst_literal_blocks=rst_literal_blocks, ) for error in errors: - lineno = contents[:error.offset].count('\n') + 1 - print(f'{filename}:{lineno}: code block parse error {error.exc}') + lineno = contents[: error.offset].count("\n") + 1 + print(f"{filename}:{lineno}: code block parse error {error.exc}") if errors and not skip_errors: return 1 if contents != new_contents: - print(f'{filename}: Rewriting...') - with open(filename, 'w', encoding='UTF-8') as f: + print(f"{filename}: Rewriting...") + with open(filename, "w", encoding="UTF-8") as f: f.write(new_contents) return 1 else: @@ -255,25 +255,31 @@ def format_file( def main(argv: Sequence[str] | None = None) -> int: parser = argparse.ArgumentParser() parser.add_argument( - '-l', '--line-length', type=int, default=DEFAULT_LINE_LENGTH, + "-l", + "--line-length", + type=int, + default=DEFAULT_LINE_LENGTH, ) parser.add_argument( - '-t', - '--target-version', - action='append', + "-t", + "--target-version", + action="append", type=lambda v: TargetVersion[v.upper()], default=[], - help=f'choices: {[v.name.lower() for v in TargetVersion]}', - dest='target_versions', + help=f"choices: {[v.name.lower() for v in TargetVersion]}", + dest="target_versions", ) parser.add_argument( - '-S', '--skip-string-normalization', action='store_true', + "-S", + "--skip-string-normalization", + action="store_true", ) - parser.add_argument('-E', '--skip-errors', action='store_true') + parser.add_argument("-E", "--skip-errors", action="store_true") parser.add_argument( - '--rst-literal-blocks', action='store_true', + "--rst-literal-blocks", + action="store_true", ) - parser.add_argument('filenames', nargs='*') + parser.add_argument("filenames", nargs="*") args = parser.parse_args(argv) black_mode = black.FileMode( diff --git a/src/blacken_docs/__main__.py b/src/blacken_docs/__main__.py index 7854d63..332b4cf 100644 --- a/src/blacken_docs/__main__.py +++ b/src/blacken_docs/__main__.py @@ -2,5 +2,5 @@ from blacken_docs import main -if __name__ == '__main__': # pragma: no cover +if __name__ == "__main__": # pragma: no cover raise SystemExit(main()) diff --git a/tests/test_blacken_docs.py b/tests/test_blacken_docs.py index cb03702..f441c59 100644 --- a/tests/test_blacken_docs.py +++ b/tests/test_blacken_docs.py @@ -13,85 +13,43 @@ def test_format_src_trivial(): - after, _ = blacken_docs.format_str('', BLACK_MODE) - assert after == '' + after, _ = blacken_docs.format_str("", BLACK_MODE) + assert after == "" def test_format_src_markdown_simple(): - before = ( - '```python\n' - 'f(1,2,3)\n' - '```\n' - ) + before = "```python\n" "f(1,2,3)\n" "```\n" after, _ = blacken_docs.format_str(before, BLACK_MODE) - assert after == ( - '```python\n' - 'f(1, 2, 3)\n' - '```\n' - ) + assert after == ("```python\n" "f(1, 2, 3)\n" "```\n") def test_format_src_markdown_leading_whitespace(): - before = ( - '``` python\n' - 'f(1,2,3)\n' - '```\n' - ) + before = "``` python\n" "f(1,2,3)\n" "```\n" after, _ = blacken_docs.format_str(before, BLACK_MODE) - assert after == ( - '``` python\n' - 'f(1, 2, 3)\n' - '```\n' - ) + assert after == ("``` python\n" "f(1, 2, 3)\n" "```\n") def test_format_src_markdown_trailing_whitespace(): - before = ( - '```python\n' - 'f(1,2,3)\n' - '``` \n' - ) + before = "```python\n" "f(1,2,3)\n" "``` \n" after, _ = blacken_docs.format_str(before, BLACK_MODE) - assert after == ( - '```python\n' - 'f(1, 2, 3)\n' - '``` \n' - ) + assert after == ("```python\n" "f(1, 2, 3)\n" "``` \n") def test_format_src_indented_markdown(): - before = ( - '- do this pls:\n' - ' ```python\n' - ' f(1,2,3)\n' - ' ```\n' - '- also this\n' - ) + before = "- do this pls:\n" " ```python\n" " f(1,2,3)\n" " ```\n" "- also this\n" after, _ = blacken_docs.format_str(before, BLACK_MODE) assert after == ( - '- do this pls:\n' - ' ```python\n' - ' f(1, 2, 3)\n' - ' ```\n' - '- also this\n' + "- do this pls:\n" " ```python\n" " f(1, 2, 3)\n" " ```\n" "- also this\n" ) def test_format_src_latex_minted(): before = ( - 'hello\n' - '\\begin{minted}{python}\n' - 'f(1,2,3)\n' - '\\end{minted}\n' - 'world!' + "hello\n" "\\begin{minted}{python}\n" "f(1,2,3)\n" "\\end{minted}\n" "world!" ) after, _ = blacken_docs.format_str(before, BLACK_MODE) assert after == ( - 'hello\n' - '\\begin{minted}{python}\n' - 'f(1, 2, 3)\n' - '\\end{minted}\n' - 'world!' + "hello\n" "\\begin{minted}{python}\n" "f(1, 2, 3)\n" "\\end{minted}\n" "world!" ) @@ -99,41 +57,41 @@ def test_format_src_latex_minted_indented(): # Personaly I would have minted python code all flush left, # with only the Python code's own four space indentation: before = ( - 'hello\n' - ' \\begin{minted}{python}\n' - ' if True:\n' - ' f(1,2,3)\n' - ' \\end{minted}\n' - 'world!' + "hello\n" + " \\begin{minted}{python}\n" + " if True:\n" + " f(1,2,3)\n" + " \\end{minted}\n" + "world!" ) after, _ = blacken_docs.format_str(before, BLACK_MODE) assert after == ( - 'hello\n' - ' \\begin{minted}{python}\n' - ' if True:\n' - ' f(1, 2, 3)\n' - ' \\end{minted}\n' - 'world!' + "hello\n" + " \\begin{minted}{python}\n" + " if True:\n" + " f(1, 2, 3)\n" + " \\end{minted}\n" + "world!" ) def test_format_src_latex_minted_pycon(): before = ( - 'Preceeding text\n' - '\\begin{minted}{pycon}\n' + "Preceeding text\n" + "\\begin{minted}{pycon}\n" ">>> print( 'Hello World' )\n" - 'Hello World\n' - '\\end{minted}\n' - 'Following text.' + "Hello World\n" + "\\end{minted}\n" + "Following text." ) after, _ = blacken_docs.format_str(before, BLACK_MODE) assert after == ( - 'Preceeding text\n' - '\\begin{minted}{pycon}\n' + "Preceeding text\n" + "\\begin{minted}{pycon}\n" '>>> print("Hello World")\n' - 'Hello World\n' - '\\end{minted}\n' - 'Following text.' + "Hello World\n" + "\\end{minted}\n" + "Following text." ) @@ -141,96 +99,66 @@ def test_format_src_latex_minted_pycon_indented(): # Nicer style to put the \begin and \end on new lines, # but not actually required for the begin line before = ( - 'Preceeding text\n' - ' \\begin{minted}{pycon}\n' + "Preceeding text\n" + " \\begin{minted}{pycon}\n" " >>> print( 'Hello World' )\n" - ' Hello World\n' - ' \\end{minted}\n' - 'Following text.' + " Hello World\n" + " \\end{minted}\n" + "Following text." ) after, _ = blacken_docs.format_str(before, BLACK_MODE) assert after == ( - 'Preceeding text\n' - ' \\begin{minted}{pycon}\n' + "Preceeding text\n" + " \\begin{minted}{pycon}\n" ' >>> print("Hello World")\n' - ' Hello World\n' - ' \\end{minted}\n' - 'Following text.' + " Hello World\n" + " \\end{minted}\n" + "Following text." ) def test_src_pythontex(): - before = ( - 'hello\n' - '\\begin{pyblock}\n' - 'f(1,2,3)\n' - '\\end{pyblock}\n' - 'world!' - ) + before = "hello\n" "\\begin{pyblock}\n" "f(1,2,3)\n" "\\end{pyblock}\n" "world!" after, _ = blacken_docs.format_str(before, BLACK_MODE) assert after == ( - 'hello\n' - '\\begin{pyblock}\n' - 'f(1, 2, 3)\n' - '\\end{pyblock}\n' - 'world!' + "hello\n" "\\begin{pyblock}\n" "f(1, 2, 3)\n" "\\end{pyblock}\n" "world!" ) def test_format_src_rst(): before = ( - 'hello\n' - '\n' - '.. code-block:: python\n' - '\n' - ' f(1,2,3)\n' - '\n' - 'world\n' + "hello\n" "\n" ".. code-block:: python\n" "\n" " f(1,2,3)\n" "\n" "world\n" ) after, _ = blacken_docs.format_str(before, BLACK_MODE) assert after == ( - 'hello\n' - '\n' - '.. code-block:: python\n' - '\n' - ' f(1, 2, 3)\n' - '\n' - 'world\n' + "hello\n" "\n" ".. code-block:: python\n" "\n" " f(1, 2, 3)\n" "\n" "world\n" ) def test_format_src_rst_literal_blocks(): - before = ( - 'hello::\n' - '\n' - ' f(1,2,3)\n' - '\n' - 'world\n' - ) + before = "hello::\n" "\n" " f(1,2,3)\n" "\n" "world\n" after, _ = blacken_docs.format_str( - before, BLACK_MODE, rst_literal_blocks=True, - ) - assert after == ( - 'hello::\n' - '\n' - ' f(1, 2, 3)\n' - '\n' - 'world\n' + before, + BLACK_MODE, + rst_literal_blocks=True, ) + assert after == ("hello::\n" "\n" " f(1, 2, 3)\n" "\n" "world\n") def test_format_src_rst_literal_blocks_nested(): before = dedent( - ''' + """ * hello .. warning:: don't hello too much - ''', + """, ) after, errors = blacken_docs.format_str( - before, BLACK_MODE, rst_literal_blocks=True, + before, + BLACK_MODE, + rst_literal_blocks=True, ) assert after == before assert errors == [] @@ -238,16 +166,18 @@ def test_format_src_rst_literal_blocks_nested(): def test_format_src_rst_literal_blocks_empty(): before = dedent( - ''' + """ Example:: .. warning:: There was no example. - ''', + """, ) after, errors = blacken_docs.format_str( - before, BLACK_MODE, rst_literal_blocks=True, + before, + BLACK_MODE, + rst_literal_blocks=True, ) assert after == before assert errors == [] @@ -255,105 +185,105 @@ def test_format_src_rst_literal_blocks_empty(): def test_format_src_rst_sphinx_doctest(): before = ( - '.. testsetup:: group1\n' - '\n' - ' import parrot \n' - ' mock = SomeMock( )\n' - '\n' - '.. testcleanup:: group1\n' - '\n' - ' mock.stop( )\n' - '\n' - '.. doctest:: group1\n' - '\n' - ' >>> parrot.voom( 3000 )\n' - ' This parrot wouldn\'t voom if you put 3000 volts through it!\n' - '\n' - '.. testcode::\n' - '\n' - ' parrot.voom( 3000 )\n' - '\n' + ".. testsetup:: group1\n" + "\n" + " import parrot \n" + " mock = SomeMock( )\n" + "\n" + ".. testcleanup:: group1\n" + "\n" + " mock.stop( )\n" + "\n" + ".. doctest:: group1\n" + "\n" + " >>> parrot.voom( 3000 )\n" + " This parrot wouldn't voom if you put 3000 volts through it!\n" + "\n" + ".. testcode::\n" + "\n" + " parrot.voom( 3000 )\n" + "\n" ) after, _ = blacken_docs.format_str(before, BLACK_MODE) assert after == ( - '.. testsetup:: group1\n' - '\n' - ' import parrot\n' - '\n' - ' mock = SomeMock()\n' - '\n' - '.. testcleanup:: group1\n' - '\n' - ' mock.stop()\n' - '\n' - '.. doctest:: group1\n' - '\n' - ' >>> parrot.voom(3000)\n' - ' This parrot wouldn\'t voom if you put 3000 volts through it!\n' - '\n' - '.. testcode::\n' - '\n' - ' parrot.voom(3000)\n' - '\n' + ".. testsetup:: group1\n" + "\n" + " import parrot\n" + "\n" + " mock = SomeMock()\n" + "\n" + ".. testcleanup:: group1\n" + "\n" + " mock.stop()\n" + "\n" + ".. doctest:: group1\n" + "\n" + " >>> parrot.voom(3000)\n" + " This parrot wouldn't voom if you put 3000 volts through it!\n" + "\n" + ".. testcode::\n" + "\n" + " parrot.voom(3000)\n" + "\n" ) def test_format_src_rst_indented(): before = ( - '.. versionadded:: 3.1\n' - '\n' - ' hello\n' - '\n' - ' .. code-block:: python\n' - '\n' - ' def hi():\n' - ' f(1,2,3)\n' - '\n' - ' world\n' + ".. versionadded:: 3.1\n" + "\n" + " hello\n" + "\n" + " .. code-block:: python\n" + "\n" + " def hi():\n" + " f(1,2,3)\n" + "\n" + " world\n" ) after, _ = blacken_docs.format_str(before, BLACK_MODE) assert after == ( - '.. versionadded:: 3.1\n' - '\n' - ' hello\n' - '\n' - ' .. code-block:: python\n' - '\n' - ' def hi():\n' - ' f(1, 2, 3)\n' - '\n' - ' world\n' + ".. versionadded:: 3.1\n" + "\n" + " hello\n" + "\n" + " .. code-block:: python\n" + "\n" + " def hi():\n" + " f(1, 2, 3)\n" + "\n" + " world\n" ) def test_format_src_rst_with_highlight_directives(): before = ( - '.. code-block:: python\n' - ' :lineno-start: 10\n' - ' :emphasize-lines: 11\n' - '\n' - ' def foo():\n' - ' bar(1,2,3)\n' + ".. code-block:: python\n" + " :lineno-start: 10\n" + " :emphasize-lines: 11\n" + "\n" + " def foo():\n" + " bar(1,2,3)\n" ) after, _ = blacken_docs.format_str(before, BLACK_MODE) assert after == ( - '.. code-block:: python\n' - ' :lineno-start: 10\n' - ' :emphasize-lines: 11\n' - '\n' - ' def foo():\n' - ' bar(1, 2, 3)\n' + ".. code-block:: python\n" + " :lineno-start: 10\n" + " :emphasize-lines: 11\n" + "\n" + " def foo():\n" + " bar(1, 2, 3)\n" ) def test_format_src_rst_python_inside_non_python_code_block(): before = ( - 'blacken-docs does changes like:\n' - '\n' - '.. code-block:: diff\n' - '\n' - ' .. code-block:: python\n' - '\n' + "blacken-docs does changes like:\n" + "\n" + ".. code-block:: diff\n" + "\n" + " .. code-block:: python\n" + "\n" " - 'Hello World'\n" ' + "Hello World"\n' ) @@ -362,226 +292,178 @@ def test_format_src_rst_python_inside_non_python_code_block(): def test_integration_ok(tmp_path, capsys): - f = tmp_path / 'f.md' + f = tmp_path / "f.md" f.write_text( - '```python\n' - 'f(1, 2, 3)\n' - '```\n', + "```python\n" "f(1, 2, 3)\n" "```\n", ) assert not blacken_docs.main((str(f),)) assert not capsys.readouterr()[1] - assert f.read_text() == ( - '```python\n' - 'f(1, 2, 3)\n' - '```\n' - ) + assert f.read_text() == ("```python\n" "f(1, 2, 3)\n" "```\n") def test_integration_modifies(tmp_path, capsys): - f = tmp_path / 'f.md' + f = tmp_path / "f.md" f.write_text( - '```python\n' - 'f(1,2,3)\n' - '```\n', + "```python\n" "f(1,2,3)\n" "```\n", ) assert blacken_docs.main((str(f),)) out, _ = capsys.readouterr() - assert out == f'{f}: Rewriting...\n' - assert f.read_text() == ( - '```python\n' - 'f(1, 2, 3)\n' - '```\n' - ) + assert out == f"{f}: Rewriting...\n" + assert f.read_text() == ("```python\n" "f(1, 2, 3)\n" "```\n") def test_integration_line_length(tmp_path): - f = tmp_path / 'f.md' + f = tmp_path / "f.md" f.write_text( - '```python\n' - 'foo(very_very_very_very_very_very_very, long_long_long_long_long)\n' - '```\n', + "```python\n" + "foo(very_very_very_very_very_very_very, long_long_long_long_long)\n" + "```\n", ) - assert not blacken_docs.main((str(f), '--line-length=80')) - assert blacken_docs.main((str(f), '--line-length=50')) + assert not blacken_docs.main((str(f), "--line-length=80")) + assert blacken_docs.main((str(f), "--line-length=50")) assert f.read_text() == ( - '```python\n' - 'foo(\n' - ' very_very_very_very_very_very_very,\n' - ' long_long_long_long_long,\n' - ')\n' - '```\n' + "```python\n" + "foo(\n" + " very_very_very_very_very_very_very,\n" + " long_long_long_long_long,\n" + ")\n" + "```\n" ) def test_integration_py36(tmp_path): - f = tmp_path / 'f.md' + f = tmp_path / "f.md" f.write_text( - '```python\n' - 'def very_very_long_function_name(\n' - ' very_very_very_very_very_very,\n' - ' very_very_very_very_very_very,\n' - ' *long_long_long_long_long_long\n' - '):\n' - ' pass\n' - '```\n', + "```python\n" + "def very_very_long_function_name(\n" + " very_very_very_very_very_very,\n" + " very_very_very_very_very_very,\n" + " *long_long_long_long_long_long\n" + "):\n" + " pass\n" + "```\n", ) assert not blacken_docs.main((str(f),)) - assert blacken_docs.main((str(f), '--target-version=py36')) + assert blacken_docs.main((str(f), "--target-version=py36")) assert f.read_text() == ( - '```python\n' - 'def very_very_long_function_name(\n' - ' very_very_very_very_very_very,\n' - ' very_very_very_very_very_very,\n' - ' *long_long_long_long_long_long,\n' - '):\n' - ' pass\n' - '```\n' + "```python\n" + "def very_very_long_function_name(\n" + " very_very_very_very_very_very,\n" + " very_very_very_very_very_very,\n" + " *long_long_long_long_long_long,\n" + "):\n" + " pass\n" + "```\n" ) def test_integration_filename_last(tmp_path): - f = tmp_path / 'f.md' + f = tmp_path / "f.md" f.write_text( - '```python\n' - 'def very_very_long_function_name(\n' - ' very_very_very_very_very_very,\n' - ' very_very_very_very_very_very,\n' - ' *long_long_long_long_long_long\n' - '):\n' - ' pass\n' - '```\n', + "```python\n" + "def very_very_long_function_name(\n" + " very_very_very_very_very_very,\n" + " very_very_very_very_very_very,\n" + " *long_long_long_long_long_long\n" + "):\n" + " pass\n" + "```\n", ) assert not blacken_docs.main((str(f),)) - assert blacken_docs.main(('--target-version', 'py36', str(f))) + assert blacken_docs.main(("--target-version", "py36", str(f))) assert f.read_text() == ( - '```python\n' - 'def very_very_long_function_name(\n' - ' very_very_very_very_very_very,\n' - ' very_very_very_very_very_very,\n' - ' *long_long_long_long_long_long,\n' - '):\n' - ' pass\n' - '```\n' + "```python\n" + "def very_very_long_function_name(\n" + " very_very_very_very_very_very,\n" + " very_very_very_very_very_very,\n" + " *long_long_long_long_long_long,\n" + "):\n" + " pass\n" + "```\n" ) def test_integration_multiple_target_version(tmp_path): - f = tmp_path / 'f.md' + f = tmp_path / "f.md" f.write_text( - '```python\n' - 'def very_very_long_function_name(\n' - ' very_very_very_very_very_very,\n' - ' very_very_very_very_very_very,\n' - ' *long_long_long_long_long_long\n' - '):\n' - ' pass\n' - '```\n', + "```python\n" + "def very_very_long_function_name(\n" + " very_very_very_very_very_very,\n" + " very_very_very_very_very_very,\n" + " *long_long_long_long_long_long\n" + "):\n" + " pass\n" + "```\n", ) assert not blacken_docs.main((str(f),)) assert not blacken_docs.main( - ('--target-version', 'py35', '--target-version', 'py36', str(f)), + ("--target-version", "py35", "--target-version", "py36", str(f)), ) def test_integration_skip_string_normalization(tmp_path): - f = tmp_path / 'f.md' + f = tmp_path / "f.md" f.write_text( - '```python\n' - "f('hi')\n" - '```\n', - ) - assert not blacken_docs.main((str(f), '--skip-string-normalization')) - assert f.read_text() == ( - '```python\n' - "f('hi')\n" - '```\n' + "```python\n" "f('hi')\n" "```\n", ) + assert not blacken_docs.main((str(f), "--skip-string-normalization")) + assert f.read_text() == ("```python\n" "f('hi')\n" "```\n") def test_integration_syntax_error(tmp_path, capsys): - f = tmp_path / 'f.md' + f = tmp_path / "f.md" f.write_text( - '```python\n' - 'f(\n' - '```\n', + "```python\n" "f(\n" "```\n", ) assert blacken_docs.main((str(f),)) out, _ = capsys.readouterr() - assert out.startswith(f'{f}:1: code block parse error') - assert f.read_text() == ( - '```python\n' - 'f(\n' - '```\n' - ) + assert out.startswith(f"{f}:1: code block parse error") + assert f.read_text() == ("```python\n" "f(\n" "```\n") def test_integration_ignored_syntax_error(tmp_path, capsys): - f = tmp_path / 'f.md' + f = tmp_path / "f.md" f.write_text( - '```python\n' - 'f( )\n' - '```\n' - '\n' - '```python\n' - 'f(\n' - '```\n', - ) - assert blacken_docs.main((str(f), '--skip-errors')) + "```python\n" "f( )\n" "```\n" "\n" "```python\n" "f(\n" "```\n", + ) + assert blacken_docs.main((str(f), "--skip-errors")) out, _ = capsys.readouterr() assert f.read_text() == ( - '```python\n' - 'f()\n' - '```\n' - '\n' - '```python\n' - 'f(\n' - '```\n' + "```python\n" "f()\n" "```\n" "\n" "```python\n" "f(\n" "```\n" ) def test_format_src_rst_jupyter_sphinx(): before = ( - 'hello\n' - '\n' - '.. jupyter-execute::\n' - '\n' - ' f(1,2,3)\n' - '\n' - 'world\n' + "hello\n" "\n" ".. jupyter-execute::\n" "\n" " f(1,2,3)\n" "\n" "world\n" ) after, _ = blacken_docs.format_str(before, BLACK_MODE) assert after == ( - 'hello\n' - '\n' - '.. jupyter-execute::\n' - '\n' - ' f(1, 2, 3)\n' - '\n' - 'world\n' + "hello\n" "\n" ".. jupyter-execute::\n" "\n" " f(1, 2, 3)\n" "\n" "world\n" ) def test_format_src_rst_jupyter_sphinx_with_directive(): before = ( - 'hello\n' - '\n' - '.. jupyter-execute::\n' - ' :hide-code:\n' - '\n' - ' f(1,2,3)\n' - '\n' - 'world\n' + "hello\n" + "\n" + ".. jupyter-execute::\n" + " :hide-code:\n" + "\n" + " f(1,2,3)\n" + "\n" + "world\n" ) after, _ = blacken_docs.format_str(before, BLACK_MODE) assert after == ( - 'hello\n' - '\n' - '.. jupyter-execute::\n' - ' :hide-code:\n' - '\n' - ' f(1, 2, 3)\n' - '\n' - 'world\n' + "hello\n" + "\n" + ".. jupyter-execute::\n" + " :hide-code:\n" + "\n" + " f(1, 2, 3)\n" + "\n" + "world\n" ) @@ -618,82 +500,77 @@ def f(): def test_format_src_rst_pycon(): before = ( - 'hello\n' - '\n' - '.. code-block:: pycon\n' - '\n' - ' >>> f(1,2,3)\n' - ' output\n' - '\n' - 'world\n' + "hello\n" + "\n" + ".. code-block:: pycon\n" + "\n" + " >>> f(1,2,3)\n" + " output\n" + "\n" + "world\n" ) after, _ = blacken_docs.format_str(before, BLACK_MODE) assert after == ( - 'hello\n' - '\n' - '.. code-block:: pycon\n' - '\n' - ' >>> f(1, 2, 3)\n' - ' output\n' - '\n' - 'world\n' + "hello\n" + "\n" + ".. code-block:: pycon\n" + "\n" + " >>> f(1, 2, 3)\n" + " output\n" + "\n" + "world\n" ) def test_format_src_rst_pycon_with_contiuation(): before = ( - '.. code-block:: pycon\n' - '\n' - ' >>> d = {\n' + ".. code-block:: pycon\n" + "\n" + " >>> d = {\n" ' ... "a": 1,\n' ' ... "b": 2,\n' ' ... "c": 3,}\n' - '\n' + "\n" ) after, _ = blacken_docs.format_str(before, BLACK_MODE) assert after == ( - '.. code-block:: pycon\n' - '\n' - ' >>> d = {\n' + ".. code-block:: pycon\n" + "\n" + " >>> d = {\n" ' ... "a": 1,\n' ' ... "b": 2,\n' ' ... "c": 3,\n' - ' ... }\n' - '\n' + " ... }\n" + "\n" ) def test_format_src_rst_pycon_adds_contiuation(): - before = ( - '.. code-block:: pycon\n' - '\n' - ' >>> d = {"a": 1,"b": 2,"c": 3,}\n' - '\n' - ) + before = ".. code-block:: pycon\n" "\n" ' >>> d = {"a": 1,"b": 2,"c": 3,}\n' "\n" after, _ = blacken_docs.format_str(before, BLACK_MODE) assert after == ( - '.. code-block:: pycon\n' - '\n' - ' >>> d = {\n' + ".. code-block:: pycon\n" + "\n" + " >>> d = {\n" ' ... "a": 1,\n' ' ... "b": 2,\n' ' ... "c": 3,\n' - ' ... }\n' - '\n' + " ... }\n" + "\n" ) def test_format_src_rst_pycon_preserves_trailing_whitespace(): before = ( - 'hello\n' - '\n' - '.. code-block:: pycon\n' - '\n' + "hello\n" + "\n" + ".. code-block:: pycon\n" + "\n" ' >>> d = {"a": 1, "b": 2, "c": 3}\n' - '\n' - '\n' - '\n' - 'world\n' + "\n" + "\n" + "\n" + "world\n" ) after, _ = blacken_docs.format_str(before, BLACK_MODE) assert after == before @@ -701,134 +578,128 @@ def test_format_src_rst_pycon_preserves_trailing_whitespace(): def test_format_src_rst_pycon_indented(): before = ( - '.. versionadded:: 3.1\n' - '\n' - ' hello\n' - '\n' - ' .. code-block:: pycon\n' - '\n' - ' >>> def hi():\n' - ' ... f(1,2,3)\n' - ' ...\n' - '\n' - ' world\n' + ".. versionadded:: 3.1\n" + "\n" + " hello\n" + "\n" + " .. code-block:: pycon\n" + "\n" + " >>> def hi():\n" + " ... f(1,2,3)\n" + " ...\n" + "\n" + " world\n" ) after, _ = blacken_docs.format_str(before, BLACK_MODE) assert after == ( - '.. versionadded:: 3.1\n' - '\n' - ' hello\n' - '\n' - ' .. code-block:: pycon\n' - '\n' - ' >>> def hi():\n' - ' ... f(1, 2, 3)\n' - ' ...\n' - '\n' - ' world\n' - + ".. versionadded:: 3.1\n" + "\n" + " hello\n" + "\n" + " .. code-block:: pycon\n" + "\n" + " >>> def hi():\n" + " ... f(1, 2, 3)\n" + " ...\n" + "\n" + " world\n" ) def test_format_src_rst_pycon_code_block_is_final_line1(): before = ( - '.. code-block:: pycon\n' - '\n' - ' >>> if True:\n' - ' ... pass\n' - ' ...\n' + ".. code-block:: pycon\n" + "\n" + " >>> if True:\n" + " ... pass\n" + " ...\n" ) after, _ = blacken_docs.format_str(before, BLACK_MODE) assert after == ( - '.. code-block:: pycon\n' - '\n' - ' >>> if True:\n' - ' ... pass\n' - ' ...\n' + ".. code-block:: pycon\n" + "\n" + " >>> if True:\n" + " ... pass\n" + " ...\n" ) def test_format_src_rst_pycon_code_block_is_final_line2(): - before = ( - '.. code-block:: pycon\n' - '\n' - ' >>> if True:\n' - ' ... pass\n' - ) + before = ".. code-block:: pycon\n" "\n" " >>> if True:\n" " ... pass\n" after, _ = blacken_docs.format_str(before, BLACK_MODE) assert after == ( - '.. code-block:: pycon\n' - '\n' - ' >>> if True:\n' - ' ... pass\n' - ' ...\n' + ".. code-block:: pycon\n" + "\n" + " >>> if True:\n" + " ... pass\n" + " ...\n" ) def test_format_src_rst_pycon_nested_def1(): before = ( - '.. code-block:: pycon\n' - '\n' - ' >>> if True:\n' - ' ... def f(): pass\n' - ' ...\n' + ".. code-block:: pycon\n" + "\n" + " >>> if True:\n" + " ... def f(): pass\n" + " ...\n" ) after, _ = blacken_docs.format_str(before, BLACK_MODE) assert after == ( - '.. code-block:: pycon\n' - '\n' - ' >>> if True:\n' - ' ... def f():\n' - ' ... pass\n' - ' ...\n' + ".. code-block:: pycon\n" + "\n" + " >>> if True:\n" + " ... def f():\n" + " ... pass\n" + " ...\n" ) def test_format_src_rst_pycon_nested_def2(): before = ( - '.. code-block:: pycon\n' - '\n' - ' >>> if True:\n' - ' ... def f(): pass\n' + ".. code-block:: pycon\n" + "\n" + " >>> if True:\n" + " ... def f(): pass\n" ) after, _ = blacken_docs.format_str(before, BLACK_MODE) assert after == ( - '.. code-block:: pycon\n' - '\n' - ' >>> if True:\n' - ' ... def f():\n' - ' ... pass\n' - ' ...\n' + ".. code-block:: pycon\n" + "\n" + " >>> if True:\n" + " ... def f():\n" + " ... pass\n" + " ...\n" ) def test_format_src_rst_pycon_empty_line(): before = ( - '.. code-block:: pycon\n' - '\n' - ' >>> l = [\n' - ' ...\n' - ' ... 1,\n' - ' ... ]\n' + ".. code-block:: pycon\n" + "\n" + " >>> l = [\n" + " ...\n" + " ... 1,\n" + " ... ]\n" ) after, _ = blacken_docs.format_str(before, BLACK_MODE) assert after == ( - '.. code-block:: pycon\n' - '\n' - ' >>> l = [\n' - ' ... 1,\n' - ' ... ]\n' + ".. code-block:: pycon\n" + "\n" + " >>> l = [\n" + " ... 1,\n" + " ... ]\n" ) def test_format_src_rst_pycon_preserves_output_indentation(): before = ( - '.. code-block:: pycon\n' - '\n' - ' >>> 1 / 0\n' - ' Traceback (most recent call last):\n' + ".. code-block:: pycon\n" + "\n" + " >>> 1 / 0\n" + " Traceback (most recent call last):\n" ' File "", line 1, in \n' - ' ZeroDivisionError: division by zero\n' + " ZeroDivisionError: division by zero\n" ) after, _ = blacken_docs.format_str(before, BLACK_MODE) assert after == before @@ -836,76 +707,57 @@ def test_format_src_rst_pycon_preserves_output_indentation(): def test_format_src_rst_pycon_elided_traceback(): before = ( - '.. code-block:: pycon\n' - '\n' - ' >>> 1 / 0\n' - ' Traceback (most recent call last):\n' - ' ...\n' - ' ZeroDivisionError: division by zero\n' + ".. code-block:: pycon\n" + "\n" + " >>> 1 / 0\n" + " Traceback (most recent call last):\n" + " ...\n" + " ZeroDivisionError: division by zero\n" ) after, _ = blacken_docs.format_str(before, BLACK_MODE) assert after == before def test_format_src_rst_pycon_no_prompt(): - before = ( - '.. code-block:: pycon\n' - '\n' - ' pass\n' - ) + before = ".. code-block:: pycon\n" "\n" " pass\n" after, _ = blacken_docs.format_str(before, BLACK_MODE) assert after == before def test_format_src_rst_pycon_no_trailing_newline(): - before = ( - '.. code-block:: pycon\n' - '\n' - ' >>> pass' - ) + before = ".. code-block:: pycon\n" "\n" " >>> pass" after, _ = blacken_docs.format_str(before, BLACK_MODE) - assert after == ( - '.. code-block:: pycon\n' - '\n' - ' >>> pass\n' - ) + assert after == (".. code-block:: pycon\n" "\n" " >>> pass\n") def test_format_src_rst_pycon_comment_before_promopt(): before = ( - '.. code-block:: pycon\n' - '\n' - ' # Comment about next line\n' - ' >>> pass\n' + ".. code-block:: pycon\n" + "\n" + " # Comment about next line\n" + " >>> pass\n" ) after, _ = blacken_docs.format_str(before, BLACK_MODE) assert after == ( - '.. code-block:: pycon\n' - '\n' - ' # Comment about next line\n' - ' >>> pass\n' + ".. code-block:: pycon\n" + "\n" + " # Comment about next line\n" + " >>> pass\n" ) def test_format_src_markdown_pycon(): before = ( - 'hello\n' - '\n' - '```pycon\n' - '\n' - ' >>> f(1,2,3)\n' - ' output\n' - '```\n' - 'world\n' + "hello\n" + "\n" + "```pycon\n" + "\n" + " >>> f(1,2,3)\n" + " output\n" + "```\n" + "world\n" ) after, _ = blacken_docs.format_str(before, BLACK_MODE) assert after == ( - 'hello\n' - '\n' - '```pycon\n' - '\n' - '>>> f(1, 2, 3)\n' - 'output\n' - '```\n' - 'world\n' + "hello\n" "\n" "```pycon\n" "\n" ">>> f(1, 2, 3)\n" "output\n" "```\n" "world\n" )