Ubuntu 16.04: disabilitare Tracker

8 giugno 2018 Nessun commento

Tracker

Tracker è uno strumento per l’indicizzazione e la ricerca di metadati.
Essendo molto avido di risorse, vediamo come disattivare questo servizio.

Per vedere quali file sono coinvolti, da terminale:

$ ls  /etc/xdg/autostart/tracker-*
/etc/xdg/autostart/tracker-extract.desktop
/etc/xdg/autostart/tracker-miner-fs.desktop
/etc/xdg/autostart/tracker-store.desktop
/etc/xdg/autostart/tracker-miner-apps.desktop
/etc/xdg/autostart/tracker-miner-user-guides.desktop

Per disabilitarli al prossimo riavvio, basta aggiungere la coppia chiave=valore
Hidden=true in ognuno di questi file.

Usiamo il comando:

echo -e "\nHidden=true\n" | sudo tee --append /etc/xdg/autostart/tracker-{extract,miner-apps,miner-fs,miner-user-guides,store}.desktop > /dev/null

Dal man page di tracker-miner-fs:

crawling-interval:
“Interval in days to check whether the filesystem is up to date in the database. 0 forces crawling anytime, -1 forces it only after unclean shutdowns, and -2 disables it entirely.
Values range from -2 to 365.”

enable-monitors:
“Set to false to completely disable any file monitoring”

settare quindi questi due parametri a:

crawling-interval=-2
enable-monitors=true

con il comando:

gsettings set org.freedesktop.Tracker.Miner.Files crawling-interval -2  
gsettings set org.freedesktop.Tracker.Miner.Files enable-monitors false  

oppure tramite dconf-editor con il percorso org > freedesktop > Tracker > Miner > Files:
e settando i parametri suddetti.

Non rimane che recuperare l’enorme spazio occupato dai database creati da Tracker, eliminandoli.
Per fare questo si usa tracker-reset con il comando:

tracker reset --hard 

dal manuale:

"--hard        This  kills  all  processes  in the same way that tracker daemon
               --kill does  but  it  also  removes  all  databases.  Restarting
               tracker-store re-creates the databases."

Per controllare il nuovo stato:

tracker-control -S
Categorie:Ubuntu Tag:

Conky: Xfce4

9 maggio 2018 Commenti chiusi

Installazione Conky

Installare i pacchetti conky-all, curl, lm-sensors e hddtemp,
con il comando:

sudo apt-get install conky-all curl lm-sensors hddtemp

Per prima cosa impostare il bit SUID su hddtemp in modo da assegnare allo user che esegue hddtemp, gli stessi privilegi dell’utente root.
Questo è necessario perchè conky non potrà altrimenti eseguire sudo autonomamente dal suo file di configurazione conkyrc:

sudo chmod u+s /usr/sbin/hddtemp

Comandi base di Conky

per eseguire conky da terminale:

conky &

per eseguire conky in background ed evitare che venga terminato alla chiusura del terminale:

conky -d

File di configurazione

Le configurazioni di conky risiedono nel file ~/.conkyrc, se non devesse esistere, fare una copia del file di default:

cp /etc/conky/conky.conf  ~/.conkyrc

E’ necessario riavviare conky per poter utilizzare il nostro file di configurazione:

killall conky
conky &

Il file di configurazione è diviso in due parti:
tutto ciò che riguarda la resa a schermo di conky risiede in conky.config mentre tutto ciò che riguarda la formattazione del testo risiede in conky.text.
Tutto ciò che non è compreso tra

${ }

viene interpretato da conky come testo semplice.

conky.config = {
    alignment = 'top_left',
    background = false,
    border_width = 1,
    cpu_avg_samples = 2,
    default_color = 'white',
    default_outline_color = 'white',
    default_shade_color = 'white',
    draw_borders = false,
    draw_graph_borders = true,
    draw_outline = false,
    draw_shades = false,
    use_xft = true,
    font = 'DejaVu Sans Mono:size=12',
    gap_x = 5,
    gap_y = 60,
    minimum_height = 5,
    minimum_width = 5,
    net_avg_samples = 2,
    no_buffers = true,
    out_to_console = false,
    out_to_stderr = false,
    extra_newline = false,
    own_window = true,
    own_window_class = 'Conky',
    own_window_type = 'desktop',
    stippled_borders = 0,
    update_interval = 1.0,
    uppercase = false,
    use_spacer = 'none',
    show_graph_scale = false,
    show_graph_range = false
}

conky.text = [[
${scroll 16 $nodename - $sysname $kernel on $machine | }
$hr
${color grey}Uptime:$color $uptime
${color grey}Frequency (in MHz):$color $freq
${color grey}Frequency (in GHz):$color $freq_g
${color grey}RAM Usage:$color $mem/$memmax - $memperc% ${membar 4}
${color grey}Swap Usage:$color $swap/$swapmax - $swapperc% ${swapbar 4}
${color grey}CPU Usage:$color $cpu% ${cpubar 4}
${color grey}Processes:$color $processes  ${color grey}Running:$color $running_processes
$hr
${color grey}File systems:
 / $color${fs_used /}/${fs_size /} ${fs_bar 6 /}
${color grey}Networking:
Up:$color ${upspeed eth0} ${color grey} - Down:$color ${downspeed eth0}
$hr
${color grey}Name              PID   CPU%   MEM%
${color lightgrey} ${top name 1} ${top pid 1} ${top cpu 1} ${top mem 1}
${color lightgrey} ${top name 2} ${top pid 2} ${top cpu 2} ${top mem 2}
${color lightgrey} ${top name 3} ${top pid 3} ${top cpu 3} ${top mem 3}
${color lightgrey} ${top name 4} ${top pid 4} ${top cpu 4} ${top mem 4}
]]

e corrisponde alla seguente grafica:

La lista di tutti i parametri è reperibile sul sito ufficiale.

alignment = ‘top_left’:
Indica la posizione della finestra di conky sullo schermo.
I valori accettati sono: alignment top_left, alignment top_right, alignment bottom_left, alignment bottom_right, alignment none

background = false:
Se settato a true, conky viene forzato a funzionare in background e non dipende da nessun terminale

border_width = 1:
Spessore del bordo in pixels

cpu_avg_samples = 2:
Numero di campionamenti per il monitoraggio della cpu

default_color = ‘white’:
colore di default di testo e bordo

default_outline_color = ‘white’:
colore di default dell’outline

default_shade_color = ‘white’:
colore di default dell’ombreggiatura

draw_borders = false:
Disegna i bordi del testo

draw_graph_borders = true:
Disegna i bordi dei grafici

draw_outline = false:
Disegna i bordi attorno a testi e linee, utile se il contrasto di background è insufficiente

draw_shades = false:
Aggiunge una sottile ombra sotto testi e linee per facilitare la lettura con background a medio
contrasto. Per contrasti insufficienti, vedere draw_outline.

use_xft = true:
Utilizza Xft (X FreeType interface Library) per fonts anti-aliased

font = ‘DejaVu Sans Mono:size=12’:
Il nome del font utilizzato in X. Costituito da tre parametri:
Font Name – Il nome del font, nel nostro caso “‘DejaVu Sans Mono”;
[size=] – [optional] la dimensione del font in pixels;
[weight] – [optional] in caso si voglia il grassetto, inserire la parola “bold”.

gap_x = 5:
Gap sull’asse x, rispetto al bordo dello schermo

gap_y = 60:
Gap sull’asse y, rispoetto al bordo dello schermo

minimum_height = 5:
Minima altezza della finestra di conky

minimum_width = 5:
Minima larghezza della finestra di conky

net_avg_samples = 2:
numero campionamenti per il traffico di dati

no_buffers = true:
Sottrae i buffers (file system) dalla memoria utilizzata

out_to_console = false:
Stampa sullo “stdout” (standard output) per essere visualizzato a terminale

out_to_stderr = false
Stampa sullo “stderr” (standard error)

extra_newline = false
Aggiunge una linea extra alla fine, quando sta scrivendo sullo “stdout”

own_window_class = ‘Conky’
Imposta manualmente il nome del window manager WM_CLASS. “Conky” di default

own_window_type = ‘desktop’
Serve per utilizzare alcuni hints del window manager che influiscono sulla visualizzazione di Conky

stippled_borders = 0
Stippling dei bordi in pixels

update_interval = 1.0
Intervallo di update di conky in secondi

uppercase = false
Serve per visualizzare il testo in maiuscolo

use_spacer = ‘none’
Aggiunge spazi attorno a certi oggetti. Utile quando si usano font particolari come “Bitstream Vera Sans Mono”

show_graph_scale = false
Mostra il valore massimo nella scala del grafico

show_graph_range = false
Mostra il time-range del grafico

Analizzando ora il formato del testo visualizzato nel file di default:

${scroll 16 $nodename - $sysname $kernel on $machine | }

Scrolling del testo (su 16 caratteri in movimento) delle variabili indicate con $

$hr

Disegna una riga orizzontale

${color grey}Uptime:$color $uptime

Visualizza la scritta uptime in grigio (delimitata dai tag $color).
La variabile che segue, $uptime, utilizza il colore di default (“white”)

${color grey}Frequency (in MHz):$color $freq
${color grey}Frequency (in GHz):$color $freq_g
RAM Usage:$color $mem/$memmax - $memperc% ${membar 4}
${color grey}Swap Usage:$color $swap/$swapmax - $swapperc% ${swapbar 4}
${color grey}CPU Usage:$color $cpu% ${cpubar 4}
${color grey}Processes:$color $processes  ${color grey}Running:$color $running_processes

Stessa cosa del punto precedente con altri parametri.

$hr

Disegna una riga orizzontale

${color grey}File systems:
 / $color${fs_used /}/${fs_size /} ${fs_bar 6 /}
${color grey}Networking:
Up:$color ${upspeed eth0} ${color grey} - Down:$color ${downspeed eth0}
$hr

Disegna una riga orizzontale

${color grey}Name              PID   CPU%   MEM%
${color lightgrey} ${top name 1} ${top pid 1} ${top cpu 1} ${top mem 1}
${color lightgrey} ${top name 2} ${top pid 2} ${top cpu 2} ${top mem 2}
${color lightgrey} ${top name 3} ${top pid 3} ${top cpu 3} ${top mem 3}
${color lightgrey} ${top name 4} ${top pid 4} ${top cpu 4} ${top mem 4}

Modifica File di configurazione

Un esempio di file personalizzato del mio desktop è il seguente e sono stati modificati i font, i size del font, i colori e i parametri da visualizzare.
E’ necessaria l’installazione del font-awesome quindi:

sudo apt-get install fonts-font-awesome
conky.config = {
	alignment = 'top_right',
	background = true,
	cpu_avg_samples = 2,
	default_color = "FFFFFF",
	draw_borders = false,
	draw_graph_borders = false,
	draw_outline = false,
	draw_shades = true,
	use_xft = true,
	font = 'Ubuntu Mono:size=10',
	gap_x = 10,
	gap_y = 10,
	minimum_width = 0, minimum_height = 0,
	net_avg_samples = 2,
	no_buffers = true,
	out_to_console = false,
	own_window = true,
	own_window_class = "Conky",
	own_window_type = "normal",
	own_window_hints = "undecorated,below,sticky,skip_taskbar,skip_pager",
	own_window_transparent = true,
	own_window_colour = "000000",
	update_interval = 1,
	uppercase = false,
	override_utf8_locale = true,
	double_buffer = true,
	text_buffer_size = 32768,
	border_inner_margin = 10,
	border_outer_margin = 0,
	xftalpha = 0.8,
        color1 = CCAB8D,
};

conky.text = [[
	${color1}
	${voffset 5}
	${alignr}${font Ubuntu:style=Medium:pixelsize=50}${time %H:%M}${font}
	${voffset 5}
	${alignr}${font Ubuntu:style=Medium:pixelsize=13}${time %A %d %B %Y}${font}
	${voffset 5}
	${color #DD3A21}$nodename: ${scroll 16 $sysname $kernel on $machine}${color}
	${hr}
	${font FontAwesome}?${font} IP address:
        ${goto 20}${addrs eth0}
	${goto 20}${upspeedgraph eth0 30,178 06E9F8 2104FA}${goto 202}${downspeedgraph eth0 30,175 FFFF00 DD3A21}
	${font FontAwesome}${goto 20}?${font} ${upspeed eth0}${font FontAwesome}${goto 202}?${font} ${downspeed eth0}
	${hr}
	${font FontAwesome}?${font} DiskIO:
	${goto 20}${diskiograph_read 30,178 06E9F8 2104FA}${goto 202}${diskiograph_write 30,175 FFFF00 DD3A21}
	${font FontAwesome}${goto 20}?${font} ${diskio_read}${font FontAwesome}${goto 202}?${font} ${diskio_write}
	${hr}
	${font FontAwesome}?${font} Memory usage: 
        ${goto 20}${mem}/${memmax} (${memperc}%) | Swap: ${swapperc}%
	${goto 20}${memgraph 30,355 AAF5D0 00B35B}
	${hr}
	${color1}File systems:
	${color1}sda: /home${goto 125}${color}${fs_used /home}/${fs_size /home} ${fs_used_perc /home}% ${color1}					
	${color1}sda: /${goto 125}${color}${fs_used /}/${fs_size /} ${fs_used_perc /}% ${color1}								
        ${color1}sdb: /home${goto 125}${color}${fs_used /home/banco/mediaHD/}/${fs_size /home/banco/mediaHD/} ${fs_used_perc /home/banco/mediaHD/}% ${color1}							

	${hr}
	${color1}Temperatures in Celsius:
	${color1}sda			${alignr}	${color} ${execi 10 hddtemp /dev/sda | cut -c32-36}
	${color1}sdb			${alignr}	${color} ${execi 10 hddtemp /dev/sdb | cut -c31-36}
	${color1}Core0 			${alignr}${color} ${execi 60 sensors | grep "Core 0" | cut -c16-22}
	${color1}Core1 			${alignr}${color} ${execi 60 sensors | grep "Core 1" | cut -c16-22}
	${color1}GPU 			${alignr}	${color} ${execi 60 nvidia-settings -query [gpu:0]/GPUCoreTemp -t}°C
	${hr}
	${goto 20}CPU0: ${cpu cpu0}%${goto 100}${cpubar 7,80 cpu0}
	${goto 20}CPU1: ${cpu cpu1}%${goto 100}${cpubar 7,80 cpu1}
	${hr}
	${color #FFFF00}${goto 20}Name ${goto 200}Pid${goto 255}Cpu%${goto 310}Mem%${color}
	${goto 20}${top name 1} ${goto 180}${top pid 1}${goto 235}${top cpu 1}${goto 290}${top mem 1}
	${goto 20}${top name 2} ${goto 180}${top pid 2}${goto 235}${top cpu 2}${goto 290}${top mem 2}
	${goto 20}${top name 3} ${goto 180}${top pid 3}${goto 235}${top cpu 3}${goto 290}${top mem 3}
	${goto 20}${top name 4} ${goto 180}${top pid 4}${goto 235}${top cpu 4}${goto 290}${top mem 4}
	${goto 20}${top name 5} ${goto 180}${top pid 5}${goto 235}${top cpu 5}${goto 290}${top mem 5}

]];

Ecco le sezioni una per una

Orario e data

	${color1}
	${voffset 5}
	${alignr}${font Ubuntu:style=Medium:pixelsize=50}${time %H:%M}${font}
	${voffset 5}
	${alignr}${font Ubuntu:style=Medium:pixelsize=13}${time %A %d %B %Y}${font}


Nodename e Net

	${color #DD3A21}$nodename: ${scroll 16 $sysname $kernel on $machine}${color}
	${hr}
	${font FontAwesome}?${font} IP address:
        ${goto 20}${addrs eth0}
	${goto 20}${upspeedgraph eth0 30,178 06E9F8 2104FA}${goto 202}${downspeedgraph eth0 30,175 FFFF00 DD3A21}
	${font FontAwesome}${goto 20}?${font} ${upspeed eth0}${font FontAwesome}${goto 202}?${font} ${downspeed eth0}

Con scroll è possibile far scorrere il testo (16 caratteri) delle variabili sysname, kernel e machine.
Il traffico di rete in entrata ed uscita si ottiene con le variabili:
upspeedgraph, downspeedgraph, upspeed e downspeed
“hr” indica una linea di separazione

Disk IO

	${hr}
	${font FontAwesome}?${font} DiskIO:
	${goto 20}${diskiograph_read 30,178 06E9F8 2104FA}${goto 202}${diskiograph_write 30,175 FFFF00 DD3A21}
	${font FontAwesome}${goto 20}?${font} ${diskio_read}${font FontAwesome}${goto 202}?${font} ${diskio_write}

Il traffico di dati sull’HDD in lettura e scrittura si ottiene con le variabili:
diskiograph_read, diskiograph_write, diskio_read e diskio_write

Memory usage

	${hr}
	${font FontAwesome}?${font} Memory usage: 
        ${goto 20}${mem}/${memmax} (${memperc}%) | Swap: ${swapperc}%
	${goto 20}${memgraph 30,355 AAF5D0 00B35B}

“mem” indica la memoria utilizzata
“memmax” indica la memoria totale disponibile
“memperc” indica il rapporto tra le due
“swapperc” indica la percentuale di swap utilizzata


File Systems

	${hr}
	${color1}File systems:
	${color1}sda: /home${goto 125}${color}${fs_used /home}/${fs_size /home} ${fs_used_perc /home}% ${color1}					
	${color1}sda: /${goto 125}${color}${fs_used /}/${fs_size /} ${fs_used_perc /}% ${color1}								
        ${color1}sdb: /home${goto 125}${color}${fs_used /home/banco/mediaHD/}/${fs_size /home/banco/mediaHD/} ${fs_used_perc /home/banco/mediaHD/}% ${color1}							

“fs_used” indica la quantità di spazio utilizzato
“fs_size” indica la quantità di spazio totale disponibile
“fs_used_perc” indica la quantità di spazio disponibile occupata

Temperatures

	${hr}
	${color1}Temperatures in Celsius:
	${color1}sda			${alignr}	${color} ${execi 10 hddtemp /dev/sda | cut -c32-36}
	${color1}sdb			${alignr}	${color} ${execi 10 hddtemp /dev/sdb | cut -c31-36}
	${color1}Core0 			${alignr}${color} ${execi 60 sensors | grep "Core 0" | cut -c16-22}
	${color1}Core1 			${alignr}${color} ${execi 60 sensors | grep "Core 1" | cut -c16-22}
	${color1}GPU 			${alignr}	${color} ${execi 60 nvidia-settings -query [gpu:0]/GPUCoreTemp -t}°C
	${hr}

execi esegue il comando “command” ogni “num” secondi.
Nel caso specifico viene eseguito

hddtemp /dev/sda | cut -c32-36

ecco il perchè dell’assegnare il bit SUID ad hddtemp, che altrimenti, senza sudo non ritornerebbe nessun output. Dalla stringa in output di hddtem si estrapolano i gradi tramite cut.
Nel mio caso, avendo 2 HDD, si esegue la stessa cosa, sia per sda che sdb.
Per i processori si utilizza invece sensors.

	${color1}Core0 			${alignr}${color} ${execi 60 sensors | grep "Core 0" | cut -c16-22}
	${color1}Core1 			${alignr}${color} ${execi 60 sensors | grep "Core 1" | cut -c16-22}

Il discorso GPU invece dipende dai driver utilizzati.
Nel mio caso, avendo installato i driver NVIDIA proprietari, è necessario utilizzare il tool nvidia-settings con:

	${color1}GPU 			${alignr}	${color} ${execi 60 nvidia-settings -query [gpu:0]/GPUCoreTemp -t}°C

Con i driver open invece, è sempre possibile estrapolare i dati con sensors.
sensors può essere eseguito da terminale per visualizzare parecchie informazioni

	${color1}GPU 			${alignr}	${color} ${execi 60 nvidia-settings -query [gpu:0]/GPUCoreTemp -t}°C

La temperatura inerente la GPU, dovrebbe essere qualcosa simile a “temp1”, in questo caso:

sensors | grep "temp"

Nel mio caso l’output sarebbe di più righe e quindi ci si potrebbe avvalere di cut e awk.
Con awk selezionerei solo la seconda riga, poi filtrerei solo i caratteri indicanti la temperatura:

sensors | grep "temp1" | awk 'FNR == 2 {print}' | cut -c16-19}°C

Cpus

	${hr}
	${goto 20}CPU0: ${cpu cpu0}%${goto 100}${cpubar 7,80 cpu0}
	${goto 20}CPU1: ${cpu cpu1}%${goto 100}${cpubar 7,80 cpu1}
	${hr}
	${color #FFFF00}${goto 20}Name ${goto 200}Pid${goto 255}Cpu%${goto 310}Mem%${color}
	${goto 20}${top name 1} ${goto 180}${top pid 1}${goto 235}${top cpu 1}${goto 290}${top mem 1}
	${goto 20}${top name 2} ${goto 180}${top pid 2}${goto 235}${top cpu 2}${goto 290}${top mem 2}
	${goto 20}${top name 3} ${goto 180}${top pid 3}${goto 235}${top cpu 3}${goto 290}${top mem 3}
	${goto 20}${top name 4} ${goto 180}${top pid 4}${goto 235}${top cpu 4}${goto 290}${top mem 4}
	${goto 20}${top name 5} ${goto 180}${top pid 5}${goto 235}${top cpu 5}${goto 290}${top mem 5}

Qui vengono indicate le cpu e le barre grafiche (cpubar)
Infine con top vengon mostrati i 5 processi più esosi di risorse.

Inserire in avvio automatico il nostro script personalizzato.

Nel mio caso (xfce4) avviare Sessione e Avvio e nella sezione Avvio Automatico aggiungere
la voce conky, la descrizione del comando e il comando conky stesso:

Riavviando conky dovrebbe avviarsi in automatico secondo le nostre indicazioni.

Categorie:Conky, Xfce Tag: , ,

SublimeText2 e Virtual Environment

24 aprile 2018 Commenti chiusi

Stiamo utilizzando sublime text 2 per scrivere codice.
Il nostro complicatissimo codice è il seguente:

# example python 2

if __name__ == '__main__':
    print "Python 2 example"

Per eseguirlo accediamo al menu Tools -> Build-systems e scegliamo Python
Ora premendo CTRL-B o Tools -> Build il “programma” va in esecuzione.


SUpponiamo di voler utilizzare python 3; creiamo nella stessa directory un virtual environment (ad es. venv3) e modifichiamo il nostro codice in

# example python 3
class A:
	pass

if __name__ == '__main__':
    a = A()
    print("Python 3:", a.__mro__)

Lo eseguiamo e come è giusto che sia, riceviasmo un errore inquanto Sublime Text continua ad utilizzare il suo interprete Python, selezionato in precedenza dal menu Tools -> Build-systems.

Per poter utilizzare un virtual environments è necessario salvare il progetto con nome .
Nel caso specifico, il virtualenv è stato creato nella stessa directory del progetto.
Successivamente editiamo il file .sublime-project generato in automatico da Sublime Text ed inseriamo il seguente contenuto:

{
    "folders":
    [
        {
            "path": ".",
            "file_exclude_patterns": ["*.pyc"]
        }
    ],

    "build_systems":
    [
        {
            "name":"Virtualenv 3.6",
            "working_dir": "${project_path:${folder}}/",
            "cmd":
            [
                "${project_path}/<nome_mio_venv>/Scripts/activate"
            ],
            
            "cmd":
            [
                "${project_path}/<nome_mio_venv>/Scripts/pythonw",
                "$file"
            ]
        }
    ]
}

la chiave “folders” contiene la path del mio progetto ed è possibile scriverla come path assoluta, nella forma “/C/PATH_TO_PROJECT”

la chiave “build_systems” contiene una lista di dizionari.
Ogni dizionario rappresenta il build-system che potremo selezionare dal menu tools > Build-Systems
Nel nostro caso le chiavi fondamentali del dizionario sono:
“name”: il nome che apparirà nel menu Tools > Build-systems.
“working_dir”: la directory dove stiamo lavorando
“cmd”: il comando che viene eseguito.

L’ordine dei comandi cmd è importante, nel nostro caso attiviamo il virtual environment e poi, apriamo il file con l’eseguibile python desiderato (python o pythonw).

Fatto questo, selezioniamo l’interprete desiderato dal solito menu
Tools -> Build-systems, nel nostro caso
“Virtualenv 3.6” ed eseguiamo il codice con CTRL-B (o Tools -> Build).

Categorie:python Tag: ,

Django: favicon

13 aprile 2018 Commenti chiusi

Django favicon

Scaricare l’immagine django desiderata ad es.

e ridimensionarla a 16×16, rinominandola favicon.ico.
Posizionarla nella directory /static/ della propria app.

/path_to_django_site/app_name/static/favicon.ico

Nella template base.html, dalla quale ereditiamo tutte le altre, inserire nel tag il link alla favicon:

{% load staticfiles %}
...

{% block head %}
   ...
  <link rel="shortcut icon" href="{%  static 'favicon.ico' %}">
{% endblock %}

Ricordarsi assolutamente di caricare gli staticfiles come indicato con:

{% load staticfiles %}

Assicurarsi che nel file settings.py del sito sia definita la costante STATIC_URL:

STATIC_URL = '/static/'

Avviato il server, la favicon dovrebbe essere correttamente caricata e visualizzata senza così incorrere nell’errore

[...] "GET /favicon.ico HTTP/1.1" 404 -

Categorie:Django, python Tag: ,

pyodbc: Access primi passi

11 aprile 2018 Commenti chiusi

Installare pyodbc:

pip install pyodbc

Creare un database access

Ci serviremo di un utilissimo modulo chiamato msaccessdb l’utilizzo è molto semplice, importiamo per prima cosa il modulo msaccessdb:

>>> import msaccessdb

creaiamo un database:

>>> db_file = r'path_to_db\test.accdb'
>>> msaccessdb.create(db_file)

Il database è stato creato. Ora con pyodbc vediamo alcuni tra i comandi più comuni.

Creare una tabella su database access

Per prima cosa stabiliamo una connessione al database e creiamo il cursore che ci permetterà di lavorare con il database stesso:

>>> import pyodbc
>>> driver = r'DRIVER={Microsoft Access Driver (*.mdb, *.accdb)};DBQ=%s;'
>>> conn = pyodbc.connect(driver % db_file)
>>> cur = conn.cursor()
>>>

In questo momento siamo connessi al database e tramite cursor possiamo creare la tabella di prova “persone” con i campi “nome”, “cognome”, “anni”.

>>> sql = "CREATE TABLE persone(nome varchar(16), cognome varchar(32), anni integer)"
>>> cur.execute(sql)
<pyodbc.Cursor object at 0x02091D20>
>>> conn.commit()
>>>

controlliamo che la tabella sia stata creata e qui ci viene utile l’oggetto pyodbc.Cursor con i suoi metodi.
Per controllare le tabelle:

>>> for row in cur.tables():
...     print(row.table_name)
...
MSysACEs
MSysComplexColumns
MSysObjects
MSysQueries
MSysRelationships
persone
>>>

Per controllare le colonne:

>>> for row in cur.columns():
...     print(row.column_name)
...
nome
cognome
anni

Inserimento dati su database access

Ovviamente finchè la connessione al database è attiva, possiamo continuare con il cursore ad effettuare operazioni sul database. Inseriamo alcuni dati…

>>> sql = "INSERT INTO persone(nome, cognome, anni) VALUES ('Giuseppe', 'Rossi', 40)"
>>> cur.execute(sql)
<pyodbc.Cursor object at 0x02091D20>
>>> conn.commit()

vediamo se i dati sono stati inseriti:

>>> sql = "SELECT * FROM persone WHERE cognome LIKE '%{}%'".format('Rossi')
>>> cur.execute(sql)
<pyodbc.Cursor object at 0x02091D20>

l’oggetto cursore, tramite “description” ci rende disponibile la struttura dei dati trovati:

>>> cur.description
(('nome', <class 'str'>, None, 16, 16, 0, True), ('cognome', <class 'str'>, None, 32, 32, 0, True), ('anni', <class 

'int'>, None, 10, 10, 0, True))
>>>

con il metodo fetchone() dell’oggetto cursore, otteniamo la prima riga del queryset precedentemente creato:

>>> row = cur.fetchone()
>>> row
('Giuseppe', 'Rossi', 40)
>>> type(row)
<class 'pyodbc.Row'>

a differenza del metodo fetchall() che rende disponibili tutte le righe del query set.

>>> sql = "SELECT * FROM persone WHERE cognome LIKE '%{}%'".format('Rossi')
>>> cur.execute(sql)
<pyodbc.Cursor object at 0x02091D20>
>>> rows = cur.fetchall()
>>> for row in rows:
...     print(row.nome, row.cognome, row.anni)
...
Giuseppe Rossi 40
Franco Rossi 25

l’oggetto pyodbc.Row è simile ad una tupla ed è comodo poichè è possibile accedere ai dati mediante il nome della colonna:

>>> row
('Franco', 'Rossi', 25)
>>> row.nome
'Franco'

Eliminazione dati su database access

Per l’eliminazione di una riga dal database, il procedimento è simile a quelli visti fino ad ora:

>>> sql = "DELETE FROM persone WHERE nome LIKE '%{}%' AND cognome LIKE '%{}%'".format('Franco', 'Rossi')
>>> cur.execute(sql)
<pyodbc.Cursor object at 0x02091D20>
>>> conn.commit()
>>> sql = "SELECT * FROM persone WHERE cognome LIKE '%{}%'".format('Rossi')
>>> cur.execute(sql)
<pyodbc.Cursor object at 0x02091D20>
>>> rows = cur.fetchall()
>>> rows
[('Giuseppe', 'Rossi', 40)]
>>>

la riga precedente è stata correttamente eliminata.

Aggiornare dati su database access

>>> sql = "UPDATE persone SET nome='%s', anni='%s' WHERE cognome='%s'" % ('Giovanni', 18, 'Rossi')
>>> cur.execute(sql)
<pyodbc.Cursor object at 0x02091D20>
>>> conn.commit()
>>> sql = "SELECT * FROM persone WHERE cognome LIKE '%{}%'".format('Rossi')
>>> cur.execute(sql)
<pyodbc.Cursor object at 0x02091D20>
>>> row = cur.fetchone()
>>> row
('Giovanni', 'Rossi', 18)

Questi sono solo alcuni dei comandi più semplici per giocare con un database Access,
per andare nello specifico consultare il sito del progetto pyodbc.

Categorie:python Tag: ,

wxpython: statusbar + gauge

22 novembre 2017 Commenti chiusi
import wx
import time


class View(wx.Frame):
    def __init__(self, parent):
        self.parent = parent
        super(View, self).__init__(parent=self.parent)
        self.panel = wx.Panel(parent=self)
        self.SetSize((350, 100))
        self.status_bar = self.CreateStatusBar(2)
        self.status_bar.SetStatusText('0/0')
        self.status_bar.SetStatusWidths([100, -1])
        gauge_pos, gauge_size = self.get_gauge_dimensions()
        self.gauge = wx.Gauge (self.status_bar, -1, 100, gauge_pos, gauge_size)
        # bindings
        self.Bind(wx.EVT_SIZE, self.on_size)
        self.Show()

    def get_gauge_dimensions(self):
        """Get gauge position and dimensions"""
        pos_x, pos_y, dim_x, dim_y = self.status_bar.GetFieldRect(1)
        return (pos_x, pos_y), (dim_x, dim_y)
       
    def on_quit(self, event):
        self.Destroy()

    def on_size(self, event):
        """Resize gauge when the main frame is resized"""
        size = self.GetSize()
        self.SetSize(size)
        gauge_pos, gauge_size = self.get_gauge_dimensions()
        self.gauge.SetSize(gauge_size)
        event.Skip ()       
        self.Update()

    def set_range(self, value):
        """Set the range of gauge"""
        self.gauge.SetRange(value)

    def get_range(self):
        """Get the range of gauge"""
        return self.gauge.GetRange()

    def set_progress(self, value):
        """Set the indicator gauges progress"""
        self.gauge.SetValue(value)

    def set_status_text(self, value):
        """Set the indicator text gauges progress"""
        self.status_bar.SetStatusText(value)


if __name__ == "__main__":
    app = wx.App(False)
    tot = 300  # maximum value for gauge
    v = View(parent=None)
    v.set_range(tot)
    for n in range(1, tot + 1):
        v.set_progress(n)
        time.sleep(.001)
        v.set_status_text('%s/%s' % (n, tot))
    v.set_progress(0)
    app.MainLoop()

Categorie:python, wxPython Tag: ,

FantaStat 2.0

22 novembre 2017 Commenti chiusi

Introduzione

Fstat 2.0 è una semplice applicazione per visualizzare le statistiche
dei giocatori di fantacalcio.
La precedente versione serviva a visualizzare i file.txt veccio formato, quelli che indicavano anche i goal segnati, gli assist ecc.
I file più recenti indicano solo il fanta voto, voto senza bonus malus e la quotazione:

code|NAME|TEAM|fanta voto|voto|quotazione

Link utili

Il codice dell’applicazione è reperibile nel repo corrispondente di github.
I binari win con database players.db qui.
I file txt delle giornate di fantacampionato sono reperibili sul blog.

Moduli utilizzati
Python 2.7.8
grafica: wx 3.0.2.0
ORM: Django 1.10.1

L’utilizzo è molto semplice e di seguito viene descritto:

Creazione database

Qualora ci si dimenticasse di creare il database per primo, al lancio dell’applicazione si verrà avvisati da un messaggio.

Ogni baco segnalato sarà ben gradito.

Creare quindi il database con il seguente comando:

python manage.py makemigrations players

Le migrations iniziali dovrebbero già essere presenti nel repo di github, quindi potrebbero non risultare modifiche, procedere quindi con il secondo comando:

python manage.py migrate

Avviare Fstat2.0

Per avviare l’applicazione eseguire lo script main.py con il comando:

python main.py

Non avendo ancora importato nessun giocatore, verremo avvisati da un messaggio che è necessario importare il primo file:

Le prime giornata disputate sono già fornite con il repo in posizione players/days, oppure sono sempre reperibili qui.
Dal menu Import-> Import players importare il file desiderato, solitamente la giornata 1 (MCC1.txt)

Il file dei giocatori va importato solo la prima volta, dopodichè il menu non sarà più attivo.
Da qui in avanti si importeranno solo i file dei voti.
Il primo sarà nuovamente MCC1.txt. Dal menu Import -> Import Evaluations, procedere con l’importazione.

Finita un’importazione eseguire un refresh dall’apposito pulsante.
L’interfaccia si presenta come in figura:

I radio-buttons permettono di filtrare i giocatori per ruolo, mentre cliccando sulle colonne della lista,
l’ordinamento avverrà in base alla colonna cliccata. Ad esempio cliccando su real_team, i giocatori
saranno ordinati per ruolo e per squadra di appartenenza.

Cliccando invece sulla “riga” di un determinato giocatore, sarà possibile modificarlo.

Dal menu Player -> Summary si accede alla lista riassuntiva del giocatori, poichè la visualizzazione della schermata del frame principale, mostra le medie dei giocatori e non i valori iniziali.
Da qui cliccando sui giocatori si possono modificare come in precedenza.

Qualora nei file non risultasse un giocatore, sarà possibile crearlo dal menu Players -> New Player

Stesso discorso vale per le valutazioni; esiste un sommario accessibile dal menu Evaluations -> Summary

dove cliccando sulla riga di una valutazione, sarà possibile modificarla

Come per i giocatori, sarà possibile aggiungere una valutazione ad hoc, dal menu
Evaluations -> New Evaluation

Come ultima operazione, è possibile cancellare tutti i dati, dal menu Reset.

Pyinstaller: django stand alone application spec file

20 novembre 2017 Commenti chiusi

Relativamente ad applicazioni django stand-alone, descritte in questo articolo, qualora si dovessero creare i binari per windows con pyinstaller, è utile usare questo scheletro di file spec.

# -*- mode: python -*-

block_cipher = None


a = Analysis(['main.py'],
             pathex=['<path-of-application>'],
             hiddenimports=['htmlentitydefs',
                            'HTMLParser',
                            'Cookie',
			    'django.template.defaulttags',
			    'django.template.loader_tags',
                            'django.middleware.common',
                            'django.core.handlers.wsgi',
			    'settings'],
             hookspath=None,
             runtime_hooks=None,
             excludes=None,
             cipher=block_cipher)

pyz = PYZ(a.pure,cipher=block_cipher)

exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          name='fstat.exe',
          debug=False,
          strip=None,
          upx=True,
          console=True )

attenzione al pathex, la directory dove dovrà risiedere il binario risultante.

Negli hidden imports, come si nota, deve comparire anche il file settings.py, file descritto nell’articolo relativo alla struttura delle applicazioni django stand-alone.

La creazione del binario si eseguirà con il comando:

pyinstaller --onefile <my-app>.spec

Ubuntu minimal: errori .Xauthority parse_vt_settings

8 novembre 2017 Commenti chiusi

Installare ubuntu minimal come da guida

Al riavvio Loggarsi con il proprio utente

se siamo su virtualbox procedere con l’installazione dei pacchetti
virtualbox-guest-utils e virtualbox-guest-dkms:

sudo apt-get install virtualbox-guest-utils virtualbox-guest-dkms

e creare il file virtualbox.conf con i moduli da caricare all’avvio…

sudo nano /etc/modules-load.d/virtualbox.conf

…inserendo all’interno del file i moduli:

vboxguest
vboxsf
vboxvideo

ora installare xfce4 e lightdm:

sudo apt-get install xfce4 lightdm

Al termine dell’installazione, editare il file lightdm.conf:

sudo nano /etc/lightdm/lightdm.conf

inserendo/modificando le seguenti coppie chiave=valore:

[SeatDefaults]
allow-guest=false
autologin-user=<username>
user-session=xfce

La prima opzione non consente accesso ad utente ospite;
la seconda permette l’autologin (cancellare la coppia in caso si voglia accedere ogni volta inserendo le credenziali);
la terza non ha bisogno di commenti.

per le configurazioni di lightdm seguire
questa guida.

Riavviare:

sudo reboot

Se al riavvio lightdm non riesce ad avviare la sessione con
errore “Avvio sessione non riuscito”, potrebbero esserci più
cause.

Permessi file .Xauthority

il file .Xauthority risiede nella home directory di ogni user e memorizza le credenziali degli stessi users, in cookies utilizzati da xauth per l’identificazione delle sessioni di X. Quando viene avviata una sessione X il cookie viene usato per autenticare le connessioni ad un determinato display.
Se non si hanno i diritti di accesso a tale file, non è possibile avviare la sessione.

Assicurarsi quindi di avere i diritti sul file .Xauthority

ls -l .Xauthority

in caso i diritti fossero solo per root, modificarli riassegnadoli ad ‘username’:

sudo chown <username>:<username> -R /home/<username>/.Xauthority

E’ possibile anche eliminare lo stesso file, inquanto verrà ricreato al riavvio.

Riavviare. Se continua a presentarsi l’impossibilità del login:

Consultare il file log

E’ bene consultare il file /home/username/.local/share/xorg/Xorg.1.log
in modo da risalire agli errori. Solitamente vengono evidenziati anche quando si tenta di avviare la sessione da terminale con startxfce4, ma nel nostro caso abbiamo installato lightdm e potremmo essere bloccati nel DM con il messaggio “Avvio Sessione NON riuscito”.

Con la combinazione CTRL+ALT+F2 entriamo nella console virtuale ed effettuaiamo il login con il nostro utente.
Blocchiamo prima il servizio lightdm:

sudo service lightdm stop

visualizziamo il log suddetto:

cat /home/<username>/.local/share/xorg/Xorg.1.log

(EE) parse_vt_settings: Cannot open /dev/tty0 (Permission denied)

Alla presenza di questo errore dovrebbe essere risolutivo aggiungere al gruppo tty.
/dev/tty0 rappresenta il display corrente, se quindi il nostro utente non ha i diritti su questo dispositivo, non è possibile avviare la sessione.

sudo usermod -a -G tty <username>

(EE) parse_vt_settings: Cannot open /dev/tty0 (No such file or directory)

Altro errore ricorrente.
Il pacchetto xserver-xorg-legacy fornisce un wrapper per il server X, quando si hanno driver obsoleti e kernel diversi. Se non necessario, come nel mio caso, è bene disinstallarlo:

sudo apt-get remove xserver-xorg-legacy

Ovviamente il file Xwrapper deve rimanere quindi assicuriamoci che esista ed abbia la giusta configurazione

sudo nano /etc/X11/Xwrapper.config

le coppie nome=valore sono:

allowed-users=anybody
needs-root-rights=yes

need-root-rights serve per assicurare che Xorg venga avviato con privilegi da amministratore da qualsiasi utente (il nostro caso).

riavviare con

sudo reboot

Al riavvio si dovrebbe riuscire ad effettuare il login.

Categorie:Linux, Ubuntu Tag: ,

scrapy: spider

12 ottobre 2017 Commenti chiusi

Articolo precedente: primi passi con scrapy

Spiders

Gli Spiders sono classi che definiscono come un sito o gruppi di siti, debbano essere analizzati.
In queste classi si decide come sarà il crawling/parsing del sito o dei gruppi di siti e come
saranno strutturati i dati estratti da tali pagine web.

Il progetto è stato già creato precedentemente, si tratta ora di creare lo spider adatto al nostro scopo.
Esiste un direttorio nome-progetto/nome-progetto//spiders all’interno del quale creeremo un file nome-progetto_spider.py nel mio caso, nel direttorio ansa/ansa/spiders, creerò un file ‘ansa_spider.py‘ con all’interno il codice necessario per lo scraping/crawling del sito in oggetto.

Vediamo il ciclo di funzionamento dello spider.

1. Requests iniziali

Generazione delle Requests iniziali per “raschiare” (crawl) le prime URLs e
specifica della funzione di callback da invocare con il Response ottenuto da queste prime Requests.
Le prime requests da eseguire sono ottenute con la chiamata del metodo start_requests()
che di default genera Request per le URLs specificate in una lista, chiamando per ognuna di esse
la corrispondente funzione di callback parse().

import scrapy


class AnsaSpider(scrapy.Spider):
    name = "ansa"
    allowed_domains = ["ansa.it"]

    def start_requests(self):
        urls = ["http://www.ansa.it",]
        for url in urls:
            yield scrapy.Request(url=url, callback=self.parse)

    def parse(self, response):
        pass

“name” è il nome univoco con il quale scrapy troverà ed utilizzerà lo spider.

“allowed_domains” è la lista dei domini autorizzati ad essere analizzati dallo spider.
Se il middleware OffsiteMiddleware sarà abilitato, i domini non presenti in questa lista,
non verranno analizzati dallo spider.

“start_requests” è il metodo che ritorna la lista con le prime Requests da analizzare. Viene invocato da Scrapy
quando apre lo spider per iniziare l’analisi.

Callback parse()

Nella funzione di callback parse(), eseguiamo appunto il parsing del response (web page) e ritorniamo:
– dizionario con i dati estratti
– Item object
– Request objects, o un iterable di tali oggetti

Con sintassi xpath, il primo abbozzo di spider sarebbe:

# ansa_spider.py
import scrapy


class AnsaSpider(scrapy.Spider):
    name = "ansa"
    allowed_domains = ["ansa.it"]

    def start_requests(self):
        start_urls = ["http://www.ansa.it",]
        for url in start_urls:
            yield scrapy.Request(url=url, callback=self.parse)

    def parse(self, response):
        xf = '//article[@class="news"]/descendant::a/@href'
        for url in response.xpath(xf).extract():
             yield {"title": url}

mentre la stessa con il metodo css():

# ansa_spider.py
import scrapy


class AnsaSpider(scrapy.Spider):
    name = "ansa"
    allowed_domains = ["ansa.it"]

    def start_requests(self):
        start_urls = ["http://www.ansa.it",]
        for url in start_urls:
            yield scrapy.Request(url=url, callback=self.parse)

    def parse(self, response):
        for url in response.css('article.news a::attr(href)').extract():
             yield {"title": url}

Lanciamo lo spider e viediamo che succede:

scrapy crawl ansa

come si nota, lo spider estrapola tutti i link presenti nella web page, ritornando un dizionario per ogni
link trovato. Se vogliamo generare un file con questi dati:

scrapy crawl ansa -o ansa.json

Nota:

Al momento scrapy esegue solo l’append dei dati e non sovrascrive il file, se già esistente.
Ricordarsi di eliminarlo prima di procedere con l’estrazione dei dati!

volendo estrarre i dati dal file, entriamo nella shell:

scrapy shell
import json


with open('ansa.json') as f:
    data = json.loads(f.read())

d = {n: v.get('link') for n, v in enumerate(data, 1) if v.get('link') != "javascript:void(0);"}

Tutte queste Requests potranno essere parsate e scaricate a loro volta da scrapy, facendo riferimento ad
una ulteriore callback (anche la stessa parse() volendo).

import scrapy


class AnsaSpider(scrapy.Spider):
    name = "ansa"
    allowed_domains = ["ansa.it"]

    def start_requests(self):
        start_urls = ["http://www.ansa.it",]
        for url in start_urls:
            yield scrapy.Request(url=url, callback=self.parse)

    def parse(self, response):
        xf = '//article[@class="news"]/descendant::a/@href'
        for url in response.xpath(xf).extract():
            if url and url != "javascript:void(0);":
                yield response.follow(url, callback=self.parse_news)

    def parse_news(self, response):
        title = response.xpath('//title/text()').extract_first()
        x_body = '//div[@class="news-txt"]/descendant::p'
        body = ' '.join(([node.xpath('string()').extract()[0]
                          for node in response.xpath(x_body)]))
        yield {'title': title,
               'body': body,
               }

Ora possiamo accedere ad un dizionario che al posto dei singoli link, ha i testi degli articoli.
Ma se volessimo portarci dietro dal primo parse, all’interno delle pagine figlie qualche attributo tipo ad es.
il link alla pagina figlia? Questo ha senso ovviamento per parametri che non sono reperibili nelle pagine figlie,
ma che debbano essere “trasportati” da un parse all’altro.

In questo caso ci vengono in aiuto gli items.

Dentro al file ansa/items.py definiamo il nostro personale Item:

import scrapy


class AnsaItem(scrapy.Item):
    # define the fields for your item here like:
    link = scrapy.Field()

Con l’ausilio di quest’ultimo, possiamo modificare il codice dello spider come segue:

import scrapy
from ansa.items import AnsaItem
from scrapy.exceptions import NotSupported


class AnsaSpider(scrapy.Spider):
    name = "ansa"
    allowed_domains = ["ansa.it"]

    def start_requests(self):
        start_urls = ["http://www.ansa.it",]
        for url in start_urls:
            print '[INFO] Parsing url %s...' % url
            yield scrapy.Request(url=url, callback=self.parse)

    def parse(self, response):
        xf = '//article[@class="news"]/descendant::a[position()=1]/@href'
        for url in response.xpath(xf).extract():
            if url and url != "javascript:void(0);":
                short_url = '/.../%s' % url.split('/')[-1]
                print '[INFO] Parsing urls %s = %s' % (n, short_url)
                ansa_item = AnsaItem()
                # ansa_item assignments
                ansa_item['link'] = url
                yield response.follow(url, callback=self.parse_news,
                                      meta={'ansa_item': ansa_item})

    def parse_news(self, response):
        ansa_item = response.meta.get('ansa_item')
        link = ansa_item.get('link')
        try:
            title = response.xpath('//title/text()').extract_first()
            x_body = '//div[@class="news-txt"]/descendant::p'
            body = ' '.join(([node.xpath('string()').extract()[0]
                              for node in response.xpath(x_body)]))
            yield {'link': link.strip(),
                   'title': title.strip(),
                   'body': body.strip(),
                  }
        except NotSupported:
            print "[WARNING] Response %s not crawled" % response

Nell’Item, gli assegnamenti agli attributi e l’accesso ad essi si comportano
allo stesso modo dei dizionari.
Come si vede, nella prima callback parse(), viene creato l’item e gli si assegna alla chiave ‘link’ il
valore di url. Quando utilizzeremo il metodo follow dell’oggetto response, per analizzare le sottopagine,
richiameremo la callback parse_news() e passeremo al metodo follow(),
l’attributo meta, un dizionario con all’interno il nostro item.
Questo item, viene recuperato all’interno della callback parse_news() ed il valore della sua
chiave ‘link’, ritornato nel dizionario con yield, insieme agli altri valori.

Eliminiamo un eventuale file json preesistente e ricreiamo il tutto:


>>> import json
>>> with open('ansa.json') as f:
...     data = json.loads(f.read())
...
>>> news_dict = {n: value for n, value in enumerate(data, 1)}
>>> news_1 = news_dict.get(1)
>>> news_1.get('title')
u"Ultimatum..."
>>> news_1.get('link')
u'/sito/notizie/mondo/europa/...'

link utili:
scrapy: appunti
scrapy
xpath: appunti

Categorie:python, scrapy, xpath Tag: , ,