Skip to content

Filenames containing pipe (|) character break report markdown table #2141

@ellieayla

Description

@ellieayla

Describe the bug

The markdown report doesn't fully escape filenames.

In markdown files, some characters are meaningful. In the markdown report, some characters in filenames are escaped. For example, underscores _ are super common in filenames and escaped by the markdown report generator, since they would start/stop an underline.

But a markdown report does not escape pipe | characters names in filenames. Pipe characters are used to make tables.

A markdown report with pipe characters in filenames is broken.

Yes, pipe characters in filenames is kinda silly.

To Reproduce

How can we reproduce the problem? Please be specific. Don't link to a failing CI job. Think about the time it will take us to recreate your situation: the easier you make it, the more likely your issue will be addressed.

  1. What version of Python are you using?: cpython 3.14.2 / macOS-15.6.1-arm64-arm-64bit-Mach-O
  2. What version of coverage.py shows the problem? Coverage.py, version 7.13.4 with C extension
  3. What versions of what packages do you have installed? The output of pip freeze is helpful. Nothing?
  4. What code shows the problem? Give us a specific commit of a specific repo that we can check out. If you've already worked around the problem, please provide a commit before that fix. See below.
  5. What commands should we run to reproduce the problem? Be specific. Include everything, even git clone, pip install, and so on. Explain like we're five!
touch 'pipe|.py'
uv tool run coverage erase
uv tool run coverage run 'pipe|.py'
uv tool run coverage report --format=markdown
| Name      |    Stmts |     Miss |    Cover |   Missing |
|---------- | -------: | -------: | -------: | --------: |
| pipe|.py  |        0 |        0 |     100% |           |
| **TOTAL** |    **0** |    **0** | **100%** |           |

Which renders in GFM as:

Name Stmts Miss Cover Missing
pipe .py 0 0 100%
TOTAL 0 0 100%

Note the filename was split into a new column.

Alternatively, a testcase for tests/test_report.py:

    @pytest.mark.skipif(env.WINDOWS, reason="No pipe characters in filenames on Windows")
    def test_markdown_escape_filename(self) -> None:
        self.make_file("subdir/so_me|file.py", "print(1)")
        self.make_data_file(lines={"subdir/so_me|file.py": [1]})

        cov = coverage.Coverage()
        cov.load()
        report = self.get_report(cov, ignore_errors=True, output_format="markdown")
        
        squeezed = self.squeezed_lines(report)
        assert squeezed[2] == '| subdir/so/_me/|file.py | 1 | 1 | 0% |'  # get_report replaces \\ with /

Expected behavior

Underscore _ is already escaped in markdown output. Pipe should be escaped too.

| Name       |    Stmts |     Miss |    Cover |   Missing |
|----------- | -------: | -------: | -------: | --------: |
| pipe\|.py  |        0 |        0 |     100% |           |
| **TOTAL**  |    **0** |    **0** | **100%** |           |

... ideally rendering in GFM as

Name Stmts Miss Cover Missing
pipe|.py 0 0 100%
TOTAL 0 0 100%

Additional context

Noticed while reading

str(value).replace("_", "\\_"), name_len=max_name, n=max_n - 1

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions