dosisod / refurb

A tool for refurbishing and modernizing Python codebases
GNU General Public License v3.0
2.48k stars 53 forks source link

[Enhancement]: `textwrap.dedent()` to prettify a multiline string #328

Open opk12 opened 7 months ago

opk12 commented 7 months ago

Overview

Is it in-scope to suggest wrapping a multiline string literal inside textwrap.dedent() to keep it readable and consistently indented?

Proposal

$ cat a.py
#!/usr/bin/env python3

import textwrap

class C:
    def make_with_dedent(self):
        literal = textwrap.dedent("""\
            This is a multiline
            string literal.
        """)
        return literal

    def make_without_dedent(self):
        literal = """\
This is another multiline
string literal.
        """
        return literal

print(C().make_with_dedent())
print(C().make_without_dedent())

$ ./a.py 
This is a multiline
string literal.

This is another multiline
string literal.

A big thanks to alonzodemo at OpenStreetMap for teaching me the trick.

dosisod commented 6 months ago

Personally I like using code without dedent() since there is less whitespace, and it saves me an extra import.

With that being said, reliably detecting when to emit an error for this will be hard. Since Refurb is built on Mypy, and Mypy stores string nodes in a normalized form, "\n" and """<newline>""" are identical, making it hard to detect when multi-line strings are being used.

I'm not against adding this, but doing so will be difficult for the reason above, and because it may be hard to gauge when using dedent() will improve readability (for example, very long/wide multi-line strings).