YAPF é um formatador Python baseado no clang-format
(desenvolvido por Daniel Jasper). Em essência, o algoritmo pega o código e calcula a melhor formatação que está de acordo com o estilo configurado. Isso elimina muito do trabalho penoso de manter seu código.
O objetivo final é que o código produzido pelo YAPF seja tão bom quanto o código que um programador escreveria se estivesse seguindo o guia de estilo.
Observação: YAPF não é um produto oficial do Google (experimental ou não), é apenas um código que pertence ao Google.
Para instalar o YAPF do PyPI:
$ pip install yapf
O YAPF ainda é considerado em estágio "beta" e a versão lançada pode mudar frequentemente; portanto, a melhor maneira de se manter atualizado com os desenvolvimentos mais recentes é clonar este repositório ou instalar diretamente do github:
$ pip install git+https://github.com/google/yapf.git
Observe que se você pretende usar o YAPF como uma ferramenta de linha de comando em vez de uma biblioteca, a instalação não será necessária. YAPF suporta ser executado como um diretório pelo interpretador Python. Se você clonou/descompactou o YAPF em DIR
, é possível executar:
$ PYTHONPATH=DIR python DIR/yapf [options] ...
O YAPF é suportado por vários editores por meio de extensões ou plug-ins da comunidade. Consulte Suporte ao Editor para obter mais informações.
YAPF suporta Python 3.7+.
usage: yapf [-h] [-v] [-d | -i | -q] [-r | -l START-END] [-e PATTERN]
[--style STYLE] [--style-help] [--no-local-style] [-p] [-m] [-vv]
[files ...]
Formatter for Python code.
positional arguments:
files reads from stdin when no files are specified.
optional arguments:
-h, --help show this help message and exit
-v, --version show program's version number and exit
-d, --diff print the diff for the fixed source
-i, --in-place make changes to files in place
-q, --quiet output nothing and set return value
-r, --recursive run recursively over directories
-l START-END, --lines START-END
range of lines to reformat, one-based
-e PATTERN, --exclude PATTERN
patterns for files to exclude from formatting
--style STYLE specify formatting style: either a style name (for
example "pep8" or "google"), or the name of a file
with style settings. The default is pep8 unless a
.style.yapf or setup.cfg or pyproject.toml file
located in the same directory as the source or one of
its parent directories (for stdin, the current
directory is used).
--style-help show style settings and exit; this output can be saved
to .style.yapf to make your settings permanent
--no-local-style don't search for local style definition
-p, --parallel run YAPF in parallel when formatting multiple files.
-m, --print-modified print out file names of modified files
-vv, --verbose print out file names while processing
Normalmente o YAPF retorna zero no encerramento bem-sucedido do programa e diferente de zero caso contrário.
Se --diff
for fornecido, YAPF retornará zero quando nenhuma alteração for necessária, diferente de zero caso contrário (incluindo erro de programa). Você pode usar isso em um fluxo de trabalho de CI para testar se o código foi formatado em YAPF.
Além de excluir padrões fornecidos na linha de comando, o YAPF procura padrões adicionais especificados em um arquivo chamado .yapfignore
ou pyproject.toml
localizado no diretório de trabalho a partir do qual o YAPF é chamado.
A sintaxe de .yapfignore
é semelhante à correspondência de padrão de nome de arquivo do UNIX:
* matches everything
? matches any single character
[seq] matches any character in seq
[!seq] matches any character not in seq
Observe que nenhuma entrada deve começar com ./
.
Se você usar pyproject.toml
, os padrões de exclusão serão especificados pela chave ignore_patterns
na seção [tool.yapfignore]
. Por exemplo:
[tool.yapfignore]
ignore_patterns = [
" temp/**/*.py " ,
" temp2/*.py "
]
O estilo de formatação usado pelo YAPF é configurável e existem muitos "botões" que podem ser usados para ajustar como o YAPF faz a formatação. Veja o módulo style.py
para a lista completa.
Para controlar o estilo, execute YAPF com o argumento --style
. Ele aceita um dos estilos predefinidos (por exemplo, pep8
ou google
), um caminho para um arquivo de configuração que especifica o estilo desejado ou um dicionário de pares chave/valor.
O arquivo de configuração é uma lista simples de pares key = value
(sem distinção entre maiúsculas e minúsculas) com um título [style]
. Por exemplo:
[style]
based_on_style = pep8
spaces_before_comment = 4
split_before_logical_operator = true
A configuração based_on_style
determina em qual dos estilos predefinidos esse estilo personalizado se baseia (pense nisso como uma subclasse). Quatro estilos são predefinidos:
pep8
(padrão)google
(baseado no Guia de estilo do Google Python)yapf
(para uso com projetos de código aberto do Google)facebook
Consulte _STYLE_NAME_TO_FACTORY
em style.py
para obter detalhes.
Também é possível fazer o mesmo na linha de comando com um dicionário. Por exemplo:
--style= ' {based_on_style: pep8, indent_width: 2} '
Isso pegará o estilo base pep8
e o modificará para ter dois recuos de espaço.
O YAPF procurará o estilo de formatação da seguinte maneira:
[style]
de um arquivo .style.yapf
no diretório atual ou em um de seus diretórios pai.[yapf]
de um arquivo setup.cfg
no diretório atual ou em um de seus diretórios pai.[tool.yapf]
de um arquivo pyproject.toml
no diretório atual ou em um de seus diretórios pai.[style]
de um arquivo ~/.config/yapf/style
em seu diretório inicial.Se nenhum desses arquivos for encontrado, o estilo padrão PEP8 será usado.
Um exemplo do tipo de formatação que o YAPF pode fazer, vai levar esse código feio:
x = { 'a' : 37 , 'b' : 42 ,
'c' : 927 }
y = 'hello ' 'world'
z = 'hello ' + 'world'
a = 'hello {}' . format ( 'world' )
class foo ( object ):
def f ( self ):
return 37 * - + 2
def g ( self , x , y = 42 ):
return y
def f ( a ) :
return 37 + - + a [ 42 - x : y ** 3 ]
e reformate-o em:
x = { 'a' : 37 , 'b' : 42 , 'c' : 927 }
y = 'hello ' 'world'
z = 'hello ' + 'world'
a = 'hello {}' . format ( 'world' )
class foo ( object ):
def f ( self ):
return 37 * - + 2
def g ( self , x , y = 42 ):
return y
def f ( a ):
return 37 + - + a [ 42 - x : y ** 3 ]
As duas APIs principais para chamar YAPF são FormatCode
e FormatFile
, e compartilham vários argumentos descritos abaixo:
> >> from yapf . yapflib . yapf_api import FormatCode # reformat a string of code
> >> formatted_code , changed = FormatCode ( "f ( a = 1, b = 2 )" )
> >> formatted_code
'f(a=1, b=2) n '
> >> changed
True
Um argumento style_config
: um nome de estilo ou um caminho para um arquivo que contém configurações de estilo de formatação. Se None for especificado, use o estilo padrão conforme definido em style.DEFAULT_STYLE_FACTORY
.
> >> FormatCode ( "def g(): n return True" , style_config = 'pep8' )[ 0 ]
'def g(): n return True n '
Um argumento lines
: uma lista de tuplas de linhas (ints), [início, fim], que queremos formatar. As linhas são indexadas com base em 1. Ele pode ser usado por código de terceiros (por exemplo, IDEs) ao reformatar um trecho de código em vez de um arquivo inteiro.
> >> FormatCode ( "def g( ): n a=1 n b = 2 n return a==b" , lines = [( 1 , 1 ), ( 2 , 3 )])[ 0 ]
'def g(): n a = 1 n b = 2 n return a==b n '
Um print_diff
(bool): Em vez de retornar a fonte reformatada, retorne um diff que transforma a fonte formatada em fonte reformatada.
>>> print(FormatCode("a==b", filename="foo.py", print_diff=True)[0])
--- foo.py (original)
+++ foo.py (reformatted)
@@ -1 +1 @@
- a==b
+ a == b
Nota: o argumento filename
para FormatCode
é o que é inserido no diff, o padrão é <unknown>
.
FormatFile
retorna o código reformatado do arquivo passado junto com sua codificação:
> >> from yapf . yapflib . yapf_api import FormatFile # reformat a file
> >> print ( open ( "foo.py" ). read ()) # contents of file
a == b
> >> reformatted_code , encoding , changed = FormatFile ( "foo.py" )
> >> formatted_code
'a == b n '
> >> encoding
'utf-8'
> >> changed
True
O argumento in_place
salva o código reformatado de volta no arquivo:
> >> FormatFile ( "foo.py" , in_place = True )[: 2 ]
( None , 'utf-8' )
> >> print ( open ( "foo.py" ). read ()) # contents of file (now fixed)
a == b
Opções:
usage: yapf-diff [-h] [-i] [-p NUM] [--regex PATTERN] [--iregex PATTERN][-v]
[--style STYLE] [--binary BINARY]
This script reads input from a unified diff and reformats all the changed
lines. This is useful to reformat all the lines touched by a specific patch.
Example usage for git/svn users:
git diff -U0 --no-color --relative HEAD^ | yapf-diff -i
svn diff --diff-cmd=diff -x-U0 | yapf-diff -p0 -i
It should be noted that the filename contained in the diff is used
unmodified to determine the source file to update. Users calling this script
directly should be careful to ensure that the path in the diff is correct
relative to the current working directory.
optional arguments:
-h, --help show this help message and exit
-i, --in-place apply edits to files instead of displaying a diff
-p NUM, --prefix NUM strip the smallest prefix containing P slashes
--regex PATTERN custom pattern selecting file paths to reformat
(case sensitive, overrides -iregex)
--iregex PATTERN custom pattern selecting file paths to reformat
(case insensitive, overridden by -regex)
-v, --verbose be more verbose, ineffective without -i
--style STYLE specify formatting style: either a style name (for
example "pep8" or "google"), or the name of a file
with style settings. The default is pep8 unless a
.style.yapf or setup.cfg or pyproject.toml file
located in the same directory as the source or one of
its parent directories (for stdin, the current
directory is used).
--binary BINARY location of binary to use for YAPF
ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT
Alinhe o colchete de fechamento com o recuo visual.
ALLOW_MULTILINE_LAMBDAS
Permitir que lambdas sejam formatados em mais de uma linha.
ALLOW_MULTILINE_DICTIONARY_KEYS
Permitir que chaves de dicionário existam em várias linhas. Por exemplo:
x = {
( 'this is the first element of a tuple' ,
'this is the second element of a tuple' ):
value ,
}
ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS
Permitir a divisão antes de uma atribuição padrão/nomeada em uma lista de argumentos.
ALLOW_SPLIT_BEFORE_DICT_VALUE
Permitir divisões antes do valor do dicionário.
ARITHMETIC_PRECEDENCE_INDICATION
Deixe o espaçamento indicar a precedência do operador. Por exemplo:
a = 1 * 2 + 3 / 4
b = 1 / 2 - 3 * 4
c = ( 1 + 2 ) * ( 3 - 4 )
d = ( 1 - 2 ) / ( 3 + 4 )
e = 1 * 2 - 3
f = 1 + 2 + 3 + 4
será formatado da seguinte forma para indicar precedência:
a = 1 * 2 + 3 / 4
b = 1 / 2 - 3 * 4
c = ( 1 + 2 ) * ( 3 - 4 )
d = ( 1 - 2 ) / ( 3 + 4 )
e = 1 * 2 - 3
f = 1 + 2 + 3 + 4
BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION
Define o número de linhas em branco desejadas em torno das definições de funções e classes de nível superior. Por exemplo:
class Foo :
pass
# <------ having two blank lines here
# <------ is the default setting
class Bar :
pass
BLANK_LINE_BEFORE_CLASS_DOCSTRING
Insira uma linha em branco antes de uma docstring de nível de classe.
BLANK_LINE_BEFORE_MODULE_DOCSTRING
Insira uma linha em branco antes de uma docstring do módulo.
BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF
Insira uma linha em branco antes de um
def
ouclass
imediatamente aninhado em outrodef
ouclass
. Por exemplo:
class Foo :
# <------ this blank line
def method ():
pass
BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES
Define o número de linhas em branco desejadas entre importações de nível superior e definições de variáveis. Útil para compatibilidade com ferramentas como isort.
COALESCE_BRACKETS
Não divida colchetes consecutivos. Relevante apenas quando
DEDENT_CLOSING_BRACKETS
ouINDENT_CLOSING_BRACKETS
está definido. Por exemplo:
call_func_that_takes_a_dict (
{
'key1' : 'value1' ,
'key2' : 'value2' ,
}
)
reformataria para:
call_func_that_takes_a_dict ({
'key1' : 'value1' ,
'key2' : 'value2' ,
})
COLUMN_LIMIT
O limite da coluna (ou comprimento máximo da linha)
CONTINUATION_ALIGN_STYLE
O estilo para alinhamento de continuação. Os valores possíveis são:
SPACE
: Use espaços para alinhamento de continuação. Este é o comportamento padrão.FIXED
: Use um número fixo (CONTINUATION_INDENT_WIDTH
) de colunas (ou seja, guiasCONTINUATION_INDENT_WIDTH
/INDENT_WIDTH
ou espaçosCONTINUATION_INDENT_WIDTH
) para alinhamento de continuação.VALIGN-RIGHT
: Alinha verticalmente as linhas de continuação a múltiplas colunasINDENT_WIDTH
. Ligeiramente à direita (uma tabulação ou alguns espaços) se não for possível alinhar verticalmente as linhas de continuação com caracteres de recuo.
CONTINUATION_INDENT_WIDTH
Largura do recuo usada para continuações de linha.
DEDENT_CLOSING_BRACKETS
Coloque colchetes de fechamento em uma linha separada, sem recuo, se a expressão entre colchetes não couber em uma única linha. Aplica-se a todos os tipos de colchetes, incluindo definições e chamadas de funções. Por exemplo:
config = {
'key1' : 'value1' ,
'key2' : 'value2' ,
} # <--- this bracket is dedented and on a separate line
time_series = self . remote_client . query_entity_counters (
entity = 'dev3246.region1' ,
key = 'dns.query_latency_tcp' ,
transform = Transformation . AVERAGE ( window = timedelta ( seconds = 60 )),
start_ts = now () - timedelta ( days = 3 ),
end_ts = now (),
) # <--- this bracket is dedented and on a separate line
DISABLE_ENDING_COMMA_HEURISTIC
Desative a heurística que coloca cada elemento da lista em uma linha separada se a lista for terminada por vírgula.
Nota: O comportamento deste sinalizador mudou na v0.40.3. Antes, se esse sinalizador fosse verdadeiro, dividiríamos as listas que continham uma vírgula ou um comentário no final. Agora temos um sinalizador separado,
DISABLE_SPLIT_LIST_WITH_COMMENT
, que controla a divisão quando uma lista contém um comentário. Para obter o comportamento antigo, defina ambos os sinalizadores como verdadeiros. Mais informações em CHANGELOG.md.
DISABLE_SPLIT_LIST_WITH_COMMENT
Não coloque todos os elementos em uma nova linha em uma lista que contenha comentários intersticiais.
Sem este sinalizador (padrão):
[ a, b, # c ]
Com esta bandeira:
[ a, b, # c ]
Isso reflete o comportamento do formato clang e é útil para formar "grupos lógicos" de elementos em uma lista. Também funciona em declarações de funções.
EACH_DICT_ENTRY_ON_SEPARATE_LINE
Coloque cada entrada do dicionário em sua própria linha.
FORCE_MULTILINE_DICT
Respeite
EACH_DICT_ENTRY_ON_SEPARATE_LINE
mesmo que a linha seja menor queCOLUMN_LIMIT
.
I18N_COMMENT
A regex para um comentário de internacionalização. A presença deste comentário interrompe a reformatação daquela linha, pois os comentários devem estar próximos à string que traduzem.
I18N_FUNCTION_CALL
A função de internacionalização chama nomes. A presença desta função interrompe a reformatação nessa linha, pois a string que ela possui não pode ser afastada do comentário i18n.
INDENT_BLANK_LINES
Defina como
True
para preferir linhas em branco recuadas em vez de vazias
INDENT_CLOSING_BRACKETS
Coloque colchetes de fechamento em uma linha separada, recuada, se a expressão entre colchetes não couber em uma única linha. Aplica-se a todos os tipos de colchetes, incluindo definições e chamadas de funções. Por exemplo:
config = {
'key1' : 'value1' ,
'key2' : 'value2' ,
} # <--- this bracket is indented and on a separate line
time_series = self . remote_client . query_entity_counters (
entity = 'dev3246.region1' ,
key = 'dns.query_latency_tcp' ,
transform = Transformation . AVERAGE ( window = timedelta ( seconds = 60 )),
start_ts = now () - timedelta ( days = 3 ),
end_ts = now (),
) # <--- this bracket is indented and on a separate line
INDENT_DICTIONARY_VALUE
Recue o valor do dicionário se ele não couber na mesma linha que a chave do dicionário. Por exemplo:
config = {
'key1' :
'value1' ,
'key2' : value1 +
value2 ,
}
INDENT_WIDTH
O número de colunas a serem usadas para recuo.
JOIN_MULTIPLE_LINES
Junte linhas curtas em uma linha. Por exemplo, instruções
if
de linha única.
NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS
Não inclua espaços ao redor dos operadores binários selecionados. Por exemplo:
1 + 2 * 3 - 4 / 5
será formatado da seguinte forma quando configurado com
*
,/
:
1 + 2 * 3 - 4 / 5
SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET
Insira um espaço entre a vírgula final e o colchete de fechamento de uma lista, etc.
SPACE_INSIDE_BRACKETS
Use spaces inside brackets, braces, and parentheses. For example:
method_call ( 1 )
my_dict [ 3 ][ 1 ][ get_index ( * args , ** kwargs ) ]
my_set = { 1 , 2 , 3 }
SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN
Defina como
True
para preferir espaços ao redor do operador de atribuição para argumentos padrão ou de palavras-chave.
SPACES_AROUND_DICT_DELIMITERS
Adiciona um espaço após os delimitadores de dict de abertura '{' e antes do final '}'.
{ 1 : 2 }
será formatado como:
{ 1 : 2 }
SPACES_AROUND_LIST_DELIMITERS
Adiciona um espaço após os delimitadores de lista de abertura '[' e antes do final ']'.
[ 1 , 2 ]
será formatado como:
[ 1 , 2 ]
SPACES_AROUND_POWER_OPERATOR
Defina como
True
para preferir usar espaços ao redor**
.
SPACES_AROUND_SUBSCRIPT_COLON
Use espaços ao redor do operador subscrito/fatia. Por exemplo:
my_list [ 1 : 10 : 2 ]
SPACES_AROUND_TUPLE_DELIMITERS
Adiciona um espaço após os delimitadores de tupla de abertura '(' e antes do final ')'.
( 1 , 2 , 3 )
será formatado como:
( 1 , 2 , 3 )
SPACES_BEFORE_COMMENT
O número de espaços necessários antes de um comentário final. Pode ser um valor único (representando o número de espaços antes de cada comentário final) ou uma lista de valores (representando valores de coluna de alinhamento; os comentários finais dentro de um bloco serão alinhados ao valor da primeira coluna que for maior que o comprimento máximo da linha dentro do bloco). bloquear).
Nota: Listas de valores podem precisar ser citadas em alguns contextos (por exemplo, shells ou arquivos de configuração do editor).
Por exemplo, com
spaces_before_comment=5
:
1 + 1 # Adding values
será formatado como:
1 + 1 # Adding values <-- 5 spaces between the end of the statement and comment
com
spaces_before_comment="15, 20"
:
1 + 1 # Adding values
two + two # More adding
longer_statement # This is a longer statement
short # This is a shorter statement
a_very_long_statement_that_extends_beyond_the_final_column # Comment
short # This is a shorter statement
será formatado como:
1 + 1 # Adding values <-- end of line comments in block aligned to col 15
two + two # More adding
longer_statement # This is a longer statement <-- end of line comments in block aligned to col 20
short # This is a shorter statement
a_very_long_statement_that_extends_beyond_the_final_column # Comment <-- the end of line comments are aligned based on the line length
short # This is a shorter statement
SPLIT_ALL_COMMA_SEPARATED_VALUES
Se uma lista separada por vírgula (
dict
,list
,tuple
ou functiondef
) estiver em uma linha muito longa, divida de forma que cada elemento fique em uma linha separada.
SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES
Variação de
SPLIT_ALL_COMMA_SEPARATED_VALUES
em que, se uma subexpressão com vírgula couber em sua linha inicial, então a subexpressão não é dividida. Isso evita divisões como a deb
neste código:
abcdef (
aReallyLongThing : int ,
b : [ Int ,
Int ])
com o novo botão isso é dividido como:
abcdef (
aReallyLongThing : int ,
b : [ Int , Int ])
SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED
Dividir antes dos argumentos se a lista de argumentos terminar com uma vírgula.
SPLIT_BEFORE_ARITHMETIC_OPERATOR
Defina como
True
para preferir a divisão antes de+
,-
,*
,/
,//
ou@
em vez de depois.
SPLIT_BEFORE_BITWISE_OPERATOR
Defina como
True
para preferir a divisão antes de&
,|
ou^
em vez de depois.
SPLIT_BEFORE_CLOSING_BRACKET
Divida antes do colchete de fechamento se uma
list
oudict
literal não couber em uma única linha.
SPLIT_BEFORE_DICT_SET_GENERATOR
Dividir antes de um dicionário ou gerador de conjunto (
comp_for
). Por exemplo, observe a divisão antes dofor
:
foo = {
variable : 'Hello world, have a nice day!'
for variable in bar if variable != 42
}
SPLIT_BEFORE_DOT
Dividir antes do
.
se precisarmos dividir uma expressão mais longa:
foo = ( 'This is a really long string: {}, {}, {}, {}' . format ( a , b , c , d ))
reformataria para algo como:
foo = ( 'This is a really long string: {}, {}, {}, {}'
. format ( a , b , c , d ))
SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN
Dividir após o parêntese de abertura que circunda uma expressão se ela não couber em uma única linha.
SPLIT_BEFORE_FIRST_ARGUMENT
Se uma lista de argumentos/parâmetros for dividida, divida antes do primeiro argumento.
SPLIT_BEFORE_LOGICAL_OPERATOR
Defina como
True
para preferir a divisão antesand
ouor
em vez de depois.
SPLIT_BEFORE_NAMED_ASSIGNS
Divida as atribuições nomeadas em linhas individuais.
SPLIT_COMPLEX_COMPREHENSION
Para compreensões de listas e expressões geradoras com múltiplas cláusulas (por exemplo, múltiplas
for
chamadas,if
expressões de filtro) e que precisam ser refluídas, divida cada cláusula em sua própria linha. Por exemplo:
result = [
a_var + b_var for a_var in xrange ( 1000 ) for b_var in xrange ( 1000 )
if a_var % b_var ]
reformataria para algo como:
result = [
a_var + b_var
for a_var in xrange ( 1000 )
for b_var in xrange ( 1000 )
if a_var % b_var ]
SPLIT_PENALTY_AFTER_OPENING_BRACKET
A penalidade por divisão logo após a chave de abertura.
SPLIT_PENALTY_AFTER_UNARY_OPERATOR
A penalidade por dividir a linha após um operador unário.
SPLIT_PENALTY_ARITHMETIC_OPERATOR
A penalidade de dividir a linha em torno dos operadores
+
,-
,*
,/
,//
,%
e@
.
SPLIT_PENALTY_BEFORE_IF_EXPR
A penalidade pela divisão logo antes de uma expressão
if
.
SPLIT_PENALTY_BITWISE_OPERATOR
A penalidade de dividir a linha em torno de
&
,|
e^
operadores.
SPLIT_PENALTY_COMPREHENSION
A penalidade por dividir uma compreensão de lista ou expressão geradora.
SPLIT_PENALTY_EXCESS_CHARACTER
A penalidade para caracteres acima do limite da coluna.
SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT
A penalidade incorrida pela adição de uma divisão de linha à linha lógica. Quanto mais divisões de linha forem adicionadas, maior será a penalidade.
SPLIT_PENALTY_IMPORT_NAMES
A penalidade de dividir uma lista de
import as
nomes. Por exemplo:
from a_very_long_or_indented_module_name_yada_yad import ( long_argument_1 ,
long_argument_2 ,
long_argument_3 )
reformataria para algo como:
from a_very_long_or_indented_module_name_yada_yad import (
long_argument_1 , long_argument_2 , long_argument_3 )
SPLIT_PENALTY_LOGICAL_OPERATOR
A penalidade de dividir a linha em torno dos operadores
and
eor
.
USE_TABS
Use o caractere Tab para recuo.
O YAPF se esforça muito para obter a formatação correta. Mas para alguns códigos, não será tão bom quanto a formatação manual. Em particular, grandes literais de dados podem ficar terrivelmente desfigurados sob o YAPF.
As razões para isso são muitas. Resumindo, o YAPF é simplesmente uma ferramenta para ajudar no desenvolvimento. Ele formatará as coisas para coincidir com o guia de estilo, mas isso pode não ser equivalente à legibilidade.
O que pode ser feito para aliviar esta situação é indicar as regiões que o YAPF deve ignorar ao reformatar algo:
# yapf: disable
FOO = {
# ... some very large, complex data literal.
}
BAR = [
# ... another large data literal.
]
# yapf: enable
Você também pode desabilitar a formatação para um único literal como este:
BAZ = {
( 1 , 2 , 3 , 4 ),
( 5 , 6 , 7 , 8 ),
( 9 , 10 , 11 , 12 ),
} # yapf: disable
Para preservar os colchetes de fechamento dentados, use dedent_closing_brackets
em seu estilo. Observe que, neste caso, todos os colchetes, incluindo definições de funções e chamadas, usarão esse estilo. Isso fornece consistência em toda a base de código formatada.
Queríamos usar o algoritmo de reformatação do formato clang. É muito poderoso e projetado para oferecer a melhor formatação possível. As ferramentas existentes foram criadas com objetivos diferentes em mente e exigiriam extensas modificações para serem convertidas para o uso do algoritmo do formato clang.
Por favor, faça! O YAPF foi projetado para ser usado como uma biblioteca e também como uma ferramenta de linha de comando. Isso significa que uma ferramenta ou plugin IDE é gratuito para usar o YAPF.
A YAPF se esforça ao máximo para ser totalmente compatível com o PEP 8. Porém, é fundamental não correr o risco de alterar a semântica do seu código. Assim, o YAPF tenta ser o mais seguro possível e não altera o fluxo de tokens (por exemplo, adicionando parênteses). Todos esses casos, entretanto, podem ser facilmente corrigidos manualmente. Por exemplo,
from my_package import my_function_1 , my_function_2 , my_function_3 , my_function_4 , my_function_5
FOO = my_variable_1 + my_variable_2 + my_variable_3 + my_variable_4 + my_variable_5 + my_variable_6 + my_variable_7 + my_variable_8
não será dividido, mas você pode acertar facilmente apenas adicionando parênteses:
from my_package import ( my_function_1 , my_function_2 , my_function_3 ,
my_function_4 , my_function_5 )
FOO = ( my_variable_1 + my_variable_2 + my_variable_3 + my_variable_4 +
my_variable_5 + my_variable_6 + my_variable_7 + my_variable_8 )
A principal estrutura de dados no YAPF é o objeto LogicalLine
. Ele contém uma lista de FormatToken
s, que gostaríamos de colocar em uma única linha se não houvesse limite de colunas. Uma exceção sendo um comentário no meio de uma instrução de expressão forçará a formatação da linha em mais de uma linha. O formatador funciona em um objeto LogicalLine
por vez.
Um LogicalLine
normalmente não afetará a formatação das linhas antes ou depois dele. Existe uma parte do algoritmo que pode juntar dois ou mais LogicalLine
s em uma linha. Por exemplo, uma instrução if-then com corpo curto pode ser colocada em uma única linha:
if a == 42 : continue
O algoritmo de formatação do YAPF cria uma árvore ponderada que atua como espaço de solução para o algoritmo. Cada nó na árvore representa o resultado de uma decisão de formatação --- ou seja, dividir ou não antes de um token. Cada decisão de formatação tem um custo associado. Portanto, o custo é realizado na borda entre dois nós. (Na realidade, a árvore ponderada não possui objetos de borda separados, portanto o custo reside nos próprios nós.)
Por exemplo, pegue o seguinte trecho de código Python. Para fins deste exemplo, suponha que a linha (1) viola a restrição de limite de coluna e precisa ser reformatada.
def xxxxxxxxxxx ( aaaaaaaaaaaa , bbbbbbbbb , cccccccc , dddddddd , eeeeee ): # 1
pass # 2
Para a linha (1), o algoritmo construirá uma árvore onde cada nó (um objeto FormattingDecisionState
) é o estado da linha naquele token, dada a decisão de dividir antes do token ou não. Nota: os objetos FormatDecisionState
são copiados por valor para que cada nó no gráfico seja único e uma alteração em um não afete outros nós.
Heurísticas são usadas para determinar os custos de divisão ou não divisão. Como um nó mantém o estado da árvore até a inserção de um token, ele pode facilmente determinar se uma decisão de divisão violará um dos requisitos de estilo. Por exemplo, a heurística é capaz de aplicar uma penalidade extra à borda ao não dividir entre o token anterior e o que está sendo adicionado.
Existem alguns casos em que nunca desejaremos dividir a linha, porque isso sempre será prejudicial (ou seja, exigirá uma barra invertida-nova linha, o que raramente é desejável). Para a linha (1), nunca desejaremos dividir os três primeiros tokens: def
, xxxxxxxxxxx
e (
. Nem desejaremos dividir entre )
e :
no final. Diz-se que essas regiões são “inquebráveis”. Isto se reflete na árvore por não haver uma decisão "dividida" (ramo esquerdo) dentro da região inquebrável.
Agora que temos a árvore, determinamos qual é a “melhor” formatação encontrando o caminho na árvore com o menor custo.
E é isso!