Mostrando entradas con la etiqueta python. Mostrar todas las entradas
Mostrando entradas con la etiqueta python. Mostrar todas las entradas

martes, 17 de noviembre de 2015

Python simbólico resolver ecuación

Resolver esta ecuación en wolfram alpha,




... y su equivalente usando sympy



>>> from sympy import symbols, var
>>> v1,v2,v3,vo,r1,r2,r3,r4,rf=symbols('v1,v2,v3,vo,r1,r2,r3,r4,rf')
>>> from sympy.solvers import solve
>>> from sympy import init_printing
>>> init_printing(use_unicode=False, wrap_line=False, no_global=True)
>>> solve(v1/r1 + v2/r2 - ((v3*(r4/(r3+r4)))-vo)/rf, vo)
 r1*r2*r4*v3 - r1*r3*rf*v2 - r1*r4*rf*v2 - r2*r3*rf*v1 - r2*r4*rf*v1 
[-------------------------------------------------------------------]
                           r1*r2*(r3 + r4)                 

miércoles, 17 de octubre de 2012

Campos calculados en django

Las operaciones sobre los objetos model de django se mapean a SQL mediante el ORM (Object-relational mapping). Un problema que tiene el ORM de django es que no tiene soporte directo para los campos calculados, que son aquellos que se obtienen a partir de los valores de los campos del registro para cada registro.

Por ejemplo, tenemos unos movimientos en los que interviene cantidad, precio y comisión. ¿Qué sentido tiene guardar en la BD el campo importe si en realidad ya tenemos toda la información para calcularlo?.

class Movimiento(models.Model):
   cantidad=models.DecimalField()
   precio=models.DecimalField()
   comision=models.DecimalField()

¿Cómo calculamos entonces el importe?. Hay dos alternativas: Una usando una property de python en el propio objeto model y otra usando extra en el queryset. Veamos:

class Movimiento(models.Model):
   cantidad=models.DecimalField()
   precio=models.DecimalField()
   comision=models.DecimalField()

   def _get_importe(self):
      return self.cantidad*self.cambio*(1-self.comision)
   importe = property(_get_importe)

Y ahí tenemos el importe del movimiento via movimiento.importe

La otra solución es usar extra en el queryset para añadir "a mano" el campo en la consulta SQL, sería:

target=movimiento.objects.extra(select={
          'importe': 'cantidad*cambio*(1-comision)',})
for f in target:
    print f.importe

Entonces, ¿Cuál es el problema?. Pues que todo esto son soluciones "de mentirijilla" puesto que realmente el campo importe no existe como tal en el gestor de BD y no podemos hacer cosas como sumar todos los importes haciendo una agregación, así esto

total_importe=modelo.aggregate(Sum('importe'))

Nos genera un error diciendo que el campo importe no existe.

Sin duda, el soporte para campos calculados es uno de las mejoras del ORM que puede trabajarse.


Fuentes:
http://stackoverflow.com/questions/3690343/django-orm-equivalent-for-this-sql-calculated-field-derived-from-related-table

jueves, 2 de agosto de 2012

Aún otro ejemplo de try, except, else, finally / Yet another try, except, else, finally example

Estaba pasando datos de una DB mysql a otra en django y me ha salido este "snippet" que ejemplifica el uso de try-except-else-finally.

try contiene el código que queremos proteger
except captura la excepción (usar la clase genérica exception para capturarlas todas)
else código que se ejecutará si no salta ninguna excepción
finally código que se ejecutará en todo caso tanto si hay como si no hay excepción

Las únicas obligatorias son try y except. Si queremos capturar más de una excepción, las ponemos una detrás de otra:

from django.core.exceptions import ObjectDoesNotExist
try:
    cl=Cliente.objects.get(clave=id)
except ObjectDoesNotExist, ex:
    print "el cliente no existe"
except Exception, ex:
    print "se ha producido un error", str(ex)

Ejemplo:


try:  
   try:  
     c=db_marcajes.cursor(MySQLdb.cursors.DictCursor)  
     c.execute("select id, fecha, event, door, user from logs where fecha>%s", (last_marcaje,))  
     rows=c.fetchall()     
   except Exception, e:  
     print "Impossible efectuar consulta"  
     exit(1)  
   else:  
     elapsed = (time.clock() - start)  
     print "Consulta realitzada en", elapsed, "msegs"  
     num_rows=len(rows)  
     print "Numero de filas ", num_rows  
     i=0    
     while i<num_rows:  
       row=rows[i]     
       print "procesando fila ", repr(row)  
       try:  
         em=Empleado.objects.get(pin=row['user'])  
         pt=Puerta.objects.get(pk=row['door'])  
         print ("guardando acceso %s de %s" % (row['user'],em.descripcion,))  
       except Exception, ex:  
         print ("Error de busqueda empleado %s puerta %s: %s", ( row['user'], row['door'], ex, ))  
       else:  
         try:  
           acc=Acceso(  
             empleado=em,  
             es=row['event'],  
             fecha=row['fecha'],  
             puerta=pt,  
             )  
           #acc.save()  
           print "Guardado"  
         except Exception, ex:  
           print ("Error grabando acceso: %s" % (ex,))  
       finally:  
         i+=1  
         last_marcaje=row['fecha']  
   finally:  
     c.close()           
 finally:  
   # guardam darrer marcatje  
   conv=Convenio.objects.get(pk=1)  
   conv.last_marcaje=last_marcaje  
   conv.save()  

lunes, 23 de abril de 2012

Dado un numero de semana ¿Cuál es la fecha del lunes? / Given an (iso) week number, Whats the date of Monday?


¿En qué semana cae el 7 de junio de 2012? / What's the week number of june 7, 2012?
datetime.date(2012, 6, 7).isocalendar()[1]
23
¿Cuál es el lunes de la semana 23 de 2012?. What's the monday of the week 23 of 2012?

time.asctime(time.strptime(('%s %s 1' % (2012, 23,)), '%Y %U %w'))
'Mon Jun  4 00:00:00 2012' 



domingo, 11 de marzo de 2012

Usar cliente Mysql python en windows

Si has intentado, sin éxito, instalar el módulo MySQLdb en windows tal vez te interese pasar por este sitio web y bajarte el instalador para windows en vez de tener que compilar las librerías en tu PC ;-)

jueves, 8 de marzo de 2012

Paso de parámetros a programas en python / How to pass parameters to a python program

Para pasar parámetros a los programas se usa el módulo getopt, que nos permite trabajar cómodamente con ellos.

En primer lugar tenemos que saber que el contenido de la línea de comandos nos viene en forma de lista en sys.argv.

Si invocamos un programa en python, como parámetros nos interesará todo lo que venga después de la primera posición, es decir sys.argv[1:], así que en general llamaremos a una función main así
if __name__=='__main__':
 main(sys.argv[1:])

Ahora veremos el funcionamiento de getopt, os paso un ejemplo:
def main(argv): 
 try:      
  opts, args = getopt.getopt(argv, "hps:", 
                                                  ["help", "prn", "server="])
 except getopt.GetoptError:          
  print "Opcion no valida"
  usage()                         
  sys.exit(2)                     
  
Vemos que getopt toma tres argumentos:

  1. El primero es la cadena que le pasamos para analizar
  2. El segundo son las opciones en forma corta, las que se usan con la sintaxis -h, -p, -s="algo"
  3. El tercero son las mismas opciones pero en forma larga que se usan con dos guiones --help, --prn, --server="algo"
Observamos que las opciones en forma corta seguidas de dos puntos o en forma larga seguidas del símbolo igual esperan que les pasemos un argumento. Getopt se encarga de que si al programa le pasamos alguna opción que no esté en la lista salte la excepción GetoptError.

Como ahora ya tenemos las opciones y sus posibles valores, el tratamiento será algo similar a esto
for opt, arg in opts:                
  if opt in ("-h", "--help"):      
   usage()                     
   sys.exit()                  
  elif opt in ('-p', "--prn"):                
   p_pantalla=True             
  elif opt in ("-s", "--server"):          
   r_server=arg            

Si hay algún tipo de error durante el parseado de los argumentos, es una buena idea dar una ayuda al usuario antes de terminar el programa, por ejemplo
def usage():
 print """
Opcions:
--help (-h)\t\tTreu aquesta ajuda
--prn (-p)\t\tTreu impressio de tickets per pantalla
--server (-s)\t\tServidor actualització
"""


Y esto es todo por hoy

jueves, 1 de marzo de 2012

Con qué día empieza la semana en python? What's the first day of the week in python?

Venga, vamos a jugar un poco más con las fechas. ¿Con qué día empezó esta semana?.

d=datetime.date.today()
delta=datetime.timedelta(days=1)
fecha_inicio_semana=d-(delta*(d.isoweekday()-1))

Warning, for the the non-ISO calendars such as UK/USA: the function isoweekday assumes that the first day of the week is Monday.

miércoles, 29 de febrero de 2012

Menor de edad en python / Legal age in python

Hoy día 29/02/2012 (29 de febrero de año bisiesto), me he encontrado con que el algoritmo que usaba para el cálculo de minoría de edad me ha fallado. Después de varias indagaciones he dejado este como bueno:

from datetime import date, datetime, timedelta

def menor_edad(nascut):
  """ accepts a string date in iso format Y-m-d and returns True if
        it is in spanish legal age today """
  t=timedelta(seconds=31556926*18)
  fa_divuit=date.today()-t
  fecha=datetime.strptime(nascut, '%Y-%m-%d').date()
  return (fecha > =fa_divuit)


viernes, 24 de febrero de 2012

Filtrado fácil de clave foránea en una ficha de django

Es sabido que django mapea las claves foráneas a un ModelChoiceField en ModelForm, pero ¿qué ocurre cuando sólo queremos seleccionar un subconjunto de ellas?.

Por ejemplo, supongamos que estamos dando de alta un empleado y a la hora de seleccionar su categoría sólo queremos que aparezcan las que están asociadas a su sección.

Tenemos la ficha:


class AddForm(forms.ModelForm):
  class Meta:
   model=Empleado
    fields=('clave', 'descripcion', 'categoria', 'jefe_seccion', 'email',)


La propiedad queryset del campo categoría estará definida por defecto como Categoria.objects.all(), así que hacemos:

p=AddForm()
p.fields['categoria'].queryset=Categoria.objects.filter(seccion=self.seccion)

Con lo que en la ficha sólo nos saldrán las categorías de la sección actual.
Otra forma más complicada consiste en pasarle el parámetro al constructor de la clase pero hay que hacerlo con los kwargs por que si no tendremos problemas en cuando queramos usar la ficha para editar.

class AddForm(forms.ModelForm):
  categoria=forms.ModelChoiceField( label=u'Categoría', queryset = Categoria.objects.none())
  def __init__(self, *args, **kwargs):
   sec = kwargs.pop('sec', None)
   super(AddForm, self).__init__(*args, **kwargs)
   if sec:
    self.fields['categoria'].queryset = Categoria.objects.filter(seccion = sec)
  class Meta:
   model=Empleado
   fields=('clave', 'descripcion', 'categoria', 'jefe_seccion', 'email',)

sábado, 11 de febrero de 2012

Procesador de texto "Sublime Text"

No soy yo muy dado a cambiar mi preciado vi para programar. Sin embargo, me he encontrado con este procesador de texto (hecho en python) que tiene versiones para Linux, Win y Mac. Tiene muy buena pinta. Su nombre es Sublime Text.

Para empezar a usarlo ve a una carpeta que tenga código. Haz Project->Save As... luego Project->Add Folder.

 Voy a probarlo una temporada a ver que tal.


martes, 7 de febrero de 2012

Configurar logging en python y django con yaml

Os paso el esquema de logging que utilizo en mis aplicaciones por si os puede servir de ayuda. Lo he ido montando a partir de diversas fuentes y experiencias.

Un punto importante es dejar el fichero de configuración del logging fuera del programa para independizar mejor el sistema de logging de la aplicación.

Este puede ser un ejemplo del fichero de configuración en yaml (logger.conf):


version: 1
formatters:
  brief:
    format: '%(name)s - %(levelname)s - %(message)s'
  simple:
    format: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
  detailed:
    format: '%(asctime)s %(module)-17s line:%(lineno)-4d %(levelname)-8s %(message)s'
  email:
    format: 'Timestamp: %(asctime)s\nModule: %(module)s\n Line: %(lineno)d\nMessage: %(message)s'
handlers:
  console:
    class: logging.StreamHandler
    level: DEBUG
    formatter: brief
    stream: ext://sys.stdout
  file:
    class: logging.handlers.RotatingFileHandler
    level: INFO
    formatter: detailed
    filename: app.log
    mode: a
    maxBytes: 10485760
    backupCount: 5
  smtp:
    class: logging.handlers.SMTPHandler
    level: ERROR
    formatter: email
    mailhost: smtp.xxxxx.es
    fromaddr: yyy@xxxx.es
    toaddrs:  yyyy@xxxx.es
    subject:  Error en aplicacion XX
root:
  level: DEBUG
  handlers: [console]

Se observan los formateadores de los mensajes y los handlers para la cónsola, fichero y correo. Por defecto el logging sale por cónsola, si queremos que los errores salgan por email handlers de root sería [console, smtp], para fichero que rotara cada maxBytes [file], etc... Realmente cómodo.

Para cargar la configuración, primero parseamos el yaml (PyYAML) y luego lo enviamos a dictConfig, que realiza la configuración así:


import yaml
import logging


#nos aseguramos de que dictConfig esté presente (python 2.7), sino, lo cargamos de la libreria de django 



try: 
    from logging.config import dictConfig 
except ImportError: 
    from django.utils.dictconfig import dictConfig

# Cargamos la configuracion del fichero, la parseamos y la enviamos a dictConf
try:
    logging.config.dictConfig(yaml.load(file('logger.conf','r')))
except Exception, e:
    print "Error configurating logger ", str(e)

Ahora ya podemos el usar el sistema. En general, es conveniente nombrar cada logger con el nombre de su módulo para que cuando haya muchos mensajes sepamos cuál los está enviando, para ello podemos usar el valor de __name__, así:

logger=logging.getLogger(__name__) # __name__ contiene el nombre del modulo
logger.debug("blah blah")

Si queremos que cada clase tenga su logger privado, tenemos que tomar una pequeña precaución para evitar un error si otros usan una librería nuestra con otro sistema de handles,

Declaramos una clase "nula":

class Nullhandler(logging.Handler):
   def emit(self, record):
      pass

y ahora, en la clase hacemos

class Clase():
   def __init__(self):
      self.__logger=logging.getLogger(__name__)
      self.__logger.addHandler(NullHandler())
      self.__logger.debug("clase iniciada")

Como veis es un tema un poco denso pero que una vez bien configurado nos será imprescindible para trazar correctamente las aplicaciones. Espero que os haya ayudado.

lunes, 5 de diciembre de 2011

Shell en django

Ocurre muchas veces que necesitamos una shell en django para realizar pruebas o tareas de mantenimiento. Conseguirla es muy sencillo ya que settings.py se cargará desde el primer momento en que importemos un modelo o cualquier módulo de django.  Lo único que tenemos que hacer es exportar la variable DJANGO_SETTINGS_MODULE con el valor del fichero de settings que queremos utilizar. Yo uso este script (suponiendo que nuestros settings están en settings.py):

shell.sh
export DJANGO_SETTINGS_MODULE="settings"
python


desde aquí ya podemos operar con los modelos:

from gesion.models import Cliente
c=Cliente(clave='444', descripcion='Pepe Perez')
c.save()


Si queremos acceder desde un script independiente en python podemos usar setup_environ de esta forma:

mantenimiento.py
from django.core.management import setup_environ

try:
  import settings
except ImportError:
  import sys
  sys.stderr.write("No encuentro el fichero de settings")
  sys.exit(1)

setup_environ(settings)

....


Espero que os sirva.

sábado, 29 de octubre de 2011

Copia de seguridad en pdf o mobi de archivos con DRM de Adobe

Si habéis adquirido algún libro en las librerías de ebooks españolas os habréis dado cuenta de tres cosas:

  1. Adobe Digital Editions no tiene versión para Linux, lo cuál me parece una falta de respeto a los usuarios de este sistema operativo libre.
  2. El renderizado del documento lo hace el propio digital editions siendo la calidad de visualización inferior al de cualquier visor de pdf.
  3. No podéis leer el documento en vuestro lector de ebooks o tableta.

A mí personalmente me parece una tomadura de pelo, por que para eso es mejor comprarse la versión en papel. Por lo tanto, he decidido compartir este link con vosotros para que podáis realizar una copia de seguridad privada en un formato con el contenido en claro. Tened en cuenta que compartir este fichero en claro puede ser ilegal y debe usarse sólo para mejorar el visionado o leer el texto en la tableta.

Método
Según el autor, el DRM de Adobe tiene una debilidad bastante evidente y es que aunque usa una criptografía fuerte para el texto es muy sencillo reproducir la forma como baja y descifra la clave única de usuario usada para descifrar el texto.

Su método hace uso de dos scripts en python: 

  • Uno de ellos rompe la ofuscación de la clave única de usuario y la graba al disco duro (es conveniente guardarla).
  • El otro descrifa el texto usando esa clave.

Sólo tenéis que pasar el fichero con DRM a linux y ejecutar los dos scripts. Para los usuarios de windows hay instruciones adicionales :


  1. Bajar e instalar Python 2.6 y PyCrypto.
  2. Bajar los dos scripts anteriores y guardarlos en un directorio con los nombres intepkey.pyw e ineptpub.pyw.
  3. Guardar el libro a descifrar en el mismo directorio y ejecutar inetkey.pyw y luego ineptepub.pyw sobre el libro.

viernes, 7 de octubre de 2011

Uso correcto de super en python

Sea
class Base(object):
    def __init__(self):
        print "Base created"
class ChildA(Base):
    def __init__(self):
        Base.__init__(self)
class ChildB(Base):
    def __init__(self):
        super(ChildB, self).__init__()
¿Qué diferencia hay entre la construcción de A y de B?. Pues ninguna, lo que ocurre es que super (versión B) nos permite mayor flexibilidad para gestionar la jerarquía ya que no tenemos que referirnos a una clase en particular.

Usar super es también la única forma de hacer herencia múltiple aunque yo no la uso por ser fuente de errores.

En python 3, la sintaxis se simplifica de super(ChildB,self).__init__() a super().__init().

Fuentes:
Understanding Python super() and init methods
http://stackoverflow.com/questions/576169/understanding-python-super-and-init-methods

How to use 'super' in python
http://stackoverflow.com/questions/222877/how-to-use-super-in-python

lunes, 20 de junio de 2011

Cuidado con el directorio de instalación de django

El directorio de instalación, tal y como indica el manual , lo obtenemos con

from distutils.sysconfig import get_python_lib;print get_python_lib()

y muestra

/usr/lib/python2.6/dist-packages

Peeero, en realidad en ubuntu se instala en

/usr/local/lib/python2.6/dist-packages
o
/usr/lib/pymodules/python2.6/django

¿Cómo podemos saber la localización de este directorio?. Pues usando la librería sys, que mantiene la localización del __init__.py de cada import:

Python 2.6.5 (r265:79063, Apr 16 2010, 13:09:56)
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys, os, django
>>> sys.modules['django']
module 'django' from '/usr/local/lib/python2.6/dist-packages/django/__init__.pyc'

Sacado de esta entrada de stackoverflow http://stackoverflow.com/questions/2647862/how-can-i-tell-what-directory-an-imported-library-comes-from-in-python

sábado, 21 de mayo de 2011

Python extraer año de datetime.date


datetime.date.today().isocalendar()[0]

Python, más aritmética con meses


def suma_mes(current_date, month_step):
""" suma month_setp mesos a current_date """
carry, new_month=divmod(current_date.month-1+month_step, 12)
new_month+=1
return current_date.replace(year=current_date.year+carry, month=new_month)


¿Cuántos días faltan para el mismo día de hoy del mes que viene?


>>> print (suma_mes(datetime.date.today(), 1)-datetime.date.today()).days

Sumar un mes con python


>>> from datetime import date
>>> current_date=date.today()
>>> carry, new_month=divmod(current_date.month-1+1, 12)
>>> new_month+=1
>>> current_date=current_date.replace(year=current_date.year+carry, month=new_month)
>>> print date.today()
2011-05-21
>>> print current_date
2011-06-21
>>>