Compare commits

..

8 Commits

Author SHA1 Message Date
konstin
8d54302e05 Import cases dir from black tests 2023-11-10 13:45:30 +01:00
Charlie Marsh
036b6bc0bd Document context manager breaking deviation vs. Black (#8597)
Closes https://github.com/astral-sh/ruff/issues/8180.
Closes https://github.com/astral-sh/ruff/issues/8580.
Closes https://github.com/astral-sh/ruff/issues/7441.
2023-11-10 04:32:29 +00:00
Dhruv Manilawala
d5606b7705 Consider the new f-string tokens for flake8-commas (#8582)
## Summary

This fixes the bug where the `flake8-commas` rules weren't taking the
new f-string tokens into account.

## Test Plan

Add new test cases around f-strings for all of `flake8-commas`'s rules.

fixes: #8556
2023-11-10 09:49:14 +05:30
Charlie Marsh
7968e190dd Write unchanged, excluded files to stdout when read via stdin (#8596)
## Summary

When you run Ruff via stdin, and pass `format` or `check --fix`, we
typically write the changed or unchanged contents to stdout. It turns
out we forgot to do this when the file is _excluded_, so if you run
`ruff format /path/to/excluded/file.py`, we don't write _anything_ to
`stdout`. This led to a bug in the LSP whereby we deleted file contents
for third-party files.

The right thing to do here is write back the unchanged contents, as it
should always be safe to write the output of stdout back to a file.
2023-11-09 23:15:01 -05:00
Charlie Marsh
346a828db2 Add a BindingKind for WithItem variables (#8594) 2023-11-09 22:44:49 -05:00
Charlie Marsh
0ac124acef Make unpacked assignment a flag rather than a BindingKind (#8595)
## Summary

An assignment can be _both_ (e.g.) a loop variable _and_ assigned via
unpacking. In other words, unpacking is a quality of an assignment, not
a _kind_.
2023-11-09 21:41:30 -05:00
Adrian
4ebd0bd31e Support local and dynamic class- and static-method decorators (#8592)
## Summary

This brings ruff's behavior in line with what `pep8-naming` already does
and thus closes #8397.

I had initially implemented this to look at the last segment of a dotted
path only when the entry in the `*-decorators` setting started with a
`.`, but in the end I thought it's better to remain consistent w/
`pep8-naming` and doing a match against the last segment of the
decorator name in any case.

If you prefer to diverge from this in favor of less ambiguity in the
configuration let me know and I'll change it so you would need to put
e.g. `.expression` in the `classmethod-decorators` list.

## Test Plan

Tested against the file in the issue linked below, plus the new testcase
added in this PR.
2023-11-10 02:04:25 +00:00
Zanie Blue
565ddebb15 Improve detection of TYPE_CHECKING blocks imported from typing_extensions or _typeshed (#8429)
~Improves detection of types imported from `typing_extensions`. Removes
the hard-coded list of supported types in `typing_extensions`; instead
assuming all types could be imported from `typing`, `_typeshed`, or
`typing_extensions`.~

~The typing extensions package appears to re-export types even if they
do not need modification.~


Adds detection of `if typing_extensions.TYPE_CHECKING` blocks. Avoids
inserting a new `if TYPE_CHECKING` block and `from typing import
TYPE_CHECKING` if `typing_extensions.TYPE_CHECKING` is used (closes
https://github.com/astral-sh/ruff/issues/8427)

---------

Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
2023-11-09 12:21:03 -06:00
427 changed files with 44065 additions and 143 deletions

View File

@@ -8,7 +8,7 @@ use ruff_workspace::resolver::{match_exclusion, python_file_at_path, PyprojectCo
use crate::args::CliOverrides;
use crate::diagnostics::{lint_stdin, Diagnostics};
use crate::stdin::read_from_stdin;
use crate::stdin::{parrot_stdin, read_from_stdin};
/// Run the linter over a single file, read from `stdin`.
pub(crate) fn check_stdin(
@@ -21,6 +21,9 @@ pub(crate) fn check_stdin(
if pyproject_config.settings.file_resolver.force_exclude {
if let Some(filename) = filename {
if !python_file_at_path(filename, pyproject_config, overrides)? {
if fix_mode.is_apply() {
parrot_stdin()?;
}
return Ok(Diagnostics::default());
}
@@ -29,14 +32,17 @@ pub(crate) fn check_stdin(
.file_name()
.is_some_and(|name| match_exclusion(filename, name, &lint_settings.exclude))
{
if fix_mode.is_apply() {
parrot_stdin()?;
}
return Ok(Diagnostics::default());
}
}
}
let stdin = read_from_stdin()?;
let package_root = filename.and_then(Path::parent).and_then(|path| {
packaging::detect_package_root(path, &pyproject_config.settings.linter.namespace_packages)
});
let stdin = read_from_stdin()?;
let mut diagnostics = lint_stdin(
filename,
package_root,

View File

@@ -15,7 +15,7 @@ use crate::commands::format::{
FormatResult, FormattedSource,
};
use crate::resolve::resolve;
use crate::stdin::read_from_stdin;
use crate::stdin::{parrot_stdin, read_from_stdin};
use crate::ExitStatus;
/// Run the formatter over a single file, read from `stdin`.
@@ -34,6 +34,9 @@ pub(crate) fn format_stdin(cli: &FormatArguments, overrides: &CliOverrides) -> R
if pyproject_config.settings.file_resolver.force_exclude {
if let Some(filename) = cli.stdin_filename.as_deref() {
if !python_file_at_path(filename, &pyproject_config, overrides)? {
if mode.is_write() {
parrot_stdin()?;
}
return Ok(ExitStatus::Success);
}
@@ -42,6 +45,9 @@ pub(crate) fn format_stdin(cli: &FormatArguments, overrides: &CliOverrides) -> R
.file_name()
.is_some_and(|name| match_exclusion(filename, name, &format_settings.exclude))
{
if mode.is_write() {
parrot_stdin()?;
}
return Ok(ExitStatus::Success);
}
}
@@ -50,6 +56,9 @@ pub(crate) fn format_stdin(cli: &FormatArguments, overrides: &CliOverrides) -> R
let path = cli.stdin_filename.as_deref();
let SourceType::Python(source_type) = path.map(SourceType::from).unwrap_or_default() else {
if mode.is_write() {
parrot_stdin()?;
}
return Ok(ExitStatus::Success);
};

View File

@@ -1,5 +1,5 @@
use std::io;
use std::io::Read;
use std::io::{Read, Write};
/// Read a string from `stdin`.
pub(crate) fn read_from_stdin() -> Result<String, io::Error> {
@@ -7,3 +7,11 @@ pub(crate) fn read_from_stdin() -> Result<String, io::Error> {
io::stdin().lock().read_to_string(&mut buffer)?;
Ok(buffer)
}
/// Read bytes from `stdin` and write them to `stdout`.
pub(crate) fn parrot_stdin() -> Result<(), io::Error> {
let mut buffer = String::new();
io::stdin().lock().read_to_string(&mut buffer)?;
io::stdout().write_all(buffer.as_bytes())?;
Ok(())
}

View File

@@ -320,6 +320,11 @@ if __name__ == '__main__':
exit_code: 0
----- stdout -----
from test import say_hy
if __name__ == '__main__':
say_hy("dear Ruff contributor")
----- stderr -----
"###);
Ok(())

View File

@@ -639,3 +639,18 @@ foo = namedtuple(
:20
],
)
# F-strings
kwargs.pop("remove", f"this {trailing_comma}",)
raise Exception(
"first", extra=f"Add trailing comma here ->"
)
assert False, f"<- This is not a trailing comma"
f"""This is a test. {
"Another sentence."
if True else
"Don't add a trailing comma here ->"
}"""

View File

@@ -172,3 +172,14 @@ def f():
from module import Member
x: Member = 1
def f():
from typing_extensions import TYPE_CHECKING
from pandas import y
if TYPE_CHECKING:
_type = x
elif True:
_type = y

View File

@@ -0,0 +1,10 @@
from __future__ import annotations
from typing_extensions import TYPE_CHECKING
if TYPE_CHECKING:
from pandas import DataFrame
def example() -> DataFrame:
pass

View File

@@ -0,0 +1,10 @@
from __future__ import annotations
from typing_extensions import TYPE_CHECKING
if TYPE_CHECKING:
from pandas import DataFrame
def example() -> DataFrame:
x = DataFrame()

View File

@@ -37,3 +37,9 @@ if False:
if 0:
x: List
from typing_extensions import TYPE_CHECKING
if TYPE_CHECKING:
pass # TCH005

View File

@@ -0,0 +1,9 @@
from __future__ import annotations
from typing_extensions import Self
def func():
from pandas import DataFrame
df: DataFrame

View File

@@ -0,0 +1,9 @@
from __future__ import annotations
import typing_extensions
def func():
from pandas import DataFrame
df: DataFrame

View File

@@ -63,3 +63,33 @@ class PosOnlyClass:
def bad_method_pos_only(this, blah, /, self, something: str):
pass
class ModelClass:
@hybrid_property
def bad(cls):
pass
@bad.expression
def bad(self):
pass
@bad.wtf
def bad(cls):
pass
@hybrid_property
def good(self):
pass
@good.expression
def good(cls):
pass
@good.wtf
def good(self):
pass
@foobar.thisisstatic
def badstatic(foo):
pass

View File

@@ -1615,38 +1615,28 @@ impl<'a> Checker<'a> {
fn handle_node_store(&mut self, id: &'a str, expr: &Expr) {
let parent = self.semantic.current_statement();
let mut flags = BindingFlags::empty();
if helpers::is_unpacking_assignment(parent, expr) {
flags.insert(BindingFlags::UNPACKED_ASSIGNMENT);
}
// Match the left-hand side of an annotated assignment, like `x` in `x: int`.
if matches!(
parent,
Stmt::AnnAssign(ast::StmtAnnAssign { value: None, .. })
) && !self.semantic.in_annotation()
{
self.add_binding(
id,
expr.range(),
BindingKind::Annotation,
BindingFlags::empty(),
);
self.add_binding(id, expr.range(), BindingKind::Annotation, flags);
return;
}
if parent.is_for_stmt() {
self.add_binding(
id,
expr.range(),
BindingKind::LoopVar,
BindingFlags::empty(),
);
self.add_binding(id, expr.range(), BindingKind::LoopVar, flags);
return;
}
if helpers::is_unpacking_assignment(parent, expr) {
self.add_binding(
id,
expr.range(),
BindingKind::UnpackedAssignment,
BindingFlags::empty(),
);
if parent.is_with_stmt() {
self.add_binding(id, expr.range(), BindingKind::WithItemVar, flags);
return;
}
@@ -1681,7 +1671,6 @@ impl<'a> Checker<'a> {
let (all_names, all_flags) =
extract_all_names(parent, |name| self.semantic.is_builtin(name));
let mut flags = BindingFlags::empty();
if all_flags.intersects(DunderAllFlags::INVALID_OBJECT) {
flags |= BindingFlags::INVALID_ALL_OBJECT;
}
@@ -1705,21 +1694,11 @@ impl<'a> Checker<'a> {
.current_expressions()
.any(Expr::is_named_expr_expr)
{
self.add_binding(
id,
expr.range(),
BindingKind::NamedExprAssignment,
BindingFlags::empty(),
);
self.add_binding(id, expr.range(), BindingKind::NamedExprAssignment, flags);
return;
}
self.add_binding(
id,
expr.range(),
BindingKind::Assignment,
BindingFlags::empty(),
);
self.add_binding(id, expr.range(), BindingKind::Assignment, flags);
}
fn handle_node_delete(&mut self, expr: &'a Expr) {

View File

@@ -141,7 +141,7 @@ pub(crate) fn check_tokens(
Rule::TrailingCommaOnBareTuple,
Rule::ProhibitedTrailingComma,
]) {
flake8_commas::rules::trailing_commas(&mut diagnostics, tokens, locator);
flake8_commas::rules::trailing_commas(&mut diagnostics, tokens, locator, indexer);
}
if settings.rules.enabled(Rule::ExtraneousParentheses) {

View File

@@ -132,11 +132,7 @@ impl<'a> Importer<'a> {
)?;
// Import the `TYPE_CHECKING` symbol from the typing module.
let (type_checking_edit, type_checking) = self.get_or_import_symbol(
&ImportRequest::import_from("typing", "TYPE_CHECKING"),
at,
semantic,
)?;
let (type_checking_edit, type_checking) = self.get_or_import_type_checking(at, semantic)?;
// Add the import to a `TYPE_CHECKING` block.
let add_import_edit = if let Some(block) = self.preceding_type_checking_block(at) {
@@ -161,6 +157,30 @@ impl<'a> Importer<'a> {
})
}
/// Generate an [`Edit`] to reference `typing.TYPE_CHECKING`. Returns the [`Edit`] necessary to
/// make the symbol available in the current scope along with the bound name of the symbol.
fn get_or_import_type_checking(
&self,
at: TextSize,
semantic: &SemanticModel,
) -> Result<(Edit, String), ResolutionError> {
for module in semantic.typing_modules() {
if let Some((edit, name)) = self.get_symbol(
&ImportRequest::import_from(module, "TYPE_CHECKING"),
at,
semantic,
)? {
return Ok((edit, name));
}
}
self.import_symbol(
&ImportRequest::import_from("typing", "TYPE_CHECKING"),
at,
semantic,
)
}
/// Generate an [`Edit`] to reference the given symbol. Returns the [`Edit`] necessary to make
/// the symbol available in the current scope along with the bound name of the symbol.
///

View File

@@ -245,10 +245,10 @@ impl Renamer {
| BindingKind::Argument
| BindingKind::TypeParam
| BindingKind::NamedExprAssignment
| BindingKind::UnpackedAssignment
| BindingKind::Assignment
| BindingKind::BoundException
| BindingKind::LoopVar
| BindingKind::WithItemVar
| BindingKind::Global
| BindingKind::Nonlocal(_)
| BindingKind::ClassDefinition(_)

View File

@@ -3,6 +3,7 @@ use itertools::Itertools;
use ruff_diagnostics::{AlwaysFixableViolation, Violation};
use ruff_diagnostics::{Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_index::Indexer;
use ruff_python_parser::lexer::{LexResult, Spanned};
use ruff_python_parser::Tok;
use ruff_source_file::Locator;
@@ -29,22 +30,33 @@ enum TokenType {
/// Simplified token specialized for the task.
#[derive(Copy, Clone)]
struct Token<'tok> {
type_: TokenType,
// Underlying token.
spanned: Option<&'tok Spanned>,
struct Token {
r#type: TokenType,
range: TextRange,
}
impl<'tok> Token<'tok> {
const fn irrelevant() -> Token<'static> {
Token {
type_: TokenType::Irrelevant,
spanned: None,
}
impl Ranged for Token {
fn range(&self) -> TextRange {
self.range
}
}
impl Token {
fn new(r#type: TokenType, range: TextRange) -> Self {
Self { r#type, range }
}
const fn from_spanned(spanned: &'tok Spanned) -> Token<'tok> {
let type_ = match &spanned.0 {
fn irrelevant() -> Token {
Token {
r#type: TokenType::Irrelevant,
range: TextRange::default(),
}
}
}
impl From<&Spanned> for Token {
fn from(spanned: &Spanned) -> Self {
let r#type = match &spanned.0 {
Tok::NonLogicalNewline => TokenType::NonLogicalNewline,
Tok::Newline => TokenType::Newline,
Tok::For => TokenType::For,
@@ -63,8 +75,8 @@ impl<'tok> Token<'tok> {
_ => TokenType::Irrelevant,
};
Self {
spanned: Some(spanned),
type_,
range: spanned.1,
r#type,
}
}
}
@@ -92,14 +104,14 @@ enum ContextType {
/// Comma context - described a comma-delimited "situation".
#[derive(Copy, Clone)]
struct Context {
type_: ContextType,
r#type: ContextType,
num_commas: u32,
}
impl Context {
const fn new(type_: ContextType) -> Self {
const fn new(r#type: ContextType) -> Self {
Self {
type_,
r#type,
num_commas: 0,
}
}
@@ -222,21 +234,49 @@ pub(crate) fn trailing_commas(
diagnostics: &mut Vec<Diagnostic>,
tokens: &[LexResult],
locator: &Locator,
indexer: &Indexer,
) {
let mut fstrings = 0u32;
let tokens = tokens
.iter()
.flatten()
// Completely ignore comments -- they just interfere with the logic.
.filter(|&r| !matches!(r, (Tok::Comment(_), _)))
.map(Token::from_spanned);
.filter_map(|spanned @ (tok, tok_range)| match tok {
// Completely ignore comments -- they just interfere with the logic.
Tok::Comment(_) => None,
// F-strings are handled as `String` token type with the complete range
// of the outermost f-string. This means that the expression inside the
// f-string is not checked for trailing commas.
Tok::FStringStart => {
fstrings = fstrings.saturating_add(1);
None
}
Tok::FStringEnd => {
fstrings = fstrings.saturating_sub(1);
if fstrings == 0 {
indexer
.fstring_ranges()
.outermost(tok_range.start())
.map(|range| Token::new(TokenType::String, range))
} else {
None
}
}
_ => {
if fstrings == 0 {
Some(Token::from(spanned))
} else {
None
}
}
});
let tokens = [Token::irrelevant(), Token::irrelevant()]
.into_iter()
.chain(tokens);
// Collapse consecutive newlines to the first one -- trailing commas are
// added before the first newline.
let tokens = tokens.coalesce(|previous, current| {
if previous.type_ == TokenType::NonLogicalNewline
&& current.type_ == TokenType::NonLogicalNewline
if previous.r#type == TokenType::NonLogicalNewline
&& current.r#type == TokenType::NonLogicalNewline
{
Ok(previous)
} else {
@@ -249,8 +289,8 @@ pub(crate) fn trailing_commas(
for (prev_prev, prev, token) in tokens.tuple_windows() {
// Update the comma context stack.
match token.type_ {
TokenType::OpeningBracket => match (prev.type_, prev_prev.type_) {
match token.r#type {
TokenType::OpeningBracket => match (prev.r#type, prev_prev.r#type) {
(TokenType::Named, TokenType::Def) => {
stack.push(Context::new(ContextType::FunctionParameters));
}
@@ -261,7 +301,7 @@ pub(crate) fn trailing_commas(
stack.push(Context::new(ContextType::Tuple));
}
},
TokenType::OpeningSquareBracket => match prev.type_ {
TokenType::OpeningSquareBracket => match prev.r#type {
TokenType::ClosingBracket | TokenType::Named | TokenType::String => {
stack.push(Context::new(ContextType::Subscript));
}
@@ -288,8 +328,8 @@ pub(crate) fn trailing_commas(
let context = &stack[stack.len() - 1];
// Is it allowed to have a trailing comma before this token?
let comma_allowed = token.type_ == TokenType::ClosingBracket
&& match context.type_ {
let comma_allowed = token.r#type == TokenType::ClosingBracket
&& match context.r#type {
ContextType::No => false,
ContextType::FunctionParameters => true,
ContextType::CallArguments => true,
@@ -304,22 +344,21 @@ pub(crate) fn trailing_commas(
};
// Is prev a prohibited trailing comma?
let comma_prohibited = prev.type_ == TokenType::Comma && {
let comma_prohibited = prev.r#type == TokenType::Comma && {
// Is `(1,)` or `x[1,]`?
let is_singleton_tuplish =
matches!(context.type_, ContextType::Subscript | ContextType::Tuple)
matches!(context.r#type, ContextType::Subscript | ContextType::Tuple)
&& context.num_commas <= 1;
// There was no non-logical newline, so prohibit (except in `(1,)` or `x[1,]`).
if comma_allowed && !is_singleton_tuplish {
true
// Lambdas not handled by comma_allowed so handle it specially.
} else {
context.type_ == ContextType::LambdaParameters && token.type_ == TokenType::Colon
context.r#type == ContextType::LambdaParameters && token.r#type == TokenType::Colon
}
};
if comma_prohibited {
let comma = prev.spanned.unwrap();
let mut diagnostic = Diagnostic::new(ProhibitedTrailingComma, comma.1);
let mut diagnostic = Diagnostic::new(ProhibitedTrailingComma, prev.range());
diagnostic.set_fix(Fix::safe_edit(Edit::range_deletion(diagnostic.range())));
diagnostics.push(diagnostic);
}
@@ -327,10 +366,9 @@ pub(crate) fn trailing_commas(
// Is prev a prohibited trailing comma on a bare tuple?
// Approximation: any comma followed by a statement-ending newline.
let bare_comma_prohibited =
prev.type_ == TokenType::Comma && token.type_ == TokenType::Newline;
prev.r#type == TokenType::Comma && token.r#type == TokenType::Newline;
if bare_comma_prohibited {
let comma = prev.spanned.unwrap();
diagnostics.push(Diagnostic::new(TrailingCommaOnBareTuple, comma.1));
diagnostics.push(Diagnostic::new(TrailingCommaOnBareTuple, prev.range()));
}
// Comma is required if:
@@ -339,40 +377,37 @@ pub(crate) fn trailing_commas(
// - Not already present,
// - Not on an empty (), {}, [].
let comma_required = comma_allowed
&& prev.type_ == TokenType::NonLogicalNewline
&& prev.r#type == TokenType::NonLogicalNewline
&& !matches!(
prev_prev.type_,
prev_prev.r#type,
TokenType::Comma
| TokenType::OpeningBracket
| TokenType::OpeningSquareBracket
| TokenType::OpeningCurlyBracket
);
if comma_required {
let missing_comma = prev_prev.spanned.unwrap();
let mut diagnostic = Diagnostic::new(
MissingTrailingComma,
TextRange::empty(missing_comma.1.end()),
);
let mut diagnostic =
Diagnostic::new(MissingTrailingComma, TextRange::empty(prev_prev.end()));
// Create a replacement that includes the final bracket (or other token),
// rather than just inserting a comma at the end. This prevents the UP034 fix
// removing any brackets in the same linter pass - doing both at the same time could
// lead to a syntax error.
let contents = locator.slice(missing_comma.1);
let contents = locator.slice(prev_prev.range());
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
format!("{contents},"),
missing_comma.1,
prev_prev.range(),
)));
diagnostics.push(diagnostic);
}
// Pop the current context if the current token ended it.
// The top context is never popped (if unbalanced closing brackets).
let pop_context = match context.type_ {
let pop_context = match context.r#type {
// Lambda terminated by `:`.
ContextType::LambdaParameters => token.type_ == TokenType::Colon,
ContextType::LambdaParameters => token.r#type == TokenType::Colon,
// All others terminated by a closing bracket.
// flake8-commas doesn't verify that it matches the opening...
_ => token.type_ == TokenType::ClosingBracket,
_ => token.r#type == TokenType::ClosingBracket,
};
if pop_context && stack.len() > 1 {
stack.pop();

View File

@@ -939,4 +939,43 @@ COM81.py:632:42: COM812 [*] Trailing comma missing
634 634 |
635 635 | foo = namedtuple(
COM81.py:644:46: COM819 [*] Trailing comma prohibited
|
643 | # F-strings
644 | kwargs.pop("remove", f"this {trailing_comma}",)
| ^ COM819
645 |
646 | raise Exception(
|
= help: Remove trailing comma
Safe fix
641 641 | )
642 642 |
643 643 | # F-strings
644 |-kwargs.pop("remove", f"this {trailing_comma}",)
644 |+kwargs.pop("remove", f"this {trailing_comma}")
645 645 |
646 646 | raise Exception(
647 647 | "first", extra=f"Add trailing comma here ->"
COM81.py:647:49: COM812 [*] Trailing comma missing
|
646 | raise Exception(
647 | "first", extra=f"Add trailing comma here ->"
| COM812
648 | )
|
= help: Add trailing comma
Safe fix
644 644 | kwargs.pop("remove", f"this {trailing_comma}",)
645 645 |
646 646 | raise Exception(
647 |- "first", extra=f"Add trailing comma here ->"
647 |+ "first", extra=f"Add trailing comma here ->",
648 648 | )
649 649 |
650 650 | assert False, f"<- This is not a trailing comma"

View File

@@ -23,6 +23,8 @@ mod tests {
#[test_case(Rule::RuntimeImportInTypeCheckingBlock, Path::new("TCH004_13.py"))]
#[test_case(Rule::RuntimeImportInTypeCheckingBlock, Path::new("TCH004_14.pyi"))]
#[test_case(Rule::RuntimeImportInTypeCheckingBlock, Path::new("TCH004_15.py"))]
#[test_case(Rule::RuntimeImportInTypeCheckingBlock, Path::new("TCH004_16.py"))]
#[test_case(Rule::RuntimeImportInTypeCheckingBlock, Path::new("TCH004_17.py"))]
#[test_case(Rule::RuntimeImportInTypeCheckingBlock, Path::new("TCH004_2.py"))]
#[test_case(Rule::RuntimeImportInTypeCheckingBlock, Path::new("TCH004_3.py"))]
#[test_case(Rule::RuntimeImportInTypeCheckingBlock, Path::new("TCH004_4.py"))]
@@ -36,6 +38,8 @@ mod tests {
#[test_case(Rule::TypingOnlyStandardLibraryImport, Path::new("snapshot.py"))]
#[test_case(Rule::TypingOnlyThirdPartyImport, Path::new("TCH002.py"))]
#[test_case(Rule::TypingOnlyThirdPartyImport, Path::new("strict.py"))]
#[test_case(Rule::TypingOnlyThirdPartyImport, Path::new("typing_modules_1.py"))]
#[test_case(Rule::TypingOnlyThirdPartyImport, Path::new("typing_modules_2.py"))]
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", rule_code.as_ref(), path.to_string_lossy());
let diagnostics = test_path(

View File

@@ -96,4 +96,19 @@ TCH005.py:22:9: TCH005 [*] Found empty type-checking block
24 22 |
25 23 |
TCH005.py:45:5: TCH005 [*] Found empty type-checking block
|
44 | if TYPE_CHECKING:
45 | pass # TCH005
| ^^^^ TCH005
|
= help: Delete empty type-checking block
Safe fix
41 41 |
42 42 | from typing_extensions import TYPE_CHECKING
43 43 |
44 |-if TYPE_CHECKING:
45 |- pass # TCH005

View File

@@ -0,0 +1,4 @@
---
source: crates/ruff_linter/src/rules/flake8_type_checking/mod.rs
---

View File

@@ -0,0 +1,25 @@
---
source: crates/ruff_linter/src/rules/flake8_type_checking/mod.rs
---
TCH004_17.py:6:24: TCH004 [*] Move import `pandas.DataFrame` out of type-checking block. Import is used for more than type hinting.
|
5 | if TYPE_CHECKING:
6 | from pandas import DataFrame
| ^^^^^^^^^ TCH004
|
= help: Move out of type-checking block
Unsafe fix
1 1 | from __future__ import annotations
2 2 |
3 3 | from typing_extensions import TYPE_CHECKING
4 |+from pandas import DataFrame
4 5 |
5 6 | if TYPE_CHECKING:
6 |- from pandas import DataFrame
7 |+ pass
7 8 |
8 9 |
9 10 | def example() -> DataFrame:

View File

@@ -248,5 +248,6 @@ TCH002.py:172:24: TCH002 [*] Move third-party import `module.Member` into a type
172 |- from module import Member
173 176 |
174 177 | x: Member = 1
175 178 |

View File

@@ -0,0 +1,29 @@
---
source: crates/ruff_linter/src/rules/flake8_type_checking/mod.rs
---
typing_modules_1.py:7:24: TCH002 [*] Move third-party import `pandas.DataFrame` into a type-checking block
|
6 | def func():
7 | from pandas import DataFrame
| ^^^^^^^^^ TCH002
8 |
9 | df: DataFrame
|
= help: Move into type-checking block
Unsafe fix
1 1 | from __future__ import annotations
2 2 |
3 3 | from typing_extensions import Self
4 |+from typing import TYPE_CHECKING
5 |+
6 |+if TYPE_CHECKING:
7 |+ from pandas import DataFrame
4 8 |
5 9 |
6 10 | def func():
7 |- from pandas import DataFrame
8 11 |
9 12 | df: DataFrame

View File

@@ -0,0 +1,27 @@
---
source: crates/ruff_linter/src/rules/flake8_type_checking/mod.rs
---
typing_modules_2.py:7:24: TCH002 [*] Move third-party import `pandas.DataFrame` into a type-checking block
|
6 | def func():
7 | from pandas import DataFrame
| ^^^^^^^^^ TCH002
8 |
9 | df: DataFrame
|
= help: Move into type-checking block
Unsafe fix
2 2 |
3 3 | import typing_extensions
4 4 |
5 |+if typing_extensions.TYPE_CHECKING:
6 |+ from pandas import DataFrame
7 |+
5 8 |
6 9 | def func():
7 |- from pandas import DataFrame
8 10 |
9 11 | df: DataFrame

View File

@@ -46,7 +46,6 @@ pub(super) fn test_expression(expr: &Expr, semantic: &SemanticModel) -> Resoluti
BindingKind::Annotation
| BindingKind::Assignment
| BindingKind::NamedExprAssignment
| BindingKind::UnpackedAssignment
| BindingKind::LoopVar
| BindingKind::Global
| BindingKind::Nonlocal(_) => Resolution::RelevantLocal,

View File

@@ -96,6 +96,26 @@ mod tests {
classmethod_decorators: vec![
"classmethod".to_string(),
"pydantic.validator".to_string(),
"expression".to_string(),
],
..Default::default()
},
..settings::LinterSettings::for_rule(Rule::InvalidFirstArgumentNameForMethod)
},
)?;
assert_messages!(diagnostics);
Ok(())
}
#[test]
fn staticmethod_decorators() -> Result<()> {
let diagnostics = test_path(
Path::new("pep8_naming").join("N805.py").as_path(),
&settings::LinterSettings {
pep8_naming: pep8_naming::settings::Settings {
staticmethod_decorators: vec![
"staticmethod".to_string(),
"thisisstatic".to_string(),
],
..Default::default()
},

View File

@@ -43,4 +43,37 @@ N805.py:64:29: N805 First argument of a method should be named `self`
65 | pass
|
N805.py:70:13: N805 First argument of a method should be named `self`
|
68 | class ModelClass:
69 | @hybrid_property
70 | def bad(cls):
| ^^^ N805
71 | pass
|
N805.py:78:13: N805 First argument of a method should be named `self`
|
77 | @bad.wtf
78 | def bad(cls):
| ^^^ N805
79 | pass
|
N805.py:86:14: N805 First argument of a method should be named `self`
|
85 | @good.expression
86 | def good(cls):
| ^^^ N805
87 | pass
|
N805.py:94:19: N805 First argument of a method should be named `self`
|
93 | @foobar.thisisstatic
94 | def badstatic(foo):
| ^^^ N805
95 | pass
|

View File

@@ -27,4 +27,29 @@ N805.py:64:29: N805 First argument of a method should be named `self`
65 | pass
|
N805.py:70:13: N805 First argument of a method should be named `self`
|
68 | class ModelClass:
69 | @hybrid_property
70 | def bad(cls):
| ^^^ N805
71 | pass
|
N805.py:78:13: N805 First argument of a method should be named `self`
|
77 | @bad.wtf
78 | def bad(cls):
| ^^^ N805
79 | pass
|
N805.py:94:19: N805 First argument of a method should be named `self`
|
93 | @foobar.thisisstatic
94 | def badstatic(foo):
| ^^^ N805
95 | pass
|

View File

@@ -0,0 +1,71 @@
---
source: crates/ruff_linter/src/rules/pep8_naming/mod.rs
---
N805.py:7:20: N805 First argument of a method should be named `self`
|
6 | class Class:
7 | def bad_method(this):
| ^^^^ N805
8 | pass
|
N805.py:12:30: N805 First argument of a method should be named `self`
|
10 | if False:
11 |
12 | def extra_bad_method(this):
| ^^^^ N805
13 | pass
|
N805.py:31:15: N805 First argument of a method should be named `self`
|
30 | @pydantic.validator
31 | def lower(cls, my_field: str) -> str:
| ^^^ N805
32 | pass
|
N805.py:35:15: N805 First argument of a method should be named `self`
|
34 | @pydantic.validator("my_field")
35 | def lower(cls, my_field: str) -> str:
| ^^^ N805
36 | pass
|
N805.py:64:29: N805 First argument of a method should be named `self`
|
62 | pass
63 |
64 | def bad_method_pos_only(this, blah, /, self, something: str):
| ^^^^ N805
65 | pass
|
N805.py:70:13: N805 First argument of a method should be named `self`
|
68 | class ModelClass:
69 | @hybrid_property
70 | def bad(cls):
| ^^^ N805
71 | pass
|
N805.py:78:13: N805 First argument of a method should be named `self`
|
77 | @bad.wtf
78 | def bad(cls):
| ^^^ N805
79 | pass
|
N805.py:86:14: N805 First argument of a method should be named `self`
|
85 | @good.expression
86 | def good(cls):
| ^^^ N805
87 | pass
|

View File

@@ -324,8 +324,9 @@ pub(crate) fn unused_variable(checker: &Checker, scope: &Scope, diagnostics: &mu
.filter_map(|(name, binding)| {
if (binding.kind.is_assignment()
|| binding.kind.is_named_expr_assignment()
|| (matches!(checker.settings.preview, PreviewMode::Enabled)
&& binding.kind.is_unpacked_assignment()))
|| binding.kind.is_with_item_var())
&& (!binding.is_unpacked_assignment()
|| matches!(checker.settings.preview, PreviewMode::Enabled))
&& !binding.is_nonlocal()
&& !binding.is_global()
&& !binding.is_used()

View File

@@ -49,10 +49,10 @@ pub(crate) fn non_ascii_name(binding: &Binding, locator: &Locator) -> Option<Dia
BindingKind::Annotation => Kind::Annotation,
BindingKind::Argument => Kind::Argument,
BindingKind::NamedExprAssignment => Kind::NamedExprAssignment,
BindingKind::UnpackedAssignment => Kind::UnpackedAssignment,
BindingKind::Assignment => Kind::Assignment,
BindingKind::TypeParam => Kind::TypeParam,
BindingKind::LoopVar => Kind::LoopVar,
BindingKind::WithItemVar => Kind::WithItemVar,
BindingKind::Global => Kind::Global,
BindingKind::Nonlocal(_) => Kind::Nonlocal,
BindingKind::ClassDefinition(_) => Kind::ClassDefinition,
@@ -85,10 +85,10 @@ enum Kind {
Annotation,
Argument,
NamedExprAssignment,
UnpackedAssignment,
Assignment,
TypeParam,
LoopVar,
WithItemVar,
Global,
Nonlocal,
ClassDefinition,
@@ -102,10 +102,10 @@ impl fmt::Display for Kind {
Kind::Annotation => f.write_str("Annotation"),
Kind::Argument => f.write_str("Argument"),
Kind::NamedExprAssignment => f.write_str("Variable"),
Kind::UnpackedAssignment => f.write_str("Variable"),
Kind::Assignment => f.write_str("Variable"),
Kind::TypeParam => f.write_str("Type parameter"),
Kind::LoopVar => f.write_str("Variable"),
Kind::WithItemVar => f.write_str("Variable"),
Kind::Global => f.write_str("Global"),
Kind::Nonlocal => f.write_str("Nonlocal"),
Kind::ClassDefinition => f.write_str("Class"),

View File

@@ -0,0 +1,22 @@
x = 123456789 .bit_count()
x = (123456).__abs__()
x = .1.is_integer()
x = 1. .imag
x = 1E+1.imag
x = 1E-1.real
x = 123456789.123456789.hex()
x = 123456789.123456789E123456789 .real
x = 123456789E123456789 .conjugate()
x = 123456789J.real
x = 123456789.123456789J.__add__(0b1011.bit_length())
x = 0XB1ACC.conjugate()
x = 0B1011 .conjugate()
x = 0O777 .real
x = 0.000000006 .hex()
x = -100.0000J
if 10 .real:
...
y = 100[no]
y = 100(no)

View File

@@ -0,0 +1,22 @@
x = (123456789).bit_count()
x = (123456).__abs__()
x = (0.1).is_integer()
x = (1.0).imag
x = (1e1).imag
x = (1e-1).real
x = (123456789.123456789).hex()
x = (123456789.123456789e123456789).real
x = (123456789e123456789).conjugate()
x = 123456789j.real
x = 123456789.123456789j.__add__(0b1011.bit_length())
x = 0xB1ACC.conjugate()
x = 0b1011.conjugate()
x = 0o777.real
x = (0.000000006).hex()
x = -100.0000j
if (10).real:
...
y = 100[no]
y = 100(no)

View File

@@ -0,0 +1,7 @@
\
print("hello, world")

View File

@@ -0,0 +1 @@
print("hello, world")

View File

@@ -0,0 +1,6 @@
for ((x in {}) or {})['a'] in x:
pass
pem_spam = lambda l, spam = {
"x": 3
}: not spam.get(l.strip())
lambda x=lambda y={1: 3}: y['x':lambda y: {1: 2}]: x

View File

@@ -0,0 +1,4 @@
for ((x in {}) or {})["a"] in x:
pass
pem_spam = lambda l, spam={"x": 3}: not spam.get(l.strip())
lambda x=lambda y={1: 3}: y["x" : lambda y: {1: 2}]: x

View File

@@ -0,0 +1,14 @@
def bitey():
b" not a docstring"
def bitey2():
b' also not a docstring'
def triple_quoted_bytes():
b""" not a docstring"""
def triple_quoted_bytes2():
b''' also not a docstring'''
def capitalized_bytes():
B" NOT A DOCSTRING"

View File

@@ -0,0 +1,18 @@
def bitey():
b" not a docstring"
def bitey2():
b" also not a docstring"
def triple_quoted_bytes():
b""" not a docstring"""
def triple_quoted_bytes2():
b""" also not a docstring"""
def capitalized_bytes():
b" NOT A DOCSTRING"

View File

@@ -0,0 +1,23 @@
class SimpleClassWithBlankParentheses():
pass
class ClassWithSpaceParentheses ( ):
first_test_data = 90
second_test_data = 100
def test_func(self):
return None
class ClassWithEmptyFunc(object):
def func_with_blank_parentheses():
return 5
def public_func_with_blank_parentheses():
return None
def class_under_the_func_with_blank_parentheses():
class InsideFunc():
pass
class NormalClass (
):
def func_for_testing(self, first, second):
sum = first + second
return sum

View File

@@ -0,0 +1,30 @@
class SimpleClassWithBlankParentheses:
pass
class ClassWithSpaceParentheses:
first_test_data = 90
second_test_data = 100
def test_func(self):
return None
class ClassWithEmptyFunc(object):
def func_with_blank_parentheses():
return 5
def public_func_with_blank_parentheses():
return None
def class_under_the_func_with_blank_parentheses():
class InsideFunc:
pass
class NormalClass:
def func_for_testing(self, first, second):
sum = first + second
return sum

View File

@@ -0,0 +1,100 @@
class ClassSimplest:
pass
class ClassWithSingleField:
a = 1
class ClassWithJustTheDocstring:
"""Just a docstring."""
class ClassWithInit:
def __init__(self):
pass
class ClassWithTheDocstringAndInit:
"""Just a docstring."""
def __init__(self):
pass
class ClassWithInitAndVars:
cls_var = 100
def __init__(self):
pass
class ClassWithInitAndVarsAndDocstring:
"""Test class"""
cls_var = 100
def __init__(self):
pass
class ClassWithDecoInit:
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVars:
cls_var = 100
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVarsAndDocstring:
"""Test class"""
cls_var = 100
@deco
def __init__(self):
pass
class ClassSimplestWithInner:
class Inner:
pass
class ClassSimplestWithInnerWithDocstring:
class Inner:
"""Just a docstring."""
def __init__(self):
pass
class ClassWithSingleFieldWithInner:
a = 1
class Inner:
pass
class ClassWithJustTheDocstringWithInner:
"""Just a docstring."""
class Inner:
pass
class ClassWithInitWithInner:
class Inner:
pass
def __init__(self):
pass
class ClassWithInitAndVarsWithInner:
cls_var = 100
class Inner:
pass
def __init__(self):
pass
class ClassWithInitAndVarsAndDocstringWithInner:
"""Test class"""
cls_var = 100
class Inner:
pass
def __init__(self):
pass
class ClassWithDecoInitWithInner:
class Inner:
pass
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVarsWithInner:
cls_var = 100
class Inner:
pass
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVarsAndDocstringWithInner:
"""Test class"""
cls_var = 100
class Inner:
pass
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVarsAndDocstringWithInner2:
"""Test class"""
class Inner:
pass
cls_var = 100
@deco
def __init__(self):
pass

View File

@@ -0,0 +1,165 @@
class ClassSimplest:
pass
class ClassWithSingleField:
a = 1
class ClassWithJustTheDocstring:
"""Just a docstring."""
class ClassWithInit:
def __init__(self):
pass
class ClassWithTheDocstringAndInit:
"""Just a docstring."""
def __init__(self):
pass
class ClassWithInitAndVars:
cls_var = 100
def __init__(self):
pass
class ClassWithInitAndVarsAndDocstring:
"""Test class"""
cls_var = 100
def __init__(self):
pass
class ClassWithDecoInit:
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVars:
cls_var = 100
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVarsAndDocstring:
"""Test class"""
cls_var = 100
@deco
def __init__(self):
pass
class ClassSimplestWithInner:
class Inner:
pass
class ClassSimplestWithInnerWithDocstring:
class Inner:
"""Just a docstring."""
def __init__(self):
pass
class ClassWithSingleFieldWithInner:
a = 1
class Inner:
pass
class ClassWithJustTheDocstringWithInner:
"""Just a docstring."""
class Inner:
pass
class ClassWithInitWithInner:
class Inner:
pass
def __init__(self):
pass
class ClassWithInitAndVarsWithInner:
cls_var = 100
class Inner:
pass
def __init__(self):
pass
class ClassWithInitAndVarsAndDocstringWithInner:
"""Test class"""
cls_var = 100
class Inner:
pass
def __init__(self):
pass
class ClassWithDecoInitWithInner:
class Inner:
pass
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVarsWithInner:
cls_var = 100
class Inner:
pass
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVarsAndDocstringWithInner:
"""Test class"""
cls_var = 100
class Inner:
pass
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVarsAndDocstringWithInner2:
"""Test class"""
class Inner:
pass
cls_var = 100
@deco
def __init__(self):
pass

View File

@@ -0,0 +1,71 @@
import core, time, a
from . import A, B, C
# keeps existing trailing comma
from foo import (
bar,
)
# also keeps existing structure
from foo import (
baz,
qux,
)
# `as` works as well
from foo import (
xyzzy as magic,
)
a = {1,2,3,}
b = {
1,2,
3}
c = {
1,
2,
3,
}
x = 1,
y = narf(),
nested = {(1,2,3),(4,5,6),}
nested_no_trailing_comma = {(1,2,3),(4,5,6)}
nested_long_lines = ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "cccccccccccccccccccccccccccccccccccccccc", (1, 2, 3), "dddddddddddddddddddddddddddddddddddddddd"]
{"oneple": (1,),}
{"oneple": (1,)}
['ls', 'lsoneple/%s' % (foo,)]
x = {"oneple": (1,)}
y = {"oneple": (1,),}
assert False, ("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa wraps %s" % bar)
# looping over a 1-tuple should also not get wrapped
for x in (1,):
pass
for (x,) in (1,), (2,), (3,):
pass
[1, 2, 3,]
division_result_tuple = (6/2,)
print("foo %r", (foo.bar,))
if True:
IGNORED_TYPES_FOR_ATTRIBUTE_CHECKING = (
Config.IGNORED_TYPES_FOR_ATTRIBUTE_CHECKING
| {pylons.controllers.WSGIController}
)
if True:
ec2client.get_waiter('instance_stopped').wait(
InstanceIds=[instance.id],
WaiterConfig={
'Delay': 5,
})
ec2client.get_waiter("instance_stopped").wait(
InstanceIds=[instance.id],
WaiterConfig={"Delay": 5,},
)
ec2client.get_waiter("instance_stopped").wait(
InstanceIds=[instance.id], WaiterConfig={"Delay": 5,},
)

View File

@@ -0,0 +1,99 @@
import core, time, a
from . import A, B, C
# keeps existing trailing comma
from foo import (
bar,
)
# also keeps existing structure
from foo import (
baz,
qux,
)
# `as` works as well
from foo import (
xyzzy as magic,
)
a = {
1,
2,
3,
}
b = {1, 2, 3}
c = {
1,
2,
3,
}
x = (1,)
y = (narf(),)
nested = {
(1, 2, 3),
(4, 5, 6),
}
nested_no_trailing_comma = {(1, 2, 3), (4, 5, 6)}
nested_long_lines = [
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"cccccccccccccccccccccccccccccccccccccccc",
(1, 2, 3),
"dddddddddddddddddddddddddddddddddddddddd",
]
{
"oneple": (1,),
}
{"oneple": (1,)}
["ls", "lsoneple/%s" % (foo,)]
x = {"oneple": (1,)}
y = {
"oneple": (1,),
}
assert False, (
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa wraps %s"
% bar
)
# looping over a 1-tuple should also not get wrapped
for x in (1,):
pass
for (x,) in (1,), (2,), (3,):
pass
[
1,
2,
3,
]
division_result_tuple = (6 / 2,)
print("foo %r", (foo.bar,))
if True:
IGNORED_TYPES_FOR_ATTRIBUTE_CHECKING = (
Config.IGNORED_TYPES_FOR_ATTRIBUTE_CHECKING
| {pylons.controllers.WSGIController}
)
if True:
ec2client.get_waiter("instance_stopped").wait(
InstanceIds=[instance.id],
WaiterConfig={
"Delay": 5,
},
)
ec2client.get_waiter("instance_stopped").wait(
InstanceIds=[instance.id],
WaiterConfig={
"Delay": 5,
},
)
ec2client.get_waiter("instance_stopped").wait(
InstanceIds=[instance.id],
WaiterConfig={
"Delay": 5,
},
)

View File

@@ -0,0 +1,9 @@
def bob(): \
# pylint: disable=W9016
pass
def bobtwo(): \
\
# some comment here
pass

View File

@@ -0,0 +1,6 @@
def bob(): # pylint: disable=W9016
pass
def bobtwo(): # some comment here
pass

View File

@@ -0,0 +1,96 @@
#!/usr/bin/env python3
# fmt: on
# Some license here.
#
# Has many lines. Many, many lines.
# Many, many, many lines.
"""Module docstring.
Possibly also many, many lines.
"""
import os.path
import sys
import a
from b.c import X # some noqa comment
try:
import fast
except ImportError:
import slow as fast
# Some comment before a function.
y = 1
(
# some strings
y # type: ignore
)
def function(default=None):
"""Docstring comes first.
Possibly many lines.
"""
# FIXME: Some comment about why this function is crap but still in production.
import inner_imports
if inner_imports.are_evil():
# Explains why we have this if.
# In great detail indeed.
x = X()
return x.method1() # type: ignore
# This return is also commented for some reason.
return default
# Explains why we use global state.
GLOBAL_STATE = {"a": a(1), "b": a(2), "c": a(3)}
# Another comment!
# This time two lines.
class Foo:
"""Docstring for class Foo. Example from Sphinx docs."""
#: Doc comment for class attribute Foo.bar.
#: It can have multiple lines.
bar = 1
flox = 1.5 #: Doc comment for Foo.flox. One line only.
baz = 2
"""Docstring for class attribute Foo.baz."""
def __init__(self):
#: Doc comment for instance attribute qux.
self.qux = 3
self.spam = 4
"""Docstring for instance attribute spam."""
#' <h1>This is pweave!</h1>
@fast(really=True)
async def wat():
# This comment, for some reason \
# contains a trailing backslash.
async with X.open_async() as x: # Some more comments
result = await x.method1()
# Comment after ending a block.
if result:
print("A OK", file=sys.stdout)
# Comment between things.
print()
# Some closing comments.
# Maybe Vim or Emacs directives for formatting.
# Who knows.

View File

@@ -0,0 +1,96 @@
#!/usr/bin/env python3
# fmt: on
# Some license here.
#
# Has many lines. Many, many lines.
# Many, many, many lines.
"""Module docstring.
Possibly also many, many lines.
"""
import os.path
import sys
import a
from b.c import X # some noqa comment
try:
import fast
except ImportError:
import slow as fast
# Some comment before a function.
y = 1
(
# some strings
y # type: ignore
)
def function(default=None):
"""Docstring comes first.
Possibly many lines.
"""
# FIXME: Some comment about why this function is crap but still in production.
import inner_imports
if inner_imports.are_evil():
# Explains why we have this if.
# In great detail indeed.
x = X()
return x.method1() # type: ignore
# This return is also commented for some reason.
return default
# Explains why we use global state.
GLOBAL_STATE = {"a": a(1), "b": a(2), "c": a(3)}
# Another comment!
# This time two lines.
class Foo:
"""Docstring for class Foo. Example from Sphinx docs."""
#: Doc comment for class attribute Foo.bar.
#: It can have multiple lines.
bar = 1
flox = 1.5 #: Doc comment for Foo.flox. One line only.
baz = 2
"""Docstring for class attribute Foo.baz."""
def __init__(self):
#: Doc comment for instance attribute qux.
self.qux = 3
self.spam = 4
"""Docstring for instance attribute spam."""
#' <h1>This is pweave!</h1>
@fast(really=True)
async def wat():
# This comment, for some reason \
# contains a trailing backslash.
async with X.open_async() as x: # Some more comments
result = await x.method1()
# Comment after ending a block.
if result:
print("A OK", file=sys.stdout)
# Comment between things.
print()
# Some closing comments.
# Maybe Vim or Emacs directives for formatting.
# Who knows.

View File

@@ -0,0 +1,168 @@
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
MyLovelyCompanyTeamProjectComponent # NOT DRY
)
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
MyLovelyCompanyTeamProjectComponent as component # DRY
)
# Please keep __all__ alphabetized within each category.
__all__ = [
# Super-special typing primitives.
'Any',
'Callable',
'ClassVar',
# ABCs (from collections.abc).
'AbstractSet', # collections.abc.Set.
'ByteString',
'Container',
# Concrete collection types.
'Counter',
'Deque',
'Dict',
'DefaultDict',
'List',
'Set',
'FrozenSet',
'NamedTuple', # Not really a type.
'Generator',
]
not_shareables = [
# singletons
True,
False,
NotImplemented, ...,
# builtin types and objects
type,
object,
object(),
Exception(),
42,
100.0,
"spam",
# user-defined types and objects
Cheese,
Cheese("Wensleydale"),
SubBytes(b"spam"),
]
if 'PYTHON' in os.environ:
add_compiler(compiler_from_env())
else:
# for compiler in compilers.values():
# add_compiler(compiler)
add_compiler(compilers[(7.0, 32)])
# add_compiler(compilers[(7.1, 64)])
# Comment before function.
def inline_comments_in_brackets_ruin_everything():
if typedargslist:
parameters.children = [
children[0], # (1
body,
children[-1] # )1
]
parameters.children = [
children[0],
body,
children[-1], # type: ignore
]
else:
parameters.children = [
parameters.children[0], # (2 what if this was actually long
body,
parameters.children[-1], # )2
]
parameters.children = [parameters.what_if_this_was_actually_long.children[0], body, parameters.children[-1]] # type: ignore
if (self._proc is not None
# has the child process finished?
and self._returncode is None
# the child process has finished, but the
# transport hasn't been notified yet?
and self._proc.poll() is None):
pass
# no newline before or after
short = [
# one
1,
# two
2]
# no newline after
call(arg1, arg2, """
short
""", arg3=True)
############################################################################
call2(
#short
arg1,
#but
arg2,
#multiline
"""
short
""",
# yup
arg3=True)
lcomp = [
element # yup
for element in collection # yup
if element is not None # right
]
lcomp2 = [
# hello
element
# yup
for element in collection
# right
if element is not None
]
lcomp3 = [
# This one is actually too long to fit in a single line.
element.split('\n', 1)[0]
# yup
for element in collection.select_elements()
# right
if element is not None
]
while True:
if False:
continue
# and round and round we go
# and round and round we go
# let's return
return Node(
syms.simple_stmt,
[
Node(statement, result),
Leaf(token.NEWLINE, '\n') # FIXME: \r\n?
],
)
CONFIG_FILES = [CONFIG_FILE, ] + SHARED_CONFIG_FILES + USER_CONFIG_FILES # type: Final
class Test:
def _init_host(self, parsed) -> None:
if (parsed.hostname is None or # type: ignore
not parsed.hostname.strip()):
pass
a = "type comment with trailing space" # type: str
#######################
### SECTION COMMENT ###
#######################
instruction()#comment with bad spacing
# END COMMENTS
# MORE END COMMENTS

View File

@@ -0,0 +1,175 @@
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
MyLovelyCompanyTeamProjectComponent, # NOT DRY
)
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
MyLovelyCompanyTeamProjectComponent as component, # DRY
)
# Please keep __all__ alphabetized within each category.
__all__ = [
# Super-special typing primitives.
"Any",
"Callable",
"ClassVar",
# ABCs (from collections.abc).
"AbstractSet", # collections.abc.Set.
"ByteString",
"Container",
# Concrete collection types.
"Counter",
"Deque",
"Dict",
"DefaultDict",
"List",
"Set",
"FrozenSet",
"NamedTuple", # Not really a type.
"Generator",
]
not_shareables = [
# singletons
True,
False,
NotImplemented,
...,
# builtin types and objects
type,
object,
object(),
Exception(),
42,
100.0,
"spam",
# user-defined types and objects
Cheese,
Cheese("Wensleydale"),
SubBytes(b"spam"),
]
if "PYTHON" in os.environ:
add_compiler(compiler_from_env())
else:
# for compiler in compilers.values():
# add_compiler(compiler)
add_compiler(compilers[(7.0, 32)])
# add_compiler(compilers[(7.1, 64)])
# Comment before function.
def inline_comments_in_brackets_ruin_everything():
if typedargslist:
parameters.children = [children[0], body, children[-1]] # (1 # )1
parameters.children = [
children[0],
body,
children[-1], # type: ignore
]
else:
parameters.children = [
parameters.children[0], # (2 what if this was actually long
body,
parameters.children[-1], # )2
]
parameters.children = [parameters.what_if_this_was_actually_long.children[0], body, parameters.children[-1]] # type: ignore
if (
self._proc is not None
# has the child process finished?
and self._returncode is None
# the child process has finished, but the
# transport hasn't been notified yet?
and self._proc.poll() is None
):
pass
# no newline before or after
short = [
# one
1,
# two
2,
]
# no newline after
call(
arg1,
arg2,
"""
short
""",
arg3=True,
)
############################################################################
call2(
# short
arg1,
# but
arg2,
# multiline
"""
short
""",
# yup
arg3=True,
)
lcomp = [
element for element in collection if element is not None # yup # yup # right
]
lcomp2 = [
# hello
element
# yup
for element in collection
# right
if element is not None
]
lcomp3 = [
# This one is actually too long to fit in a single line.
element.split("\n", 1)[0]
# yup
for element in collection.select_elements()
# right
if element is not None
]
while True:
if False:
continue
# and round and round we go
# and round and round we go
# let's return
return Node(
syms.simple_stmt,
[Node(statement, result), Leaf(token.NEWLINE, "\n")], # FIXME: \r\n?
)
CONFIG_FILES = (
[
CONFIG_FILE,
]
+ SHARED_CONFIG_FILES
+ USER_CONFIG_FILES
) # type: Final
class Test:
def _init_host(self, parsed) -> None:
if parsed.hostname is None or not parsed.hostname.strip(): # type: ignore
pass
a = "type comment with trailing space" # type: str
#######################
### SECTION COMMENT ###
#######################
instruction() # comment with bad spacing
# END COMMENTS
# MORE END COMMENTS

View File

@@ -0,0 +1,48 @@
# The percent-percent comments are Spyder IDE cells.
# %%
def func():
x = """
a really long string
"""
lcomp3 = [
# This one is actually too long to fit in a single line.
element.split("\n", 1)[0]
# yup
for element in collection.select_elements()
# right
if element is not None
]
# Capture each of the exceptions in the MultiError along with each of their causes and contexts
if isinstance(exc_value, MultiError):
embedded = []
for exc in exc_value.exceptions:
if exc not in _seen:
embedded.append(
# This should be left alone (before)
traceback.TracebackException.from_exception(
exc,
limit=limit,
lookup_lines=lookup_lines,
capture_locals=capture_locals,
# copy the set of _seen exceptions so that duplicates
# shared between sub-exceptions are not omitted
_seen=set(_seen),
)
# This should be left alone (after)
)
# everything is fine if the expression isn't nested
traceback.TracebackException.from_exception(
exc,
limit=limit,
lookup_lines=lookup_lines,
capture_locals=capture_locals,
# copy the set of _seen exceptions so that duplicates
# shared between sub-exceptions are not omitted
_seen=set(_seen),
)
# %%

View File

@@ -0,0 +1,48 @@
# The percent-percent comments are Spyder IDE cells.
# %%
def func():
x = """
a really long string
"""
lcomp3 = [
# This one is actually too long to fit in a single line.
element.split("\n", 1)[0]
# yup
for element in collection.select_elements()
# right
if element is not None
]
# Capture each of the exceptions in the MultiError along with each of their causes and contexts
if isinstance(exc_value, MultiError):
embedded = []
for exc in exc_value.exceptions:
if exc not in _seen:
embedded.append(
# This should be left alone (before)
traceback.TracebackException.from_exception(
exc,
limit=limit,
lookup_lines=lookup_lines,
capture_locals=capture_locals,
# copy the set of _seen exceptions so that duplicates
# shared between sub-exceptions are not omitted
_seen=set(_seen),
)
# This should be left alone (after)
)
# everything is fine if the expression isn't nested
traceback.TracebackException.from_exception(
exc,
limit=limit,
lookup_lines=lookup_lines,
capture_locals=capture_locals,
# copy the set of _seen exceptions so that duplicates
# shared between sub-exceptions are not omitted
_seen=set(_seen),
)
# %%

View File

@@ -0,0 +1,94 @@
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
MyLovelyCompanyTeamProjectComponent, # NOT DRY
)
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
MyLovelyCompanyTeamProjectComponent as component, # DRY
)
class C:
@pytest.mark.parametrize(
("post_data", "message"),
[
# metadata_version errors.
(
{},
"None is an invalid value for Metadata-Version. Error: This field is"
" required. see"
" https://packaging.python.org/specifications/core-metadata",
),
(
{"metadata_version": "-1"},
"'-1' is an invalid value for Metadata-Version. Error: Unknown Metadata"
" Version see"
" https://packaging.python.org/specifications/core-metadata",
),
# name errors.
(
{"metadata_version": "1.2"},
"'' is an invalid value for Name. Error: This field is required. see"
" https://packaging.python.org/specifications/core-metadata",
),
(
{"metadata_version": "1.2", "name": "foo-"},
"'foo-' is an invalid value for Name. Error: Must start and end with a"
" letter or numeral and contain only ascii numeric and '.', '_' and"
" '-'. see https://packaging.python.org/specifications/core-metadata",
),
# version errors.
(
{"metadata_version": "1.2", "name": "example"},
"'' is an invalid value for Version. Error: This field is required. see"
" https://packaging.python.org/specifications/core-metadata",
),
(
{"metadata_version": "1.2", "name": "example", "version": "dog"},
"'dog' is an invalid value for Version. Error: Must start and end with"
" a letter or numeral and contain only ascii numeric and '.', '_' and"
" '-'. see https://packaging.python.org/specifications/core-metadata",
),
],
)
def test_fails_invalid_post_data(
self, pyramid_config, db_request, post_data, message
):
pyramid_config.testing_securitypolicy(userid=1)
db_request.POST = MultiDict(post_data)
def foo(list_a, list_b):
results = (
User.query.filter(User.foo == "bar")
.filter( # Because foo.
db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b))
)
.filter(User.xyz.is_(None))
# Another comment about the filtering on is_quux goes here.
.filter(db.not_(User.is_pending.astext.cast(db.Boolean).is_(True)))
.order_by(User.created_at.desc())
.with_for_update(key_share=True)
.all()
)
return results
def foo2(list_a, list_b):
# Standalone comment reasonably placed.
return (
User.query.filter(User.foo == "bar")
.filter(
db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b))
)
.filter(User.xyz.is_(None))
)
def foo3(list_a, list_b):
return (
# Standalone comment but weirdly placed.
User.query.filter(User.foo == "bar")
.filter(
db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b))
)
.filter(User.xyz.is_(None))
)

View File

@@ -0,0 +1,94 @@
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
MyLovelyCompanyTeamProjectComponent, # NOT DRY
)
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
MyLovelyCompanyTeamProjectComponent as component, # DRY
)
class C:
@pytest.mark.parametrize(
("post_data", "message"),
[
# metadata_version errors.
(
{},
"None is an invalid value for Metadata-Version. Error: This field is"
" required. see"
" https://packaging.python.org/specifications/core-metadata",
),
(
{"metadata_version": "-1"},
"'-1' is an invalid value for Metadata-Version. Error: Unknown Metadata"
" Version see"
" https://packaging.python.org/specifications/core-metadata",
),
# name errors.
(
{"metadata_version": "1.2"},
"'' is an invalid value for Name. Error: This field is required. see"
" https://packaging.python.org/specifications/core-metadata",
),
(
{"metadata_version": "1.2", "name": "foo-"},
"'foo-' is an invalid value for Name. Error: Must start and end with a"
" letter or numeral and contain only ascii numeric and '.', '_' and"
" '-'. see https://packaging.python.org/specifications/core-metadata",
),
# version errors.
(
{"metadata_version": "1.2", "name": "example"},
"'' is an invalid value for Version. Error: This field is required. see"
" https://packaging.python.org/specifications/core-metadata",
),
(
{"metadata_version": "1.2", "name": "example", "version": "dog"},
"'dog' is an invalid value for Version. Error: Must start and end with"
" a letter or numeral and contain only ascii numeric and '.', '_' and"
" '-'. see https://packaging.python.org/specifications/core-metadata",
),
],
)
def test_fails_invalid_post_data(
self, pyramid_config, db_request, post_data, message
):
pyramid_config.testing_securitypolicy(userid=1)
db_request.POST = MultiDict(post_data)
def foo(list_a, list_b):
results = (
User.query.filter(User.foo == "bar")
.filter( # Because foo.
db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b))
)
.filter(User.xyz.is_(None))
# Another comment about the filtering on is_quux goes here.
.filter(db.not_(User.is_pending.astext.cast(db.Boolean).is_(True)))
.order_by(User.created_at.desc())
.with_for_update(key_share=True)
.all()
)
return results
def foo2(list_a, list_b):
# Standalone comment reasonably placed.
return (
User.query.filter(User.foo == "bar")
.filter(
db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b))
)
.filter(User.xyz.is_(None))
)
def foo3(list_a, list_b):
return (
# Standalone comment but weirdly placed.
User.query.filter(User.foo == "bar")
.filter(
db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b))
)
.filter(User.xyz.is_(None))
)

View File

@@ -0,0 +1,73 @@
while True:
if something.changed:
do.stuff() # trailing comment
# Comment belongs to the `if` block.
# This one belongs to the `while` block.
# Should this one, too? I guess so.
# This one is properly standalone now.
for i in range(100):
# first we do this
if i % 33 == 0:
break
# then we do this
print(i)
# and finally we loop around
with open(some_temp_file) as f:
data = f.read()
try:
with open(some_other_file) as w:
w.write(data)
except OSError:
print("problems")
import sys
# leading function comment
def wat():
...
# trailing function comment
# SECTION COMMENT
# leading 1
@deco1
# leading 2
@deco2(with_args=True)
# leading 3
@deco3
def decorated1():
...
# leading 1
@deco1
# leading 2
@deco2(with_args=True)
# leading function comment
def decorated1():
...
# Note: this is fixed in
# Preview.empty_lines_before_class_or_def_with_leading_comments.
# In the current style, the user will have to split those lines by hand.
some_instruction
# This comment should be split from `some_instruction` by two lines but isn't.
def g():
...
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,73 @@
while True:
if something.changed:
do.stuff() # trailing comment
# Comment belongs to the `if` block.
# This one belongs to the `while` block.
# Should this one, too? I guess so.
# This one is properly standalone now.
for i in range(100):
# first we do this
if i % 33 == 0:
break
# then we do this
print(i)
# and finally we loop around
with open(some_temp_file) as f:
data = f.read()
try:
with open(some_other_file) as w:
w.write(data)
except OSError:
print("problems")
import sys
# leading function comment
def wat():
...
# trailing function comment
# SECTION COMMENT
# leading 1
@deco1
# leading 2
@deco2(with_args=True)
# leading 3
@deco3
def decorated1():
...
# leading 1
@deco1
# leading 2
@deco2(with_args=True)
# leading function comment
def decorated1():
...
# Note: this is fixed in
# Preview.empty_lines_before_class_or_def_with_leading_comments.
# In the current style, the user will have to split those lines by hand.
some_instruction
# This comment should be split from `some_instruction` by two lines but isn't.
def g():
...
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,118 @@
from typing import Any, Tuple
def f(
a, # type: int
):
pass
# test type comments
def f(a, b, c, d, e, f, g, h, i):
# type: (int, int, int, int, int, int, int, int, int) -> None
pass
def f(
a, # type: int
b, # type: int
c, # type: int
d, # type: int
e, # type: int
f, # type: int
g, # type: int
h, # type: int
i, # type: int
):
# type: (...) -> None
pass
def f(
arg, # type: int
*args, # type: *Any
default=False, # type: bool
**kwargs, # type: **Any
):
# type: (...) -> None
pass
def f(
a, # type: int
b, # type: int
c, # type: int
d, # type: int
):
# type: (...) -> None
element = 0 # type: int
another_element = 1 # type: float
another_element_with_long_name = 2 # type: int
another_really_really_long_element_with_a_unnecessarily_long_name_to_describe_what_it_does_enterprise_style = (
3
) # type: int
an_element_with_a_long_value = calls() or more_calls() and more() # type: bool
tup = (
another_element,
another_really_really_long_element_with_a_unnecessarily_long_name_to_describe_what_it_does_enterprise_style,
) # type: Tuple[int, int]
a = (
element
+ another_element
+ another_element_with_long_name
+ element
+ another_element
+ another_element_with_long_name
) # type: int
def f(
x, # not a type comment
y, # type: int
):
# type: (...) -> None
pass
def f(
x, # not a type comment
): # type: (int) -> None
pass
def func(
a=some_list[0], # type: int
): # type: () -> int
c = call(
0.0123,
0.0456,
0.0789,
0.0123,
0.0456,
0.0789,
0.0123,
0.0456,
0.0789,
a[-1], # type: ignore
)
c = call(
"aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa" # type: ignore
)
result = ( # aaa
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
)
AAAAAAAAAAAAA = [AAAAAAAAAAAAA] + SHARED_AAAAAAAAAAAAA + USER_AAAAAAAAAAAAA + AAAAAAAAAAAAA # type: ignore
call_to_some_function_asdf(
foo,
[AAAAAAAAAAAAAAAAAAAAAAA, AAAAAAAAAAAAAAAAAAAAAAA, AAAAAAAAAAAAAAAAAAAAAAA, BBBBBBBBBBBB], # type: ignore
)
aaaaaaaaaaaaa, bbbbbbbbb = map(list, map(itertools.chain.from_iterable, zip(*items))) # type: ignore[arg-type]

View File

@@ -0,0 +1,118 @@
from typing import Any, Tuple
def f(
a, # type: int
):
pass
# test type comments
def f(a, b, c, d, e, f, g, h, i):
# type: (int, int, int, int, int, int, int, int, int) -> None
pass
def f(
a, # type: int
b, # type: int
c, # type: int
d, # type: int
e, # type: int
f, # type: int
g, # type: int
h, # type: int
i, # type: int
):
# type: (...) -> None
pass
def f(
arg, # type: int
*args, # type: *Any
default=False, # type: bool
**kwargs, # type: **Any
):
# type: (...) -> None
pass
def f(
a, # type: int
b, # type: int
c, # type: int
d, # type: int
):
# type: (...) -> None
element = 0 # type: int
another_element = 1 # type: float
another_element_with_long_name = 2 # type: int
another_really_really_long_element_with_a_unnecessarily_long_name_to_describe_what_it_does_enterprise_style = (
3
) # type: int
an_element_with_a_long_value = calls() or more_calls() and more() # type: bool
tup = (
another_element,
another_really_really_long_element_with_a_unnecessarily_long_name_to_describe_what_it_does_enterprise_style,
) # type: Tuple[int, int]
a = (
element
+ another_element
+ another_element_with_long_name
+ element
+ another_element
+ another_element_with_long_name
) # type: int
def f(
x, # not a type comment
y, # type: int
):
# type: (...) -> None
pass
def f(
x, # not a type comment
): # type: (int) -> None
pass
def func(
a=some_list[0], # type: int
): # type: () -> int
c = call(
0.0123,
0.0456,
0.0789,
0.0123,
0.0456,
0.0789,
0.0123,
0.0456,
0.0789,
a[-1], # type: ignore
)
c = call(
"aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa" # type: ignore
)
result = ( # aaa
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
)
AAAAAAAAAAAAA = [AAAAAAAAAAAAA] + SHARED_AAAAAAAAAAAAA + USER_AAAAAAAAAAAAA + AAAAAAAAAAAAA # type: ignore
call_to_some_function_asdf(
foo,
[AAAAAAAAAAAAAAAAAAAAAAA, AAAAAAAAAAAAAAAAAAAAAAA, AAAAAAAAAAAAAAAAAAAAAAA, BBBBBBBBBBBB], # type: ignore
)
aaaaaaaaaaaaa, bbbbbbbbb = map(list, map(itertools.chain.from_iterable, zip(*items))) # type: ignore[arg-type]

View File

@@ -0,0 +1,6 @@
# The percent-percent comments are Spyder IDE cells.
# Both `#%%`` and `# %%` are accepted, so `black` standardises
# to the latter.
#%%
# %%

View File

@@ -0,0 +1,6 @@
# The percent-percent comments are Spyder IDE cells.
# Both `#%%`` and `# %%` are accepted, so `black` standardises
# to the latter.
# %%
# %%

View File

@@ -0,0 +1,139 @@
# Test for https://github.com/psf/black/issues/246.
some = statement
# This comment should be split from the statement above by two lines.
def function():
pass
some = statement
# This multiline comments section
# should be split from the statement
# above by two lines.
def function():
pass
some = statement
# This comment should be split from the statement above by two lines.
async def async_function():
pass
some = statement
# This comment should be split from the statement above by two lines.
class MyClass:
pass
some = statement
# This should be stick to the statement above
# This should be split from the above by two lines
class MyClassWithComplexLeadingComments:
pass
class ClassWithDocstring:
"""A docstring."""
# Leading comment after a class with just a docstring
class MyClassAfterAnotherClassWithDocstring:
pass
some = statement
# leading 1
@deco1
# leading 2
# leading 2 extra
@deco2(with_args=True)
# leading 3
@deco3
# leading 4
def decorated():
pass
some = statement
# leading 1
@deco1
# leading 2
@deco2(with_args=True)
# leading 3 that already has an empty line
@deco3
# leading 4
def decorated_with_split_leading_comments():
pass
some = statement
# leading 1
@deco1
# leading 2
@deco2(with_args=True)
# leading 3
@deco3
# leading 4 that already has an empty line
def decorated_with_split_leading_comments():
pass
def main():
if a:
# Leading comment before inline function
def inline():
pass
# Another leading comment
def another_inline():
pass
else:
# More leading comments
def inline_after_else():
pass
if a:
# Leading comment before "top-level inline" function
def top_level_quote_inline():
pass
# Another leading comment
def another_top_level_quote_inline_inline():
pass
else:
# More leading comments
def top_level_quote_inline_after_else():
pass
class MyClass:
# First method has no empty lines between bare class def.
# More comments.
def first_method(self):
pass
# Regression test for https://github.com/psf/black/issues/3454.
def foo():
pass
# Trailing comment that belongs to this function
@decorator1
@decorator2 # fmt: skip
def bar():
pass
# Regression test for https://github.com/psf/black/issues/3454.
def foo():
pass
# Trailing comment that belongs to this function.
# NOTE this comment only has one empty line below, and the formatter
# should enforce two blank lines.
@decorator1
# A standalone comment
def bar():
pass

View File

@@ -0,0 +1,161 @@
# Test for https://github.com/psf/black/issues/246.
some = statement
# This comment should be split from the statement above by two lines.
def function():
pass
some = statement
# This multiline comments section
# should be split from the statement
# above by two lines.
def function():
pass
some = statement
# This comment should be split from the statement above by two lines.
async def async_function():
pass
some = statement
# This comment should be split from the statement above by two lines.
class MyClass:
pass
some = statement
# This should be stick to the statement above
# This should be split from the above by two lines
class MyClassWithComplexLeadingComments:
pass
class ClassWithDocstring:
"""A docstring."""
# Leading comment after a class with just a docstring
class MyClassAfterAnotherClassWithDocstring:
pass
some = statement
# leading 1
@deco1
# leading 2
# leading 2 extra
@deco2(with_args=True)
# leading 3
@deco3
# leading 4
def decorated():
pass
some = statement
# leading 1
@deco1
# leading 2
@deco2(with_args=True)
# leading 3 that already has an empty line
@deco3
# leading 4
def decorated_with_split_leading_comments():
pass
some = statement
# leading 1
@deco1
# leading 2
@deco2(with_args=True)
# leading 3
@deco3
# leading 4 that already has an empty line
def decorated_with_split_leading_comments():
pass
def main():
if a:
# Leading comment before inline function
def inline():
pass
# Another leading comment
def another_inline():
pass
else:
# More leading comments
def inline_after_else():
pass
if a:
# Leading comment before "top-level inline" function
def top_level_quote_inline():
pass
# Another leading comment
def another_top_level_quote_inline_inline():
pass
else:
# More leading comments
def top_level_quote_inline_after_else():
pass
class MyClass:
# First method has no empty lines between bare class def.
# More comments.
def first_method(self):
pass
# Regression test for https://github.com/psf/black/issues/3454.
def foo():
pass
# Trailing comment that belongs to this function
@decorator1
@decorator2 # fmt: skip
def bar():
pass
# Regression test for https://github.com/psf/black/issues/3454.
def foo():
pass
# Trailing comment that belongs to this function.
# NOTE this comment only has one empty line below, and the formatter
# should enforce two blank lines.
@decorator1
# A standalone comment
def bar():
pass

View File

@@ -0,0 +1,111 @@
# Test cases from:
# - https://github.com/psf/black/issues/1798
# - https://github.com/psf/black/issues/1499
# - https://github.com/psf/black/issues/1211
# - https://github.com/psf/black/issues/563
(
lambda
# a comment
: None
)
(
lambda:
# b comment
None
)
(
lambda
# a comment
:
# b comment
None
)
[
x
# Let's do this
for
# OK?
x
# Some comment
# And another
in
# One more
y
]
return [
(offers[offer_index], 1.0)
for offer_index, _
# avoid returning any offers that don't match the grammar so
# that the return values here are consistent with what would be
# returned in AcceptValidHeader
in self._parse_and_normalize_offers(offers)
]
from foo import (
bar,
# qux
)
def convert(collection):
# replace all variables by integers
replacement_dict = {
variable: f"{index}"
for index, variable
# 0 is reserved as line terminator
in enumerate(collection.variables(), start=1)
}
{
i: i
for i
# a comment
in range(5)
}
def get_subtree_proof_nodes(
chunk_index_groups: Sequence[Tuple[int, ...], ...],
) -> Tuple[int, ...]:
subtree_node_paths = (
# We take a candidate element from each group and shift it to
# remove the bits that are not common to other group members, then
# we convert it to a tree path that all elements from this group
# have in common.
chunk_index
for chunk_index, bits_to_truncate
# Each group will contain an even "power-of-two" number of# elements.
# This tells us how many tailing bits each element has# which need to
# be truncated to get the group's common prefix.
in ((group[0], (len(group) - 1).bit_length()) for group in chunk_index_groups)
)
return subtree_node_paths
if (
# comment1
a
# comment2
or (
# comment3
(
# comment4
b
)
# comment5
and
# comment6
c
or (
# comment7
d
)
)
):
print("Foo")

View File

@@ -0,0 +1,111 @@
# Test cases from:
# - https://github.com/psf/black/issues/1798
# - https://github.com/psf/black/issues/1499
# - https://github.com/psf/black/issues/1211
# - https://github.com/psf/black/issues/563
(
lambda
# a comment
: None
)
(
lambda:
# b comment
None
)
(
lambda
# a comment
:
# b comment
None
)
[
x
# Let's do this
for
# OK?
x
# Some comment
# And another
in
# One more
y
]
return [
(offers[offer_index], 1.0)
for offer_index, _
# avoid returning any offers that don't match the grammar so
# that the return values here are consistent with what would be
# returned in AcceptValidHeader
in self._parse_and_normalize_offers(offers)
]
from foo import (
bar,
# qux
)
def convert(collection):
# replace all variables by integers
replacement_dict = {
variable: f"{index}"
for index, variable
# 0 is reserved as line terminator
in enumerate(collection.variables(), start=1)
}
{
i: i
for i
# a comment
in range(5)
}
def get_subtree_proof_nodes(
chunk_index_groups: Sequence[Tuple[int, ...], ...],
) -> Tuple[int, ...]:
subtree_node_paths = (
# We take a candidate element from each group and shift it to
# remove the bits that are not common to other group members, then
# we convert it to a tree path that all elements from this group
# have in common.
chunk_index
for chunk_index, bits_to_truncate
# Each group will contain an even "power-of-two" number of# elements.
# This tells us how many tailing bits each element has# which need to
# be truncated to get the group's common prefix.
in ((group[0], (len(group) - 1).bit_length()) for group in chunk_index_groups)
)
return subtree_node_paths
if (
# comment1
a
# comment2
or (
# comment3
(
# comment4
b
)
# comment5
and
# comment6
c
or (
# comment7
d
)
)
):
print("Foo")

View File

@@ -0,0 +1,19 @@
from .config import ( ConfigTypeAttributes, Int, Path, # String,
# DEFAULT_TYPE_ATTRIBUTES,
)
result = 1 # A simple comment
result = ( 1, ) # Another one
result = 1 # type: ignore
result = 1# This comment is talking about type: ignore
square = Square(4) # type: Optional[Square]
def function(a:int=42):
""" This docstring is already formatted
a
b
"""
#  There's a NBSP + 3 spaces before
# And 4 spaces on the next line
pass

View File

@@ -0,0 +1,23 @@
from .config import (
ConfigTypeAttributes,
Int,
Path, # String,
# DEFAULT_TYPE_ATTRIBUTES,
)
result = 1 # A simple comment
result = (1,) # Another one
result = 1 #  type: ignore
result = 1 # This comment is talking about type: ignore
square = Square(4) #  type: Optional[Square]
def function(a: int = 42):
"""This docstring is already formatted
a
b
"""
# There's a NBSP + 3 spaces before
# And 4 spaces on the next line
pass

View File

@@ -0,0 +1,181 @@
class C:
def test(self) -> None:
with patch("black.out", print):
self.assertEqual(
unstyle(str(report)), "1 file reformatted, 1 file failed to reformat."
)
self.assertEqual(
unstyle(str(report)),
"1 file reformatted, 1 file left unchanged, 1 file failed to reformat.",
)
self.assertEqual(
unstyle(str(report)),
"2 files reformatted, 1 file left unchanged, 1 file failed to"
" reformat.",
)
self.assertEqual(
unstyle(str(report)),
"2 files reformatted, 2 files left unchanged, 2 files failed to"
" reformat.",
)
for i in (a,):
if (
# Rule 1
i % 2 == 0
# Rule 2
and i % 3 == 0
):
while (
# Just a comment
call()
# Another
):
print(i)
xxxxxxxxxxxxxxxx = Yyyy2YyyyyYyyyyy(
push_manager=context.request.resource_manager,
max_items_to_push=num_items,
batch_size=Yyyy2YyyyYyyyyYyyy.FULL_SIZE,
).push(
# Only send the first n items.
items=items[:num_items]
)
return (
'Utterly failed doctest test for %s\n File "%s", line %s, in %s\n\n%s'
% (test.name, test.filename, lineno, lname, err)
)
def omitting_trailers(self) -> None:
get_collection(
hey_this_is_a_very_long_call, it_has_funny_attributes, really=True
)[OneLevelIndex]
get_collection(
hey_this_is_a_very_long_call, it_has_funny_attributes, really=True
)[OneLevelIndex][TwoLevelIndex][ThreeLevelIndex][FourLevelIndex]
d[0][1][2][3][4][5][6][7][8][9][10][11][12][13][14][15][16][17][18][19][20][21][
22
]
assignment = (
some.rather.elaborate.rule() and another.rule.ending_with.index[123]
)
def easy_asserts(self) -> None:
assert {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
} == expected, "Not what we expected"
assert expected == {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}, "Not what we expected"
assert expected == {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}
def tricky_asserts(self) -> None:
assert {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
} == expected(
value, is_going_to_be="too long to fit in a single line", srsly=True
), "Not what we expected"
assert {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
} == expected, (
"Not what we expected and the message is too long to fit in one line"
)
assert expected(
value, is_going_to_be="too long to fit in a single line", srsly=True
) == {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}, "Not what we expected"
assert expected == {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}, (
"Not what we expected and the message is too long to fit in one line"
" because it's too long"
)
dis_c_instance_method = """\
%3d 0 LOAD_FAST 1 (x)
2 LOAD_CONST 1 (1)
4 COMPARE_OP 2 (==)
6 LOAD_FAST 0 (self)
8 STORE_ATTR 0 (x)
10 LOAD_CONST 0 (None)
12 RETURN_VALUE
""" % (
_C.__init__.__code__.co_firstlineno + 1,
)
assert (
expectedexpectedexpectedexpectedexpectedexpectedexpectedexpectedexpect
== {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}
)

View File

@@ -0,0 +1,181 @@
class C:
def test(self) -> None:
with patch("black.out", print):
self.assertEqual(
unstyle(str(report)), "1 file reformatted, 1 file failed to reformat."
)
self.assertEqual(
unstyle(str(report)),
"1 file reformatted, 1 file left unchanged, 1 file failed to reformat.",
)
self.assertEqual(
unstyle(str(report)),
"2 files reformatted, 1 file left unchanged, 1 file failed to"
" reformat.",
)
self.assertEqual(
unstyle(str(report)),
"2 files reformatted, 2 files left unchanged, 2 files failed to"
" reformat.",
)
for i in (a,):
if (
# Rule 1
i % 2 == 0
# Rule 2
and i % 3 == 0
):
while (
# Just a comment
call()
# Another
):
print(i)
xxxxxxxxxxxxxxxx = Yyyy2YyyyyYyyyyy(
push_manager=context.request.resource_manager,
max_items_to_push=num_items,
batch_size=Yyyy2YyyyYyyyyYyyy.FULL_SIZE,
).push(
# Only send the first n items.
items=items[:num_items]
)
return (
'Utterly failed doctest test for %s\n File "%s", line %s, in %s\n\n%s'
% (test.name, test.filename, lineno, lname, err)
)
def omitting_trailers(self) -> None:
get_collection(
hey_this_is_a_very_long_call, it_has_funny_attributes, really=True
)[OneLevelIndex]
get_collection(
hey_this_is_a_very_long_call, it_has_funny_attributes, really=True
)[OneLevelIndex][TwoLevelIndex][ThreeLevelIndex][FourLevelIndex]
d[0][1][2][3][4][5][6][7][8][9][10][11][12][13][14][15][16][17][18][19][20][21][
22
]
assignment = (
some.rather.elaborate.rule() and another.rule.ending_with.index[123]
)
def easy_asserts(self) -> None:
assert {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
} == expected, "Not what we expected"
assert expected == {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}, "Not what we expected"
assert expected == {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}
def tricky_asserts(self) -> None:
assert {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
} == expected(
value, is_going_to_be="too long to fit in a single line", srsly=True
), "Not what we expected"
assert {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
} == expected, (
"Not what we expected and the message is too long to fit in one line"
)
assert expected(
value, is_going_to_be="too long to fit in a single line", srsly=True
) == {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}, "Not what we expected"
assert expected == {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}, (
"Not what we expected and the message is too long to fit in one line"
" because it's too long"
)
dis_c_instance_method = """\
%3d 0 LOAD_FAST 1 (x)
2 LOAD_CONST 1 (1)
4 COMPARE_OP 2 (==)
6 LOAD_FAST 0 (self)
8 STORE_ATTR 0 (x)
10 LOAD_CONST 0 (None)
12 RETURN_VALUE
""" % (
_C.__init__.__code__.co_firstlineno + 1,
)
assert (
expectedexpectedexpectedexpectedexpectedexpectedexpectedexpectedexpect
== {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}
)

View File

@@ -0,0 +1,181 @@
class C:
def test(self) -> None:
with patch("black.out", print):
self.assertEqual(
unstyle(str(report)), "1 file reformatted, 1 file failed to reformat."
)
self.assertEqual(
unstyle(str(report)),
"1 file reformatted, 1 file left unchanged, 1 file failed to reformat.",
)
self.assertEqual(
unstyle(str(report)),
"2 files reformatted, 1 file left unchanged, 1 file failed to"
" reformat.",
)
self.assertEqual(
unstyle(str(report)),
"2 files reformatted, 2 files left unchanged, 2 files failed to"
" reformat.",
)
for i in (a,):
if (
# Rule 1
i % 2 == 0
# Rule 2
and i % 3 == 0
):
while (
# Just a comment
call()
# Another
):
print(i)
xxxxxxxxxxxxxxxx = Yyyy2YyyyyYyyyyy(
push_manager=context.request.resource_manager,
max_items_to_push=num_items,
batch_size=Yyyy2YyyyYyyyyYyyy.FULL_SIZE
).push(
# Only send the first n items.
items=items[:num_items]
)
return (
'Utterly failed doctest test for %s\n File "%s", line %s, in %s\n\n%s'
% (test.name, test.filename, lineno, lname, err)
)
def omitting_trailers(self) -> None:
get_collection(
hey_this_is_a_very_long_call, it_has_funny_attributes, really=True
)[OneLevelIndex]
get_collection(
hey_this_is_a_very_long_call, it_has_funny_attributes, really=True
)[OneLevelIndex][TwoLevelIndex][ThreeLevelIndex][FourLevelIndex]
d[0][1][2][3][4][5][6][7][8][9][10][11][12][13][14][15][16][17][18][19][20][21][
22
]
assignment = (
some.rather.elaborate.rule() and another.rule.ending_with.index[123]
)
def easy_asserts(self) -> None:
assert {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9
} == expected, "Not what we expected"
assert expected == {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9
}, "Not what we expected"
assert expected == {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9
}
def tricky_asserts(self) -> None:
assert {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9
} == expected(
value, is_going_to_be="too long to fit in a single line", srsly=True
), "Not what we expected"
assert {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9
} == expected, (
"Not what we expected and the message is too long to fit in one line"
)
assert expected(
value, is_going_to_be="too long to fit in a single line", srsly=True
) == {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9
}, "Not what we expected"
assert expected == {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9
}, (
"Not what we expected and the message is too long to fit in one line"
" because it's too long"
)
dis_c_instance_method = """\
%3d 0 LOAD_FAST 1 (x)
2 LOAD_CONST 1 (1)
4 COMPARE_OP 2 (==)
6 LOAD_FAST 0 (self)
8 STORE_ATTR 0 (x)
10 LOAD_CONST 0 (None)
12 RETURN_VALUE
""" % (
_C.__init__.__code__.co_firstlineno + 1,
)
assert (
expectedexpectedexpectedexpectedexpectedexpectedexpectedexpectedexpect
== {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9
}
)

View File

@@ -0,0 +1,181 @@
class C:
def test(self) -> None:
with patch("black.out", print):
self.assertEqual(
unstyle(str(report)), "1 file reformatted, 1 file failed to reformat."
)
self.assertEqual(
unstyle(str(report)),
"1 file reformatted, 1 file left unchanged, 1 file failed to reformat.",
)
self.assertEqual(
unstyle(str(report)),
"2 files reformatted, 1 file left unchanged, 1 file failed to"
" reformat.",
)
self.assertEqual(
unstyle(str(report)),
"2 files reformatted, 2 files left unchanged, 2 files failed to"
" reformat.",
)
for i in (a,):
if (
# Rule 1
i % 2 == 0
# Rule 2
and i % 3 == 0
):
while (
# Just a comment
call()
# Another
):
print(i)
xxxxxxxxxxxxxxxx = Yyyy2YyyyyYyyyyy(
push_manager=context.request.resource_manager,
max_items_to_push=num_items,
batch_size=Yyyy2YyyyYyyyyYyyy.FULL_SIZE,
).push(
# Only send the first n items.
items=items[:num_items]
)
return (
'Utterly failed doctest test for %s\n File "%s", line %s, in %s\n\n%s'
% (test.name, test.filename, lineno, lname, err)
)
def omitting_trailers(self) -> None:
get_collection(
hey_this_is_a_very_long_call, it_has_funny_attributes, really=True
)[OneLevelIndex]
get_collection(
hey_this_is_a_very_long_call, it_has_funny_attributes, really=True
)[OneLevelIndex][TwoLevelIndex][ThreeLevelIndex][FourLevelIndex]
d[0][1][2][3][4][5][6][7][8][9][10][11][12][13][14][15][16][17][18][19][20][21][
22
]
assignment = (
some.rather.elaborate.rule() and another.rule.ending_with.index[123]
)
def easy_asserts(self) -> None:
assert {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
} == expected, "Not what we expected"
assert expected == {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}, "Not what we expected"
assert expected == {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}
def tricky_asserts(self) -> None:
assert {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
} == expected(
value, is_going_to_be="too long to fit in a single line", srsly=True
), "Not what we expected"
assert {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
} == expected, (
"Not what we expected and the message is too long to fit in one line"
)
assert expected(
value, is_going_to_be="too long to fit in a single line", srsly=True
) == {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}, "Not what we expected"
assert expected == {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}, (
"Not what we expected and the message is too long to fit in one line"
" because it's too long"
)
dis_c_instance_method = """\
%3d 0 LOAD_FAST 1 (x)
2 LOAD_CONST 1 (1)
4 COMPARE_OP 2 (==)
6 LOAD_FAST 0 (self)
8 STORE_ATTR 0 (x)
10 LOAD_CONST 0 (None)
12 RETURN_VALUE
""" % (
_C.__init__.__code__.co_firstlineno + 1,
)
assert (
expectedexpectedexpectedexpectedexpectedexpectedexpectedexpectedexpect
== {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}
)

View File

@@ -0,0 +1,68 @@
# flags: --preview
long_kwargs_single_line = my_function(
foo="test, this is a sample value",
bar=some_long_value_name_foo_bar_baz if some_boolean_variable else some_fallback_value_foo_bar_baz,
baz="hello, this is a another value",
)
multiline_kwargs_indented = my_function(
foo="test, this is a sample value",
bar=some_long_value_name_foo_bar_baz
if some_boolean_variable
else some_fallback_value_foo_bar_baz,
baz="hello, this is a another value",
)
imploding_kwargs = my_function(
foo="test, this is a sample value",
bar=a
if foo
else b,
baz="hello, this is a another value",
)
imploding_line = (
1
if 1 + 1 == 2
else 0
)
exploding_line = "hello this is a slightly long string" if some_long_value_name_foo_bar_baz else "this one is a little shorter"
positional_argument_test(some_long_value_name_foo_bar_baz if some_boolean_variable else some_fallback_value_foo_bar_baz)
def weird_default_argument(x=some_long_value_name_foo_bar_baz
if SOME_CONSTANT
else some_fallback_value_foo_bar_baz):
pass
nested = "hello this is a slightly long string" if (some_long_value_name_foo_bar_baz if
nesting_test_expressions else some_fallback_value_foo_bar_baz) \
else "this one is a little shorter"
generator_expression = (
some_long_value_name_foo_bar_baz if some_boolean_variable else some_fallback_value_foo_bar_baz for some_boolean_variable in some_iterable
)
def limit_offset_sql(self, low_mark, high_mark):
"""Return LIMIT/OFFSET SQL clause."""
limit, offset = self._get_limit_offset_params(low_mark, high_mark)
return " ".join(
sql
for sql in (
"LIMIT %d" % limit if limit else None,
("OFFSET %d" % offset) if offset else None,
)
if sql
)
def something():
clone._iterable_class = (
NamedValuesListIterable
if named
else FlatValuesListIterable
if flat
else ValuesListIterable
)

View File

@@ -0,0 +1,90 @@
long_kwargs_single_line = my_function(
foo="test, this is a sample value",
bar=(
some_long_value_name_foo_bar_baz
if some_boolean_variable
else some_fallback_value_foo_bar_baz
),
baz="hello, this is a another value",
)
multiline_kwargs_indented = my_function(
foo="test, this is a sample value",
bar=(
some_long_value_name_foo_bar_baz
if some_boolean_variable
else some_fallback_value_foo_bar_baz
),
baz="hello, this is a another value",
)
imploding_kwargs = my_function(
foo="test, this is a sample value",
bar=a if foo else b,
baz="hello, this is a another value",
)
imploding_line = 1 if 1 + 1 == 2 else 0
exploding_line = (
"hello this is a slightly long string"
if some_long_value_name_foo_bar_baz
else "this one is a little shorter"
)
positional_argument_test(
some_long_value_name_foo_bar_baz
if some_boolean_variable
else some_fallback_value_foo_bar_baz
)
def weird_default_argument(
x=(
some_long_value_name_foo_bar_baz
if SOME_CONSTANT
else some_fallback_value_foo_bar_baz
),
):
pass
nested = (
"hello this is a slightly long string"
if (
some_long_value_name_foo_bar_baz
if nesting_test_expressions
else some_fallback_value_foo_bar_baz
)
else "this one is a little shorter"
)
generator_expression = (
(
some_long_value_name_foo_bar_baz
if some_boolean_variable
else some_fallback_value_foo_bar_baz
)
for some_boolean_variable in some_iterable
)
def limit_offset_sql(self, low_mark, high_mark):
"""Return LIMIT/OFFSET SQL clause."""
limit, offset = self._get_limit_offset_params(low_mark, high_mark)
return " ".join(
sql
for sql in (
"LIMIT %d" % limit if limit else None,
("OFFSET %d" % offset) if offset else None,
)
if sql
)
def something():
clone._iterable_class = (
NamedValuesListIterable
if named
else FlatValuesListIterable if flat else ValuesListIterable
)

View File

@@ -0,0 +1,228 @@
class MyClass:
""" Multiline
class docstring
"""
def method(self):
"""Multiline
method docstring
"""
pass
def foo():
"""This is a docstring with
some lines of text here
"""
return
def bar():
'''This is another docstring
with more lines of text
'''
return
def baz():
'''"This" is a string with some
embedded "quotes"'''
return
def troz():
'''Indentation with tabs
is just as OK
'''
return
def zort():
"""Another
multiline
docstring
"""
pass
def poit():
"""
Lorem ipsum dolor sit amet.
Consectetur adipiscing elit:
- sed do eiusmod tempor incididunt ut labore
- dolore magna aliqua
- enim ad minim veniam
- quis nostrud exercitation ullamco laboris nisi
- aliquip ex ea commodo consequat
"""
pass
def under_indent():
"""
These lines are indented in a way that does not
make sense.
"""
pass
def over_indent():
"""
This has a shallow indent
- But some lines are deeper
- And the closing quote is too deep
"""
pass
def single_line():
"""But with a newline after it!
"""
pass
def this():
r"""
'hey ho'
"""
def that():
""" "hey yah" """
def and_that():
"""
"hey yah" """
def and_this():
'''
"hey yah"'''
def multiline_whitespace():
'''
'''
def oneline_whitespace():
''' '''
def empty():
""""""
def single_quotes():
'testing'
def believe_it_or_not_this_is_in_the_py_stdlib(): '''
"hey yah"'''
def ignored_docstring():
"""a => \
b"""
def single_line_docstring_with_whitespace():
""" This should be stripped """
def docstring_with_inline_tabs_and_space_indentation():
"""hey
tab separated value
tab at start of line and then a tab separated value
multiple tabs at the beginning and inline
mixed tabs and spaces at beginning. next line has mixed tabs and spaces only.
line ends with some tabs
"""
def docstring_with_inline_tabs_and_tab_indentation():
"""hey
tab separated value
tab at start of line and then a tab separated value
multiple tabs at the beginning and inline
mixed tabs and spaces at beginning. next line has mixed tabs and spaces only.
line ends with some tabs
"""
pass
def backslash_space():
"""\ """
def multiline_backslash_1():
'''
hey\there\
\ '''
def multiline_backslash_2():
'''
hey there \ '''
# Regression test for #3425
def multiline_backslash_really_long_dont_crash():
"""
hey there hello guten tag hi hoow are you ola zdravstvuyte ciao como estas ca va \ """
def multiline_backslash_3():
'''
already escaped \\ '''
def my_god_its_full_of_stars_1():
"I'm sorry Dave\u2001"
# the space below is actually a \u2001, removed in output
def my_god_its_full_of_stars_2():
"I'm sorry Dave"
def docstring_almost_at_line_limit():
"""long docstring................................................................."""
def docstring_almost_at_line_limit2():
"""long docstring.................................................................
..................................................................................
"""
def docstring_at_line_limit():
"""long docstring................................................................"""
def multiline_docstring_at_line_limit():
"""first line-----------------------------------------------------------------------
second line----------------------------------------------------------------------"""
def stable_quote_normalization_with_immediate_inner_single_quote(self):
''''<text here>
<text here, since without another non-empty line black is stable>
'''
def foo():
"""
Docstring with a backslash followed by a space\
and then another line
"""

View File

@@ -0,0 +1,226 @@
class MyClass:
"""Multiline
class docstring
"""
def method(self):
"""Multiline
method docstring
"""
pass
def foo():
"""This is a docstring with
some lines of text here
"""
return
def bar():
"""This is another docstring
with more lines of text
"""
return
def baz():
'''"This" is a string with some
embedded "quotes"'''
return
def troz():
"""Indentation with tabs
is just as OK
"""
return
def zort():
"""Another
multiline
docstring
"""
pass
def poit():
"""
Lorem ipsum dolor sit amet.
Consectetur adipiscing elit:
- sed do eiusmod tempor incididunt ut labore
- dolore magna aliqua
- enim ad minim veniam
- quis nostrud exercitation ullamco laboris nisi
- aliquip ex ea commodo consequat
"""
pass
def under_indent():
"""
These lines are indented in a way that does not
make sense.
"""
pass
def over_indent():
"""
This has a shallow indent
- But some lines are deeper
- And the closing quote is too deep
"""
pass
def single_line():
"""But with a newline after it!"""
pass
def this():
r"""
'hey ho'
"""
def that():
""" "hey yah" """
def and_that():
"""
"hey yah" """
def and_this():
'''
"hey yah"'''
def multiline_whitespace():
""" """
def oneline_whitespace():
""" """
def empty():
""""""
def single_quotes():
"testing"
def believe_it_or_not_this_is_in_the_py_stdlib():
'''
"hey yah"'''
def ignored_docstring():
"""a => \
b"""
def single_line_docstring_with_whitespace():
"""This should be stripped"""
def docstring_with_inline_tabs_and_space_indentation():
"""hey
tab separated value
tab at start of line and then a tab separated value
multiple tabs at the beginning and inline
mixed tabs and spaces at beginning. next line has mixed tabs and spaces only.
line ends with some tabs
"""
def docstring_with_inline_tabs_and_tab_indentation():
"""hey
tab separated value
tab at start of line and then a tab separated value
multiple tabs at the beginning and inline
mixed tabs and spaces at beginning. next line has mixed tabs and spaces only.
line ends with some tabs
"""
pass
def backslash_space():
"""\ """
def multiline_backslash_1():
"""
hey\there\
\ """
def multiline_backslash_2():
"""
hey there \ """
# Regression test for #3425
def multiline_backslash_really_long_dont_crash():
"""
hey there hello guten tag hi hoow are you ola zdravstvuyte ciao como estas ca va \ """
def multiline_backslash_3():
"""
already escaped \\"""
def my_god_its_full_of_stars_1():
"I'm sorry Dave\u2001"
# the space below is actually a \u2001, removed in output
def my_god_its_full_of_stars_2():
"I'm sorry Dave"
def docstring_almost_at_line_limit():
"""long docstring................................................................."""
def docstring_almost_at_line_limit2():
"""long docstring.................................................................
..................................................................................
"""
def docstring_at_line_limit():
"""long docstring................................................................"""
def multiline_docstring_at_line_limit():
"""first line-----------------------------------------------------------------------
second line----------------------------------------------------------------------"""
def stable_quote_normalization_with_immediate_inner_single_quote(self):
"""'<text here>
<text here, since without another non-empty line black is stable>
"""
def foo():
"""
Docstring with a backslash followed by a space\
and then another line
"""

View File

@@ -0,0 +1,4 @@
# Make sure when the file ends with class's docstring,
# It doesn't add extra blank lines.
class ClassWithDocstring:
"""A docstring."""

View File

@@ -0,0 +1,4 @@
# Make sure when the file ends with class's docstring,
# It doesn't add extra blank lines.
class ClassWithDocstring:
"""A docstring."""

View File

@@ -0,0 +1,124 @@
# flags: --skip-string-normalization
class ALonelyClass:
'''
A multiline class docstring.
'''
def AnEquallyLonelyMethod(self):
'''
A multiline method docstring'''
pass
def one_function():
'''This is a docstring with a single line of text.'''
pass
def shockingly_the_quotes_are_normalized():
'''This is a multiline docstring.
This is a multiline docstring.
This is a multiline docstring.
'''
pass
def foo():
"""This is a docstring with
some lines of text here
"""
return
def baz():
'''"This" is a string with some
embedded "quotes"'''
return
def poit():
"""
Lorem ipsum dolor sit amet.
Consectetur adipiscing elit:
- sed do eiusmod tempor incididunt ut labore
- dolore magna aliqua
- enim ad minim veniam
- quis nostrud exercitation ullamco laboris nisi
- aliquip ex ea commodo consequat
"""
pass
def under_indent():
"""
These lines are indented in a way that does not
make sense.
"""
pass
def over_indent():
"""
This has a shallow indent
- But some lines are deeper
- And the closing quote is too deep
"""
pass
def single_line():
"""But with a newline after it!
"""
pass
def this():
r"""
'hey ho'
"""
def that():
""" "hey yah" """
def and_that():
"""
"hey yah" """
def and_this():
'''
"hey yah"'''
def believe_it_or_not_this_is_in_the_py_stdlib(): '''
"hey yah"'''
def shockingly_the_quotes_are_normalized_v2():
'''
Docstring Docstring Docstring
'''
pass
def backslash_space():
'\ '
def multiline_backslash_1():
'''
hey\there\
\ '''
def multiline_backslash_2():
'''
hey there \ '''
def multiline_backslash_3():
'''
already escaped \\ '''

View File

@@ -0,0 +1,123 @@
class ALonelyClass:
'''
A multiline class docstring.
'''
def AnEquallyLonelyMethod(self):
'''
A multiline method docstring'''
pass
def one_function():
'''This is a docstring with a single line of text.'''
pass
def shockingly_the_quotes_are_normalized():
'''This is a multiline docstring.
This is a multiline docstring.
This is a multiline docstring.
'''
pass
def foo():
"""This is a docstring with
some lines of text here
"""
return
def baz():
'''"This" is a string with some
embedded "quotes"'''
return
def poit():
"""
Lorem ipsum dolor sit amet.
Consectetur adipiscing elit:
- sed do eiusmod tempor incididunt ut labore
- dolore magna aliqua
- enim ad minim veniam
- quis nostrud exercitation ullamco laboris nisi
- aliquip ex ea commodo consequat
"""
pass
def under_indent():
"""
These lines are indented in a way that does not
make sense.
"""
pass
def over_indent():
"""
This has a shallow indent
- But some lines are deeper
- And the closing quote is too deep
"""
pass
def single_line():
"""But with a newline after it!"""
pass
def this():
r"""
'hey ho'
"""
def that():
""" "hey yah" """
def and_that():
"""
"hey yah" """
def and_this():
'''
"hey yah"'''
def believe_it_or_not_this_is_in_the_py_stdlib():
'''
"hey yah"'''
def shockingly_the_quotes_are_normalized_v2():
'''
Docstring Docstring Docstring
'''
pass
def backslash_space():
'\ '
def multiline_backslash_1():
'''
hey\there\
\ '''
def multiline_backslash_2():
'''
hey there \ '''
def multiline_backslash_3():
'''
already escaped \\'''

View File

@@ -0,0 +1,50 @@
def docstring_almost_at_line_limit():
"""long docstring.................................................................
"""
def docstring_almost_at_line_limit_with_prefix():
f"""long docstring................................................................
"""
def mulitline_docstring_almost_at_line_limit():
"""long docstring.................................................................
..................................................................................
"""
def mulitline_docstring_almost_at_line_limit_with_prefix():
f"""long docstring................................................................
..................................................................................
"""
def docstring_at_line_limit():
"""long docstring................................................................"""
def docstring_at_line_limit_with_prefix():
f"""long docstring..............................................................."""
def multiline_docstring_at_line_limit():
"""first line-----------------------------------------------------------------------
second line----------------------------------------------------------------------"""
def multiline_docstring_at_line_limit_with_prefix():
f"""first line----------------------------------------------------------------------
second line----------------------------------------------------------------------"""
def single_quote_docstring_over_line_limit():
"We do not want to put the closing quote on a new line as that is invalid (see GH-3141)."
def single_quote_docstring_over_line_limit2():
'We do not want to put the closing quote on a new line as that is invalid (see GH-3141).'

View File

@@ -0,0 +1,49 @@
def docstring_almost_at_line_limit():
"""long docstring................................................................."""
def docstring_almost_at_line_limit_with_prefix():
f"""long docstring................................................................
"""
def mulitline_docstring_almost_at_line_limit():
"""long docstring.................................................................
..................................................................................
"""
def mulitline_docstring_almost_at_line_limit_with_prefix():
f"""long docstring................................................................
..................................................................................
"""
def docstring_at_line_limit():
"""long docstring................................................................"""
def docstring_at_line_limit_with_prefix():
f"""long docstring..............................................................."""
def multiline_docstring_at_line_limit():
"""first line-----------------------------------------------------------------------
second line----------------------------------------------------------------------"""
def multiline_docstring_at_line_limit_with_prefix():
f"""first line----------------------------------------------------------------------
second line----------------------------------------------------------------------"""
def single_quote_docstring_over_line_limit():
"We do not want to put the closing quote on a new line as that is invalid (see GH-3141)."
def single_quote_docstring_over_line_limit2():
"We do not want to put the closing quote on a new line as that is invalid (see GH-3141)."

View File

@@ -0,0 +1,92 @@
"""Docstring."""
# leading comment
def f():
NO = ''
SPACE = ' '
DOUBLESPACE = ' '
t = leaf.type
p = leaf.parent # trailing comment
v = leaf.value
if t in ALWAYS_NO_SPACE:
pass
if t == token.COMMENT: # another trailing comment
return DOUBLESPACE
assert p is not None, f"INTERNAL ERROR: hand-made leaf without parent: {leaf!r}"
prev = leaf.prev_sibling
if not prev:
prevp = preceding_leaf(p)
if not prevp or prevp.type in OPENING_BRACKETS:
return NO
if prevp.type == token.EQUAL:
if prevp.parent and prevp.parent.type in {
syms.typedargslist,
syms.varargslist,
syms.parameters,
syms.arglist,
syms.argument,
}:
return NO
elif prevp.type == token.DOUBLESTAR:
if prevp.parent and prevp.parent.type in {
syms.typedargslist,
syms.varargslist,
syms.parameters,
syms.arglist,
syms.dictsetmaker,
}:
return NO
###############################################################################
# SECTION BECAUSE SECTIONS
###############################################################################
def g():
NO = ''
SPACE = ' '
DOUBLESPACE = ' '
t = leaf.type
p = leaf.parent
v = leaf.value
# Comment because comments
if t in ALWAYS_NO_SPACE:
pass
if t == token.COMMENT:
return DOUBLESPACE
# Another comment because more comments
assert p is not None, f'INTERNAL ERROR: hand-made leaf without parent: {leaf!r}'
prev = leaf.prev_sibling
if not prev:
prevp = preceding_leaf(p)
if not prevp or prevp.type in OPENING_BRACKETS:
# Start of the line or a bracketed expression.
# More than one line for the comment.
return NO
if prevp.type == token.EQUAL:
if prevp.parent and prevp.parent.type in {
syms.typedargslist,
syms.varargslist,
syms.parameters,
syms.arglist,
syms.argument,
}:
return NO

View File

@@ -0,0 +1,89 @@
"""Docstring."""
# leading comment
def f():
NO = ""
SPACE = " "
DOUBLESPACE = " "
t = leaf.type
p = leaf.parent # trailing comment
v = leaf.value
if t in ALWAYS_NO_SPACE:
pass
if t == token.COMMENT: # another trailing comment
return DOUBLESPACE
assert p is not None, f"INTERNAL ERROR: hand-made leaf without parent: {leaf!r}"
prev = leaf.prev_sibling
if not prev:
prevp = preceding_leaf(p)
if not prevp or prevp.type in OPENING_BRACKETS:
return NO
if prevp.type == token.EQUAL:
if prevp.parent and prevp.parent.type in {
syms.typedargslist,
syms.varargslist,
syms.parameters,
syms.arglist,
syms.argument,
}:
return NO
elif prevp.type == token.DOUBLESTAR:
if prevp.parent and prevp.parent.type in {
syms.typedargslist,
syms.varargslist,
syms.parameters,
syms.arglist,
syms.dictsetmaker,
}:
return NO
###############################################################################
# SECTION BECAUSE SECTIONS
###############################################################################
def g():
NO = ""
SPACE = " "
DOUBLESPACE = " "
t = leaf.type
p = leaf.parent
v = leaf.value
# Comment because comments
if t in ALWAYS_NO_SPACE:
pass
if t == token.COMMENT:
return DOUBLESPACE
# Another comment because more comments
assert p is not None, f"INTERNAL ERROR: hand-made leaf without parent: {leaf!r}"
prev = leaf.prev_sibling
if not prev:
prevp = preceding_leaf(p)
if not prevp or prevp.type in OPENING_BRACKETS:
# Start of the line or a bracketed expression.
# More than one line for the comment.
return NO
if prevp.type == token.EQUAL:
if prevp.parent and prevp.parent.type in {
syms.typedargslist,
syms.varargslist,
syms.parameters,
syms.arglist,
syms.argument,
}:
return NO

View File

@@ -0,0 +1,254 @@
...
'some_string'
b'\\xa3'
Name
None
True
False
1
1.0
1j
True or False
True or False or None
True and False
True and False and None
(Name1 and Name2) or Name3
Name1 and Name2 or Name3
Name1 or (Name2 and Name3)
Name1 or Name2 and Name3
(Name1 and Name2) or (Name3 and Name4)
Name1 and Name2 or Name3 and Name4
Name1 or (Name2 and Name3) or Name4
Name1 or Name2 and Name3 or Name4
v1 << 2
1 >> v2
1 % finished
1 + v2 - v3 * 4 ^ 5 ** v6 / 7 // 8
((1 + v2) - (v3 * 4)) ^ (((5 ** v6) / 7) // 8)
not great
~great
+value
-1
~int and not v1 ^ 123 + v2 | True
(~int) and (not ((v1 ^ (123 + v2)) | True))
+really ** -confusing ** ~operator ** -precedence
flags & ~ select.EPOLLIN and waiters.write_task is not None
lambda arg: None
lambda a=True: a
lambda a, b, c=True: a
lambda a, b, c=True, *, d=(1 << v2), e='str': a
lambda a, b, c=True, *vararg, d=(v1 << 2), e='str', **kwargs: a + b
manylambdas = lambda x=lambda y=lambda z=1: z: y(): x()
foo = (lambda port_id, ignore_missing: {"port1": port1_resource, "port2": port2_resource}[port_id])
1 if True else 2
str or None if True else str or bytes or None
(str or None) if True else (str or bytes or None)
str or None if (1 if True else 2) else str or bytes or None
(str or None) if (1 if True else 2) else (str or bytes or None)
((super_long_variable_name or None) if (1 if super_long_test_name else 2) else (str or bytes or None))
{'2.7': dead, '3.7': (long_live or die_hard)}
{'2.7': dead, '3.7': (long_live or die_hard), **{'3.6': verygood}}
{**a, **b, **c}
{'2.7', '3.6', '3.7', '3.8', '3.9', ('4.0' if gilectomy else '3.10')}
({'a': 'b'}, (True or False), (+value), 'string', b'bytes') or None
()
(1,)
(1, 2)
(1, 2, 3)
[]
[1, 2, 3, 4, 5, 6, 7, 8, 9, (10 or A), (11 or B), (12 or C)]
[1, 2, 3,]
[*a]
[*range(10)]
[*a, 4, 5,]
[4, *a, 5,]
[this_is_a_very_long_variable_which_will_force_a_delimiter_split, element, another, *more]
{i for i in (1, 2, 3)}
{(i ** 2) for i in (1, 2, 3)}
{(i ** 2) for i, _ in ((1, 'a'), (2, 'b'), (3, 'c'))}
{((i ** 2) + j) for i in (1, 2, 3) for j in (1, 2, 3)}
[i for i in (1, 2, 3)]
[(i ** 2) for i in (1, 2, 3)]
[(i ** 2) for i, _ in ((1, 'a'), (2, 'b'), (3, 'c'))]
[((i ** 2) + j) for i in (1, 2, 3) for j in (1, 2, 3)]
{i: 0 for i in (1, 2, 3)}
{i: j for i, j in ((1, 'a'), (2, 'b'), (3, 'c'))}
{a: b * 2 for a, b in dictionary.items()}
{a: b * -2 for a, b in dictionary.items()}
{k: v for k, v in this_is_a_very_long_variable_which_will_cause_a_trailing_comma_which_breaks_the_comprehension}
Python3 > Python2 > COBOL
Life is Life
call()
call(arg)
call(kwarg='hey')
call(arg, kwarg='hey')
call(arg, another, kwarg='hey', **kwargs)
call(this_is_a_very_long_variable_which_will_force_a_delimiter_split, arg, another, kwarg='hey', **kwargs) # note: no trailing comma pre-3.6
call(*gidgets[:2])
call(a, *gidgets[:2])
call(**self.screen_kwargs)
call(b, **self.screen_kwargs)
lukasz.langa.pl
call.me(maybe)
1 .real
1.0 .real
....__class__
list[str]
dict[str, int]
tuple[str, ...]
tuple[
str, int, float, dict[str, int]
]
tuple[str, int, float, dict[str, int],]
very_long_variable_name_filters: t.List[
t.Tuple[str, t.Union[str, t.List[t.Optional[str]]]],
]
xxxx_xxxxx_xxxx_xxx: Callable[..., List[SomeClass]] = classmethod( # type: ignore
sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__)
)
xxxx_xxx_xxxx_xxxxx_xxxx_xxx: Callable[..., List[SomeClass]] = classmethod( # type: ignore
sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__)
)
xxxx_xxx_xxxx_xxxxx_xxxx_xxx: Callable[
..., List[SomeClass]
] = classmethod(sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__)) # type: ignore
slice[0]
slice[0:1]
slice[0:1:2]
slice[:]
slice[:-1]
slice[1:]
slice[::-1]
slice[d :: d + 1]
slice[:c, c - 1]
numpy[:, 0:1]
numpy[:, :-1]
numpy[0, :]
numpy[:, i]
numpy[0, :2]
numpy[:N, 0]
numpy[:2, :4]
numpy[2:4, 1:5]
numpy[4:, 2:]
numpy[:, (0, 1, 2, 5)]
numpy[0, [0]]
numpy[:, [i]]
numpy[1 : c + 1, c]
numpy[-(c + 1) :, d]
numpy[:, l[-2]]
numpy[:, ::-1]
numpy[np.newaxis, :]
(str or None) if (sys.version_info[0] > (3,)) else (str or bytes or None)
{'2.7': dead, '3.7': long_live or die_hard}
{'2.7', '3.6', '3.7', '3.8', '3.9', '4.0' if gilectomy else '3.10'}
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10 or A, 11 or B, 12 or C]
(SomeName)
SomeName
(Good, Bad, Ugly)
(i for i in (1, 2, 3))
((i ** 2) for i in (1, 2, 3))
((i ** 2) for i, _ in ((1, 'a'), (2, 'b'), (3, 'c')))
(((i ** 2) + j) for i in (1, 2, 3) for j in (1, 2, 3))
(*starred,)
{"id": "1","type": "type","started_at": now(),"ended_at": now() + timedelta(days=10),"priority": 1,"import_session_id": 1,**kwargs}
a = (1,)
b = 1,
c = 1
d = (1,) + a + (2,)
e = (1,).count(1)
f = 1, *range(10)
g = 1, *"ten"
what_is_up_with_those_new_coord_names = (coord_names + set(vars_to_create)) + set(vars_to_remove)
what_is_up_with_those_new_coord_names = (coord_names | set(vars_to_create)) - set(vars_to_remove)
result = session.query(models.Customer.id).filter(models.Customer.account_id == account_id, models.Customer.email == email_address).order_by(models.Customer.id.asc()).all()
result = session.query(models.Customer.id).filter(models.Customer.account_id == account_id, models.Customer.email == email_address).order_by(models.Customer.id.asc(),).all()
Ø = set()
authors.łukasz.say_thanks()
mapping = {
A: 0.25 * (10.0 / 12),
B: 0.1 * (10.0 / 12),
C: 0.1 * (10.0 / 12),
D: 0.1 * (10.0 / 12),
}
def gen():
yield from outside_of_generator
a = (yield)
b = ((yield))
c = (((yield)))
async def f():
await some.complicated[0].call(with_args=(True or (1 is not 1)))
print(* [] or [1])
print(**{1: 3} if False else {x: x for x in range(3)})
print(* lambda x: x)
assert(not Test),("Short message")
assert this is ComplexTest and not requirements.fit_in_a_single_line(force=False), "Short message"
assert(((parens is TooMany)))
for x, in (1,), (2,), (3,): ...
for y in (): ...
for z in (i for i in (1, 2, 3)): ...
for i in (call()): ...
for j in (1 + (2 + 3)): ...
while(this and that): ...
for addr_family, addr_type, addr_proto, addr_canonname, addr_sockaddr in socket.getaddrinfo('google.com', 'http'):
pass
a = aaaa.bbbb.cccc.dddd.eeee.ffff.gggg.hhhh.iiii.jjjj.kkkk.llll.mmmm.nnnn.oooo.pppp in qqqq.rrrr.ssss.tttt.uuuu.vvvv.xxxx.yyyy.zzzz
a = aaaa.bbbb.cccc.dddd.eeee.ffff.gggg.hhhh.iiii.jjjj.kkkk.llll.mmmm.nnnn.oooo.pppp not in qqqq.rrrr.ssss.tttt.uuuu.vvvv.xxxx.yyyy.zzzz
a = aaaa.bbbb.cccc.dddd.eeee.ffff.gggg.hhhh.iiii.jjjj.kkkk.llll.mmmm.nnnn.oooo.pppp is qqqq.rrrr.ssss.tttt.uuuu.vvvv.xxxx.yyyy.zzzz
a = aaaa.bbbb.cccc.dddd.eeee.ffff.gggg.hhhh.iiii.jjjj.kkkk.llll.mmmm.nnnn.oooo.pppp is not qqqq.rrrr.ssss.tttt.uuuu.vvvv.xxxx.yyyy.zzzz
if (
threading.current_thread() != threading.main_thread() and
threading.current_thread() != threading.main_thread() or
signal.getsignal(signal.SIGINT) != signal.default_int_handler
):
return True
if (
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
):
return True
if (
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
):
return True
if (
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
):
return True
if (
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
):
return True
if (
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa *
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
):
return True
if (
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa /
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
):
return True
if (
~ aaaa.a + aaaa.b - aaaa.c * aaaa.d / aaaa.e | aaaa.f & aaaa.g % aaaa.h ^ aaaa.i << aaaa.k >> aaaa.l ** aaaa.m // aaaa.n
):
return True
if (
~ aaaaaaaa.a + aaaaaaaa.b - aaaaaaaa.c @ aaaaaaaa.d / aaaaaaaa.e | aaaaaaaa.f & aaaaaaaa.g % aaaaaaaa.h ^ aaaaaaaa.i << aaaaaaaa.k >> aaaaaaaa.l ** aaaaaaaa.m // aaaaaaaa.n
):
return True
if (
~ aaaaaaaaaaaaaaaa.a + aaaaaaaaaaaaaaaa.b - aaaaaaaaaaaaaaaa.c * aaaaaaaaaaaaaaaa.d @ aaaaaaaaaaaaaaaa.e | aaaaaaaaaaaaaaaa.f & aaaaaaaaaaaaaaaa.g % aaaaaaaaaaaaaaaa.h ^ aaaaaaaaaaaaaaaa.i << aaaaaaaaaaaaaaaa.k >> aaaaaaaaaaaaaaaa.l ** aaaaaaaaaaaaaaaa.m // aaaaaaaaaaaaaaaa.n
):
return True
aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa - aaaaaaaaaaaaaaaa * (aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa) / (aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa)
aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa >> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa << aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
bbbb >> bbbb * bbbb
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ^bbbb.a & aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
last_call()
# standalone comment at ENDMARKER

View File

@@ -0,0 +1,371 @@
...
"some_string"
b"\\xa3"
Name
None
True
False
1
1.0
1j
True or False
True or False or None
True and False
True and False and None
(Name1 and Name2) or Name3
Name1 and Name2 or Name3
Name1 or (Name2 and Name3)
Name1 or Name2 and Name3
(Name1 and Name2) or (Name3 and Name4)
Name1 and Name2 or Name3 and Name4
Name1 or (Name2 and Name3) or Name4
Name1 or Name2 and Name3 or Name4
v1 << 2
1 >> v2
1 % finished
1 + v2 - v3 * 4 ^ 5**v6 / 7 // 8
((1 + v2) - (v3 * 4)) ^ (((5**v6) / 7) // 8)
not great
~great
+value
-1
~int and not v1 ^ 123 + v2 | True
(~int) and (not ((v1 ^ (123 + v2)) | True))
+(really ** -(confusing ** ~(operator**-precedence)))
flags & ~select.EPOLLIN and waiters.write_task is not None
lambda arg: None
lambda a=True: a
lambda a, b, c=True: a
lambda a, b, c=True, *, d=(1 << v2), e="str": a
lambda a, b, c=True, *vararg, d=(v1 << 2), e="str", **kwargs: a + b
manylambdas = lambda x=lambda y=lambda z=1: z: y(): x()
foo = lambda port_id, ignore_missing: {
"port1": port1_resource,
"port2": port2_resource,
}[port_id]
1 if True else 2
str or None if True else str or bytes or None
(str or None) if True else (str or bytes or None)
str or None if (1 if True else 2) else str or bytes or None
(str or None) if (1 if True else 2) else (str or bytes or None)
(
(super_long_variable_name or None)
if (1 if super_long_test_name else 2)
else (str or bytes or None)
)
{"2.7": dead, "3.7": (long_live or die_hard)}
{"2.7": dead, "3.7": (long_live or die_hard), **{"3.6": verygood}}
{**a, **b, **c}
{"2.7", "3.6", "3.7", "3.8", "3.9", ("4.0" if gilectomy else "3.10")}
({"a": "b"}, (True or False), (+value), "string", b"bytes") or None
()
(1,)
(1, 2)
(1, 2, 3)
[]
[1, 2, 3, 4, 5, 6, 7, 8, 9, (10 or A), (11 or B), (12 or C)]
[
1,
2,
3,
]
[*a]
[*range(10)]
[
*a,
4,
5,
]
[
4,
*a,
5,
]
[
this_is_a_very_long_variable_which_will_force_a_delimiter_split,
element,
another,
*more,
]
{i for i in (1, 2, 3)}
{(i**2) for i in (1, 2, 3)}
{(i**2) for i, _ in ((1, "a"), (2, "b"), (3, "c"))}
{((i**2) + j) for i in (1, 2, 3) for j in (1, 2, 3)}
[i for i in (1, 2, 3)]
[(i**2) for i in (1, 2, 3)]
[(i**2) for i, _ in ((1, "a"), (2, "b"), (3, "c"))]
[((i**2) + j) for i in (1, 2, 3) for j in (1, 2, 3)]
{i: 0 for i in (1, 2, 3)}
{i: j for i, j in ((1, "a"), (2, "b"), (3, "c"))}
{a: b * 2 for a, b in dictionary.items()}
{a: b * -2 for a, b in dictionary.items()}
{
k: v
for k, v in this_is_a_very_long_variable_which_will_cause_a_trailing_comma_which_breaks_the_comprehension
}
Python3 > Python2 > COBOL
Life is Life
call()
call(arg)
call(kwarg="hey")
call(arg, kwarg="hey")
call(arg, another, kwarg="hey", **kwargs)
call(
this_is_a_very_long_variable_which_will_force_a_delimiter_split,
arg,
another,
kwarg="hey",
**kwargs
) # note: no trailing comma pre-3.6
call(*gidgets[:2])
call(a, *gidgets[:2])
call(**self.screen_kwargs)
call(b, **self.screen_kwargs)
lukasz.langa.pl
call.me(maybe)
(1).real
(1.0).real
....__class__
list[str]
dict[str, int]
tuple[str, ...]
tuple[str, int, float, dict[str, int]]
tuple[
str,
int,
float,
dict[str, int],
]
very_long_variable_name_filters: t.List[
t.Tuple[str, t.Union[str, t.List[t.Optional[str]]]],
]
xxxx_xxxxx_xxxx_xxx: Callable[..., List[SomeClass]] = classmethod( # type: ignore
sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__)
)
xxxx_xxx_xxxx_xxxxx_xxxx_xxx: Callable[..., List[SomeClass]] = classmethod( # type: ignore
sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__)
)
xxxx_xxx_xxxx_xxxxx_xxxx_xxx: Callable[..., List[SomeClass]] = classmethod(
sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__)
) # type: ignore
slice[0]
slice[0:1]
slice[0:1:2]
slice[:]
slice[:-1]
slice[1:]
slice[::-1]
slice[d :: d + 1]
slice[:c, c - 1]
numpy[:, 0:1]
numpy[:, :-1]
numpy[0, :]
numpy[:, i]
numpy[0, :2]
numpy[:N, 0]
numpy[:2, :4]
numpy[2:4, 1:5]
numpy[4:, 2:]
numpy[:, (0, 1, 2, 5)]
numpy[0, [0]]
numpy[:, [i]]
numpy[1 : c + 1, c]
numpy[-(c + 1) :, d]
numpy[:, l[-2]]
numpy[:, ::-1]
numpy[np.newaxis, :]
(str or None) if (sys.version_info[0] > (3,)) else (str or bytes or None)
{"2.7": dead, "3.7": long_live or die_hard}
{"2.7", "3.6", "3.7", "3.8", "3.9", "4.0" if gilectomy else "3.10"}
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10 or A, 11 or B, 12 or C]
(SomeName)
SomeName
(Good, Bad, Ugly)
(i for i in (1, 2, 3))
((i**2) for i in (1, 2, 3))
((i**2) for i, _ in ((1, "a"), (2, "b"), (3, "c")))
(((i**2) + j) for i in (1, 2, 3) for j in (1, 2, 3))
(*starred,)
{
"id": "1",
"type": "type",
"started_at": now(),
"ended_at": now() + timedelta(days=10),
"priority": 1,
"import_session_id": 1,
**kwargs,
}
a = (1,)
b = (1,)
c = 1
d = (1,) + a + (2,)
e = (1,).count(1)
f = 1, *range(10)
g = 1, *"ten"
what_is_up_with_those_new_coord_names = (coord_names + set(vars_to_create)) + set(
vars_to_remove
)
what_is_up_with_those_new_coord_names = (coord_names | set(vars_to_create)) - set(
vars_to_remove
)
result = (
session.query(models.Customer.id)
.filter(
models.Customer.account_id == account_id, models.Customer.email == email_address
)
.order_by(models.Customer.id.asc())
.all()
)
result = (
session.query(models.Customer.id)
.filter(
models.Customer.account_id == account_id, models.Customer.email == email_address
)
.order_by(
models.Customer.id.asc(),
)
.all()
)
Ø = set()
authors.łukasz.say_thanks()
mapping = {
A: 0.25 * (10.0 / 12),
B: 0.1 * (10.0 / 12),
C: 0.1 * (10.0 / 12),
D: 0.1 * (10.0 / 12),
}
def gen():
yield from outside_of_generator
a = yield
b = yield
c = yield
async def f():
await some.complicated[0].call(with_args=(True or (1 is not 1)))
print(*[] or [1])
print(**{1: 3} if False else {x: x for x in range(3)})
print(*lambda x: x)
assert not Test, "Short message"
assert this is ComplexTest and not requirements.fit_in_a_single_line(
force=False
), "Short message"
assert parens is TooMany
for (x,) in (1,), (2,), (3,):
...
for y in ():
...
for z in (i for i in (1, 2, 3)):
...
for i in call():
...
for j in 1 + (2 + 3):
...
while this and that:
...
for (
addr_family,
addr_type,
addr_proto,
addr_canonname,
addr_sockaddr,
) in socket.getaddrinfo("google.com", "http"):
pass
a = (
aaaa.bbbb.cccc.dddd.eeee.ffff.gggg.hhhh.iiii.jjjj.kkkk.llll.mmmm.nnnn.oooo.pppp
in qqqq.rrrr.ssss.tttt.uuuu.vvvv.xxxx.yyyy.zzzz
)
a = (
aaaa.bbbb.cccc.dddd.eeee.ffff.gggg.hhhh.iiii.jjjj.kkkk.llll.mmmm.nnnn.oooo.pppp
not in qqqq.rrrr.ssss.tttt.uuuu.vvvv.xxxx.yyyy.zzzz
)
a = (
aaaa.bbbb.cccc.dddd.eeee.ffff.gggg.hhhh.iiii.jjjj.kkkk.llll.mmmm.nnnn.oooo.pppp
is qqqq.rrrr.ssss.tttt.uuuu.vvvv.xxxx.yyyy.zzzz
)
a = (
aaaa.bbbb.cccc.dddd.eeee.ffff.gggg.hhhh.iiii.jjjj.kkkk.llll.mmmm.nnnn.oooo.pppp
is not qqqq.rrrr.ssss.tttt.uuuu.vvvv.xxxx.yyyy.zzzz
)
if (
threading.current_thread() != threading.main_thread()
and threading.current_thread() != threading.main_thread()
or signal.getsignal(signal.SIGINT) != signal.default_int_handler
):
return True
if (
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
| aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
):
return True
if (
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
& aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
):
return True
if (
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
):
return True
if (
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
):
return True
if (
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
* aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
):
return True
if (
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
/ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
):
return True
if (
~aaaa.a + aaaa.b - aaaa.c * aaaa.d / aaaa.e
| aaaa.f & aaaa.g % aaaa.h ^ aaaa.i << aaaa.k >> aaaa.l**aaaa.m // aaaa.n
):
return True
if (
~aaaaaaaa.a + aaaaaaaa.b - aaaaaaaa.c @ aaaaaaaa.d / aaaaaaaa.e
| aaaaaaaa.f & aaaaaaaa.g % aaaaaaaa.h
^ aaaaaaaa.i << aaaaaaaa.k >> aaaaaaaa.l**aaaaaaaa.m // aaaaaaaa.n
):
return True
if (
~aaaaaaaaaaaaaaaa.a
+ aaaaaaaaaaaaaaaa.b
- aaaaaaaaaaaaaaaa.c * aaaaaaaaaaaaaaaa.d @ aaaaaaaaaaaaaaaa.e
| aaaaaaaaaaaaaaaa.f & aaaaaaaaaaaaaaaa.g % aaaaaaaaaaaaaaaa.h
^ aaaaaaaaaaaaaaaa.i
<< aaaaaaaaaaaaaaaa.k
>> aaaaaaaaaaaaaaaa.l**aaaaaaaaaaaaaaaa.m // aaaaaaaaaaaaaaaa.n
):
return True
(
aaaaaaaaaaaaaaaa
+ aaaaaaaaaaaaaaaa
- aaaaaaaaaaaaaaaa
* (aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa)
/ (aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa)
)
aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa
(
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
>> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
<< aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
)
bbbb >> bbbb * bbbb
(
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
^ bbbb.a & aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
^ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
)
last_call()
# standalone comment at ENDMARKER

View File

@@ -0,0 +1,8 @@
def foo(e):
f""" {'.'.join(e)}"""
def bar(e):
f"{'.'.join(e)}"
def baz(e):
F""" {'.'.join(e)}"""

View File

@@ -0,0 +1,10 @@
def foo(e):
f""" {'.'.join(e)}"""
def bar(e):
f"{'.'.join(e)}"
def baz(e):
f""" {'.'.join(e)}"""

View File

@@ -0,0 +1,186 @@
#!/usr/bin/env python3
import asyncio
import sys
from third_party import X, Y, Z
from library import some_connection, \
some_decorator
# fmt: off
from third_party import (X,
Y, Z)
# fmt: on
f'trigger 3.6 mode'
# Comment 1
# Comment 2
# fmt: off
def func_no_args():
a; b; c
if True: raise RuntimeError
if False: ...
for i in range(10):
print(i)
continue
exec('new-style exec', {}, {})
return None
async def coroutine(arg, exec=False):
'Single-line docstring. Multiline is harder to reformat.'
async with some_connection() as conn:
await conn.do_what_i_mean('SELECT bobby, tables FROM xkcd', timeout=2)
await asyncio.sleep(1)
@asyncio.coroutine
@some_decorator(
with_args=True,
many_args=[1,2,3]
)
def function_signature_stress_test(number:int,no_annotation=None,text:str='default',* ,debug:bool=False,**kwargs) -> str:
return text[number:-1]
# fmt: on
def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r''):
offset = attr.ib(default=attr.Factory( lambda: _r.uniform(1, 2)))
assert task._cancel_stack[:len(old_stack)] == old_stack
def spaces_types(a: int = 1, b: tuple = (), c: list = [], d: dict = {}, e: bool = True, f: int = -1, g: int = 1 if False else 2, h: str = "", i: str = r''): ...
def spaces2(result= _core.Value(None)):
...
something = {
# fmt: off
key: 'value',
}
def subscriptlist():
atom[
# fmt: off
'some big and',
'complex subscript',
# fmt: on
goes + here, andhere,
]
def import_as_names():
# fmt: off
from hello import a, b
'unformatted'
# fmt: on
def testlist_star_expr():
# fmt: off
a , b = *hello
'unformatted'
# fmt: on
def yield_expr():
# fmt: off
yield hello
'unformatted'
# fmt: on
'formatted'
# fmt: off
( yield hello )
'unformatted'
# fmt: on
def example(session):
# fmt: off
result = session\
.query(models.Customer.id)\
.filter(models.Customer.account_id == account_id,
models.Customer.email == email_address)\
.order_by(models.Customer.id.asc())\
.all()
# fmt: on
def off_and_on_without_data():
"""All comments here are technically on the same prefix.
The comments between will be formatted. This is a known limitation.
"""
# fmt: off
#hey, that won't work
# fmt: on
pass
def on_and_off_broken():
"""Another known limitation."""
# fmt: on
# fmt: off
this=should.not_be.formatted()
and_=indeed . it is not formatted
because . the . handling . inside . generate_ignored_nodes()
now . considers . multiple . fmt . directives . within . one . prefix
# fmt: on
# fmt: off
# ...but comments still get reformatted even though they should not be
# fmt: on
def long_lines():
if True:
typedargslist.extend(
gen_annotated_params(ast_args.kwonlyargs, ast_args.kw_defaults, parameters, implicit_default=True)
)
# fmt: off
a = (
unnecessary_bracket()
)
# fmt: on
_type_comment_re = re.compile(
r"""
^
[\t ]*
\#[ ]type:[ ]*
(?P<type>
[^#\t\n]+?
)
(?<!ignore) # note: this will force the non-greedy + in <type> to match
# a trailing space which is why we need the silliness below
(?<!ignore[ ]{1})(?<!ignore[ ]{2})(?<!ignore[ ]{3})(?<!ignore[ ]{4})
(?<!ignore[ ]{5})(?<!ignore[ ]{6})(?<!ignore[ ]{7})(?<!ignore[ ]{8})
(?<!ignore[ ]{9})(?<!ignore[ ]{10})
[\t ]*
(?P<nl>
(?:\#[^\n]*)?
\n?
)
$
""",
# fmt: off
re.MULTILINE|re.VERBOSE
# fmt: on
)
def single_literal_yapf_disable():
"""Black does not support this."""
BAZ = {
(1, 2, 3, 4),
(5, 6, 7, 8),
(9, 10, 11, 12)
} # yapf: disable
cfg.rule(
"Default", "address",
xxxx_xxxx=["xxx-xxxxxx-xxxxxxxxxx"],
xxxxxx="xx_xxxxx", xxxxxxx="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
xxxxxxxxx_xxxx=True, xxxxxxxx_xxxxxxxxxx=False,
xxxxxx_xxxxxx=2, xxxxxx_xxxxx_xxxxxxxx=70, xxxxxx_xxxxxx_xxxxx=True,
# fmt: off
xxxxxxx_xxxxxxxxxxxx={
"xxxxxxxx": {
"xxxxxx": False,
"xxxxxxx": False,
"xxxx_xxxxxx": "xxxxx",
},
"xxxxxxxx-xxxxx": {
"xxxxxx": False,
"xxxxxxx": True,
"xxxx_xxxxxx": "xxxxxx",
},
},
# fmt: on
xxxxxxxxxx_xxxxxxxxxxx_xxxxxxx_xxxxxxxxx=5
)
# fmt: off
yield 'hello'
# No formatting to the end of the file
l=[1,2,3]
d={'a':1,
'b':2}

View File

@@ -0,0 +1,223 @@
#!/usr/bin/env python3
import asyncio
import sys
from third_party import X, Y, Z
from library import some_connection, some_decorator
# fmt: off
from third_party import (X,
Y, Z)
# fmt: on
f"trigger 3.6 mode"
# Comment 1
# Comment 2
# fmt: off
def func_no_args():
a; b; c
if True: raise RuntimeError
if False: ...
for i in range(10):
print(i)
continue
exec('new-style exec', {}, {})
return None
async def coroutine(arg, exec=False):
'Single-line docstring. Multiline is harder to reformat.'
async with some_connection() as conn:
await conn.do_what_i_mean('SELECT bobby, tables FROM xkcd', timeout=2)
await asyncio.sleep(1)
@asyncio.coroutine
@some_decorator(
with_args=True,
many_args=[1,2,3]
)
def function_signature_stress_test(number:int,no_annotation=None,text:str='default',* ,debug:bool=False,**kwargs) -> str:
return text[number:-1]
# fmt: on
def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r""):
offset = attr.ib(default=attr.Factory(lambda: _r.uniform(1, 2)))
assert task._cancel_stack[: len(old_stack)] == old_stack
def spaces_types(
a: int = 1,
b: tuple = (),
c: list = [],
d: dict = {},
e: bool = True,
f: int = -1,
g: int = 1 if False else 2,
h: str = "",
i: str = r"",
):
...
def spaces2(result=_core.Value(None)):
...
something = {
# fmt: off
key: 'value',
}
def subscriptlist():
atom[
# fmt: off
'some big and',
'complex subscript',
# fmt: on
goes + here,
andhere,
]
def import_as_names():
# fmt: off
from hello import a, b
'unformatted'
# fmt: on
def testlist_star_expr():
# fmt: off
a , b = *hello
'unformatted'
# fmt: on
def yield_expr():
# fmt: off
yield hello
'unformatted'
# fmt: on
"formatted"
# fmt: off
( yield hello )
'unformatted'
# fmt: on
def example(session):
# fmt: off
result = session\
.query(models.Customer.id)\
.filter(models.Customer.account_id == account_id,
models.Customer.email == email_address)\
.order_by(models.Customer.id.asc())\
.all()
# fmt: on
def off_and_on_without_data():
"""All comments here are technically on the same prefix.
The comments between will be formatted. This is a known limitation.
"""
# fmt: off
# hey, that won't work
# fmt: on
pass
def on_and_off_broken():
"""Another known limitation."""
# fmt: on
# fmt: off
this=should.not_be.formatted()
and_=indeed . it is not formatted
because . the . handling . inside . generate_ignored_nodes()
now . considers . multiple . fmt . directives . within . one . prefix
# fmt: on
# fmt: off
# ...but comments still get reformatted even though they should not be
# fmt: on
def long_lines():
if True:
typedargslist.extend(
gen_annotated_params(
ast_args.kwonlyargs,
ast_args.kw_defaults,
parameters,
implicit_default=True,
)
)
# fmt: off
a = (
unnecessary_bracket()
)
# fmt: on
_type_comment_re = re.compile(
r"""
^
[\t ]*
\#[ ]type:[ ]*
(?P<type>
[^#\t\n]+?
)
(?<!ignore) # note: this will force the non-greedy + in <type> to match
# a trailing space which is why we need the silliness below
(?<!ignore[ ]{1})(?<!ignore[ ]{2})(?<!ignore[ ]{3})(?<!ignore[ ]{4})
(?<!ignore[ ]{5})(?<!ignore[ ]{6})(?<!ignore[ ]{7})(?<!ignore[ ]{8})
(?<!ignore[ ]{9})(?<!ignore[ ]{10})
[\t ]*
(?P<nl>
(?:\#[^\n]*)?
\n?
)
$
""",
# fmt: off
re.MULTILINE|re.VERBOSE
# fmt: on
)
def single_literal_yapf_disable():
"""Black does not support this."""
BAZ = {(1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)} # yapf: disable
cfg.rule(
"Default",
"address",
xxxx_xxxx=["xxx-xxxxxx-xxxxxxxxxx"],
xxxxxx="xx_xxxxx",
xxxxxxx="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
xxxxxxxxx_xxxx=True,
xxxxxxxx_xxxxxxxxxx=False,
xxxxxx_xxxxxx=2,
xxxxxx_xxxxx_xxxxxxxx=70,
xxxxxx_xxxxxx_xxxxx=True,
# fmt: off
xxxxxxx_xxxxxxxxxxxx={
"xxxxxxxx": {
"xxxxxx": False,
"xxxxxxx": False,
"xxxx_xxxxxx": "xxxxx",
},
"xxxxxxxx-xxxxx": {
"xxxxxx": False,
"xxxxxxx": True,
"xxxx_xxxxxx": "xxxxxx",
},
},
# fmt: on
xxxxxxxxxx_xxxxxxxxxxx_xxxxxxx_xxxxxxxxx=5,
)
# fmt: off
yield 'hello'
# No formatting to the end of the file
l=[1,2,3]
d={'a':1,
'b':2}

View File

@@ -0,0 +1,40 @@
import pytest
TmSt = 1
TmEx = 2
# fmt: off
# Test data:
# Position, Volume, State, TmSt/TmEx/None, [call, [arg1...]]
@pytest.mark.parametrize('test', [
# Test don't manage the volume
[
('stuff', 'in')
],
])
def test_fader(test):
pass
def check_fader(test):
pass
def verify_fader(test):
# misaligned comment
pass
def verify_fader(test):
"""Hey, ho."""
assert test.passed()
def test_calculate_fades():
calcs = [
# one is zero/none
(0, 4, 0, 0, 10, 0, 0, 6, 10),
(None, 4, 0, 0, 10, 0, 0, 6, 10),
]
# fmt: on

View File

@@ -0,0 +1,40 @@
import pytest
TmSt = 1
TmEx = 2
# fmt: off
# Test data:
# Position, Volume, State, TmSt/TmEx/None, [call, [arg1...]]
@pytest.mark.parametrize('test', [
# Test don't manage the volume
[
('stuff', 'in')
],
])
def test_fader(test):
pass
def check_fader(test):
pass
def verify_fader(test):
# misaligned comment
pass
def verify_fader(test):
"""Hey, ho."""
assert test.passed()
def test_calculate_fades():
calcs = [
# one is zero/none
(0, 4, 0, 0, 10, 0, 0, 6, 10),
(None, 4, 0, 0, 10, 0, 0, 6, 10),
]
# fmt: on

View File

@@ -0,0 +1,17 @@
# fmt: off
x = [
1, 2,
3, 4,
]
# fmt: on
# fmt: off
x = [
1, 2,
3, 4,
]
# fmt: on
x = [
1, 2, 3, 4
]

View File

@@ -0,0 +1,15 @@
# fmt: off
x = [
1, 2,
3, 4,
]
# fmt: on
# fmt: off
x = [
1, 2,
3, 4,
]
# fmt: on
x = [1, 2, 3, 4]

View File

@@ -0,0 +1,13 @@
# fmt: off
@test([
1, 2,
3, 4,
])
# fmt: on
def f(): pass
@test([
1, 2,
3, 4,
])
def f(): pass

View File

@@ -0,0 +1,20 @@
# fmt: off
@test([
1, 2,
3, 4,
])
# fmt: on
def f():
pass
@test(
[
1,
2,
3,
4,
]
)
def f():
pass

View File

@@ -0,0 +1,84 @@
# Regression test for https://github.com/psf/black/issues/3129.
setup(
entry_points={
# fmt: off
"console_scripts": [
"foo-bar"
"=foo.bar.:main",
# fmt: on
] # Includes an formatted indentation.
},
)
# Regression test for https://github.com/psf/black/issues/2015.
run(
# fmt: off
[
"ls",
"-la",
]
# fmt: on
+ path,
check=True,
)
# Regression test for https://github.com/psf/black/issues/3026.
def test_func():
# yapf: disable
if unformatted( args ):
return True
# yapf: enable
elif b:
return True
return False
# Regression test for https://github.com/psf/black/issues/2567.
if True:
# fmt: off
for _ in range( 1 ):
# fmt: on
print ( "This won't be formatted" )
print ( "This won't be formatted either" )
else:
print ( "This will be formatted" )
# Regression test for https://github.com/psf/black/issues/3184.
class A:
async def call(param):
if param:
# fmt: off
if param[0:4] in (
"ABCD", "EFGH"
) :
# fmt: on
print ( "This won't be formatted" )
elif param[0:4] in ("ZZZZ",):
print ( "This won't be formatted either" )
print ( "This will be formatted" )
# Regression test for https://github.com/psf/black/issues/2985.
class Named(t.Protocol):
# fmt: off
@property
def this_wont_be_formatted ( self ) -> str: ...
class Factory(t.Protocol):
def this_will_be_formatted ( self, **kwargs ) -> Named: ...
# fmt: on
# Regression test for https://github.com/psf/black/issues/3436.
if x:
return x
# fmt: off
elif unformatted:
# fmt: on
will_be_formatted ()

View File

@@ -0,0 +1,87 @@
# Regression test for https://github.com/psf/black/issues/3129.
setup(
entry_points={
# fmt: off
"console_scripts": [
"foo-bar"
"=foo.bar.:main",
# fmt: on
] # Includes an formatted indentation.
},
)
# Regression test for https://github.com/psf/black/issues/2015.
run(
# fmt: off
[
"ls",
"-la",
]
# fmt: on
+ path,
check=True,
)
# Regression test for https://github.com/psf/black/issues/3026.
def test_func():
# yapf: disable
if unformatted( args ):
return True
# yapf: enable
elif b:
return True
return False
# Regression test for https://github.com/psf/black/issues/2567.
if True:
# fmt: off
for _ in range( 1 ):
# fmt: on
print ( "This won't be formatted" )
print ( "This won't be formatted either" )
else:
print("This will be formatted")
# Regression test for https://github.com/psf/black/issues/3184.
class A:
async def call(param):
if param:
# fmt: off
if param[0:4] in (
"ABCD", "EFGH"
) :
# fmt: on
print ( "This won't be formatted" )
elif param[0:4] in ("ZZZZ",):
print ( "This won't be formatted either" )
print("This will be formatted")
# Regression test for https://github.com/psf/black/issues/2985.
class Named(t.Protocol):
# fmt: off
@property
def this_wont_be_formatted ( self ) -> str: ...
class Factory(t.Protocol):
def this_will_be_formatted(self, **kwargs) -> Named:
...
# fmt: on
# Regression test for https://github.com/psf/black/issues/3436.
if x:
return x
# fmt: off
elif unformatted:
# fmt: on
will_be_formatted()

View File

@@ -0,0 +1,19 @@
# Regression test for https://github.com/psf/black/issues/3438
import ast
import collections # fmt: skip
import dataclasses
# fmt: off
import os
# fmt: on
import pathlib
import re # fmt: skip
import secrets
# fmt: off
import sys
# fmt: on
import tempfile
import zoneinfo

View File

@@ -0,0 +1,19 @@
# Regression test for https://github.com/psf/black/issues/3438
import ast
import collections # fmt: skip
import dataclasses
# fmt: off
import os
# fmt: on
import pathlib
import re # fmt: skip
import secrets
# fmt: off
import sys
# fmt: on
import tempfile
import zoneinfo

Some files were not shown because too many files have changed in this diff Show More