Forum >> Principianti >> Lista variabili non dichiarate in script

Pagina: 1

Buongiorno!
Sto cercando una sorta di workaround per estrarre delle informazioni da alcuni script che verranno eseguiti da un tool a runtime nel main namespace (usando exec o qualcosa di equivalente).

Un Syntax check sullo script singolo presenta degli errori dovuti a variabili non dichiarate, che peró a runtime dovrebbero essere disponibili nel namespace (create dal tool), sul quale non ho controllo.

Esiste un modo (pensavo a moduli tipo inspect o ast) per estrarre una lista di oggetti utilizzati in uno script (variabili, classi, funzioni) ma non dichiarati o importati esplicitamente nello stesso che quindi per forza di cose devono "preesistenti" nel namespace (builtins o estensioni dell 'interprete) per rendere lo script eseguibile.

# spam.py
foo = bar + 1
x = list_undeclared('spam.py')
# >>> ['bar']



/OT Da storico utente di forumpython.it è stata una sorpresa vederlo offline, è questo ora l'unico forum rimasto? /OT

/OT Da storico utente di forumpython.it è stata una sorpresa vederlo offline, è questo ora l'unico forum rimasto? /OT

Ciao caro, neanche io sapevo nulla. Magari si tratta solo di un disguido col rinnovo del dominio.

Mi sembra che i forum classici stiano "morendo" ovunque in favore di risorse meno specializzate, ma più immediate. Che sia un bene o un male non saprei, i vecchietti dicono un male mentre i giovincelli che i vecchi non capiscono niente. Insomma a seconda della tua angolazione si vedono cose diverse.

Sappi che nella pagina della comunità c'è il link al nostro canale Telegram, sempre piuttosto attivo, se qui non dovessi essere fortunato.

Cya
Daniele aka Palmux said @ 2023-09-28 14:32:11:
/OT Da storico utente di forumpython.it è stata una sorpresa vederlo offline, è questo ora l'unico forum rimasto? /OT

Ciao caro, neanche io sapevo nulla. Magari si tratta solo di un disguido col rinnovo del dominio.

Purtroppo non credo sia così, anche io, malgrado la mia pochezza, scrivevo in quel forum, il dominio è rimasto "sospeso" per un paio di mesi e poi è diventato disponibile per l'acquisto da fine giugno ... il tempo trascorso eccede i tempi di un semplice "disguido" ... cosa che mi dispiace moltissimo, ho imparato molto li ed era un archivio prezioso di concetti.
Per altro, c'è da dire che interventi da parte di utenti esperti erano diventati estremamente rari, forse anche per la banalità delle domande poste mediamente (cui cercavo di rispondere quando ne ero capace), il forum languiva.

Venendo alla domanda di imbuto : proporrei di provare con "vars(object)"

Ti faccio un esempio: supposto di avere un modulo così fatto:

# -*- coding: utf-8 -*-

X = 25.5

def make_global_var() -> None:
    global A
    A = 'Apelle figlio di Apollo'


def print_global_var() -> None:
    try:
        print(A)
        print(X)
    except Exception:
        print('Errore nella stampa delle variabili globali')
puoi analizzarlo e scremarlo tramite detta funzione built-in, segue un esempio in una shell idle

Python 3.10.12 (main, Jun 11 2023, 05:26:2  8) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license()" for more information.
import test_per_imbuto as tpi
definizioni = vars(tpi)
for k in definizioni.keys():
    print(k)

    
__name__
__doc__
__package__
__loader__
__spec__
__file__
__cached__
__builtins__
X
make_global_var
print_global_var
# scartiamo definizioni "speciali" e valori con "function"
for k in [x for x in definizioni.keys() if not x[:2] == '__']:
    if not 'function' in str(definizioni[k]):
        print(k)

        
X
tpi.make_global_var()
definizioni = vars(tpi)
for k in [x for x in definizioni.keys() if not x[:2] == '__']:
    if not 'function' in str(definizioni[k]):
        print(k, definizioni[k])

        
X 25.5
A Apelle figlio di Apollo
come puoi vedere, dal dizionario restituito da "vars(tpi)" ho scartato le chiavi "speciali" ed ho, quindi, non stampato quelle che avevano "function" nel loro valore (solo le globali, quindi), avendo "lanciato" un metodo che mi crea una nuova variabile globale nel modulo, ho ricaricato le definizioni e ricavato le variabili globali aggiornate.




Giochicchiandoci un po' credo Tu possa risolvere le Tue esigenze.

Ciao




Corrette alcune modifiche al codice da parte dello editore dei post



--- Ultima modifica di nuzzopippo in data 2023-09-28 20:04:39 ---
Fatti non foste a viver come bruti...
Purtroppo non credo sia così, anche io, malgrado la mia pochezza, scrivevo in quel forum, il dominio è rimasto "sospeso" per un paio di mesi e poi è diventato disponibile per l'acquisto da fine giugno ... il tempo trascorso eccede i tempi di un semplice "disguido" ... cosa che mi dispiace moltissimo, ho imparato molto li ed era un archivio prezioso di concetti.
Per altro, c'è da dire che interventi da parte di utenti esperti erano diventati estremamente rari, forse anche per la banalità delle domande poste mediamente (cui cercavo di rispondere quando ne ero capace), il forum languiva.
Ah cavolo, non sapevo nulla. Sì, in effetti dispiace molto perché la perdita di tutte le informazioni scritte nel tempo, al netto dei vari archivi online, è sempre qualcosa che dispiace.

Un vero peccato.
Per la cronaca, alla fine ho risolto con una cosa del genere (non ricordo se questa è la versione definitiva):
import ast
import builtins

def find_undeclared_identifiers(script):
    undeclared_identifiers = []

    # Parse the script into an abstract syntax tree (AST)
    try:
        tree = ast.parse(script)
    except SyntaxError as e:
        return [str(e)]

    # Define a set of built-in identifiers
    builtins_set = set(dir(builtins))

    # Define a visitor class to traverse the AST and collect undeclared identifiers
    class UndeclaredIdentifierVisitor(ast.NodeVisitor):
        def __init__(self):
            self.declared_identifiers = set()
            self.used_identifiers = set()

        def visit_Name(self, node):
            if isinstance(node.ctx, ast.Load):
                if node.id not in self.declared_identifiers and node.id not in builtins_set:
                    self.used_identifiers.add(node.id)
            self.generic_visit(node)

        def visit_FunctionDef(self, node):
            self.declared_identifiers.add(node.name)
            self.generic_visit(node)

        def visit_ClassDef(self, node):
            self.declared_identifiers.add(node.name)
            self.generic_visit(node)

        def visit_Assign(self, node):
            for target in node.targets:
                if isinstance(target, ast.Name):
                    self.declared_identifiers.add(target.id)
            self.generic_visit(node)

    visitor = UndeclaredIdentifierVisitor()
    visitor.visit(tree)

    # Filter out declared identifiers from used identifiers to find undeclared ones
    undeclared_identifiers = list(visitor.used_identifiers - visitor.declared_identifiers)

    return undeclared_identifiers


Non conoscevo "ast", interessante, grazie
Fatti non foste a viver come bruti...


Pagina: 1



Esegui il login per scrivere una risposta.