Conversation
|
Current dependencies on/for this PR:
This comment was auto-generated by Graphite. |
There was a problem hiding this comment.
This test uses an indentation of 4 spaces and tab width of 8. We can't support this anymore but I think that's fine.
There was a problem hiding this comment.
It seems reasonable though hopefully we're not overlooking some valid usage. This is all inferred, right, so there's no way to GitHub Code Search to find users that might rely on this?
There was a problem hiding this comment.
Editorconfig doesn't support different visual width for tabs and indent. And I think that makes sense. You don't need a tab-width setting if you don't use tabs.
This particular test case applies only to unformatted code where black assumes a tab size of 8 for tabs in docstrings before normalizing the docstring indentation. This is only a heuristic and I think it probably works best anyway if the space indentation and tab indentation sizes match, because that's probably how you aligned your docstring before even if you happened to have mixed tabs and spaces.
f1e1320 to
df61da0
Compare
There was a problem hiding this comment.
These tests were off, probably because we now use best fitting for strings now. I verified manually that they don't exceed the line width for the configured indent width.
There was a problem hiding this comment.
It seems reasonable though hopefully we're not overlooking some valid usage. This is all inferred, right, so there's no way to GitHub Code Search to find users that might rely on this?
| fn count_indentation_like_black(line: &str, tab_width: TabWidth) -> TextSize { | ||
| /// with the exception that Ruff uses [`IndentWidth`] for the tab width. | ||
| fn count_indentation_like_black(line: &str, indent_width: IndentWidth) -> TextSize { | ||
| let mut indentation = TextSize::default(); | ||
| let indent_width = indent_width.value(); | ||
| for char in line.chars() { | ||
| if char == '\t' { | ||
| // Pad to the next multiple of tab_width | ||
| indentation += TextSize::from( | ||
| tab_width.value() - (indentation.to_u32().rem_euclid(tab_width.value())), | ||
| ); | ||
| indentation += |
There was a problem hiding this comment.
Both black and cpython itself have this hardcoded to 8, e.g.
print(inspect.cleandoc('''
def a():
"""doc line 1
doc line 2
\tdoc line 3
"""
'''))expands to
def a():
"""doc line 1
doc line 2
doc line 3
"""Given that this is a cpython choice, i don't think we should have an option to overwrite it.
There was a problem hiding this comment.
Thanks for bringing this up. I wasn't aware of this (although this PR doesn't change the configurable nature of tab width).
I think the reason why Black hardcoded this is simply because black doesn't support tab indentation and choosing the default tab size used by cpython seems a good choice.
Picking the configured indent-width still seems reasonable to me, except we foresee issues when using indent-style: tab with any tab-width value other than 8. For example, does it mean that the output of inspect.cleancode has incorrect indentation or is it okay for as long as all code uses tabs?
There was a problem hiding this comment.
I've tested the semantics:
source = '''
class A:
\tdef a():
\t\t"""doc line 1
\t\tdoc line 2
\t\t doc line 3
\t\t"""
def a():
\t"""doc line 1
\tdoc line 2
\t doc line 3
\t"""
class A2:
\tdef a():
\t\t"""doc line 1
\t\t\tdoc line 2
\t\t doc line 3
\t\t"""
def a2():
\t"""doc line 1
\t\tdoc line 2
\t doc line 3
\t"""
'''
exec(source)
docs = [A.a.__doc__, a.__doc__, A2.a.__doc__, a2.__doc__]
for doc in docs:
print(f"---\n{inspect.cleandoc(doc)}")prints
---
doc line 1
doc line 2
doc line 3
---
doc line 1
doc line 2
doc line 3
---
doc line 1
doc line 2
doc line 3
---
doc line 1
doc line 2
doc line 3
I've also checked that
source2 = '''
def f():
\tprint()
\tprint()
def f():
\t \t print()
\t \t print()
'''
exec(source2)passes. Python seems to not care about how you mix tabs and spaces as long as you're consistent.
Inside of docstrings, cleandoc doesn't mind inconsistent indentation and will just pad to multiples of 8:
source2 = '''
class A:
\tdef a():
\t\t"""doc line 1
\t \t doc line 2
\t \t doc line 3
\t\t"""
'''
exec(source2)
print(f"---\n{inspect.cleandoc(A.a.__doc__)}")My suggestion would be to special case count_indentation_like_black by hard code padding to 8 and converting to spaces in docstrings.
There was a problem hiding this comment.
Thanks for taking a closer look at this. I updated the PR to hardcode 8 for the normalization.
|
I like the general improvement, but unfortunately cpython gives us hardcoded precedence about tabs handling in docstrings |
866ee1e to
dc50532
Compare
dc50532 to
701968f
Compare

Summary
This PR introduces the new configuration
IndentWidththat specifies the visual width of a\tcharacter or the number of spaces of an indent when usingIndentStyle::Space.IndentWidthreplacesTabWidthand the count on theIndentStyle::Space(count)setting.The motivation for this change is to reduce the configuration options and align it with Prettier and editor config that both use a single width for the tab width and number of spaces in an indent.
Unifying the two settings makes sense in my view because both
\tand the number of spaces in an indentation are about the width of an indentation and they should use consistent values.The only downside of the change is that we no longer support the configuration used by black's
docstringtest where it uses 4-space indentation but a tab width of 8.Test Plan
cargo test.