Pagina Principale/Python

Page last edited 1 860 giorni 20 ore fa
Da wiki.betaingegneria.it.

Il linguaggio di programmazione che prefersico e che so usare meno

Tutorial vero[modifica]

Vedi quello di Van Rossum [in italiano].

Tutorial di legno[modifica]

Ora il mio

scrivere questo file myClass.py:

 class MyClass:
   """A simple example class"""
   i = 12345
   
   def __init__(self):
       self.data = []
       
   def f(self):
       return 'hello world'

Poi aprire un shell e invocare l'interprete python

  $ python
  Python 2.7.3 (default, Aug  1 2012, 05:14:39) 
  [GCC 4.6.3] on linux2
  Type "help", "copyright", "credits" or "license" for more information.
  >>> 

Ora importiamo la classe MyClass così:

  >>> from myClass import MyClass
  >>> 

Verifichiamo che sia stata caricata:

  >>> MyClass
  <class myClass.MyClass at 0x7fa841640120>

Se scrivo il nome del file anziché il nome della classe, non funzionerà:

  >>> myClass
  Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
  NameError: name 'myClass' is not defined

cosa c'è dentro la classe?

  >>> dir(MyClass)
  ['__doc__', '__init__', '__module__', 'f', 'i']

Inizializziamo un oggetto della classe MyClass:

  >>> x = MyClass()

e che cosa fa questa classe?

  >>> x.__doc__
  'A simple example class'

Adesso possiamo provare metodi e attributi

  >>> x.i
  12345
  >>> x.f()
  'hello world'
  >>> 

E' tutto per ora!

Esercizi per casa[modifica]

  • Costruire una classe che gestisce i numeri complessi
  • Costruire una classe che gestisce una rubrica telefonica (cablare pure i dati nel codice)

Numeri complessi[modifica]

Al primo tentativo questo è il costruttore (file Complessi.py)

 class Complessi:
   """Wrapper per numeri complessi: la classe Complex c'e' gie', ne faccio una di nuova 
   che utilizza quella esistente interponendosi (concetto di wrapping) """
   
   def __init__(self):
       self.__repr__ = self.partition('+')
       self.re = self.__repr__[0]
       self.im = self.__repr__[1]
       

provo la classe

  >>> from Complessi import Complessi
  >>> x=Complessi('1+2j')
  Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  TypeError: __init__() takes exactly 1 argument (2 given)
  >>> 

Uno sguardo alla guida di Van Rossum che ha guarda caso lo stesso esempio; riprovo così:

 class Complessi:
   """Wrapper per numeri complessi: la classe Complex c'e' gie', ne faccio una di nuova 
   che utilizza quella esistente interponendosi (concetto di wrapping) """
   
   def __init__(self, re, im):
       self.re = re
       self.im = im

la provo

  >>> x=Complessi(1,2)
  >>> x
  <Complessi.Complessi instance at 0x7f0b6797d050>
  >>> x.re
  1
  >>> x.im
  2
  >>>

l'output non è soddisfacente. Ulteriore metodo per stampare un numero complesso

   def view(self):
       if (self.im < 0):
           self.sign = '-j';
       else:
           self.sign = '+j';
       
       self.__out__ = str(self.re) + self.sign + str(abs(self.im))
       return self.__out__


Questo è il risultato:

  >>> x=Complessi(1,-2)
  >>> x.view()
  '1-j2'
Overloading degli operatori[modifica]

Ora mi sono sbizzarrito a creare nuovi metodi ed ho anche imparato a fare l' overloading degli operatori. Ciò significa che posso riutilizzare il + per fare la somma tra numeri complessi. Ad esempio ecco come realizzare l'overloading della somma:

   def __add__(self, a):
       re = self.re + a.re
       im = self.im + a.im
       return Complessi(re,im)

la parolina magica __add__ è quella che fa tutto. Il codice parla da se.

Osservazione importante[modifica]

Attenzione si potrebbe anche implementare la funzione così:

   def __add__(self, a):
       self.re = self.re + a.re
       self.im = self.im + a.im
       return self

In questo caso non c'è alcun errore di sintassi ma l'effetto è perverso: eseguendo l'istruzione

   w = x + y

il risultato sarà sì corretto ma avremo lo spiacevole effetto collaterale di alterare anche il valore della x che è il primo parametro!

Già che ci siamo eliminiamo il metodo customizzato view e facciamo l’overload della funzione __str__ che è quella che ci permette di stampare una variabile con l’istruzione print:

  def __str__(self): # personalizza la funzione print
       if (self.im < 0):
           self.sign = '-j';
       else:
           self.sign = '+j';
Testare il codice[modifica]

Ultima cosa: come fare il test degli scipt python? esiste lo Unit test e il Doc test. Prima quest'ultimo

Doctest[modifica]

Scrivo un file python in cui definisco una funzione e il suo test viene scritto nei commenti:

  #!/usr/bin/python
  """
      >>> print x # numero complesso 1-j2
      1-j2
      >>> x.reale()
      1
      >>> x.immaginario()
      -2
      >>> print y # numero complesso 1+j1
      1+j1
      >>> print w # somma
      2-j1
      >>> print v # prodotto
      3-j1
  
  """
  from Complessi import Complessi
  x = Complessi(1,-2)
  y = Complessi(1,1)
  w = x + y
  v = x * y
  
  if __name__ == "__main__":
      import doctest
      doctest.testmod()

Ecco qui eseguo le operazioni con gli oggetti della classe da testare e alla fine metto l'invocazione della classe doctest: in sostanza i test da fare li scrivo nel commento!!! Proviamolo, nella documentazione scrivo sia l'operazione da compiere sia il valore atteso:

  #!/usr/bin/python
  """
      >>> print x # numero complesso 1-j2   <--- qui metto il test da eseguire; la variabile è inizializzata nel codice vero
      1-j2                                  <--- qui metto il risultato che il software mi dovrebbe dare (lo calcolo a mano)
      >>> x.reale()
      1
      >>> x.immaginario()
      -2
      >>> print y # numero complesso 1+j1
      1+j1
      >>> print w # somma
      2-j1
      >>> print v # prodotto
      3-j1
  
  """
  from Complessi import Complessi
  x = Complessi(1,-2)
  y = Complessi(1,1)
  w = x + y
  v = x * y
  
  if __name__ == "__main__":
      import doctest
      doctest.testmod()

nota bene: mettendo in alto la dichiarazione dell'interprete #!/usr/bin/python, da linea di comando è sufficiente scrivere ./testdoc1.py -v (occorre anche dichiarare eseguibile il file per cui da shell Linux occorre prima lanciare il comando chmod a+x testdoc1.py Ecco l'esecuzione:

  $ ./testdoc1.py -v
  Trying:
      print x # numero complesso 1-j2
  Expecting:
      1-j2
  ok
  Trying:
      x.reale()
  Expecting:
      1
  ok
  Trying:
      x.immaginario()
  Expecting:
      -2
  ok
  Trying:
      print y # numero complesso 1+j1
  Expecting:
      1+j1
  ok
  Trying:
      print w # somma
  Expecting:
      2-j1
  ok
  Trying:
      print v # prodotto
  Expecting:
      3-j1
  ok
  1 items passed all tests:
     6 tests in __main__
  6 tests in 1 items.
  6 passed and 0 failed.
  Test passed.
  

Connettore Python per Mysql[modifica]

Scaricare il connettore da [Sito Mysql] Poi:

  $ gunzip mysql-connector-python-1.0.7.tar.gz
  $ tar xf mysql-connector-python-1.0.7.tar
  $ cd mysql-connector-python-1.0.7
  $ sudo python setup.py install
  running install
  running build
  running build_py
  creating build
  creating build/lib.linux-x86_64-2.7
  creating build/lib.linux-x86_64-2.7/mysql
  copying python2/mysql/__init__.py -> build/lib.linux-x86_64-2.7/mysql
  creating build/lib.linux-x86_64-2.7/mysql/connector
  copying python2/mysql/connector/constants.py -> build/lib.linux-x86_64-2.7/mysql/connector
  copying python2/mysql/connector/connection.py -> build/lib.linux-x86_64-2.7/mysql/connector
  copying python2/mysql/connector/protocol.py -> build/lib.linux-x86_64-2.7/mysql/connector
  copying python2/mysql/connector/cursor.py -> build/lib.linux-x86_64-2.7/mysql/connector
  copying python2/mysql/connector/network.py -> build/lib.linux-x86_64-2.7/mysql/connector
  copying python2/mysql/connector/conversion.py -> build/lib.linux-x86_64-2.7/mysql/connector
  copying python2/mysql/connector/errorcode.py -> build/lib.linux-x86_64-2.7/mysql/connector
  copying python2/mysql/connector/__init__.py -> build/lib.linux-x86_64-2.7/mysql/connector
  copying python2/mysql/connector/dbapi.py -> build/lib.linux-x86_64-2.7/mysql/connector
  copying python2/mysql/connector/errors.py -> build/lib.linux-x86_64-2.7/mysql/connector
  copying python2/mysql/connector/version.py -> build/lib.linux-x86_64-2.7/mysql/connector
  copying python2/mysql/connector/utils.py -> build/lib.linux-x86_64-2.7/mysql/connector
  creating build/lib.linux-x86_64-2.7/mysql/connector/locales
  copying python2/mysql/connector/locales/__init__.py -> build/lib.linux-x86_64-2.7/mysql/connector/locales
  creating build/lib.linux-x86_64-2.7/mysql/connector/locales/eng
  copying python2/mysql/connector/locales/eng/client_error.py -> build/lib.linux-x86_64-2.7/mysql/connector/locales/eng
  copying python2/mysql/connector/locales/eng/__init__.py -> build/lib.linux-x86_64-2.7/mysql/connector/locales/eng
  running install_lib
  creating /usr/local/lib/python2.7/dist-packages/mysql
  creating /usr/local/lib/python2.7/dist-packages/mysql/connector
  copying build/lib.linux-x86_64-2.7/mysql/connector/constants.py -> /usr/local/lib/python2.7/dist-packages/mysql/connector
  copying build/lib.linux-x86_64-2.7/mysql/connector/connection.py -> /usr/local/lib/python2.7/dist-packages/mysql/connector
  copying build/lib.linux-x86_64-2.7/mysql/connector/protocol.py -> /usr/local/lib/python2.7/dist-packages/mysql/connector
  copying build/lib.linux-x86_64-2.7/mysql/connector/cursor.py -> /usr/local/lib/python2.7/dist-packages/mysql/connector
  copying build/lib.linux-x86_64-2.7/mysql/connector/network.py -> /usr/local/lib/python2.7/dist-packages/mysql/connector
  copying build/lib.linux-x86_64-2.7/mysql/connector/conversion.py -> /usr/local/lib/python2.7/dist-packages/mysql/connector
  copying build/lib.linux-x86_64-2.7/mysql/connector/errorcode.py -> /usr/local/lib/python2.7/dist-packages/mysql/connector
  copying build/lib.linux-x86_64-2.7/mysql/connector/__init__.py -> /usr/local/lib/python2.7/dist-packages/mysql/connector
  copying build/lib.linux-x86_64-2.7/mysql/connector/dbapi.py -> /usr/local/lib/python2.7/dist-packages/mysql/connector
  copying build/lib.linux-x86_64-2.7/mysql/connector/errors.py -> /usr/local/lib/python2.7/dist-packages/mysql/connector
  copying build/lib.linux-x86_64-2.7/mysql/connector/version.py -> /usr/local/lib/python2.7/dist-packages/mysql/connector
  copying build/lib.linux-x86_64-2.7/mysql/connector/utils.py -> /usr/local/lib/python2.7/dist-packages/mysql/connector
  creating /usr/local/lib/python2.7/dist-packages/mysql/connector/locales
  creating /usr/local/lib/python2.7/dist-packages/mysql/connector/locales/eng
  copying build/lib.linux-x86_64-2.7/mysql/connector/locales/eng/client_error.py -> /usr/local/lib/python2.7/dist-packages/mysql/connector/locales/eng
  copying build/lib.linux-x86_64-2.7/mysql/connector/locales/eng/__init__.py -> /usr/local/lib/python2.7/dist-packages/mysql/connector/locales/eng
  copying build/lib.linux-x86_64-2.7/mysql/connector/locales/__init__.py -> /usr/local/lib/python2.7/dist-packages/mysql/connector/locales
  copying build/lib.linux-x86_64-2.7/mysql/__init__.py -> /usr/local/lib/python2.7/dist-packages/mysql
  byte-compiling /usr/local/lib/python2.7/dist-packages/mysql/connector/constants.py to constants.pyc
  byte-compiling /usr/local/lib/python2.7/dist-packages/mysql/connector/connection.py to connection.pyc
  byte-compiling /usr/local/lib/python2.7/dist-packages/mysql/connector/protocol.py to protocol.pyc
  byte-compiling /usr/local/lib/python2.7/dist-packages/mysql/connector/cursor.py to cursor.pyc
  byte-compiling /usr/local/lib/python2.7/dist-packages/mysql/connector/network.py to network.pyc
  byte-compiling /usr/local/lib/python2.7/dist-packages/mysql/connector/conversion.py to conversion.pyc
  byte-compiling /usr/local/lib/python2.7/dist-packages/mysql/connector/errorcode.py to errorcode.pyc
  byte-compiling /usr/local/lib/python2.7/dist-packages/mysql/connector/__init__.py to __init__.pyc
  byte-compiling /usr/local/lib/python2.7/dist-packages/mysql/connector/dbapi.py to dbapi.pyc
  byte-compiling /usr/local/lib/python2.7/dist-packages/mysql/connector/errors.py to errors.pyc
  byte-compiling /usr/local/lib/python2.7/dist-packages/mysql/connector/version.py to version.pyc
  byte-compiling /usr/local/lib/python2.7/dist-packages/mysql/connector/utils.py to utils.pyc
  byte-compiling /usr/local/lib/python2.7/dist-packages/mysql/connector/locales/eng/client_error.py to client_error.pyc
  byte-compiling /usr/local/lib/python2.7/dist-packages/mysql/connector/locales/eng/__init__.py to __init__.pyc
  byte-compiling /usr/local/lib/python2.7/dist-packages/mysql/connector/locales/__init__.py to __init__.pyc
  byte-compiling /usr/local/lib/python2.7/dist-packages/mysql/__init__.py to __init__.pyc
  running install_egg_info
  Writing /usr/local/lib/python2.7/dist-packages/mysql_connector_python-1.0.7.egg-info
  $ 

Scrivo un semplice porgramma ptyhon mysql.py con la sola riga:

  import mysql

Lo eseguo

  $ python mysql.py
  $

Nessun errore generato, posso dire che ha funzionato.

Webservice con ZSI[modifica]

Zolera Service Infrastructure. Ho bisogno di chiamare un servizio usando l'infrastruttura WSS

WSS Web Service Security[modifica]

Fonte

Metodo 2 - Probabilmente la strada da percorrere, molto più personalizzabile[modifica]

Possiamo usare metodi DOM per modificare l'intestazione SOAP e inviare esattamente quello che ci serve. L'esempio implementa la strategia UsernameToken ma ne possono essere attuate anche altre modificando le intestazioni in modo simile. L'attributo generato binding della classe Port ha un attributo sig_handler al quale può essere assegnata un'istanza di una classe personalizzata. In questa classe personalizzata, è necessario implementare due metodi, sign (firmare) e verify (verifica), che sono in grado, rispettivamente, di modificare l'intestazione e controllare la sua validità. Il metodo sign prende come argomento di input una SoapWriter che ci permette di modificare l'intestazione.

Quindi, senza ulteriori indugi, ecco la classe che aggiunge intestazioni WS-Security per la busta SOAP in uscita come discusso in precedenza. Il codice è stato formattato e modificato per adattarlo alla pagina.

  # gestione dell'header
  
  import sha
  import binascii
  import base64
  import time
  import random
  
  class SignatureHandler:
  
  	OASIS_PREFIX = "http://docs.oasis-open.org/wss/2004/01/" + "oasis-200401"
  	SEC_NS = OASIS_PREFIX + "-wss-wssecurity-secext-1.0.xsd"
  	UTIL_NS = OASIS_PREFIX + "-wss-wssecurity-utility-1.0.xsd"
  	PASSWORD_DIGEST_TYPE = OASIS_PREFIX + "-wss-username-token-profile-1.0#PasswordDigest"
  	PASSWORD_PLAIN_TYPE = OASIS_PREFIX + "-wss-username-token-profile-1.0#PasswordText"
  
  	def __init__(self, user, password, useDigest=False):
  		self._user = user
  		self._created = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime(time.time()))
  		self._nonce = sha.new(str(random.random())).digest()
  		if (useDigest):
  			self._passwordType = self.PASSWORD_DIGEST_TYPE
  			digest = sha.new(self._nonce + self._created + password).digest()
  
  			# binascii.b2a_base64 adds a newline at the end
  			self._password = binascii.b2a_base64(digest)[:-1]
  		else:
  			self._passwordType = self.PASSWORD_PLAIN_TYPE
  			self._password = password
  
  	def sign(self,soapWriter):
  		# create element
  		securityElem = soapWriter._header.createAppendElement("", "wsse:Security")
  		securityElem.node.setAttribute("xmlns:wsse", self.SEC_NS)
  		securityElem.node.setAttribute("SOAP-ENV:mustunderstand", "1")
  
  		# create element
  		usernameTokenElem = securityElem.createAppendElement("", "wsse:UsernameToken")
  		usernameTokenElem.node.setAttribute("xmlns:wsse", self.SEC_NS)
  		usernameTokenElem.node.setAttribute("xmlns:wsu", self.UTIL_NS)
  
  		# create element
  		usernameElem = usernameTokenElem.createAppendElement("", "wsse:Username")
  		usernameElem.node.setAttribute("xmlns:wsse", self.SEC_NS)
  
  		# create element
  		passwordElem = usernameTokenElem.createAppendElement("", "wsse:Password")
  		passwordElem.node.setAttribute("xmlns:wsse", self.SEC_NS)
  		passwordElem.node.setAttribute("Type", self._passwordType)
  
  		# create element
  		nonceElem = usernameTokenElem.createAppendElement("", "wsse:Nonce")
  		nonceElem.node.setAttribute("xmlns:wsse", self.SEC_NS)
  
  		# create element
  		createdElem = usernameTokenElem.createAppendElement("", "wsse:Created")
  		createdElem.node.setAttribute("xmlns:wsse", self.UTIL_NS)
  
  		# put values in elements
  		usernameElem.createAppendTextNode(self._user)
  		passwordElem.createAppendTextNode(self._password)
  		# binascii.b2a_base64 adds a newline at the end
  		nonceElem.createAppendTextNode(binascii.b2a_base64(self._nonce)[:-1])
  		createdElem.createAppendTextNode(self._created)
  
  	def verify(self,soapWriter):
  		self

Un esempio d'uso è questo:

  from SportsService_client import *
  from SportsService_types import *
  
  locator = SportsServiceLocator()
  port = locator.getSportsServiceHttpPort()
  sigHandler = SignatureHandler("user", "password", True)
  port.binding.sig_handler = sigHandler
  
  request = getMascotRequest()
  teamObj = ns0.Team_Def("Team")
  teamObj._name = "toronto"
  request._team = teamObj
  
  response = port.getMascot(request)
  print response._out._name

Come si può vedere, la classe SignatureHandler sta attuando una "interfaccia" che le permette di elaborare le richieste SOAP in uscita. Il metodo di verifica è vuoto, ma può contenere codice per controllare se l'intestazione SOAP è valida.

Se vuoi scrivere un client PHP che accede a un servizio WS-Security abilitato, vi consigliamo di leggere l'articolo IdentityBlog Kim Cameron, che ha collegamenti con il codice sorgente necessario. Se si desidera semplicemente utilizzare un client PHP per un servizio web senza WS-Security, questa voce ne parla.

WebService con Bottle[modifica]

Mi aggrappo a questo prodotto. Attenzione scarico subito, dopo qualche prova, PasteServer che rende Bottle multithread (altrimenti sarebbe inutilizzabile)

  $ hg clone http://bitbucket.org/ianb/paste
     il vero URL è https://bitbucket.org/ianb/paste
     directory di destinazione: paste
     sto richiedendo tutte le modifiche
     sto aggiungendo i changeset
     sto aggiungendo i manifesti
     sto aggiungendo le modifiche ai file
     aggiunti 1506 changeset con 3112 modifiche a 762 file
     sto aggiornando al branch default
     231 files updated, 0 files merged, 0 files removed, 0 files unresolved

poi

  $ mv paste paste1
  $ mv paste1/paste .
  $ python
  >>> import paste
  >>>

(nessun errore)

Per far partire bottle occorre scrivere il web service che importa bottle (e paste) e alla fine lancia run(). Con Paste il log del server è simile a quello di Apache

Bottle + mod_wsgi[modifica]

Voglio fare funzionare bottle con il tramite di Apache, come sarà in produzione. Bottle sarà visto come un CGI da Apache. Occorre installare mod_wsgi.

Problemi cominciano dal ./configure:

  marcob@jsbach:~/Scaricati/apache2/mod_wsgi-3.4$ ./configure 
  checking for apxs2... no
  checking for apxs... no
  checking Apache version... ./configure: line 1704: apxs: command not found
  ./configure: line 1704: apxs: command not found
  ./configure: line 1705: apxs: command not found
  ./configure: line 1708: /: Is a directory
  
  checking for python... /usr/bin/python
  ./configure: line 1877: apxs: command not found
  configure: creating ./config.status
  config.status: error: cannot find input file: Makefile.in
  

apxs è un tool per sviluppare con Apache con thread. Installiamolo

  $ sudo apt-get install apache2-threaded-dev
  marcob@jsbach:~/Scaricati/apache2/mod_wsgi-3.4$ ./configure 
  checking for apxs2... no
  checking for apxs... no
  checking Apache version... ./configure: line 1704: apxs: command not found
  ./configure: line 1704: apxs: command not found
  ./configure: line 1705: apxs: command not found
  ./configure: line 1708: /: Is a directory
  
  checking for python... /usr/bin/python
  ./configure: line 1877: apxs: command not found
  configure: creating ./config.status
  config.status: error: cannot find input file: Makefile.in
  ...
  Configurazione di apache2-threaded-dev (2.2.22-1ubuntu1)...
  Elaborazione dei trigger per libc-bin...
  ldconfig deferred processing now taking place
  $

Ora lancio la configurazione. apsx è installato sotto /usr/sbin/apsx2

  ./configure --with-apxs=/usr/bin/apxs2 \
    --with-python=/usr/bin/python

(basta fare which dei due comandi)

  $ ./configure --with-apxs=/usr/bin/apxs2     --with-python=/usr/bin/python
    checking Apache version... 2.2.22
    configure: creating ./config.status
    config.status: creating Makefile

NON FUNZIONA. apxs2 è possible installarlo in due versioni:

  • threaded
  • prefork

ho provato ora a fare make la prima e non va, vediamo la seconda. Riprovo il configure e non va ancora:

  $ make
  /usr/bin/apxs2 -c -I/usr/include/python2.7 -DNDEBUG   mod_wsgi.c -L/usr/lib -L/usr/lib/python2.7/config  
   -lpython2.7 -lpthread -ldl  -lutil -lm
  /usr/share/apr-1.0/build/libtool --silent --mode=compile --tag=disable-static x86_64-linux-gnu-gcc -prefer-pic -DLINUX=2 
   -D_FORTIFY_SOURCE=2 -D_GNU_SOURCE -D_REENTRANT -I/usr/include/apr-1.0 -I/usr/include/openssl -I/usr/include/xmltok -pthread     
   -I/usr/include/apache2  -I/usr/include/apr-1.0   -I/usr/include/apr-1.0  -I/usr/include/python2.7 
   -DNDEBUG  -c -o mod_wsgi.lo mod_wsgi.c && touch mod_wsgi.slo
  mod_wsgi.c:142:20: fatal error: Python.h: No such file or directory
  compilation terminated.
  apxs:Error: Command failed with rc=65536
  .
  make: *** [mod_wsgi.la] Errore 1

[[1]] dice che occorre installare anche il development pakcage di Python 2.7.

  $ sudo apt-get install python-all-dev
  [sudo] password for marcob: 
  Lettura elenco dei pacchetti... Fatto
  Generazione albero delle dipendenze       
  Lettura informazioni sullo stato... Fatto
  Il seguente pacchetto è stato installato automaticamente e non è più richiesto:
    libax25
  Usare "apt-get autoremove" per rimuoverli.
  I seguenti pacchetti saranno inoltre installati:
    python-all python-dev python2.7-dev
  I seguenti pacchetti NUOVI saranno installati:
    python-all python-all-dev python-dev python2.7-dev
  0 aggiornati, 4 installati, 0 da rimuovere e 25 non aggiornati.
  È necessario scaricare 29,5 MB di archivi.
  Dopo quest'operazione, verranno occupati 39,3 MB di spazio su disco.
  Continuare [S/n]? S


Stavolta va:

  $ ./configure --with-apxs=/usr/bin/apxs2     --with-python=/usr/bin/python
  checking Apache version... 2.2.22
  configure: creating ./config.status
  config.status: creating Makefile
  marcob@jsbach:~/Scaricati/apache2/mod_wsgi-3.4$ make
  /usr/bin/apxs2 -c -I/usr/include/python2.7 -DNDEBUG   mod_wsgi.c 
    -L/usr/lib -L/usr/lib/python2.7/config  -lpython2.7 -lpthread -ldl  -lutil -lm
  /usr/share/apr-1.0/build/libtool --silent --mode=compile --tag=disable-static x86_64-linux-gnu-gcc 
    -prefer-pic -DLINUX=2 -D_FORTIFY_SOURCE=2 -D_GNU_SOURCE -D_REENTRANT -I/usr/include/apr-1.0 -I/usr/include/openssl -I/usr/include/xmltok -pthread     
    -I/usr/include/apache2  -I/usr/include/apr-1.0   -I/usr/include/apr-1.0  -I/usr/include/python2.7 -DNDEBUG  
    -c -o mod_wsgi.lo mod_wsgi.c && touch mod_wsgi.slo
  In file included from /usr/include/python2.7/Python.h:8:0,
                   from mod_wsgi.c:142:
  /usr/include/python2.7/pyconfig.h:1161:0: warning: "_POSIX_C_SOURCE" redefined [enabled by default]
  /usr/include/features.h:164:0: note: this is the location of the previous definition
  /usr/include/python2.7/pyconfig.h:1183:0: warning: "_XOPEN_SOURCE" redefined [enabled by default]
  /usr/include/features.h:166:0: note: this is the location of the previous definition
  /usr/share/apr-1.0/build/libtool --silent --mode=link --tag=disable-static x86_64-linux-gnu-gcc -o mod_wsgi.la  
    -rpath /usr/lib/apache2/modules -module -avoid-version    mod_wsgi.lo -L/usr/lib -L/usr/lib/python2.7/config -lpython2.7 -lpthread -ldl -lutil -lm

e finalmente

  $ sudo make install
  [sudo] password for marcob: 
  /usr/bin/apxs2 -i -S LIBEXECDIR=/usr/lib/apache2/modules -n 'mod_wsgi' mod_wsgi.la
  /usr/share/apache2/build/instdso.sh SH_LIBTOOL='/usr/share/apr-1.0/build/libtool' mod_wsgi.la /usr/lib/apache2/modules
  /usr/share/apr-1.0/build/libtool --mode=install cp mod_wsgi.la /usr/lib/apache2/modules/
  libtool: install: cp .libs/mod_wsgi.so /usr/lib/apache2/modules/mod_wsgi.so
  libtool: install: cp .libs/mod_wsgi.lai /usr/lib/apache2/modules/mod_wsgi.la
  libtool: finish: PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/sbin" ldconfig -n /usr/lib/apache2/modules
  ----------------------------------------------------------------------
  Libraries have been installed in:
     /usr/lib/apache2/modules
  
  If you ever happen to want to link against installed libraries
  in a given directory, LIBDIR, you must either use libtool, and
  specify the full pathname of the library, or use the `-LLIBDIR'
  flag during linking and do at least one of the following:
     - add LIBDIR to the `LD_LIBRARY_PATH' environment variable
       during execution
     - add LIBDIR to the `LD_RUN_PATH' environment variable
       during linking
     - use the `-Wl,-rpath -Wl,LIBDIR' linker flag
     - have your system administrator add LIBDIR to `/etc/ld.so.conf'
  
  See any operating system documentation about shared libraries for
  more information, such as the ld(1) and ld.so(8) manual pages.
  ----------------------------------------------------------------------
  chmod 644 /usr/lib/apache2/modules/mod_wsgi.so

Ora finisco di configurare apache:

  • aggiungo un virtualhost per chiamare www.mypage.com
  $ sudo vi /etc/apache2/sites-available/todo
  <VirtualHost *>
       ServerName mypage.com
       WSGIDaemonProcess todo user=www-data group=www-data processes=1 threads=5
       WSGIScriptAlias / /var/www/todo/adapter.wsgi
       <Directory /var/www/todo>
               WSGIProcessGroup todo
               WSGIApplicationGroup %{GLOBAL}
               Order deny,allow
               Allow from all
       </Directory>
  </VirtualHost>
  • lo salvo e creo il link simbolico in ../sites-anabled
  $ ln -s ../sites-available/todo
  • adesso carico il modulo wsgi:

prendo un modulo già fatto:

  marcob@jsbach:/etc/apache2/mods-available$ sudo cp vhost_alias.load wsgi.load

lo modifico così

  LoadModule wsgi_module /usr/lib/apache2/modules/mod_wsgi.so  <-- gia' make l'ha messo qui

creo il link simbolico

  marcob@jsbach:/etc/apache2/mods-enabled$ sudo ln -s ../mods-available/wsgi.load

Ora provo a far ripartire Apache:

Creare un web service in python che legge una tabella da mysql[modifica]

Vado avanti, scrivo un nuovo database:

  $ mysql -u root -p
  mysql> create database todo;
  mysql> CREATE TABLE todo (id INTEGER PRIMARY KEY auto_increment, task char(100) NOT NULL, status bool NOT NULL);
  Query OK, 0 rows affected (0.12 sec)
  
  mysql> INSERT INTO todo (task,status) VALUES ('Read A-byte-of-python to get a good introduction into Python',0);
  Query OK, 1 row affected (0.05 sec)
  
  mysql> INSERT INTO todo (task,status) VALUES ('Visit the Python website',1);
  Query OK, 1 row affected (0.06 sec)
  
  mysql> INSERT INTO todo (task,status) VALUES ('Test various editors for and check the syntax highlighting',1);
  Query OK, 1 row affected (0.05 sec)
  
  mysql> INSERT INTO todo (task,status) VALUES ('Choose your favorite WSGI-Framework',0);
  Query OK, 1 row affected (0.06 sec)

e scrivo il web service nel file todo.py

  from mysql import connector
  from bottle import route, run
  
  @route('/todo')
  
  def todo_list():
      conn = connector.connect(user='root', password='root01',host='127.0.0.1',database='todo')
      c = conn.cursor()
      c.execute("SELECT id, task FROM todo WHERE status LIKE '1'")
      result = c.fetchall()
      
      return str(result)
  
  run()
  

Lo faccio girare come server

  $ python todo.py
  Bottle v0.11.3 server starting up (using WSGIRefServer())...
  Listening on http://127.0.0.1:8080/
  Hit Ctrl-C to quit.
  
  localhost - - [18/Oct/2012 19:13:13] "GET /todo HTTP/1.1" 200 102
  localhost - - [18/Oct/2012 19:16:10] "GET /todo HTTP/1.1" 200 102

Ogni riga localhost etc è una request che arriva da un client (borowser o altro): Se punto il browser a http://localhost:8080/todo ottengo

  [(2, u'Visit the Python website'), (3, u'Test various editors for and check the syntax highlighting')]

Caricare il modulo xml.dom.ext[modifica]

Provo così

 $ sudo apt-get install python-setuptools

Poi

 # easy_install pyxml

E ora funziona

 $ python
 >>> import xml.dom.ext
 >>>

No, non è finita, ora:

 xml.parsers.expat.ExpatError: not well-formed (invalid token): line 1, column 7, referer: http://jsbach/prova_zsi.php

Installare python3[modifica]

da Ubuntu Software Center o da apt-get install python3, poi

  marcob@jsbach:~/Documenti/clienti/ComunePd/2012/acsor$ ll /usr/bin/python
  lrwxrwxrwx 1 root root 9 mag 15 10:00 /usr/bin/python -> python2.7*

cambio il puntamento

  marcob@jsbach:~/Documenti/clienti/ComunePd/2012/acsor$ sudo rm /usr/bin/python
  marcob@jsbach:~/Documenti/clienti/ComunePd/2012/acsor$ sudo ln -s /usr/bin/python3 /usr/bin/python
  marcob@jsbach:~/Documenti/clienti/ComunePd/2012/acsor$ python
  Python 3.2.3 (default, Oct 19 2012, 20:10:41) 
  >>>