13

mi piacerebbe essere in grado di fare qualcosa di simile questi due stanno facendo:sandboxing/corsa linea di codice Python per riga

Inventing on principle @18:20, Live ClojureScript Game Editor

Se non si vuole controllare i video, la mia problema è questo:

dire che ho avuto questo codice:

.... 
xs = [] 
for x in xrange(10): 
    xs.append(x) 
... 

mi piacerebbe fare un ambiente in cui posso eseguire il codice , dichiarazione per affermazione e guardare/rintracciare la gente del posto/i globali mentre cambiano. Forse dargli una lista di vars da tenere sotto controllo nei dizionari locali/globali. Come passare il codice e salvare le informazioni di stato.

In modo ottimale Mi piacerebbe salvare ogni stato ed è associato a dati di contesto (locali/globali) così posso verificare i predicati per esempio.

mi piacerebbe fare qualcosa di simile binarySearch esempio di Bret Victor Inventing on principle @18:20

Am I dare un senso? Trovo complicato da spiegare nel testo, ma i video vetrina quello che voglio provare :)

Grazie per il vostro tempo


Quello che ho provato/lettura/Googled:

il mio prossimo passo potrebbe essere esaminando ast e compilare il codice ed eseguirlo bit per bit, ma ho davvero bisogno di un orientamento .. Devo guardare più nella riflessione e la inspect -module ??

Ho già utilizzato the Spin model checker, ma utilizza la propria DSL e mi piacerebbe fare la modellazione nel linguaggio di implementazione, in questo caso python.

Oh e BTW Conosco le implicazioni di sicurezza del codice sandboxing, ma non sto cercando di creare un ambiente di esecuzione sicuro, sto cercando di creare un ambiente molto interattivo, puntando a un modello di controllo o a un'asserzione del predicato per esempio.

+2

Un debugger farebbe quello che chiedi? –

+0

Non ne sono sicuro.Mi piacerebbe manipolare la gente del posto/globalmente, quindi se posso farlo dal debugger ... Hai controllato i video? * Inventare per principio * @ 18:20 e 1 minuto avanti mostra un po 'quello che voglio. –

+1

Non posso contribuire molto in termini di risposta, ma questa è una domanda dannatamente buona (+1) – inspectorG4dget

risposta

7

Dopo il mio initial success con sys.settrace(), ho finito per passare a the ast module (alberi di sintassi). Analizzo il codice che voglio analizzare e quindi inserisco nuove chiamate dopo ogni assegnazione per riportare il nome della variabile e il suo nuovo valore. Inserisco anche le chiamate per segnalare iterazioni di loop e chiamate di funzione. Quindi eseguo l'albero modificato.

 tree = parse(source) 

     visitor = TraceAssignments() 
     new_tree = visitor.visit(tree) 
     fix_missing_locations(new_tree) 

     code = compile(new_tree, PSEUDO_FILENAME, 'exec') 

     self.environment[CONTEXT_NAME] = builder 
     exec code in self.environment 

sto lavorando su uno strumento di Live Coding come Bret Victor, e si può vedere il mio codice di lavoro on GitHub, e alcuni esempi di come si comporta in the test. È inoltre possibile trovare collegamenti a video dimostrativi, tutorial e download da the project page.

+0

+1 accettato. Questo è ESATTAMENTE quello che ho chiesto :) Grazie per aver condiviso questo. Mi dispiace di essere stato troppo impegnato per contribuire a questo. –

0

scaricare Eclipse + pydev ed eseguirlo in modalità debug ...

+0

che non sarà abbastanza potente, penso. Voglio fare di più che guardare solo lo stato del programma. Mi piacerebbe costruire un reticolo di tutti i possibili stati del programma, analizzarli tutti e far valere un predicato in ogni stato, ad esempio. 'per stato negli stati: assert state.locals [" var "]> = 0' o qualcosa –

+0

oh, capisco. Non so nulla di ciò che può fare questo .. – WeaselFox

+0

Se vuoi dire che non l'hai visto in generale, controlla [il controllo del modello Spin] (http://spinroot.com/spin/whatispin.html). DSL limitato con concurrency e IPC in grado di verificare i predicati sul codice. Costruisci un modello del tuo sistema e prova cose su di esso. –

3

Sembra che tu abbia bisogno BdB, la biblioteca pitone debugger. È integrato e i documenti sono qui: http://docs.python.org/library/bdb.html

Non ha tutte le funzionalità che sembra, ma è un buon punto per iniziare a implementarlo.

+0

Grazie amico (+1), esaminerò 'bdb' :) Speravo davvero che ci fosse qualcosa che potrei fare con le funzioni' eval'/'exec', o che mi mancava qualcosa. –

2

Per traccia semplice, suggerisco di utilizzare pdb. Ho trovato che è abbastanza ragionevole per la maggior parte degli scopi di debug/single stepping. Per il tuo esempio:

import pdb 
... 
xs = [] 
pdb.set_trace() 
for x in xrange(10): 
    xs.append(x) 

Ora il programma si fermerà alla chiamata set_trace() e si può usare n o s per scorrere il codice mentre è in esecuzione. AFAIK pdb utilizza bdb come back-end.

+0

Ho letto un po 'di 'pdb' ieri, ma sembrava che avrei dovuto fare il controllo del flusso manualmente. Ho ragione su questo? Mi piacerebbe essere in grado di controllare il flusso a livello di programmazione. Basta sfogliare il codice una dichiarazione alla volta dandomi la possibilità di fare qualcosa tra una dichiarazione e l'altra. –

+0

Così come con qualsiasi debugger interattivo è possibile impostare punti di interruzione, esaminare le variabili o modificarle. – hochl

+0

Puh - Non l'ho mai fatto, devo essere d'accordo ... l'ho usato solo per il compito di debug medio. – hochl

3

Ok ragazzi, ho fatto un po 'di progressi.

Supponiamo di avere un file di origine come questo, vogliamo eseguire istruzioni in essa contenuta:

print("single line") 
for i in xrange(3): 
    print(i) 
    print("BUG, executed outside for-scope, so only run once") 
if i < 0: 
    print("Should not get in here") 
if i > 0: 
    print("Should get in here though") 

voglio eseguirlo un'istruzione alla volta, pur avendo accesso ai locali/globali. Questa è una prova sporca rapido of concept (ignorare gli insetti e crudezza):

# returns matched text if found 
def re_match(regex, text): 
    m = regex.match(text) 
    if m: return m.groups()[0] 

# regex patterns 
newline = "\n" 
indent = "[ ]{4}" 
line = "[\w \"\'().,=<>-]*[^:]" 
block = "%s:%s%s%s" % (line, newline, indent, line) 

indent_re = re.compile(r"^%s(%s)$" % (indent, line)) 
block_re = re.compile(r"^(%s)$" % block) 
line_re = re.compile(r"^(%s)$" % (line)) 

buf = "" 
indent = False 

# parse the source using the regex-patterns 
for l in source.split(newline): 
    buf += l + newline    # add the newline we removed by splitting 

    m = re_match(indent_re, buf) # is the line indented? 
    if m: 
     indent = True    # yes it is 
    else: 
     if indent:     # else, were we indented previously? 
      indent = False   # okay, now we aren't 

    m = re_match(block_re, buf)  # are we starting a block ? 
    if m: 
     indent = True 
     exec(m) 
     buf = "" 
    else: 
     if indent: buf = buf[4:] # hack to remove indentation before exec'ing 
     m = re_match(line_re, buf) # single line statement then? 
     if m: 
      exec(m) # execute the buffer, reset it and start parsing 
      buf = "" 
     # else no match! add a line more to the buffer and try again 

uscita:

[email protected] /tmp $ python p.py 
single line 
0 
1 
2 
BUG, executed outside for-scope, son only run once 
Should get in here though 

Quindi questo è un po 'quello che voglio. Questo codice suddivide la fonte in istruzioni eseguibili e sono in grado di "mettere in pausa" tra le istruzioni e manipolare l'ambiente. Come mostra il codice sopra, non riesco a capire come rompere correttamente il codice ed eseguirlo di nuovo. Questo mi ha fatto pensare che dovrei essere in grado di usare qualche strumento per analizzare il codice ed eseguirlo come voglio io. In questo momento sto pensando ast o pdb come suggerite voi ragazzi.

Un rapido sguardo suggerisce ast può farlo, ma sembra un po 'complesso quindi dovrò scavare nei documenti. Se pdb può controllare il flusso a livello di codice, potrebbe anche essere la risposta.

Aggiornamento:

Sooo, ho fatto qualche lettura più e ho trovato questo argomento: What cool hacks can be done using sys.settrace?

ho guardato in utilizzando sys.settrace(), ma non sembra essere la strada da percorrere. Mi sto convincendo sempre più che ho bisogno di usare il modulo ast per ottenere il controllo acquisito con precisione come vorrei. FWIW ecco il codice per utilizzare settrace() a picco dentro portata funzione vars:

import sys 

def trace_func(frame,event,arg): 
    print "trace locals:" 
    for l in frame.f_locals: 
     print "\t%s = %s" % (l, frame.f_locals[l]) 

def dummy(ls): 
    for l in ls: pass 

sys.settrace(trace_func) 
x = 5 
dummy([1, 2, 3]) 
print "whatisthisidonteven-" 

uscita:

[email protected] /tmp $ python t.py 
trace locals: 
    ls = [1, 2, 3] 
whatisthisidonteven- 
trace locals: 
    item = <weakref at 0xb78289b4; dead> 
    selfref = <weakref at 0xb783d02c; to 'WeakSet' at 0xb783a80c> 
trace locals: 
    item = <weakref at 0xb782889c; dead> 
    selfref = <weakref at 0xb7828504; to 'WeakSet' at 0xb78268ac> 

UPDATE:

Va bene mi sembra di aver risolto ..:) Ho scritto un parser semplice che inietta un'istruzione tra ogni riga di codice e quindi esegue il codice. Questa istruzione è una chiamata di funzione che cattura e salva l'ambiente locale nel suo stato corrente.

Sto lavorando a un editor di testo Tkinter con due finestre che farà ciò che Bret Victor fa nella sua demo di binarySearch. Ho quasi finito :)

+1

Sì, lo caccio e rispondo qui. Mi piacerebbe provarlo per te. – Droogans

+0

Ho ancora bisogno di lavorare un po ', ma penso che finirò nel fine settimana :) Ti colpirò ogni volta che ho qualcosa in esecuzione –

+0

Sto lavorando alla stessa cosa, ma io non ho t ottenuto fino lontano Ho fatto una [prova grezza del concetto] (https://github.com/donkirkby/live-py) che esegue un intero blocco di codice ogni secondo. Ora sto provando a creare un plugin Eclipse che aggiungerà la codifica live a PyDev. Ho appena capito come [aggiungere un righello extra] (https://github.com/donkirkby/live-py-plugin) ad un editor di Eclipse. Fammi sapere se vuoi lavorare insieme. –

2

Vedo che hai trovato qualcosa che funziona per te, ma ho pensato che valesse la pena citare "pyscripter". http://code.google.com/p/pyscripter/

Sono abbastanza nuovo a Python, ma mi sto trovando molto utile
è sufficiente fare clic oltre la linea che ha una variabile voglio controllare,
quindi premere F4 per eseguirlo in un debugger modalità.
Successivamente posso passare il mouse sopra la variabile e viene visualizzato
un suggerimento con i valori della variabile.

È possibile anche solo passo attraverso lo script con F7, come descritto qui:
http://openbookproject.net/thinkcs/python/english3e/functions.html#flow-of-execution
(vedere 'Guarda il flusso di esecuzione in azione')

Anche se quando ho seguito l'esempio ancora entrò nella modulo di tartaruga per qualche ragione.

+0

Cool, ci penserò sicuramente :) –

4

Aggiornamento: Dopo il mio successo iniziale con questa tecnica, sono passato ad usare il modulo ast come descritto in my other answer.

sys.settrace() sembra funzionare molto bene. Ho preso il hacks question che hai citato e Andrew Dalke's article e ho ottenuto questo semplice esempio di lavoro.

import sys 

def dump_frame(frame, event, arg): 
    print '%d: %s' % (frame.f_lineno, event) 
    for k, v in frame.f_locals.iteritems(): 
     print ' %s = %r' % (k, v) 
    return dump_frame 

def main(): 
    c = 0 
    for i in range(3): 
     c += i 

    print 'final c = %r' % c 

sys.settrace(dump_frame) 

main() 

Ho dovuto risolvere due problemi per farlo funzionare.

  1. La funzione di traccia deve restituire se stessa o un'altra funzione di traccia se si desidera continuare la traccia.
  2. L'analisi sembra iniziare solo dopo la prima chiamata di funzione. Inizialmente non avevo il metodo principale, e andavo direttamente in loop.

ecco l'output:

9: call 
10: line 
11: line 
    c = 0 
12: line 
    i = 0 
    c = 0 
11: line 
    i = 0 
    c = 0 
12: line 
    i = 1 
    c = 0 
11: line 
    i = 1 
    c = 1 
12: line 
    i = 2 
    c = 1 
11: line 
    i = 2 
    c = 3 
14: line 
    i = 2 
    c = 3 
final c = 3 
14: return 
    i = 2 
    c = 3 
38: call 
    item = <weakref at 0x7febb692e1b0; dead> 
    selfref = <weakref at 0x17cc730; to 'WeakSet' at 0x17ce650> 
38: call 
    item = <weakref at 0x7febb692e100; dead> 
    selfref = <weakref at 0x7febb692e0a8; to 'WeakSet' at 0x7febb6932910> 
Problemi correlati