Pillole di Python: la direttiva @property

Con la direttiva @property in Python è possibile pubblicare i getter e i setter per le proprietà della classe senza doverli invocare esplicitamente, bensì utilizzando la variabile stessa. Nell’ambito Python il nome di queste direttive è decoratori. In realtà, come vedremo, si tratta solo di una pseudo variabile.

Esempio: una classe che prende un valore di temperatura intesa in gradi Celsius e lo trasforma in Fahrenheit:

class Celsius:
    def __init__(self, temperature = 0):
        self.temperature = temperature

    def to_fahrenheit(self):
        return (self.temperature * 1.8) + 32

Se utilizziamo questa classe otteniamo:

>>> from celsius0 import Celsius
>>> c=Celsius(10)
>>> c.temperature
10
>>>

Ora rilasciamo la versione nel nostro software. Subito dopo ci vengono a dire che il modulo accetta temperature sotto lo 0 assoluto (e questo è francamente imbarazzante), per cui rilasciamo subito questa patch che utilizza una proprietà privata (quella contrassegnata col prefisso _) e i get/setters per consentire il controllo del valore di ingresso:

class Celsius:
    def __init__(self, temperature = 0):
        self.set_temperature(temperature)

    def to_fahrenheit(self):
        return (self.get_temperature() * 1.8) + 32

    # getter & setters
    def get_temperature(self):
        return self._temperature

    def set_temperature(self, value):
        if value < -273:
            raise ValueError("Temperature sotto -273 non sono ammesse")
        self._temperature = value

Ora però il nostro codice non è più retro compatibile e se qualcuno per caso ha usato la nostra classe, quando userà una istruzione del tipo

>>> from celsius import Celsius
>>> c = Celsius(100)
>>> c.temperature

Traceback (most recent call last):
File "", line 1, in
AttributeError: 'Celsius' object has no attribute 'temperature'

Ohi ohi. In effetti adesso per permettere il controllo abbiamo trasferito il valore alla variabile privata _temperature, perdendo per strada la variabile temperature. Ma Python ci permette di risolvere il problema dichiarando una pseudo-proprietà temperature che sostituisce i getter e i setter e fa in modo che dall’esterno si osservi effettivamente una proprietà (nel senso della variabile della classe) che si chiama nel vecchio modo, ossia della prima versione dl software (temperature); questo senza rinunciare alla proprietà privata che ci consente il controllo che il valore non sia sotto lo zero assoluto. Per questa ultima versione utilizziamo anche un file di constanti fisiche per portare il software al miglior grado di modularità:

# celsius.py
# A silly class to show the @property decorator
# allowing to implicitly define get/setters
#
############################################################
# Celsius object
############################################################

import constants
K0 = constants.KELVIN0

class Celsius:
    def __init__(self, temperature = 0):
        try:
             if temperature < K0:
                 raise ValueError
             self._temperature = temperature
        except ValueError:
           print("Temperature sotto " + str(K0) + " non permesse")

    def to_fahrenheit(self):
        return (self.temperature * 1.8) + 32

    @property
    def temperature(self):
        print("Acquisizione valore")
        return self._temperature

    @temperature.setter
    def temperature(self, value):
        try:
             if value < K0:
                 raise ValueError
             self._temperature = value
        except ValueError:
           print("Temperature sotto " + str(K0) + " non permesse")

Qualche commento:

  • Per evitare fastidiosi messaggi di traceback del runtime environment di Python utilizziamo il costrutto try/except che ci consente una più robusta gestione delle eccezioni
  • utilizziamo le costanti importate dal file constants.py in cui ho definito una serie di costanti fisiche
  • definiamo la sezione @property che ci consente di invocare il getter semplicemente utilizzando la pseudo variabile
  • definiamo la sezione @temperature.setter che ci consente di sostituire il setter

Proviamo la nuova versione del nostro software

marcob@jsbach:python$ python3
Python 3.5.2 (default, Nov 12 2018, 13:43:14)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from celsius import Celsius
>>> c=Celsius(-2000)
Temperature sotto -273.15 non permesse
>>> c=Celsius(-20)
>>> c.temperature <-- getter!
Acquisizione valore
-20
>>> c.temperature = 130 <-- setter!
>>> c.temperature
Acquisizione valore
130

Quindi @property è un modo di sostituire getter e setter in modo tale da utilizzare nominalmente la stessa variabile come se fosse una vera proprietà della classe (in effetti non esiste, esiste soltanto l’attributo privato _temperature).

Possiamo anche trovare l’utilizzo del decoratore @property sbirciando nel codice eht-imaging, il software Python scritto per ricostruire l’immagine del buco nero nell’ambito della collaborazione Event Horizon Telescope

Ad esempio nel file movie.py c’è la dichiarazione di questa proprietà frames:

    @property
    def frames(self):
        frames = self._movdict[self.pol_prim]
        return frames

    @frames.setter
    def frames(self, frames):
        if len(frames[0]) != self.xdim*self.ydim:
            raise Exception("imvec size is not consistent with xdim*ydim!")
        #TODO -- more checks on consistency with the existing pol data???

        self._movdict[self.pol_prim] =  frames

Il getter: quando viene menzionata la pseudo variabile frames, ritorna l’attributo privato dell’oggetto self._movdict[self.pol_prim].

Il setter: dopo un controllo di consistenza, valorizza l’attributo self._movdict[self.pol_prim] con il valore assegnato alla pseudo variabile frames.

Il primo buco nero osservato direttamente

Event Horizon Telescope puntato verso M87

Gli scienziati hanno ottenuto la prima immagine di un buco nero, utilizzando le osservazioni della rete di telescopi Event Horizon (EHT) puntato verso il centro della galassia M87, distante 55 milioni di anni luce, nel cluster galattico in corrispondenza alla costellazione della Vergine. L’immagine mostra un anello luminoso formato dalla luce che proviene da dietro poiché si incurva per l’intensa gravità chhe si manifesta attorno al buco nero che ha una massa 6,5 miliardi di volte quella del Sole. Questa immagine tanto attesa fornisce la più forte evidenza ad oggi dell’esistenza di buchi neri super massicci e apre una finestra sullo studio degli stessi buchi neri, sul loro orizzonte degli eventi e sulla gravità.

https://eventhorizontelescope.org/

Allestire un db di test con Laravel

Una delle (molte) pregevoli caratteristiche di Laravel è la possibilità di allestire un database alimentandolo con dati di test (fake) che in Laravel è facilissima grazie ad una classe Faker scritta da François Zaninotto.

Dopo aver creato il file per la migrazione di una tabella Articles, Artisan ci mette a disposizione la funzionalità seeder cioè alimentatore:

$ php artisan make:seeder ArticlesTableSeeder

Questo comando costruisce la classe che servirà ad alimentare la tabella: sotto la directory /database/seeds troviamo la nuova classe dell’alimentatore del db:

use Illuminate\Database\Seeder; 
use App\Article; 

class ArticlesTableSeeder extends Seeder {
      /**
       * Run the database seeds.
       *
       * @return void
       */

      public function run()
      {
          Article::truncate();
          $faker = \Faker\Factory::create();
          // And now, let's create a few articles in our database:
          for ($i = 0; $i < 50; $i++) {
              Article::create([
                  'title' => $faker->sentence,
                  'body' => $faker->paragraph,
              ]);
          }
      } 
}

quindi facciamo girare Faker che alimenta con dati più o meno casuali la tabella

$ php artisan db:seed --class=ArticlesTableSeeder

Possiamo automatizzare il tutto al momento della creazione del database inserendo la chiamata ai metodi in fase di migrazione:

class DatabaseSeeder extends Seeder {
      public function run()
      {
          $this->call(ArticlesTableSeeder::class);
          $this->call(UsersTableSeeder::class);
           ...
      }
 }

Non resta che lanciare il comando

$ php artisan db:seed

Attributi HTML personalizzati

Boost your web application

HTML è un linguaggio di mark-up in cui sono stati definiti molti tag per conferire una semantica al testo. Quindi ci sono i marcatori di titolo h1, …, h6 per definire la gerarchia delle titolazioni nelle sezioni del documento, come i tag per le liste, i paragrafi, le immagini e così via.

Ogni marcatore (tag) è corredato di una serie di attributi standard che vengono utilizzati sia da browser che dai programmi Javascript per interagire con il DOM (Document Object Model).

Nulla vieta però all’occorrenza di definire degli attributi personalizzati (custom) se l’applicazione ne ha bisogno. Il browser ignorerà tali attributi per quanto riguarda la visualizzazione ma li metterà comunque a disposizione nel DOM per poter essere utilizzati dai programmi Javascript. Come esempio di un caso d’uso possiamo aver bisogno di identificare l’icona di un utente del social network che stiamo sviluppando etichettandolo con l’id univoco che rappresenta l’utente nello spazio dati:

<img src="images/placeholder-small.jpg" userid="8zn4938d9z3" ...>

userid non è un attributo standard; nella visualizzazione il browser non lo prederà in considerazione, però potremo accedervi con Javascript:

<script>
console.log(img.getAttribute('userid'));
</script>

Potrebbe esserci un problema di conflitto di nomi, se abbiamo definito un nome attributo che viene utilizzato in modo diverso da più librerie Javascript entrambe agenti sulla stessa pagina HTML.

HTML5 [1] da’ la possibilità di definire una convenzione per cui se i nomi degli attributi personalizzati iniziano con data-

<img src="images/placeholder-small.jpg" data-userid="8zn4938d9z3" ...>

allora i valori sono reperibili direttamente con un accesso all’oggetto img.dataset

console.log(img.dataset.userid);

Oppure con AngularJS è possibile la stessa cosa utilizzando il prefisso ng-* (le cosiddette direttive con le quali AngularJS estende gli attributi HTML):

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.8/angular.min.js"></script>
<img ng-userid="8zn4938d9z3">

Un esempio più illuminante è il seguente in AngularJS nel quale definisco una direttiva completamente custom:

<div ng-app="coolApp" pippo-directive>

<script>

var app = angular.module("coolApp", []);
app.directive("pippoDirective", function() {
return {
template : "Testo definito nel callback del costruttore della direttiva!"
};
});
</script>

Il tag coolApp (che definisce l’app AngularJS) ha una direttiva completamente custom pippo-directive che viene agganciata da Javascript tramite la directive app.directive, il cui nome è la versione camel-case del nome dell’attibuto HTML.

Fonti

[1] https://www.w3.org/TR/2011/WD-html5-20110525/elements.html#embedding-custom-non-visible-data-with-the-data-attributes

[2] https://code-maven.com/custom-html-attributes

30° anniversario del WWW

Il 12 marzo 2019, l’evento Web@30 del CERN ha dato il via alle celebrazioni in tutto il mondo. Sir Tim Berners.Lee, Robet Caillau e altri pionieri ed esperti del Web hanno condiviso la loro visione sulle sfide e le opportunità portate dal Web. L’evento è stato aperto dal Direttore Generale del CERN Fabiola Gianotti ed è stato organizzato dal CERN in collaborazione con le due organizzazioni fondate da Berners-Lee: la World World Wide Web Foundation e il World Wide Web Consortium (W3C).

[Fonte: CERN]

Problema con apt-get install per OracleVM Virtualbox

Utilizzo di tanto nj tanto un virtualizzatore per poter operare su sistemi Windows. Il software originariamente sviluppato da Sun Microsystem è ormai da anni passato sotto Oracle e fornisce delle macchine virtuali sulle quali si installa una versione di Windows (io attualmente utilizzo una Windows 7 da 64 bit).

Il problema è sorto quando al normale avvio OracleVM Virtualbox, il software mi ha avvisato del rilascio della versione 5.2.22. Lo stesso avviso mi compariva nel gestore pacchetti (Aggiornamenti Software) di Ubuntu. Ho provato prima ad installare la nuova versione dal package manager e ho ottenuto un problema “Software da sorgenti non fidate”. Problema analogo se scaricavo ed eseguivo da solo il .deb.

Il problema è dovuto al cambio della chiave crittografica per collegarsi al repository della Oracle (virtualbox.org che non è tra i repository ufficiali fidati di Ubuntu). Per scaricare la nuova chiave:

wget -q http://download.virtualbox.org/virtualbox/debian/oracle_vbox.asc -O- | sudo apt-key add -

La chiave viene aggiunta al repository delle chiavi crittografiche: ripetendo l’installazione da “Aggiornamenti software” la nuova versione di OracleVM Virtualbox viene finalmente installata.

Il comando apt-key è usato per gestire la lista delle chiavi usate da apt (Advanced Package Tool, il gestore pacchetti delle distribuzioni Debian e derivate) per autenticare i pacchetti. I pacchetti che sono stati autenticati usando queste chiavi vengono considerati fidati.

Pillole Oracle: due utilità di SqlDeveloper

Vuoi salvarti delle istruzioni SQL che usi spesso in un insieme di segnalibri?

Strumenti –> Preferenze –> Database –> Modelli di codice editor SQL
Finestra di gestione dei template SQL

Per richiamare la query, digita la scorciatoia, e l’editor ti proporrà la query completa in un balloon.

Vuoi invece trasformare una query già scritta in maiuscolo, minuscolo, o prima lettera maiuscola?

Ctrl+'

Premendo ripetutamente questa sequenza, l’editor ti ciclerà la query fra i tre tipi di scrittura

Pillole Android: come visualizzare in AndroidStudio un dispositivo collegato via USB al PC

  1. da dispositivo: Abilitare il debug USB  (Impostazioni > Opzioni Sviluppatore > Debug USB -> ON)
  2. da computer: da linea di comando digitare 
$ adb devices
List of devices attached
QLF7N16406002695        device

Quindi in basso a dx attivare la tab Device File Explorer come in figura

In alto a destra compare la tab del dispositivo con tutto il contenuto del file system:

Device FIle Explorer

Per installare adb

$ sudo apt-get install adb

Per installare Android Studio, seguire questo sito.

Pillole Laravel – localizzazione

Affinché le date e il tempo dell’applicazione Laravel siano sincronizzate con l’orologio del server occorre agire sui file di configurazione dell’applicazione. Ovviamente questo non è detto sia ciò che si desidera perché per esempio vogliamo che sia un jet lag tra il server e l’applicazione. In ogni caso, il file da modificare è uno soltanto: config/app,php:

    //'timezone' => 'UTC',
    'timezone' => 'Europe/Rome',

Io per esempio ho modificato sul fuso orario del server. That’s all folks!

Pillole Laravel – protezione contro attacchi XSS

Laravel consente di proteggere con semplicità le applicazioni dagli attacchi cross site (CSRF – Cross Site Request Forgery). I CSRF sono un tipo di sfruttamento malevolo dei programmi web in cui comandi non autorizzati vengono eseguiti al posto di un utente autenticato.

Attenzione: In particolare questi attacchi si possono verificare anche se non c’è alcuno strato di protezione con autenticazione tra il browser e il modulo HTML.

Laravel realizza nel modo che segue la protezione: esso genera automaticamente una stringa cosiddetta “gettone” (token) CFRS per ogni sessione attiva (quindi per ogni browser aperto sull’applicazione). Questo gettone viene usato per verificare che l’utente che ha fatto la richiesta sia lo stesso che ha acceduto all’inizio all’applicazione. Non serve che ci sia un’autenticazione, funziona anche per una sessione non autenticata in cui semplicemente il server invia un cookie di sessione al primo accesso anche senza necessariamente legarlo da un utente fisico nel database.

Ogni volta che si definisce una form HTML nell’applicazione, dovrebbe essere incluso un token CSFR in un campo nascosto (hidden) cosicché il middleware di protezione possa validare la richiesta. Per generarlo con Blade è facile: basta usare la direttiva @csrf per generare il campo:

<form method="POST" action="/profile">
    @csrf
    ...
</form>

Il metodo incluso nel gruppo middleware (si veda il metodo /app/Http/Middleware/VerifyCsfrToken.php) verificherà automaticamente che l’input proveniente dalla richiesta corrisponda al token salvato nella sessione.

Se non si agisce in questo modo, Laravel semplicemente blocca l’applicazione sollevando un errore HTTP 419: