9

Si consideri il seguente codice di esempio:codice Controllo di warning di deprecazione

data = [] 
try: 
    print data[0] 
except IndexError as error: 
    print error.message 

Non c'è niente di sbagliato sintatticamente (usando Python2.7) con il codice, tranne che se si esegue python with warnings turned on, si vedrebbe un DeprecationWarning:

$ python -W always test.py 
test.py:5: DeprecationWarning: BaseException.message has been deprecated as of Python 2.6 
    print error.message 
list index out of range 

FYI, questo è perché .message was deprecated since python2.6 and removed in python3.

Ora, mi piacerebbe trovare tutti i punti del progetto in cui .message viene chiamato su qualsiasi istanza di eccezione utilizzando gli strumenti di analisi del codice statico. Come obiettivo finale, sto pianificando di eseguire questo controllo come parte di un'attività di controllo della qualità del codice & durante la compilazione giornaliera & e di generare un errore se la sintassi è ancora utilizzata.

È possibile? È qualcosa che è in grado di pylint, pyflakes o altri strumenti di analisi del codice?


ho scoperto che pep8 tool ha diversi controlli simili attuate, per esempio, has_key() utilizzo di controllo:

$ cat test.py 
my_dict = {} 
print my_dict.has_key('test') 
$ pep8 test.py 
test.py:2:14: W601 .has_key() is deprecated, use 'in' 

Come soluzione alternativa, posso trattare tutti gli avvisi come errori (come suggerito here) e fare i miei test falliscono ma questo ha i suoi svantaggi:

  • ci sono altri avvisi di deprecazione provenienti da pacchetti di terze parti che non riesco a f ix
  • a rigor di termini, questo richiede una copertura del 100%, che è difficile mantenere

risposta

7

Dal momento che si vuole fare questo in modo statico, è possibile utilizzare il modulo ast per analizzare il codice e quindi eseguire la scansione per qualsiasi occorrenza di il codice deprecato con una sottoclasse della classe NodeVisitor. In questo modo:

import ast, sys 

class UsingMessageAttr(ast.NodeVisitor): 

    error_object_names = [] 

    def visit_Attribute(self, node): 
     if (node.attr == 'message' and 
      hasattr(node.value, 'id') and 
      node.value.id in self.error_object_names): 

      print("Danger Will Robinson!!") 
      sys.exit(1) 

     self.generic_visit(node) 

    def visit_ExceptHandler(self, node): 
     if node.name is not None: 
      self.error_object_names.append(node.name) 
      self.generic_visit(node) 
      self.error_object_names.pop() 
     else: 
      self.generic_visit(node) 

with open('sourcefile.py', 'r') as f: 
    UsingMessageAttr().visit(ast.parse(f.read())) 

Questo funziona utilizzando python analizzare il file sorgente in un AST e quindi utilizza il modello visitatore di camminare attraverso l'intero file e trovare tutte le istanze dell'attributo deprecato. Per ulteriori informazioni su come funziona, vedere the python documentation on the ast module.

Si noti che questo non funzionerà se si utilizza qualcosa di intelligente per fare riferimento all'oggetto eccezione. Prende semplicemente il nome della variabile a cui è stato associato l'oggetto eccezione e controlla se un attributo message è mai stato letto da una variabile con lo stesso nome all'interno del corpo del gestore delle eccezioni.

+0

Immagino, in altre parole, la risposta sta dicendo: "No, non c'è nessuno strumento che possa aiutarti e tu dovresti farlo da solo" :) Grazie mille per i suggerimenti! – alecxe

+0

@alecxe Nessun problema, speravo che qualcuno potesse venire e dare una risposta facile (sembra troppo difficile per qualcosa di così semplice) ma è tutto. Non è poi così male, il codice che ti ho dato probabilmente funzionerà come script autonomo (forse potresti ottenere i nomi dei file di origine da 'sys.argv' e generare i numeri di riga con i tuoi messaggi di errore). – randomusername

+0

Sarebbe possibile aggiungere un messaggio di avviso personalizzato? (Se sì: dove/come?) Da visualizzare ad es. di PyDev – hardmooth