normalize-comment-spacing puts one space between a comment's hash run and its text, and widens the gap before a trailing comment to at least two spaces, so x = 1 #note reads x = 1 # note and the delimiter looks the same on every line.
Whether the indentation inside a comment is deliberate depends on whether the comment stands in a column. A comment opening at the same column as the comment above or below it belongs to a block the author laid out, so every indent inside that block stays:
python
# options for the run:# --fast skip the checks# --slow run everything
A bare # continues such a block rather than ending it, since it opens at the same column, which keeps a spacer line from splitting one block into two. A comment sharing its column with nothing has no layout to keep, so a padded opener such as # note is reduced to the single space every other comment takes. A run opening on any whitespace other than a space is reduced either way, a lone tab included, since no author indents a block with one.
The space goes after the whole hash run rather than shortening it, so a ## or #### heading keeps its hashes as the section marker it was written as. space-statements reads the same form when it treats a comment block as a divider rather than a description of the statement below. A run with no text after it is a divider rather than an opener, so a line of hashes alone passes through unchanged, and a comment carrying whitespace and no text drops that whitespace down to a bare #. Where the run is followed by !, :, ', or |, the opener passes through untouched, covering the shebang line and Sphinx's #: attribute doc alongside the quoted and piped forms. A trailing comment with such an opener still moves out to the two-space gap, because the exemption covers what a comment opens with rather than where it sits.
Two spaces is the minimum gap before a trailing comment rather than the target, so a wider gap stays as written and a comment column the author laid out is still there for align-comments to read. The gap is counted in characters, so a lone tab falls short and is replaced with two spaces.
x = 1 carries a trailing #note one space after the code, and a full-line #tidy this sits below it. Both comments gain the space after their #, and the trailing one moves two columns clear of x = 1, so every comment opens on the same # and the eye reads the delimiter once rather than re-parsing it per line.
x = 1 # note# tidy this
python
Three option comments listing --fast and --slow open at one column on consecutive lines, and the comment trailing value = 1 opens with a padded # already. The block keeps every indent inside it and the trailing opener closes to a single space, because the block is a layout the author wrote across consecutive lines, whereas the trailing comment shares a column with nothing.
# options for the run:# --fast skip the checks# --slow run everythingvalue = 1 # already clear of the code
python
##notes, ### Section, and ####deeper open on runs of two, three, and four hashes. ##notes becomes ## notes and ####deeper becomes #### deeper, because the space is inserted after the whole hash run rather than the run being reduced to one #, so each line survives as the section marker it was written as. ### Section already carries its space and is left as written.
The one-space opener and the two-space minimum are both fixed, so the rule carries enabled as its only facet. A comment that has to keep its own spacing takes an inline Suppression directive rather than a project-level key, since the exception is per-comment rather than per-project.
x = 1 carries a trailing #note one space after the code, and a full-line #tidy this sits below it. Both comments gain the space after their #, and the trailing one moves two columns clear of x = 1, so every comment opens on the same # and the eye reads the delimiter once rather than re-parsing it per line.
Three option comments listing --fast and --slow open at one column on consecutive lines, and the comment trailing value = 1 opens with a padded # already. The block keeps every indent inside it and the trailing opener closes to a single space, because the block is a layout the author wrote across consecutive lines, whereas the trailing comment shares a column with nothing.
The comment on value = 1 opens with no whitespace between the 1 and the #. Two spaces are inserted before the #, the minimum gap before a trailing comment, and because the # right opener already carries its single space that insertion is the only edit the comment takes.
call( opens a multi-line call and carries # note on the opener one space after the bracket. The single space widens to two, because the two-space minimum applies wherever a comment trails code, an open bracket included. strip-stranded-padding exempts the gap in that position so the comment never fuses onto the bracket, leaving this rule to set its width.
The dividers ##### and ########## are runs of hashes with nothing after them, and #---- Section ---- draws its rule from dashes after a single #. The two bare hash runs are left as written and the dashed line gains a space after its #, because text follows the hash on the dashed line and nothing follows it on the other two.
##notes, ### Section, and ####deeper open on runs of two, three, and four hashes. ##notes becomes ## notes and ####deeper becomes #### deeper, because the space is inserted after the whole hash run rather than the run being reduced to one #, so each line survives as the section marker it was written as. ### Section already carries its space and is left as written.
A full-line block listing --fast and --slow sits above warm() and a_name_that_is_far_longer_here(), each of which carries a # opener padded to five spaces. The block keeps every indent inside it and each trailing opener closes to a single space, even though the two trailing comments share a column with each other, because the block is a layout the author wrote whereas a trailing hash sits wherever its code ends, with align-comments the rule that moves it afterwards.
value = 1 carries a Sphinx attribute doc opening on #: one space after the code. The #: opener stays as written and the gap before it widens to two spaces, because the exemption covers what the comment opens with rather than where the comment sits.
BeforeAfter
No Change
value = 1 and other = 22 each carry a trailing comment with a wide gap before it, and the two comments already share a column. Both gaps are left as written, because two columns is the minimum rather than the target, so the column they share stays in place for an alignment rule to read rather than being flattened before one can.
BeforeAfter
No Change
Four full-line comments open on #!, #:, #', and #|, covering the #!/usr/bin/env python shebang, a #:sphinx attribute doc, and the #'quoted and #|piped forms. Every line is left as written with no space inserted, because a # followed by !, :, ', or | carries meaning to a downstream tool, and a full-line comment carries no gap before the hash to set either.
_handlers carries a trailing comment written #map of ..., tight against the hash, above _handlerList, and normalize-comment-spacing later writes one space after the #. _handlers and _handlerList stay unaligned, because align-equals counts that space before it sets its column and a shared column would carry the _handlers row past the 79-column budget, whereas _ok and _status below pad onto one column as usual.
normalize-comment-spacing
normalize-comment-spacing puts one space between a comment's hash run and its text, and widens the gap before a trailing comment to at least two spaces, so
x = 1 #notereadsx = 1 # noteand the delimiter looks the same on every line.Whether the indentation inside a comment is deliberate depends on whether the comment stands in a column. A comment opening at the same column as the comment above or below it belongs to a block the author laid out, so every indent inside that block stays:
A bare
#continues such a block rather than ending it, since it opens at the same column, which keeps a spacer line from splitting one block into two. A comment sharing its column with nothing has no layout to keep, so a padded opener such as# noteis reduced to the single space every other comment takes. A run opening on any whitespace other than a space is reduced either way, a lone tab included, since no author indents a block with one.The space goes after the whole hash run rather than shortening it, so a
##or####heading keeps its hashes as the section marker it was written as. space-statements reads the same form when it treats a comment block as a divider rather than a description of the statement below. A run with no text after it is a divider rather than an opener, so a line of hashes alone passes through unchanged, and a comment carrying whitespace and no text drops that whitespace down to a bare#. Where the run is followed by!,:,', or|, the opener passes through untouched, covering the shebang line and Sphinx's#:attribute doc alongside the quoted and piped forms. A trailing comment with such an opener still moves out to the two-space gap, because the exemption covers what a comment opens with rather than where it sits.Two spaces is the minimum gap before a trailing comment rather than the target, so a wider gap stays as written and a comment column the author laid out is still there for align-comments to read. The gap is counted in characters, so a lone tab falls short and is replaced with two spaces.
x = 1carries a trailing#noteone space after the code, and a full-line#tidy thissits below it. Both comments gain the space after their#, and the trailing one moves two columns clear ofx = 1, so every comment opens on the same#and the eye reads the delimiter once rather than re-parsing it per line.Three option comments listing
--fastand--slowopen at one column on consecutive lines, and the comment trailingvalue = 1opens with a padded# already. The block keeps every indent inside it and the trailing opener closes to a single space, because the block is a layout the author wrote across consecutive lines, whereas the trailing comment shares a column with nothing.##notes,### Section, and####deeperopen on runs of two, three, and four hashes.##notesbecomes## notesand####deeperbecomes#### deeper, because the space is inserted after the whole hash run rather than the run being reduced to one#, so each line survives as the section marker it was written as.### Sectionalready carries its space and is left as written.Configuration
enabledtrueThe one-space opener and the two-space minimum are both fixed, so the rule carries
enabledas its only facet. A comment that has to keep its own spacing takes an inline Suppression directive rather than a project-level key, since the exception is per-comment rather than per-project.The Canonical Case
x = 1carries a trailing#noteone space after the code, and a full-line#tidy thissits below it. Both comments gain the space after their#, and the trailing one moves two columns clear ofx = 1, so every comment opens on the same#and the eye reads the delimiter once rather than re-parsing it per line.More Examples
Three option comments listing
--fastand--slowopen at one column on consecutive lines, and the comment trailingvalue = 1opens with a padded# already. The block keeps every indent inside it and the trailing opener closes to a single space, because the block is a layout the author wrote across consecutive lines, whereas the trailing comment shares a column with nothing.The comment on
value = 1opens with no whitespace between the1and the#. Two spaces are inserted before the#, the minimum gap before a trailing comment, and because the# rightopener already carries its single space that insertion is the only edit the comment takes.call(opens a multi-line call and carries# note on the openerone space after the bracket. The single space widens to two, because the two-space minimum applies wherever a comment trails code, an open bracket included. strip-stranded-padding exempts the gap in that position so the comment never fuses onto the bracket, leaving this rule to set its width.The dividers
#####and##########are runs of hashes with nothing after them, and#---- Section ----draws its rule from dashes after a single#. The two bare hash runs are left as written and the dashed line gains a space after its#, because text follows the hash on the dashed line and nothing follows it on the other two.##notes,### Section, and####deeperopen on runs of two, three, and four hashes.##notesbecomes## notesand####deeperbecomes#### deeper, because the space is inserted after the whole hash run rather than the run being reduced to one#, so each line survives as the section marker it was written as.### Sectionalready carries its space and is left as written.A full-line block listing
--fastand--slowsits abovewarm()anda_name_that_is_far_longer_here(), each of which carries a#opener padded to five spaces. The block keeps every indent inside it and each trailing opener closes to a single space, even though the two trailing comments share a column with each other, because the block is a layout the author wrote whereas a trailing hash sits wherever its code ends, with align-comments the rule that moves it afterwards.value = 1carries a Sphinx attribute doc opening on#:one space after the code. The#:opener stays as written and the gap before it widens to two spaces, because the exemption covers what the comment opens with rather than where the comment sits.value = 1andother = 22each carry a trailing comment with a wide gap before it, and the two comments already share a column. Both gaps are left as written, because two columns is the minimum rather than the target, so the column they share stays in place for an alignment rule to read rather than being flattened before one can.Four full-line comments open on
#!,#:,#', and#|, covering the#!/usr/bin/env pythonshebang, a#:sphinxattribute doc, and the#'quotedand#|pipedforms. Every line is left as written with no space inserted, because a#followed by!,:,', or|carries meaning to a downstream tool, and a full-line comment carries no gap before the hash to set either._handlerscarries a trailing comment written#map of ..., tight against the hash, above_handlerList, and normalize-comment-spacing later writes one space after the#._handlersand_handlerListstay unaligned, because align-equals counts that space before it sets its column and a shared column would carry the_handlersrow past the 79-column budget, whereas_okand_statusbelow pad onto one column as usual.Related
align-comments
AlignmentPads the gap before each trailing comment in a run so every
#sits at one shared column.space-statements
FormattingSets the blank-line count between module-level definitions, class members, import groups, and the
__main__guard to PEP 8's canonical values.step-narration
LintReports an own-line comment that narrates a numbered step.
line-overflow
LintReports a line still over its line budget once no layout rule can shorten it.