Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

long blocks of unstructured text should be limited to 72 characters #2289

Closed
fpdotmonkey opened this issue May 31, 2021 · 6 comments
Closed
Labels
F: comments The syntactic kind. Not in the language grammar, always on our minds. Best bugs. F: docstrings How we format docstrings F: strings Related to our handling of strings T: style What do we want Blackened code to look like?

Comments

@fpdotmonkey
Copy link

fpdotmonkey commented May 31, 2021

Describe the style change

Per PEP8,

For flowing long blocks of text with fewer structural restrictions (docstrings or comments), the line length should be limited to 72 characters.

[...]

Some teams strongly prefer a longer line length. For code maintained exclusively or primarily by a team that can reach agreement on this issue, it is okay to increase the line length limit up to 99 characters, provided that comments and docstrings are still wrapped at 72 characters.

(emphasis mine)

So when the --experimental-string-processing flag is set, docstrings and very long normal strings should be wrapped at 72 characters.

Examples in the current Black style

def foo():
    """Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."""
    Nonflowing().LongCode().that().has().many().structural().restrictions()
    Thingy("I am the very model of a modern Major-Gineral, I've information vegetable, animal, and mineral, I know the kings of England, and I quote the fights historical From Marathon to Waterloo, in order categorical; I'm very well acquainted, too, with matters mathematical, I understand equations, both the simple and quadratical, About binomial theorem I'm teeming with a lot o' news, With many cheerful facts about the square of the hypotenuse.")

# output

def foo():
    """Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."""
    Nonflowing().LongCode().that().has().many().structural().restrictions()
    Thingy(
        "I am the very model of a modern Major-Gineral, I've information"
        " vegetable, animal, and mineral, I know the kings of England, and I"
        " quote the fights historical From Marathon to Waterloo, in order"
        " categorical; I'm very well acquainted, too, with matters"
        " mathematical, I understand equations, both the simple and"
        " quadratical, About binomial theorem I'm teeming with a lot o' news,"
        " With many cheerful facts about the square of the hypotenuse."
    )

Desired style

def foo():
    """Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."""
    Nonflowing().LongCode().that().has().many().structural().restrictions()
    Thingy("I am the very model of a modern Major-Gineral, I've information vegetable, animal, and mineral, I know the kings of England, and I quote the fights historical From Marathon to Waterloo, in order categorical; I'm very well acquainted, too, with matters mathematical, I understand equations, both the simple and quadratical, About binomial theorem I'm teeming with a lot o' news, With many cheerful facts about the square of the hypotenuse.")

# output

def foo():
    """Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
    eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
    ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
    aliquip ex ea commodo consequat. Duis aute irure dolor in
    reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
    pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
    culpa qui officia deserunt mollit anim id est laborum.
    """
    Nonflowing().LongCode().that().has().many().structural().restrictions()
    Thingy(
        "I am the very model of a modern Major-Gineral, I've"
        " information vegetable, animal, and mineral, I know the kings"
        " of England, and I quote the fights historical From Marathon"
        " to Waterloo, in order categorical; I'm very well acquainted,"
        " too, with matters mathematical, I understand equations, both"
        " the simple and quadratical, About binomial theorem I'm"
        " teeming with a lot o' news, With many cheerful facts about"
        " the square of the hypotenuse."
    )
@JelleZijlstra JelleZijlstra added F: comments The syntactic kind. Not in the language grammar, always on our minds. Best bugs. F: strings Related to our handling of strings T: style What do we want Blackened code to look like? labels May 31, 2021
@felix-hilden
Copy link
Collaborator

I'm a bit ambivalent about this. First is the fact that we already increase PEP 8's line length from 79 to 88 by default. Then as an aside, if we did this I think it shouldn't apply to ordinary strings.

But let's have a look at what it would do. It's common to have docstrings indented at least two levels (class method), which including the quotations of a single-line docstring leaves 74 characters to write with an 88 line length, but only 58 with 72 chars. That's the difference between:

class Foo:
    def bar(self):
        """1234567890123456789012345678901234567890123456789012345678"""

    def baz(self):
        """12345678901234567890123456789012345678901234567890123456789012345678901234"""

which to me is significant especially when wanting to fit the docstring on one line. There is more room when the quotations are on separate lines though:

class Foo:
    def bar(self):
        """
        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
        incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
        nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
        Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
        fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
        culpa qui officia deserunt mollit anim id est laborum.
        """

    def baz(self):
        """
        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
        eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
        enim ad minim veniam, quis nostrud exercitation ullamco laboris
        nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
        reprehenderit in voluptate velit esse cillum dolore eu fugiat
        nulla pariatur. Excepteur sint occaecat cupidatat non proident,
        sunt inculpa qui officia deserunt mollit anim id est laborum.
        """

And I do appreciate the fact that it is easier on the eyes. So maybe there's something to be said about this! But let's be careful and consider the current processing and what adding this would mean. I for one can't see the whole picture yet.

@fpdotmonkey
Copy link
Author

Another thought is that according to PEP 257,

The docstring of a script (a stand-alone program) should be usable as its "usage" message, printed when the script is invoked with incorrect or missing arguments (or perhaps with a "-h" option, for "help").

Some common argument parsers like argparse (notably part of the standard library) format their help messages to be 79 characters wide, so it would seem there's a conflict caused by low adherence to this rule.

Anyway, for long running copy I think it's a big win. Maybe less so for short or structured text.

@felix-hilden
Copy link
Collaborator

This is also related to #1713 which aims to introduce comment splitting.

@MrAlexBailey
Copy link

MrAlexBailey commented Dec 10, 2021

I'm not totally sure about the impact of this, but figured it may be worth pointing out that these are technically different strings:

foo = """Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."""

bar = """Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
    eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
    ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
    aliquip ex ea commodo consequat. Duis aute irure dolor in
    reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
    pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
    culpa qui officia deserunt mollit anim id est laborum.
    """

# foo != bar

As with Black's current approach for other strings, they would need to be wrapped in parenthesis to remain equivalent:

bar = ("""Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do """
    """eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim """
    """ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut """
    """aliquip ex ea commodo consequat. Duis aute irure dolor in """
    """reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla """
    """pariatur. Excepteur sint occaecat cupidatat non proident, sunt in """
    """culpa qui officia deserunt mollit anim id est laborum."""
    )

# foo == bar

I can't imagine any scenarios where this would affect docstrings specifically, but in other places using triple quotes to surround long blocks of text, we wouldn't want Black changing the literal representation of the strings by adding whitespace to the start of each line.

@fpdotmonkey
Copy link
Author

Perhaps this issue should apply narrowly to docstrings since what gets rendered by sphinx et al is invariant with formatting

@JelleZijlstra
Copy link
Collaborator

Reflowing text in comments or docstrings is out of scope for Black. It is too difficult to do programmatically and consistently without producing ugly output.

We could apply a different line length limit for multi-line implicitly concatenated strings, but that's also problematic. We couldn't just use 72 everywhere, because line length is configurable. I don't want to add a new configuration option for this, or apply a heuristic like "normal line length - 16". Let's keep the current behavior of applying the same line length to all code.

@JelleZijlstra JelleZijlstra closed this as not planned Won't fix, can't repro, duplicate, stale Apr 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
F: comments The syntactic kind. Not in the language grammar, always on our minds. Best bugs. F: docstrings How we format docstrings F: strings Related to our handling of strings T: style What do we want Blackened code to look like?
Projects
None yet
Development

No branches or pull requests

4 participants