Curs de ASCII art en Python - I


Escrit per Aaloy a 25 de October , 2009 a les 4:25 p.m.

Avui iniciam el primer curs de ASCII art en Python. Per començar un repte: el pare de n'ETE en ASCII art, generat en Python. Seria així:

1
print(chr(79))

I ja ho tenim, Don ETE!

Eps! Algú ha vist les meves pastilles?


Traducciones/Translations by apertium

0 comentaris, 0 trackbacks (URL) , Tags: Python Conyes marineres


Risc o seny


Escrit per Aaloy a 25 de October , 2009 a les 8:56 a.m.

Llegint l'article de Ned Batchelder, "The Scalability of programming languages" me n'adono que es troba en una tesitura com la que jo potser me trobaré d'aquí poc. Ell, un dels creadors de Tablo, comprat fa dos anys i mig per HP, es veu que es troba sota pressions per deixar de desenvolupar l'aplicació en Python per fer-ho en un dels llenguatges "corporatius" d'HP.

Per mi Django i Python representen un avantatge competitiu, ja que permeten una posada en producció, des de la concepció de la idea fins a posar l'aplicació al servidor, molt més curta, un temps de reacció als canvis i incidències difícilment superable, i sobretot, una capacitat de manteniment que fa que es pugui tocar una aplicació feta fa anys sense problemes.

El més curiós,però, és veure com les novetats, tot allò que pot representar una ruptura amb "la manera de fer les coses" presenta un problema fins i tot en les empreses que han fet de la innovació una de les seves raons de ser.

En una era on la tecnologia representa un avantatge competitiu important, limitar-se a allò que fa tot hom vol dir que no s'aprofita aquest avantatge. Això no vol dir tirar-se de cap cap a una nova tecnologia tan aviat com apareix, però una vegada avaluada, si la nova tecnologia representa una millora respecte al que tenim, el risc de ser dels primers en fer-la nostra es pot veure compensat per l'avantatge que ens donarà. Fins i tot si es demostra que la tecnologia no era allò que esperàvem, l'esforç necessari per a implantar-la i el canvi mental que suposa, farà que el nostre equip estigui més obert a les novetats i que llavors sigui molt més senzill anar introduint millores als nostres processos.

És un poc també com la situació en la que una empresa té l'opció de crear un nou programa per a comercialitzar els seus productes o comprar-ne un de ja fet. Desenvolupar-lo implica més risc i cost, però ens dóna un control total damunt el programa i podem fer-hi les modificacions que facin falta per adaptar-lo als nostres processos de negoci. Comprar-ho fet vol dir que qualsevol amb el capital suficient pot fer el mateix que nosaltres comprant el mateix programa que nosaltres. El que es dóna a més, és que nosaltres podem haver pagat per unes modificacions al programa que han costat temps i esforç de desenvolupar, i la nostra competència les tendrà des del primer dia a cost zero. Adéu a l'avantatge competitiu!

En aquests moments la tecnologia web i els llenguatges que li donen suport estan en un moment d'evolució important: llenguatges d'script per desenvolupar webs, pas cap a models de base de dades no relacionals, utilització de bastiments javascripts purs, serveis REST... Tot això està molt lluny dels llenguatges i tecnologies "corporatives", però són les tecnologies que formen la base de les noves aplicacions d'Internet, de la innovació.

Les empreses hauran d'elegir si prefereixen quedar-se en un sector madur i anar fent el mateix que tothom, o començar a apostar per la innovació i jugar-se-la de tant en tant amb projectes i tecnologies no tant consolidades però amb molta projecció.

Els riscs hi són, però ja se sap, qui vol peixos ...


Traducciones/Translations by apertium

0 comentaris, 0 trackbacks (URL) , Tags: Python Django


Consultes dinàmiques a Django


Escrit per Aaloy a 15 de October , 2009 a les 9 p.m.

Estic mirant de fer un poc més fàcil la integració de jqGrid amb Django, integrar la paginació ha estat força senzill ja que jqGrid i Django fan servir un conjunt de variables semblant: plana actual, total de registres i llista de registres.

jqGrid passa aquests paràmetres per GET quan feim un camvi de plana, per tant podem aprofitar l'objecte paginator de Django per fer la paginació com si fos una aplicació HTML clàssica, sols que en lloc d'HTML retornarem JSON (o XML).

La cosa es complica un poc més quan es tracta de cercar. jqGrid fa servir quatre paràmetres: _search, que es posa a true quan s'ha activat la cerca, searchField que conté el camp pel qual es cerca. SearchField retorna el contingut de la variable index de colModels si existeix o bé el nom. Llavors tenim també searchOper que ens informa del tipus de cerca que es vol fer. Per exemple, passa eq per indicar la coincidència exacta, ew per indicar acaba amb i cn correspon a la sentència IN d'SQL. Per acabar searchString conté el valor del que estam cercant.

Així doncs es tracta de montar un filtre de manera dinàmica amb Django a partir dels valors que ens envia el jqGrid. El primer que hem de fer és fer la taula d'equivalències que mapejarà cada operació de jqGrid amb una operació equivalent de Django.

Per exemple:

1
2
3
4
django_equivalences = {
              'eq': '%s__iexact',
              'lt': '%s__lt',
              'le': '%s__lte'}

Això éns permet convertir fàcilment una expressió d'igualtat per a un camp amb l'equivalent Django

1
2
field = self.request.GET.get('searchField')
op = request.GET.get('searchOper') % field

Amb això ens trobam amb dos problemes: què feim amb les condicions del tipus "no és igual a" o "no comença amb" i què feim amb les expressions "in". I si m'apurau amb un problema més, com passam aquestes condicions que constriuim (o construirem) dinàmicament a Django. Perquè Django espera construccions del tipus Entry.objects.filter(id__gt=4) i nosaltres el que farem és construir-les.

Si ens fixam en la documentació veurem que el problema dels inclosos i dels exclosos està resolt per filter i excludes. Amb la mateixa construcció i generant la consulta amb excludes en lloc de filter ja ho tenim. Sols necessitam doncs que el mapeig a més de la plantilla ens retorni el tipus a que correspon filter o bé excludes.

1
2
3
4
django_equivalences = {
              'eq': ('filter', '%s__iexact'),
              'ne': ('exclude','%s__iexact'),
              'lt': ('filter', '%s__lt')}

Suposant que la nostra classe es diu Entry podríem fer quelcom semblant a això:

1
2
3
4
5
6
7
searchField = request.GET.get('searchField')
op = self.request.GET.get('searchOper')
value = request.GET.get('searchString')
tipo, filtro = django_equivalences[op]
query = {filtro%searchField:value}
record_list = Entry.objects.filter(**query) if tipo == 'filter' \
    else  Entry.objects.exclude(**query)

Fitxem-nos com hem fet la construcció dinàmica. En lloc de crear el codi el que feim és crear un diccionary query que té com a clau l'operació de filtratge damunt el camp que jqGrid ens passa i com a valor, el que volem cercar.

Ens queda encar un petit detall, què passa amb l'in, a Django mapejaria com icontains i espera una llista de valors com a paràmetre. Està clar que ho podríem tractar com un cas particular, però anem-ho a fer divertit, el que farem serà afegir una funció com a valor del mapeig que ens dirà el que hem de fer amb el valor, llevat de in i ni (includes i not includes) no s'ha de fer res, millor dit la funció ha de retornar el mateix valor que li passam (us sona la funció identitat?) i en cas contrari convertirem el valor que ens passi a una llista de valors mitjançant el mètode split(',').

Així doncs el nostre mapeix seria:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
identity = lambda x:x
django_equivalences = {
              'eq': ('filter', '%s__iexact', identity),
              'ne': ('exclude','%s__iexact',identity),
              'lt': ('filter', '%s__lt',identity),
              'le': ('filter', '%s__lte',identity),
              'gt': ('filter', '%s__gt',identity),
              'ge': ('filter', '%s__gte',identity),
              'bw': ('filter', '%s__istartswith',identity),
              'bn': ('exclude','%s__istartswith',identity),
              'in': ('filter', '%s__in',lambda x: x.split(',')),
              'ni': ('exclude','%s__in',lambda x: x.split(',')),
              'ew': ('filter', '%s__iendswith',identity),
              'en': ('exclude','%s__iendswith', identity),
              'cn': ('filter', '%s__icontains', identity),
              'nc': ('exclude','%s__icontains', identity)
              }
field = request.GET.get('searchField')
op = self.request.GET.get('searchOper')
value = request.GET.get('searchString')
try:
    tipo, filtro, f = django_equivalences[op]
except KeyError:
    tipo, filtro, f = django_equivalences['eq']    
filtro = str(filtro % field)
query = {filtro:f(value)}
record_list = Entry.objects.filter(**query) if tipo == 'filter' \
    else  Entry.objects.exclude(**query)

Com veis un exercici interessant perquè hi ha un poc de tot: funció lambda, us dels diccionaris, ús de les funcions com a objectes i pas de paràmetres a una funció mitjançant un diccionari.


Traducciones/Translations by apertium

1 comentari, 0 trackbacks (URL) , Tags: Python Django


Prova de concepte: APSLHOTELS


Escrit per Aaloy a 11 de October , 2009 a les 10:15 a.m.

Link to Prova de concepte: APSLHOTELS

Ahir al vespre vàrem obrir al públic la nostra prova de concepte del que pot ser una plana de reserves d'hotels: http://hotelestest.apsl.net/. I quan dic prova de concepte en refereixo a poder mostrar el que es pot fer amb la tecnologia Python+Django.

A la nostra comunitat un tant per cent elevat de la informàtica gira al voltant del negoci turístic. Quan vas a parlar amb algú del sector i li dius que programaràs la seva aplicació amb Python i Django sovint ho troben un poc estrany, estan acostumats al PHP i com a molt al Java o .Net, no veuen clar que es pugui fer.

Aquesta prova de concepte vol mostrar el senzill que és i algunes de les possibilitats que té la tecnologia actualment. Per fer la demostració volíem que la plana es connectàs a un XML/SOAP d'un tercer ja que d'aquesta manera es cobreix l'ús més habitual: fer una aplicació web on el motor i la capa de presentació estan separades per un servei XML. Dels proveïdors amb que contactàrem vàrem tenir molt bona acollida i suport de la gent de Valadis/Versys, ens varen donar moltes facilitats des del començament i el seu XML és molt senzill de mapejar. Està clar que les idees que es presenten es poden desenvolupar amb gairebé qualsevol proveïdor XML d'hotels, però vàrem tenir la sort de poder topar amb aquesta gent i que ens donàs accés al seu sistema de proves sense cap problema. Des d'aquí moltes gràcies.

Així doncs, tenim una aplicació B2C que permet reserva hotels i que connecta al motor XML de test d'un proveïdor extern. Com a bon entorn de test he de dir que es troba en contínua evolució i que les dades que es mostren són sols un subconjunt molt limitat de les que es tendrien en un entorn de producció. No us fixeu massa en les dades, sinó en el bessó del que es mostra. Per cert, podeu provar tot el que volgeu, tanmateix no es fa cap tipus de pagament ni control a la tarja que poseu.

Feta aquesta introducció anem a veure un poc la bèstia:

El desenvolupament

Com he dit l'aplicació està desenvolupada fent servir Python+Django, pel control de versions s'ha fet servir Subversion i pel control del projecte s'ha fet servir Trac.

Per crear l'aplicació hem mapejat l'XML a objectes Python amb la llibreria lxml, una llibreria que envolcalla les llibreries C libxml2 i libxslt. La velocitat del C i l'expressivitat de Python.

Per la depuració i programació hem fet servir: django-extensions, debug_toolbar, ipdb i ipython. La primera llibreria ens proporciona tot un conjunt de funcions còmodes per l'administració de l'aplicació, debug_toolbar ens diu quina plantilla es fa servir en cada pantalla, les seves herències, les sql que es generen, etc. ipdb és un depurador de línia de comandes, com el pdb però amb autocompletat i ressaltat de sintaxi. ipython és una consola Python, Django l'aprofita si està instal·lada, proporciona autocompletat, resaltat de sintaxis i un gran nombre de comandes extra.

Els editors més habituals han estat Netbeans, Eclipse, Vim, Kate i Notepad++ (per Windows). L'editor importa poc, tots estan configurats per fer feina amb UTF-8 i els tabuladors configurats a 4 espais. Amb això en tenim prou per poder fer servir en qualsevol moment l'editor que més ens agradi. Particularment vaig d'un a l'altra segons la màquina que faig servir.

Per les planes de contingut estàtic hem fet servir django-page-cms, la idea és mostrar com un gestor de continguts es pot integrar dins l'aplicació.

Els css i js es comprimeixen abans de servir-se gràcies a django-compress. Això vol dir que podem fer cachés mesos. Quan el css o el js canvii sols hem de tornar a generar els arixus comprimits i la llibreria els posa un nou nom.

La configuració de sistemes

L'aplicació s'executa en un chroot propi dins un servidor propi que duu moltes més aplicacions.

vendor_id   : GenuineIntel
cpu family  : 6
model       : 15
model name  : Intel(R) Pentium(R) Dual  CPU  E2180  @ 2.00GHz
stepping    : 13
cpu MHz     : 1994.999
cache size  : 1024 KB

top - 08:52:55 up 729 days, 13:56,  0 users,  load average: 0.07, 0.02, 0.00
Tasks: 126 total,   1 running, 125 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.0%us,  0.2%sy,  0.0%ni, 99.8%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   1015232k total,   984036k used,    31196k free,   154472k buffers
Swap:  2097144k total,     2948k used,  2094196k free,    90536k cached

L'entorn d'execució s'independitza de la màquina amb aquest chroot i a més es va crear un entorn virtual separat per l'aplicació amb virtualenv, això permet tenir un control total damunt les llibreries i el Python Path.

Seguint les millors pràctiques, hem separat els dominis que serveixen el contingut estàtic del contingut dinàmic. Això és prou senzill amb Django i sols has de recordar escriure les url amb {{MEDIA_URL}}.

Donat que és una màquina amb altres aplicacions volíem que el consum de memòria fos mínim. Per això hem optat per que el servidor http no fos un Apache sinó nginx que tenim configurat tant per servir el contingut estàtic com per a fer de proxy invers cap al motor WSGI que executa l'aplicació Django.

Pel motor WSGI triarem CherryPy (d'aquí no res posarem Tornado). Amb això tenim una relació de consum de recursos de màquina i rendiment molt òptima i una escalabilitat horitzontal fabulosa. Posant-hi un balancejador podem anar copiant i aferrant chroots i dins cada chroot podem tenir tantes instàncies de l'aplicació con suporti la màquina.

És veritat que no calia complicar-se tant per a una prova de concepte, però la idea no és tan sols mostrar el que es pot fer en programació, sinó com la tecnologia i el frameworks s'adapten a les necessitats actuals i futures de rendiment. És a dir, que s'escala cap amunt i cap avall.

L'aplicació

A la primera plana hi trobam el cercador, el típic cercador afegiria. Aquí utilitzam jquery-ui pels widgets de calendari. Hi ha la demostració de l'autocompletat als apartats de destinos i nombre de hotel.

El errors es mostren a la plana de manera poc intrusiva. Per això s'utilitzen plugins de jquery i les capacitats de serialització json de Python i Django, junt amb la validació de formularis de Django. És molt més senzill del que sona.

També es pot veure la utilització que es fa del CMS en les planes de Aviso Legal per exemple i també hi podem trobar dos tipus d'ofertes.

Aquestes es mantenen dins la part d'administració. No són gaire sofisticades, però serveixen per mostrar el dinamisme que es pot aconseguir i el concepete d'url semàntica.

Picant damunt una oferta per exemple, anirem a la plana de resultats. Recordem que anam contra un entorn de proves i que les dades són les que són. La idea és poder mostrar com les dades de l'hotel es carreguen dinàmicament mitjançant una cridada AJAX i com l'aplicació manté en sessió les dades de la selecció.

Hem posat també un filtre js. Pitjant damunt el filtre de categoria desapareixen els hotels amb aquesta categoria. Es pot utilitzar el mateix concepte per a filtrar els resultats per altres camps (preu, tipus d'habitació, ...)

A partir d'aquí ja anam a les pantalles que obtenen la informació de compra i a la de gràcies. Res destacable en aquest punt que no hagi sortit abans.

Pas a producció

Hi ha gent que ens ha demanat pel pas a producció d'aquesta aplicació. Recordau que és una prova de concepte, no hi haurà pas a producció, serveix per mostrar idees de programació, conceptes tecnològics i d'optimització.

El que si es pot fer és desenvolupar una solució a mida amb aquestes tecnologies, però serà sempre per a un tercer i si es fes hi hauria molta feina que en la prova de concepte s'ha obviada:

  • Continguts estàtics: hem posat lorem ipsum gairebé per tot.
  • Filtres
  • Paginació de resultats
  • Connexió amb una passarel·la de pagament
  • Generació del bono
  • Enviament del bono al client
  • Backoffice de control

L'aplicació tal com està i en les seves possibles evolucions té per objectiu que gent com nosaltres que ens dedicam al desenvolupament Python i Django poguem mostrar al món turístic el que es pot fer. Consideram l'aplicació com un Projecte Mascota: hi anam dedicant hores quan ens fa ganes.


Traducciones/Translations by apertium

2 comentaris, 0 trackbacks (URL) , Tags: Python Django