2010-10-28 22 views
5

Comment puis-je automatiser un test pour appliquer qu'un corps de code Python 2.x ne contient aucune instance de chaîne (uniquement des instances Unicode)?Python 2.x: comment automatiser l'exécution d'unicode au lieu d'une chaîne de caractères?

Par exemple.

Puis-je le faire à partir du code?

Existe-t-il un outil d'analyse statique doté de cette fonctionnalité?

Edit:

Je voulais que ce pour une application en Python 2.5, mais il se ce n'est pas vraiment possible parce que:

  1. 2,5 ne supporte pas unicode_literals
  2. kwargs dictionnaire les clés ne peuvent pas être des objets unicode, seulement des chaînes

Donc j'accepte la réponse que dit que ce n'est pas possible, même si c'est pour des raisons différentes :)

+2

'de __future__ import unicode_literals' –

+0

@Ignacio, Ça promet! Mais cela va-t-il rechigner si le code importe également des modules tiers qui ne le connaissent pas? –

+0

Non, les directives du compilateur via '__future__' n'affectent que le module courant. –

Répondre

1

Vous ne pouvez pas appliquer cette toutes les chaînes sont Unicode; même avec from __future__ import unicode_literals dans un module, des chaînes d'octets peuvent être écrits comme b'...', comme ils peuvent en Python 3.

Il était une option qui pourrait être utilisé pour obtenir le même effet que unicode_literals globalement: l'option de ligne de commande -U. Cependant, il a été abandonné au début du 2.x série parce qu'il a fondamentalement cassé tous les scripts.

Quel est votre but pour cela? Il n'est pas souhaitable d'abolir les chaînes d'octets. Ils ne sont pas "mauvais" et les chaînes Unicode ne sont pas universellement "meilleures"; ils sont deux animaux séparés et vous aurez besoin des deux. Les chaînes d'octets seront certainement nécessaires pour parler aux fichiers binaires et aux services réseau.

Si vous voulez être prêt à la transition vers Python 3, la meilleure tactique est d'écrire b'...' pour toutes les chaînes que vous désirez vraiment être octets, et u'...' pour les chaînes qui sont intrinsèquement Unicode. Le format de chaîne par défaut '...' peut être utilisé pour tout le reste, les endroits où cela ne vous intéresse pas et/ou si Python 3 modifie le type de chaîne par défaut.

+1

Le but est que j'écrive une application multilingue qui doit être en 2.5, et j'oublie de taper le 'u' sur les chaînes qui n'ont pas besoin d'unicode mais qui peuvent le faire si elles sont éditées. Je comprends que les cordes régulières sont bien dans de nombreux cas, mais dans ce cas, j'ai besoin de quelque chose pour m'aider à être cohérent et exprimer clairement mon intention. –

1

Il me semble que vous avez vraiment besoin d'analyser le code avec un analyseur python honnête et de bonne qualité. Ensuite, vous aurez besoin de creuser à travers l'AST produit par votre analyseur pour voir s'il contient des littéraux de chaîne.

Il semble que Python soit livré avec un analyseur hors de la boîte. A partir de ce documentation je suis arrivé cet exemple de code de travail:

import parser 
from token import tok_name 

def checkForNonUnicode(codeString): 
    return checkForNonUnicodeHelper(parser.suite(codeString).tolist()) 

def checkForNonUnicodeHelper(lst): 
    returnValue = True 
    nodeType = lst[0] 
    if nodeType in tok_name and tok_name[nodeType] == 'STRING': 
     stringValue = lst[1] 
     if stringValue[0] != "u": # Kind of hacky. Does this always work? 
      print "%s is not unicode!" % stringValue 
      returnValue = False 

    else: 
     for subNode in [lst[n] for n in range(1, len(lst))]: 
      if isinstance(subNode, list): 
       returnValue = returnValue and checkForNonUnicodeHelper(subNode) 

    return returnValue 

print checkForNonUnicode(""" 
def foo(): 
    a = 'This should blow up!' 
""") 
print checkForNonUnicode(""" 
def bar(): 
    b = u'although this is ok.' 
""") 

qui imprime

'This should blow up!' is not unicode! 
False 
True 

maintenant les chaînes de doc ne sont pas unicode, mais devraient être autorisés, de sorte que vous pourriez avoir à faire quelque chose de plus compliqué, comme from symbol import sym_name où vous pouvez rechercher les types de nœud pour les définitions de classe et de fonction. Ensuite, le premier sous-noeud qui est simplement une chaîne, c'est-à-dire qui ne fait pas partie d'une affectation ou autre, devrait être autorisé à ne pas être unicode.

Bonne question!

Modifier

Juste un commentaire suivi. Idéalement pour vos objectifs, parser.suite n'évalue pas réellement votre code python. Cela signifie que vous pouvez exécuter cet analyseur sur vos fichiers Python sans vous soucier de nommer ou d'importer des erreurs. Par exemple, disons que vous avez myObscureUtilityFile.py qui contient

from ..obscure.relative.path import whatever 

Vous pouvez

checkForNonUnicode(open('/whoah/softlink/myObscureUtilityFile.py').read()) 
+0

Vous n'avez pas besoin d'analyser le code. Juste produire les lexèmes devrait être suffisant; Si un lexème n'est pas Unicode, votre fichier a échoué au test. Si votre fichier contient des "références externes" (par exemple, from_future), vous ne pouvez pas savoir sans analyser * tous * les fichiers concernés, mais je suppose que cela ne fait pas partie de la définition de votre problème. –

0

Notre SD Source Code Search Engine (SCSE) peut fournir ce résultat directement. Le SCSE fournit un moyen de rechercher extrêmement rapidement dans de grands ensembles de fichiers en utilisant une partie de la structure du langage pour permettre des requêtes précises et minimiser les faux positifs. Il gère un large éventail de langues, même en même temps, y compris Python. Une interface graphique affiche les résultats de la recherche et une page du texte réel du fichier contenant un hit sélectionné.

Il utilise les informations lexicales des langages source comme base pour les requêtes, composées de divers mots-clés langauge et de jetons de modèle qui correspondent à des éléments langauge de contenu différents. SCSE connaît les types de lexèmes disponibles dans la langue. On peut rechercher un identifiant générique (en utilisant le jeton de requête I) ou un identifiant correspondant à une expression regulatr. Similaire, on peut rechercher une chaîne générique (en utilisant le jeton de requête "S" pour "n'importe quel type de chaîne littérale") ou un type de chaîne spécifique (pour Python incluant "UnicodeStrings", chaînes non-unicode, etc. composent l'ensemble des choses Python comprenant "S").

Ainsi, une recherche:

'for' ... I=ij* 

trouve le mot-clé « pour » près (« ... ») un identifiant dont le préfixe est « ij » et vous montre tous les coups. (Des espaces spécifiques de langue, y compris les sauts de ligne et les commentaires sont ignorés

Une recherche triviale:

S 

trouve toutes les chaînes littérales Ceci est souvent un ensemble assez grand: -..}

Une recherche

UnicodeStrings 

trouve toutes les chaînes littérales qui sont lexicalement définis comme des chaînes Unicode (u "...")

Ce que vous voulez, ce sont toutes les chaînes qui ne sont pas UnicodeStrings. Le SCSE fournit un opérateur de "soustraction" qui soustrait les hits d'un type qui chevauchent les hits d'un autre. Donc, votre question, « ce que les chaînes ne sont pas unicode » est exprimé de façon concise comme:

S-UnicodeStrings 

Tous les coups seront affichés les chaînes qui ne sont pas des chaînes unicode, votre question précise.

Le SCSE fournit des fonctions de journalisation afin que vous puissiez enregistrer les appels. Vous pouvez exécuter SCSE à partir d'une ligne de commande, en activant une requête scriptée pour votre réponse. Mettre ceci dans un script de commande fournirait un outil donnant directement votre réponse.