Ce ne sont que des solutions possibles puisque je ne suis pas vraiment apt avec d'analyse statique.
Avec tokenize
:
Récemment, j'ai bricolé autour de avec la segmentation du code python et je crois qu'il a toutes les informations nécessaires pour effectuer ces contrôles, lorsque suffisamment de logique est ajouté. Pour votre liste donnée, les jetons générés avec python -m tokenize list1.py
sont comme suit:
python -m tokenize list1.py
1,0-1,4: NAME 'test'
1,5-1,6: OP '='
1,7-1,8: OP '['
1,8-1,9: NL '\n'
2,1-2,8: STRING '"item1"'
2,8-2,9: NL '\n'
3,1-3,8: STRING '"item2"'
3,8-3,9: NL '\n'
4,0-4,1: OP ']'
4,1-4,2: NEWLINE '\n'
5,0-5,0: ENDMARKER ''
C'est bien sûr la"problématique"cas où le contenu allez obtenir concaténées. Dans le cas où un ,
, la sortie légèrement modifié pour refléter cette (j'ai ajouté les tokens pour la liste du corps):
1,7-1,8: OP '['
1,8-1,9: NL '\n'
2,1-2,8: STRING '"item1"'
2,8-2,9: OP ','
2,9-2,10: NL '\n'
3,1-3,8: STRING '"item2"'
3,8-3,9: NL '\n'
4,0-4,1: OP ']'
Maintenant, nous l' OP ','
jeton signifiant la présence d'un deuxième élément séparés par des virgules.
Compte tenu de cette information, nous pouvons utiliser le vraiment pratique méthode generate_tokens
dans la tokenize
module. Méthode tokenize.generate_tokens()
, tokenize.tokenize()
en Py3
, a un seul argument readline
, une méthode sur fichier-comme des objets qui, essentiellement, retourne la prochaine ligne de ce fichier comme objet (réponse pertinente). Elle retourne un nom de tuple avec 5 éléments au total, avec des informations sur le type de jeton, le jeton de la chaîne avec le numéro de ligne et la position dans la ligne.
À l'aide de cette information, on pourrait en théorie boucle par le biais d'un fichier et quand un OP ','
est absent à l'intérieur d'une liste d'initialisation (dont le début est détecté par la vérification que les jetons NAME
, OP '='
et OP '['
existent sur le même numéro de ligne), on peut émettre un avertissement sur les lignes sur lesquelles il a été détecté.
La bonne chose à propos de cette approche est qu'il est assez simple de généraliser. Pour s'adapter à tous les cas où la chaîne de caractères littérale de concaténation prend place (à savoir, à l'intérieur du "groupement" les opérateurs (), {}, []
), de vérifier si le jeton est de type = 51
(ou 53 pour Python 3) ou qu'une valeur dans l'une de (, [, {
existe sur la même ligne (ce sont grossiers, à la tête de l'suggestions atm).
Maintenant, je ne suis pas vraiment sûr de savoir comment les autres gens avec ces sortes de problèmes , mais il semble que cela pourrait être quelque chose que vous pouvez regarder dans. Toutes les informations nécessaires est offert par tokenize
, la logique pour détecter c'est la seule chose qui manque.
La mise en œuvre Remarque: Ces valeurs (par exemple, pour type
) ne diffèrent entre les versions et sont sujettes à modification donc c'est quelque chose dont on doit être conscient. On pourrait éventuellement tirer parti de ce en travaillant uniquement avec des constantes pour les jetons, si.
Avec parser
et ast
:
Une autre solution probable qui est probablement plus fastidieux pourrait impliquer l' parser
et ast
modules. La concaténation de chaînes de caractères est en fait effectuée lors de la création de l'Arbre de Syntaxe Abstraite de sorte que vous pourrait aussi détecter qu'il y a dessus.
Je n'ai pas vraiment envie de faire un dump de la sortie complète des méthodes d' parser
et ast
que je vais parler, mais, juste pour s'assurer que nous sommes sur la même page, je vais être à l'aide de la liste suivante instruction d'initialisation:
l_init = """
test = [
"item1"
"item2",
"item3"
]
"""
Afin d'obtenir l'arbre d'analyse généré, utilisez p = parser.suite(l_init)
. Après ceci est fait, vous pouvez obtenir une vue de il avec p.tolist()
(de sortie est trop grand pour l'ajouter). Ce que vous remarquerez est que il y aura trois entrées pour les trois différents str
objets item1
, item2
, item3
.
D'autre part, lorsque l'AST est créé avec node = ast.parse(l_init)
et visualisées avec ast.dump(node)
il y a seulement deux entrées: l'une pour la concaténation str
s item1item2
et l'un pour l'autre entrée item3
.
Donc, c'est une autre probable façon de le faire mais, comme je l'ai mentionné précédemment, c'est plus fastidieux. Je ne sais pas si l'information est disponible et vous traitez avec les deux modules différents. Juste comme une arrière pensée, si vous peut-être envie de jouer avec les objets internes plus élevés dans le compilateur de la chaîne.
Commentaires de fermeture: une fermeture de la note, l' tokenize
approche semble être la plus logique dans ce cas. Au contraire même, il semble qu' pylint
fonctionne réellement avec astroid
une lib python, qui facilite l'analyse de l'arbre de Syntaxe Abstraite pour le code python. Donc, on devrait, idéalement, la regarde et la façon dont il est utilisé à l'intérieur de pylint.
Remarque: bien sûr, je suis peut-être complètement à l'analyser et d'un simple "vérifier blanc-espace ou saut de ligne' solution que vous les gars pourrait suffire. :-)