2016-03-24 30 views
8

Sto usando il potente editor di Sublime Text 3 su MacOSX per eseguire i codici Python. Voglio visualizzare una barra di avanzamento di un ciclo, e il seguente comando:Barra di avanzamento in Sublime Text con Python

sys.stdout.write('\rProgress : %03.2f %%' % (100*float(i)/(N))) 
sys.flush() 

non cancella la riga precedentemente stampato nella finestra di output come previsto (\r) ma produce N linee:

Progress : 0.25 % 
Progress : 0.50 % 
Progress : 0.75 % 
Progress : 1.00 % 
Progress : 1.25 % 
Progress : 1.50 % 
Progress : 1.75 % 
Progress : 2.00 % 
Progress : 2.25 % 
Progress : 2.50 % 
... 

Che non è molto bello da leggere - Concludo che la finestra di output potrebbe essere di sola lettura.

Qualcuno ha suggerimenti per migliorare l'uso delle barre di avanzamento in Sublime Text?

+0

Non sono esattamente sicuro di cosa stai chiedendo - intendevi che a causa della grande quantità di linee, l'output sembra davvero "spammoso", causando così uscite spiacevoli? – Jerrybibo

+0

Sì, volevo dire questo. Modifico la domanda per chiarire. –

risposta

5

Dando uno sguardo al sublime.py vediamo che il metodo flush in realtà non fa nulla:

class _LogWriter: 
    def flush(self): 
     pass 

    def write(self, s): 
     sublime_api.log_message(s) 

sys.stdout = _LogWriter() 
sys.stderr = _LogWriter() 

Tuttavia non mi consiglia di utilizzare la console per l'output dell'utente comunque. Solitamente si usano pannelli di output/viste o messaggi di stato.

I messaggi di stato sono più facili da usare ma meno potenti. sergioFC lo ha dimostrato in his answer.

Ciò dimostra come utilizzare un pannello di output. È molto flessibile, ma è necessario scrivere il proprio comando di testo per inserire il testo. Questo è necessario, perché è necessario un oggetto di modifica per modificare il contenuto della vista.

import sublime 
import sublime_plugin 


class MyInsertProgressBarCommand(sublime_plugin.TextCommand): 
    def run(self, edit, value): 
     view = self.view 
     width, _ = view.viewport_extent() 
     em_width = view.em_width() 
     # the number of columns are the width divided by the width of a char 
     # subtract two to add a little border 
     columns = int(width/em_width) - 2 

     # subtract two, because we surround it with [ and ] 
     bar_length = columns - 2 
     # calculate the size of the filled and the remaining part 
     filled_length = int(bar_length * value/100) 
     remaining_length = bar_length - filled_length 
     # assemble the string for the progress bar 
     text = "[{0}{1}]\n".format("=" * filled_length, "." * remaining_length) 
     # add the text for the percentages 
     if value >= 100: 
      percentage_text = "finished!" 
     else: 
      percentage_text = "{:3.2f} %".format(value) 
     text += " " * (columns - len(percentage_text)) + percentage_text 

     # replace the content of the view 
     view.replace(edit, sublime.Region(0, view.size()), text) 
     # reset sels 
     view.sel().clear() 
     view.sel().add(sublime.Region(0, 0)) 


class ProgressBarCommand(sublime_plugin.WindowCommand): 
    def run(self): 
     self.window.create_output_panel("progess_bar") 
     self.window.run_command("show_panel", {"panel": "output.progess_bar"}) 

     def test_progress_bar(): 
      import random 
      test_progress_bar.value += 2 * random.random() 
      if test_progress_bar.value >= 100: 
       self.finish_progress() 
       return 
      self.show_progress(test_progress_bar.value) 

      sublime.set_timeout(test_progress_bar, 100) 
     test_progress_bar.value = 0 

     sublime.set_timeout_async(test_progress_bar, 1) 

    def show_progress(self, progess): 
     view = self.window.find_output_panel("progess_bar") 
     view.run_command("my_insert_progress_bar", {"value": progess}) 

    def finish_progress(self): 
     self.show_progress(100) 
     sublime.set_timeout(self._destroy, 5000) 

    def _destroy(self): 
     self.window.destroy_output_panel("progess_bar") 

L'output:

Progress bar

+0

Cool solution:) Non ci avrei pensato. Ho lavorato per un po 'con [__unicode generation__] (https://github.com/Enteleform/Presentations/tree/master/Writing%20Your%20Own%20Sublime%20Text%20Plugins/2015-05-26#parkour) , ma il tuo metodo mi fornisce alcune informazioni su come lavorare con il testo animato. 'mdpopups' è molto interessante anche per l'output visivo, l'ho appena provato per la prima volta in [__my answer__] (http://stackoverflow.com/a/36234685/4955183) – Enteleform

+1

@Enteleform Thanks =) Inoltre non ero consapevole, che è possibile mostrare una finestra html in una vista. 'mdpopups' sembra essere un'aggiunta molto carina per quella funzionalità. –

+0

Dove dovrei avere il codice per MyInsertProgressBarCommand - lo aggiungo al mio progetto, o è qualcosa che dovrei aggiungere nella cartella Sublime? Se si sta estendendo Sublime, dove dovrebbe esserci una chiamata a questo modulo? Inoltre, si prega di dare un esempio di come chiamare questi metodi dal ciclo che progresso misuriamo. Grazie. –

2

Quello che stai cercando è un modo per impedire che l'output consumi più linee. È possibile stampare \b (il carattere di backspace) tutte le volte che c'erano caratteri precedentemente stampati. Ho scritto questo come esempio:

(Python 2.7.6)

from __future__ import print_function 
import time, sys 

for i in range(1, 6): 
    print(i, end='') 
    sys.stdout.flush() 
    time.sleep(0.5) 
    print('\b', end='') 

provare a eseguire questo e si può adattare alle proprie esigenze.

+1

Grazie per questa risposta, ma la tua proposta è abbastanza vicina al mio primo tentativo (stavo usando '\ r', il carrello di ritorno). Questa soluzione funziona bene in un terminale, ma non funziona nella finestra di output interna di Sublime Text. Ecco l'output della soluzione: '12345 [Finito in 2.6s]'. –

+0

Oh mi dispiace, non mi ero reso conto fino ad ora che stavi parlando del pannello di output in Sublime Text. In una sessione terminale, questo dovrebbe stampare 1, sostituirlo con 2, sostituirlo con 3, ecc. – thedouglenz

1

Sfortunatamente, questo non è possibile nel pannello di output di Sublime. Il pannello non è una vera console o terminale, e tra le altre differenze non interpreta sequenze di escape come \r e \b (\nè interpretato correttamente, tuttavia). Se vuoi vedere come funziona esattamente, installa PackageResourceViewer, quindi apri Packages/Default/exec.py.

Per far funzionare tutto questo, è necessario creare un nuovo build system per eseguirlo nel terminale. A causa dei capricci di OS X, dovrai creare due file. Il primo è uno script di shell:

#!/bin/sh 
osascript -e '  
    on run parameters   
    tell application "Terminal"    
     activate    
     do script with command "/path/to/python " & parameters   
    end tell  
    end run 
' [email protected] 

Cambiare /path/to con il percorso effettivo python (o python3). Salva dove vuoi come PythonTerminal.sh. Quindi, selezionare Tools -> Build System -> New Build System e incollare il seguente:

{ 
    "cmd": ["/bin/sh /path/to/Python3Terminal.sh \"$file\""], 
    "file_regex": "^[ ]*File \"(...*?)\", line ([0-9]*)", 
    "selector": "source.python", 
    "shell": true 
} 

Anche in questo caso, il cambiamento /path/to al percorso effettivo per PythonTerminal.sh. Salva il file come Packages/User/PythonTerminal.sublime-build (dovrebbe aprire automaticamente la directory corretta al momento del salvataggio).

Infine, selezionate Tools -> Build System -> PythonTerminal, passare al file Python, e costruire con B. Si aprirà una nuova finestra di Terminale e la barra di avanzamento dovrebbe essere eseguita.

4

Come un'altra soluzione alternativa è possibile utilizzare la barra di stato. Quando si imposta il messaggio sulla barra di stato, il testo precedente viene cancellato. Il controllo pacchetto utilizza anche la barra di stato durante l'installazione dei pacchetti.

Esempio:

Sublime text progress bar using status bar

import sublime, sublime_plugin 
import time 

class ExampleCommand(sublime_plugin.WindowCommand): 
    def run(self, args): 
     sublime.set_timeout_async(self.test,1) 

    def test(self): 
     i=80 
     while i <= 100: 
      sublime.status_message('%03.2f %%' % i) 
      time.sleep(0.15) 
      i+=0.25 
     sublime.status_message('100% Stackoverflow!') 
+0

Grazie amico! Anche questa è una bella implementazione, probabilmente più utile per qualcosa in esecuzione in modo asincrono che non ha bisogno di un riferimento visivo pronunciato. Forse una notifica 'mdpopup' al completamento? :) – Enteleform

+1

Cool :) Per quanto riguarda il premio, lo premierò domenica o lunedì (a causa delle regole di stackoverfow devo aspettare 24 ore prima di assegnarlo) – sergioFC

+0

Impressionante, non ho capito che c'era una taglia. Molto apprezzato:) – Enteleform

5

È possibile creare una barra di avanzamento visiva utilizzando:

 



Demo:

Demo

 



Codice:

@ GitHub

(gestita del plugin digitando Progress Bar Demo @ tavolozza dei comandi)

   



Note:

C'è uno css file che controlla lo stile di mdpopups. Per qualche motivo, la proprietà color non ha alcun effetto.

Inoltre, il parametro assume -1 per il popup da impostare nella posizione di cursore. Altrimenti, non sono sicuro di come il parametro location influenzi il popup, poiché richiede solo un singolo valore intero.  

 

ho chiesto informazioni circa queste questioni in questo thread:

[Proof Of Concept] Visual Progress Bar

 

+1

Wow, bel lavoro. Non sapevo nemmeno che fosse possibile. Voglio provare a 'mdpopups' – sergioFC

+1

Questo sembra davvero fantastico! Sono piuttosto un novizio (mi dispiace), ma se capisco bene: questo può essere usato come un plug-in Sublime Text, ma è possibile includerlo in un codice python esterno/personale? –

+0

@ Léonard: lo script che ho scritto è per l'integrazione con i plugin di SublimeText. Penso che l'unico modo per tenere traccia dei progressi nel normale codice Python sarebbe un approccio più lungo la linea di [__r-stein's answer__] (http://stackoverflow.com/a/36234502/4955183). Dovresti, naturalmente, rifattorizzarlo per escludere gli aspetti specifici di SublimeText e convertire la sua funzionalità in output della console. – Enteleform

2

È possibile utilizzare libreria progressbar. trova qui: https://pypi.python.org/pypi/progressbar/2.3-dev

Inoltre è possibile installarlo dal easy_install tipo solo: easy_install progressbar

Esempio d'uso:

se si vuole semplice progressbar informazioni fuori sulla funzione:

from progressbar import * 
from time import sleep 

progress = ProgressBar() 
for i in progress(range(80)): 
    sleep(0.01) 

altro se vuoi barra di avanzamento con informazioni sulla funzione:

from progressbar import * 
from time import sleep 

widgets = ['Something: ', Percentage(), ' ', Bar(marker=RotatingMarker()), 
      ' ', ETA(), ' ', FileTransferSpeed()] 
pbar = ProgressBar(widgets=widgets, maxval=10000000).start() 
for i in range(1000000): 
    # do something 
    pbar.update(10*i+1) 
    sleep(0.000001) 
pbar.finish()