This question already has answers here:
Wrapping comments with line breaks in PyCharm
(5 answers)
Closed 1 year ago.
I use PyCharm Professional 2020.3 with Python 3.8. I want to unwrap automatically and then rewrap multiline comments and docstrings when I change the maximum line length. Is there a tool or add-in I can install to achieve this? If not, is there some other solution?
For example, say I have set my maximum line length to be 88 characters (the Black default). Then a multiline comment and docstring will wrap like this:
"""The summary line of a multi-line docstring should be automatically wrapped. That is to
say that its line break should be moved so that it complies with the required maximum
line length.
:param a_param: int, optional
This is an example parameter, which would exist if this was the docstring for a
function. It should also be automatically wrapped and indented. However, the line
breaks that separate the list of parameters/returned variables must not be removed
when formatted.
"""
# This is an example of a multiline comment that has been wrapped to the given maximum
# line length. Behold how it is both a comment and has been wrapped.
Then, say I set my maximum line width to 120 characters (the PyCharm default). I would then like my multiline comments and docstring to be reformatted like so:
"""The summary line of a multi-line docstring should be automatically wrapped. That is to say that its line break should
be moved so that it complies with the required maximum line length.
:param a_param: int, optional
This is an example parameter, which would exist if this was the docstring for a function. It should also be
automatically wrapped and indented. However, the line breaks that separate the list of parameters/returned variables
must not be removed when formatted.
"""
# This is an example of a multiline comment that has been wrapped to the given maximum line length. Behold how it is
# both a comment and has been wrapped.
Also, I am trying to implement my docstrings with the reStructured Text format. However, I'm still new to documentation in Python, so feel free to critique the above examples.
I believe you are looking for the "textwrap" module, which controls denting, dedenting, paragraph width, etc.
Related
As you know C language allows multiline comments between the symbols /* and */.
However, there is no such feature in Python. The closest thing is using triple quotes like:
"""
Multiline
Comment-alike
in Python
"""
which is not a true comment. Instead, we just define a string that is not assigned to a variable. I guess this takes some space in the final code unlike single line comments following # symbol.
Python is being updated regularly, and we occasionally end up with very original and innovative usage of syntax. My question is what makes adding block comments so difficult in Python by an update? Why no Python developer gets themselves bothered with it?
EDIT on if multiline comments take space in the final bytecode:
I have modified the same code to see if adding multiline comments affect the size of the final bytecode. py_compile module is used.
pkg.py:
#!/usr/bin/python
print("TEST")
pkg.py (comments added):
#!/usr/bin/python
print("TEST")
"""
Here is a multiline
comment to check
if it affects the
size of the final bytecode.
"""
The result is that the latter code (with the triple quote comment) is 117 bytes while the original one is 115 bytes. Obviously, the comment string is not fully included in the final bytecode. Still, we cannot say multiline comments in Python have no effect on the size of the final code.
Note that single line comments by the symbol # did not increase the size of the final bytecode at all.
I am struggling with multi line comments in Python, I understood I can use # at the start of every line of multi line comments but there is also another way of using """ at the start and end of the comment; however, in my interpreter the """ method gives an output instead of ignoring the comment.
>>> """this should
be a multi
line comment"""
And my interpreter gives the following output:
'this should\nbe a multi\nline comment'
Can someone explain it?
Triple quoted strings are used as comments by many developers but it is actually not a comment. It is similar to regular strings in python but it allows the string to be multi-line. You will find no official reference for triple quoted strings to be a comment.
In python, there is only one type of comment that starts with hash # and can contain only a single line of text.
According to PEP 257, it can however be used as a docstring, which is again not really a comment.
def foo():
"""
Developer friendly text for describing the purpose of function
Some test cases used by different unit testing libraries
"""
<body of the function>
You can just assign them to a variable as you do with single quoted strings:
x = """a multi-line text
enclosed by
triple quotes
"""
Furthermore, if you try it in a repl, triple quoted strings get printed, had it really been a comment, should it have been printed?:
>>> #comment
>>> """triple quoted"""
'triple quoted'
This is very easy to accomplish in python.
# This is a single-line comment
'''
This is a multi-line comment
'''
Just put the comments in ''' and put whatever you want inside of them!
What is the proper syntax for a hanging indent for a method with multiple parameters and type hinting?
Align under first parameter
def get_library_book(self,
book_id: str,
library_id: str
)-> Book:
Indent one level beneath
def get_library_book(
self,
book_id: str,
library_id: str
) -> Book:
PEP8 supports the Indent one level beneath case, but does not specify if Align under first parameter is allowed. It states:
When using a hanging indent the following should be considered; there
should be no arguments on the first line and further indentation
should be used to clearly distinguish itself as a continuation line.
PEP8 has many good ideas in it, but I wouldn't rely on it to decide this kind of question about whitespace. When I studied PEP8's recommendations on whitespace, I found them to be inconsistent and even contradictory.
Instead, I would look at general principles that apply to nearly all programming languages, not just Python.
The column alignment shown in the first example has many disadvantages, and I don't use or allow it in any of my projects.
Some of the disadvantages:
If you change the function name so its length is different, you must realign all of the parameters.
When you do that realignment, your source control diffs are cluttered with unnecessary whitespace changes.
As the code is updated and maintained, it's likely that you'll miss some of the alignment when renaming variables, leading to misaligned code.
You get much longer line lengths.
The alignment doesn't work in a proportional font. (Yes, some developers prefer proportional fonts, and if you avoid column alignment, your code will be equally readable in monospaced or proportional fonts.)
It gets even worse if you use column alignment in more complex cases. Consider this example:
let mut rewrites = try_opt!(subexpr_list.iter()
.rev()
.map(|e| {
rewrite_chain_expr(e,
total_span,
context,
max_width,
indent)
})
.collect::<Option<Vec<_>>>());
This is Rust code from the Servo browser, whose coding style mandates this kind of column alignment. While it isn't Python code, exactly the same principles apply in Python or nearly any language.
It should be apparent in this code sample how the use of column alignment leads to a bad situation. What if you needed to call another function, or had a longer variable name, inside that nested rewrite_chain_expr call? You're just about out of room unless you want very long lines.
Compare the above with either of these versions which use a purely indentation-based style like your second Python example:
let mut rewrites = try_opt!(
subexpr_list
.iter()
.rev()
.map( |e| {
rewrite_chain_expr( e, total_span, context, max_width, indent )
})
.collect::<Option<Vec<_>>>()
);
Or, if the parameters to rewrite_chain_expr were longer or if you just wanted shorter lines:
let mut rewrites = try_opt!(
subexpr_list
.iter()
.rev()
.map( |e| {
rewrite_chain_expr(
e,
total_span,
context,
max_width,
indent
)
})
.collect::<Option<Vec<_>>>()
);
In contrast to the column-aligned style, this pure indentation style has many advantages and no disadvantages at all.
Appart from Terrys answer, take an example from typeshed which is the project on Python's GitHub for annotating the stdlib with stubs.
For example, in importlib.machinery (and in other cases if you look) annotations are done using your first form, for example:
def find_module(cls, fullname: str,
path: Optional[Sequence[importlib.abc._Path]]
) -> Optional[importlib.abc.Loader]:
Read the previous line of PEP 8 more carefully, the part before "or using a hanging indent".
Continuation lines should align wrapped elements either vertically using Python's implicit line joining inside parentheses, brackets and braces, or using a hanging indent.
This is intended to cover the first "yes' example, and your first example above.
# Aligned with opening delimiter.
foo = long_function_name(var_one, var_two,
var_three, var_four)
my code contains this line, which is only a (big) integer initialization:
myvalue = 0xcc9e4307e00db722fc71e019c7c74c3cd23e056d0c7cb683b9e3c1549eee3d309a6106f819417701108b9424247cc5e97a8c963a4c493573ab12d890f221d495
When I run pep8 on the script, I get a E501 line too long.
What is the most convenient way to have my code pep8-compliant?
Integer literals can't be broken across multiple lines. Your options are, in order of preference:
Add a pragma telling the linter to ignore the line. PEP8 is a guideline, not a requirement.
Calculate the number from smaller parts.
Convert from a string using int('..', 16), where you break the string over multiple lines.
You should also consider moving the number out of your python code altogether; move it into a configuration file read at start-up, for example.
I can't find any PEP reference to this detail. There has to be a blank line after function definition?
Should I do this:
def hello_function():
return 'hello'
or shoud I do this:
def hello_function():
return 'hello'
The same question applies when docstrings are used:
this:
def hello_function():
"""
Important function
"""
return 'hello'
or this
def hello_function():
"""
Important function
"""
return 'hello'
EDIT
This is what the PEP says on the blank lines, as commented by FoxMaSk, but it does not say anything on this detail.
Blank Lines
Separate top-level function and class definitions with two blank
lines.
Method definitions inside a class are separated by a single blank
line.
Extra blank lines may be used (sparingly) to separate groups of
related functions. Blank lines may be omitted between a bunch of
related one-liners (e.g. a set of dummy implementations).
Use blank lines in functions, sparingly, to indicate logical sections.
Python accepts the control-L (i.e. ^L) form feed character as
whitespace; Many tools treat these characters as page separators, so
you may use them to separate pages of related sections of your file.
Note, some editors and web-based code viewers may not recognize
control-L as a form feed and will show another glyph in its place.
Read Docstring Conventions.
It says that even if the function is really obvious you have to write a one-line docstring. And it says that:
There's no blank line either before or after the docstring.
So I would code something like
def hello_function():
"""Return 'hello' string."""
return 'hello'
As pointed out by #moliware, the Docstring Conventions state, under One-line Docstrings:
There's no blank line either before or after the docstring.
HOWEVER, it also says (under Multi-line Docstrings):
Insert a blank line after all docstrings (one-line or multi-line) that document a class -- generally speaking, the class's methods are separated from each other by a single blank line, and the docstring needs to be offset from the first method by a blank line.
My interpretation of all this: blank lines should never precede any docstring, and should only follow a docstring when it is for a class.
Projects use different docstring conventions.
For example, the pandas docstring guide explicitly requires you to put triple quotes into a line of their own.
Docstrings must be defined with three double-quotes. No blank lines should be left before or after the docstring. The text starts in the next line after the opening quotes. The closing quotes have their own line (meaning that they are not at the end of the last sentence).
Making a python script simultaneously adhere to pydocstyle and pycodestyle is a challenge. But one thing which greatly helps is that in your docstring write the first line as summary of the function or class within 79 characters including ..This way you adhere to both PEP 257 (as per pydocstyle) of having a period at the end of an unbroken line and 79 characters limit of PEP 8 (as per pycodestyle).
Then after leaving one blank line (for that using new line shortcut of your coditor is better than manually pressing enter) you can write whatever you want and at that time focusing only on pycodestyle which is slightly easier than pydocstyle and the main reason is that our understanding of line and indentation is quite different than what system understands due to indentation settings, tab settings, line settings in the various code editors we use.So in this way you will have TODO from pycodestyle which you understand and can rectify instead of banging your head against the wall on pydocstyle TODOs.