YAPF est un formateur Python basé sur clang-format
(développé par Daniel Jasper). Essentiellement, l’algorithme prend le code et calcule le meilleur formatage conforme au style configuré. Cela enlève une grande partie de la corvée liée à la maintenance de votre code.
Le but ultime est que le code produit par YAPF soit aussi bon que le code qu'un programmeur écrirait s'il suivait le guide de style.
Remarque YAPF n'est pas un produit Google officiel (expérimental ou autre), il s'agit simplement d'un code qui appartient à Google.
Pour installer YAPF depuis PyPI :
$ pip install yapf
YAPF est encore considéré comme étant en phase « bêta », et la version publiée peut changer souvent ; par conséquent, la meilleure façon de se tenir au courant des derniers développements est de cloner ce référentiel ou de l'installer directement depuis github :
$ pip install git+https://github.com/google/yapf.git
Notez que si vous avez l'intention d'utiliser YAPF comme outil de ligne de commande plutôt que comme bibliothèque, l'installation n'est pas nécessaire. YAPF prend en charge l'exécution en tant que répertoire par l'interpréteur Python. Si vous avez cloné/décompressé YAPF dans DIR
, il est possible d'exécuter :
$ PYTHONPATH=DIR python DIR/yapf [options] ...
YAPF est pris en charge par plusieurs éditeurs via des extensions communautaires ou des plugins. Voir Prise en charge de l'éditeur pour plus d'informations.
YAPF prend en charge 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
Normalement, YAPF renvoie zéro à la fin du programme et non nul dans le cas contraire.
Si --diff
est fourni, YAPF renvoie zéro lorsqu'aucune modification n'est nécessaire, différent de zéro sinon (y compris une erreur de programme). Vous pouvez l'utiliser dans un workflow CI pour tester que le code a été formaté YAPF.
En plus des modèles d'exclusion fournis sur la ligne de commande, YAPF recherche des modèles supplémentaires spécifiés dans un fichier nommé .yapfignore
ou pyproject.toml
situé dans le répertoire de travail à partir duquel YAPF est invoqué.
La syntaxe de .yapfignore
est similaire à la correspondance de modèle de nom de fichier UNIX :
* matches everything
? matches any single character
[seq] matches any character in seq
[!seq] matches any character not in seq
Notez qu'aucune entrée ne doit commencer par ./
.
Si vous utilisez pyproject.toml
, les modèles d'exclusion sont spécifiés par la clé ignore_patterns
dans la section [tool.yapfignore]
. Par exemple:
[tool.yapfignore]
ignore_patterns = [
" temp/**/*.py " ,
" temp2/*.py "
]
Le style de formatage utilisé par YAPF est configurable et il existe de nombreux « boutons » qui peuvent être utilisés pour régler la façon dont YAPF effectue le formatage. Voir le module style.py
pour la liste complète.
Pour contrôler le style, exécutez YAPF avec l'argument --style
. Il accepte l'un des styles prédéfinis (par exemple, pep8
ou google
), un chemin vers un fichier de configuration qui spécifie le style souhaité ou un dictionnaire de paires clé/valeur.
Le fichier de configuration est une simple liste de paires key = value
(insensibles à la casse) avec un en-tête [style]
. Par exemple:
[style]
based_on_style = pep8
spaces_before_comment = 4
split_before_logical_operator = true
Le paramètre based_on_style
détermine sur lequel des styles prédéfinis ce style personnalisé est basé (pensez-y comme un sous-classement). Quatre styles sont prédéfinis :
pep8
(par défaut)google
(basé sur le guide de style Google Python)yapf
(à utiliser avec les projets open source de Google)facebook
Voir _STYLE_NAME_TO_FACTORY
dans style.py
pour plus de détails.
Il est également possible de faire la même chose en ligne de commande avec un dictionnaire. Par exemple:
--style= ' {based_on_style: pep8, indent_width: 2} '
Cela prendra le style de base pep8
et le modifiera pour avoir deux indentations spatiales.
YAPF recherchera le style de formatage de la manière suivante :
[style]
d'un fichier .style.yapf
dans le répertoire courant ou dans l'un de ses répertoires parents.[yapf]
d'un fichier setup.cfg
dans le répertoire courant ou dans l'un de ses répertoires parents.[tool.yapf]
d'un fichier pyproject.toml
dans le répertoire courant ou dans l'un de ses répertoires parents.[style]
d'un fichier ~/.config/yapf/style
de votre répertoire personnel.Si aucun de ces fichiers n'est trouvé, le style par défaut PEP8 est utilisé.
Un exemple du type de formatage que YAPF peut faire, il faudra ce code laid :
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 ]
et reformatez-le en :
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 ]
Les deux principales API pour appeler YAPF sont FormatCode
et FormatFile
, elles partagent plusieurs arguments décrits ci-dessous :
> >> 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
Un argument style_config
: soit un nom de style, soit un chemin d'accès à un fichier contenant les paramètres de style de formatage. Si Aucun n'est spécifié, utilisez le style par défaut tel que défini dans style.DEFAULT_STYLE_FACTORY
.
> >> FormatCode ( "def g(): n return True" , style_config = 'pep8' )[ 0 ]
'def g(): n return True n '
Un argument lines
: une liste de tuples de lignes (entiers), [début, fin], que nous souhaitons formater. Les lignes sont indexées en base 1. Il peut être utilisé par du code tiers (par exemple, les IDE) lors du reformatage d'un extrait de code plutôt que d'un fichier entier.
> >> 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 '
A print_diff
(bool) : au lieu de renvoyer la source reformatée, renvoie un diff qui transforme la source formatée en source reformatée.
>>> print(FormatCode("a==b", filename="foo.py", print_diff=True)[0])
--- foo.py (original)
+++ foo.py (reformatted)
@@ -1 +1 @@
- a==b
+ a == b
Remarque : l'argument filename
pour FormatCode
est ce qui est inséré dans le diff, la valeur par défaut est <unknown>
.
FormatFile
renvoie le code reformaté du fichier transmis ainsi que son encodage :
> >> 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
L'argument in_place
enregistre le code reformaté dans le fichier :
> >> FormatFile ( "foo.py" , in_place = True )[: 2 ]
( None , 'utf-8' )
> >> print ( open ( "foo.py" ). read ()) # contents of file (now fixed)
a == b
Possibilités :
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
Alignez le support de fermeture avec l’indentation visuelle.
ALLOW_MULTILINE_LAMBDAS
Autoriser le formatage des lambdas sur plusieurs lignes.
ALLOW_MULTILINE_DICTIONARY_KEYS
Autoriser les clés du dictionnaire à exister sur plusieurs lignes. Par exemple:
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
Autoriser le fractionnement avant une affectation par défaut/nommée dans une liste d'arguments.
ALLOW_SPLIT_BEFORE_DICT_VALUE
Autoriser les fractionnements avant la valeur du dictionnaire.
ARITHMETIC_PRECEDENCE_INDICATION
Laissez l'espacement indiquer la priorité des opérateurs. Par exemple:
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
sera formaté comme suit pour indiquer la priorité :
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
Définit le nombre de lignes vides souhaitées entourant les définitions de fonctions et de classes de niveau supérieur. Par exemple:
class Foo :
pass
# <------ having two blank lines here
# <------ is the default setting
class Bar :
pass
BLANK_LINE_BEFORE_CLASS_DOCSTRING
Insérez une ligne vide avant une docstring au niveau de la classe.
BLANK_LINE_BEFORE_MODULE_DOCSTRING
Insérez une ligne vide avant une docstring de module.
BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF
Insérez une ligne vide avant un
def
ouclass
immédiatement imbriquée dans un autredef
ouclass
. Par exemple:
class Foo :
# <------ this blank line
def method ():
pass
BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES
Définit le nombre de lignes vides souhaitées entre les importations de niveau supérieur et les définitions de variables. Utile pour la compatibilité avec des outils comme isort.
COALESCE_BRACKETS
Ne divisez pas les parenthèses consécutives. Uniquement pertinent lorsque
DEDENT_CLOSING_BRACKETS
ouINDENT_CLOSING_BRACKETS
est défini. Par exemple:
call_func_that_takes_a_dict (
{
'key1' : 'value1' ,
'key2' : 'value2' ,
}
)
serait reformaté en :
call_func_that_takes_a_dict ({
'key1' : 'value1' ,
'key2' : 'value2' ,
})
COLUMN_LIMIT
La limite de colonne (ou longueur de ligne maximale)
CONTINUATION_ALIGN_STYLE
Le style pour l’alignement de continuation. Les valeurs possibles sont :
SPACE
: utilisez des espaces pour l'alignement de la suite. Il s'agit du comportement par défaut.FIXED
: utilisez un nombre fixe (CONTINUATION_INDENT_WIDTH
) de colonnes (c'est-à-dire des ongletsCONTINUATION_INDENT_WIDTH
/INDENT_WIDTH
ou des espacesCONTINUATION_INDENT_WIDTH
) pour l'alignement de la continuation.VALIGN-RIGHT
: alignez verticalement les lignes de continuation sur plusieurs colonnesINDENT_WIDTH
. Légèrement à droite (une tabulation ou quelques espaces) si vous ne pouvez pas aligner verticalement les lignes de suite avec les caractères de retrait.
CONTINUATION_INDENT_WIDTH
Largeur de retrait utilisée pour les continuations de ligne.
DEDENT_CLOSING_BRACKETS
Placez les crochets fermants sur une ligne séparée, en retrait, si l'expression entre crochets ne peut pas tenir sur une seule ligne. S'applique à tous les types de crochets, y compris les définitions et les appels de fonctions. Par exemple:
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
Désactivez l'heuristique qui place chaque élément de la liste sur une ligne distincte si la liste est terminée par une virgule.
Remarque : Le comportement de cet indicateur a changé dans la v0.40.3. Avant, si cet indicateur était vrai, nous scindions les listes contenant une virgule finale ou un commentaire. Nous avons désormais un indicateur distinct,
DISABLE_SPLIT_LIST_WITH_COMMENT
, qui contrôle le fractionnement lorsqu'une liste contient un commentaire. Pour obtenir l'ancien comportement, définissez les deux indicateurs sur true. Plus d'informations dans CHANGELOG.md.
DISABLE_SPLIT_LIST_WITH_COMMENT
Ne placez pas chaque élément sur une nouvelle ligne dans une liste contenant des commentaires interstitiels.
Sans cet indicateur (par défaut) :
[ a, b, # c ]
Avec ce drapeau :
[ a, b, # c ]
Cela reflète le comportement du format clang et est utile pour former des « groupes logiques » d'éléments dans une liste. Cela fonctionne également dans les déclarations de fonctions.
EACH_DICT_ENTRY_ON_SEPARATE_LINE
Placez chaque entrée du dictionnaire sur sa propre ligne.
FORCE_MULTILINE_DICT
Respectez
EACH_DICT_ENTRY_ON_SEPARATE_LINE
même si la ligne est plus courte queCOLUMN_LIMIT
.
I18N_COMMENT
L'expression régulière pour un commentaire d'internationalisation. La présence de ce commentaire arrête le reformatage de cette ligne, car les commentaires doivent être à côté de la chaîne qu'ils traduisent.
I18N_FUNCTION_CALL
La fonction d'internationalisation appelle des noms. La présence de cette fonction arrête le reformatage sur cette ligne, car la chaîne qu'elle contient ne peut pas être éloignée du commentaire i18n.
INDENT_BLANK_LINES
Définir sur
True
pour préférer les lignes vides en retrait plutôt que vides
INDENT_CLOSING_BRACKETS
Placez les crochets fermants sur une ligne distincte, en retrait, si l'expression entre crochets ne peut pas tenir sur une seule ligne. S'applique à tous les types de crochets, y compris les définitions et les appels de fonctions. Par exemple:
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
Indentez la valeur du dictionnaire si elle ne peut pas tenir sur la même ligne que la clé du dictionnaire. Par exemple:
config = {
'key1' :
'value1' ,
'key2' : value1 +
value2 ,
}
INDENT_WIDTH
Le nombre de colonnes à utiliser pour l'indentation.
JOIN_MULTIPLE_LINES
Rejoignez les lignes courtes en une seule ligne. Par exemple, une seule ligne
if
les instructions.
NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS
N'incluez pas d'espaces autour des opérateurs binaires sélectionnés. Par exemple:
1 + 2 * 3 - 4 / 5
sera formaté comme suit lorsqu'il est configuré avec
*
,/
:
1 + 2 * 3 - 4 / 5
SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET
Insérez un espace entre la virgule finale et le crochet fermant d'une liste, 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
Définissez sur
True
pour préférer les espaces autour de l'opérateur d'affectation pour les arguments par défaut ou par mot-clé.
SPACES_AROUND_DICT_DELIMITERS
Ajoute un espace après le '{' d'ouverture et avant les délimiteurs de dict de fin '}'.
{ 1 : 2 }
sera formaté comme suit :
{ 1 : 2 }
SPACES_AROUND_LIST_DELIMITERS
Ajoute un espace après les délimiteurs de liste d'ouverture '[' et avant les délimiteurs de liste ']' de fin.
[ 1 , 2 ]
sera formaté comme suit :
[ 1 , 2 ]
SPACES_AROUND_POWER_OPERATOR
Définissez sur
True
pour préférer utiliser les espaces autour de**
.
SPACES_AROUND_SUBSCRIPT_COLON
Utilisez des espaces autour de l’opérateur indice/tranche. Par exemple:
my_list [ 1 : 10 : 2 ]
SPACES_AROUND_TUPLE_DELIMITERS
Ajoute un espace après les délimiteurs de tuple d'ouverture '(' et avant les délimiteurs de tuple de fin ')'.
( 1 , 2 , 3 )
sera formaté comme suit :
( 1 , 2 , 3 )
SPACES_BEFORE_COMMENT
Le nombre d'espaces requis avant un commentaire de fin. Il peut s'agir d'une valeur unique (représentant le nombre d'espaces avant chaque commentaire de fin) ou d'une liste de valeurs (représentant les valeurs de colonne d'alignement ; les commentaires de fin dans un bloc seront alignés sur la valeur de la première colonne qui est supérieure à la longueur de ligne maximale dans le bloc. bloc).
Remarque : Les listes de valeurs peuvent devoir être citées dans certains contextes (par exemple, les shells ou les fichiers de configuration de l'éditeur).
Par exemple, avec
spaces_before_comment=5
:
1 + 1 # Adding values
sera formaté comme suit :
1 + 1 # Adding values <-- 5 spaces between the end of the statement and comment
avec
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
sera formaté comme suit :
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
Si une liste séparée par des virgules (
dict
,list
,tuple
ou functiondef
) se trouve sur une ligne trop longue, divisez-la de manière à ce que chaque élément se trouve sur une ligne distincte.
SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES
Variation de
SPLIT_ALL_COMMA_SEPARATED_VALUES
dans laquelle, si une sous-expression avec une virgule tient dans sa ligne de départ, alors la sous-expression n'est pas divisée. Cela évite les divisions comme celle deb
dans ce code :
abcdef (
aReallyLongThing : int ,
b : [ Int ,
Int ])
avec le nouveau bouton, cela est divisé comme suit :
abcdef (
aReallyLongThing : int ,
b : [ Int , Int ])
SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED
Divisé avant les arguments si la liste d'arguments se termine par une virgule.
SPLIT_BEFORE_ARITHMETIC_OPERATOR
Définissez sur
True
pour préférer le fractionnement avant+
,-
,*
,/
,//
ou@
plutôt qu'après.
SPLIT_BEFORE_BITWISE_OPERATOR
Définissez sur
True
pour préférer le fractionnement avant&
,|
ou^
plutôt qu'après.
SPLIT_BEFORE_CLOSING_BRACKET
Divisez avant le crochet fermant si une
list
ou un littéraldict
ne tient pas sur une seule ligne.
SPLIT_BEFORE_DICT_SET_GENERATOR
Divisé avant un dictionnaire ou un générateur d'ensemble (
comp_for
). Par exemple, notez le split avant lefor
:
foo = {
variable : 'Hello world, have a nice day!'
for variable in bar if variable != 42
}
SPLIT_BEFORE_DOT
Divisé avant le
.
si nous devons diviser une expression plus longue :
foo = ( 'This is a really long string: {}, {}, {}, {}' . format ( a , b , c , d ))
reformaterait en quelque chose comme :
foo = ( 'This is a really long string: {}, {}, {}, {}'
. format ( a , b , c , d ))
SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN
Divisé après la parenthèse d'ouverture qui entoure une expression si elle ne tient pas sur une seule ligne.
SPLIT_BEFORE_FIRST_ARGUMENT
Si une liste d'arguments/paramètres doit être divisée, divisez-la avant le premier argument.
SPLIT_BEFORE_LOGICAL_OPERATOR
Définissez sur
True
pour préférer le fractionnement avantand
/or
plutôt qu'après.
SPLIT_BEFORE_NAMED_ASSIGNS
Divisez les affectations nommées sur des lignes individuelles.
SPLIT_COMPLEX_COMPREHENSION
Pour les compréhensions de liste et les expressions génératrices avec plusieurs clauses (par exemple plusieurs
for
les appels,if
expressions de filtre) et qui doivent être redistribuées, divisez chaque clause sur sa propre ligne. Par exemple:
result = [
a_var + b_var for a_var in xrange ( 1000 ) for b_var in xrange ( 1000 )
if a_var % b_var ]
reformaterait en quelque chose comme :
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
La pénalité pour partage juste après le bracket d'ouverture.
SPLIT_PENALTY_AFTER_UNARY_OPERATOR
La pénalité pour diviser la ligne après un opérateur unaire.
SPLIT_PENALTY_ARITHMETIC_OPERATOR
La pénalité liée au fractionnement de la ligne autour des opérateurs
+
,-
,*
,/
,//
,%
et@
.
SPLIT_PENALTY_BEFORE_IF_EXPR
La pénalité pour le fractionnement juste avant une expression
if
.
SPLIT_PENALTY_BITWISE_OPERATOR
La pénalité liée au fractionnement de la ligne autour du
&
,|
, et^
opérateurs.
SPLIT_PENALTY_COMPREHENSION
La pénalité pour diviser une compréhension de liste ou une expression génératrice.
SPLIT_PENALTY_EXCESS_CHARACTER
La pénalité pour les caractères dépassant la limite de colonne.
SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT
Pénalité encourue en ajoutant une division de ligne à la ligne logique. Plus il y a de divisions de lignes, plus la pénalité est élevée.
SPLIT_PENALTY_IMPORT_NAMES
La pénalité de diviser une liste d'
import as
noms. Par exemple:
from a_very_long_or_indented_module_name_yada_yad import ( long_argument_1 ,
long_argument_2 ,
long_argument_3 )
reformaterait en quelque chose comme :
from a_very_long_or_indented_module_name_yada_yad import (
long_argument_1 , long_argument_2 , long_argument_3 )
SPLIT_PENALTY_LOGICAL_OPERATOR
La pénalité de diviser la ligne autour des opérateurs
and
etor
.
USE_TABS
Utilisez le caractère Tab pour l'indentation.
YAPF s'efforce d'obtenir un formatage correct. Mais pour certains codes, ce ne sera pas aussi efficace qu'un formatage manuel. En particulier, les grands littéraux de données peuvent être horriblement défigurés sous YAPF.
Les raisons en sont multiples. En bref, YAPF est simplement un outil d'aide au développement. Il formatera les choses pour qu'elles coïncident avec le guide de style, mais cela n'est peut-être pas synonyme de lisibilité.
Ce qui peut être fait pour atténuer cette situation est d'indiquer les régions que YAPF doit ignorer lors du reformatage de quelque chose :
# yapf: disable
FOO = {
# ... some very large, complex data literal.
}
BAR = [
# ... another large data literal.
]
# yapf: enable
Vous pouvez également désactiver le formatage pour un seul littéral comme ceci :
BAZ = {
( 1 , 2 , 3 , 4 ),
( 5 , 6 , 7 , 8 ),
( 9 , 10 , 11 , 12 ),
} # yapf: disable
Pour conserver les jolies parenthèses fermantes édentées, utilisez les dedent_closing_brackets
dans votre style. Notez que dans ce cas, tous les crochets, y compris les définitions et les appels de fonctions, utiliseront ce style. Cela assure la cohérence dans la base de code formatée.
Nous voulions utiliser l'algorithme de reformatage de clang-format. Il est très puissant et conçu pour proposer le meilleur formatage possible. Les outils existants ont été créés avec différents objectifs en tête et nécessiteraient des modifications importantes pour être convertis à l'aide de l'algorithme du format clang.
S'il vous plaît, faites-le ! YAPF a été conçu pour être utilisé comme bibliothèque ainsi que comme outil de ligne de commande. Cela signifie qu'un outil ou un plugin IDE est libre d'utiliser YAPF.
YAPF s'efforce d'être entièrement conforme à la norme PEP 8. Cependant, il est primordial de ne pas risquer d’altérer la sémantique de votre code. Ainsi, YAPF essaie d'être aussi sûr que possible et ne modifie pas le flux de jetons (par exemple en ajoutant des parenthèses). Cependant, tous ces cas peuvent être facilement résolus manuellement. Par exemple,
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
ne sera pas divisé, mais vous pouvez facilement y parvenir en ajoutant simplement des parenthèses :
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 )
La structure de données principale dans YAPF est l'objet LogicalLine
. Il contient une liste de FormatToken
s, que nous voudrions placer sur une seule ligne s'il n'y avait pas de limite de colonnes. Une exception étant un commentaire au milieu d'une instruction d'expression forcera le formatage de la ligne sur plusieurs lignes. Le formateur fonctionne sur un objet LogicalLine
à la fois.
Une LogicalLine
n’affectera généralement pas le formatage des lignes avant ou après. Il existe une partie de l’algorithme qui peut joindre deux ou plusieurs LogicalLine
en une seule ligne. Par exemple, une instruction if-then avec un corps court peut être placée sur une seule ligne :
if a == 42 : continue
L'algorithme de formatage de YAPF crée un arbre pondéré qui fait office d'espace de solution pour l'algorithme. Chaque nœud de l'arborescence représente le résultat d'une décision de formatage, c'est-à-dire s'il faut diviser ou non avant un jeton. Chaque décision de formatage est associée à un coût. Par conséquent, le coût est réalisé à la limite entre deux nœuds. (En réalité, l'arbre pondéré n'a pas d'objets de bord distincts, le coût réside donc sur les nœuds eux-mêmes.)
Par exemple, prenons l'extrait de code Python suivant. Pour les besoins de cet exemple, supposons que la ligne (1) viole la restriction de limite de colonnes et doit être reformatée.
def xxxxxxxxxxx ( aaaaaaaaaaaa , bbbbbbbbb , cccccccc , dddddddd , eeeeee ): # 1
pass # 2
Pour la ligne (1), l'algorithme construira un arbre où chaque nœud (un objet FormattingDecisionState
) est l'état de la ligne au niveau de ce jeton, compte tenu de la décision de se diviser ou non avant le jeton. Remarque : les objets FormatDecisionState
sont copiés par valeur, de sorte que chaque nœud du graphique est unique et qu'une modification dans l'un n'affecte pas les autres nœuds.
Les heuristiques sont utilisées pour déterminer les coûts liés ou non au fractionnement. Étant donné qu'un nœud conserve l'état de l'arborescence jusqu'à l'insertion d'un jeton, il peut facilement déterminer si une décision de fractionnement violera l'une des exigences de style. Par exemple, l'heuristique est capable d'appliquer une pénalité supplémentaire au bord lorsqu'il n'est pas divisé entre le jeton précédent et celui ajouté.
Il y a des cas où nous ne voudrons jamais diviser la ligne, car cela sera toujours préjudiciable (c'est-à-dire que cela nécessitera une nouvelle ligne avec barre oblique inverse, ce qui est très rarement souhaitable). Pour la ligne (1), nous ne voudrons jamais diviser les trois premiers jetons : def
, xxxxxxxxxxx
et (
. Nous ne voudrons pas non plus diviser entre le )
et le :
à la fin. Ces régions sont dites « incassables ». Cela se reflète dans l'arbre par l'absence de décision « fractionnée » (branche de gauche) dans la région incassable.
Maintenant que nous avons l’arborescence, nous déterminons quel est le « meilleur » formatage en trouvant le chemin à travers l’arborescence avec le coût le plus bas.
Et c'est tout !