Posts tagged python
Just a quick post on how to log, in simple Python scripts, the start and finish times of a function.
import logging
import time
import sys
def main():
start = time.time()
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s %(levelname)s - %(message)s',
datefmt='%H:%M:%S',
)
logging.info("Start processing after %s", format_time_since(start))
# Do some processing ...
logging.info("Finished processing after %s", format_time_since(start))
sys.exit(0)
def format_time_since(start):
now = time.time()
elapsed = now - start
return time.strftime("%H:%M:%S", time.gmtime(elapsed))
SVN
Python’s setuptools provide a simple mechanism to tag your built distributions with the SVN revision they belong to, by creating a setup.cfg
file along the normal setup.py
, and there write
[egg_info]
# Add svn revision to the file name
tag_svn_revision = 1
Git
How to do the same for Git? Or in general, with other information? (Date tagging is also supported by default).
Answer: modify directly the options
dictionary in the call to setup
, in setup.py
. There, you can put anything you can compute with Python or system calls. E.g. for git:
import shlex
from subprocess import check_output
GIT_HEAD_REV = check_output(shlex.split('git rev-parse --short HEAD')).strip()
setup(
# ... other keys like project name, version, etc ...
options = dict(egg_info = dict(tag_build = "dev_" + GIT_HEAD_REV)),
)
With that setup, distributions (sdist
or bdist
) would be tagged with the string “dev” and the git hash of the latest commit:
$ bin/python setup.py sdist bdist_egg
$ ls dist
pyhello-0.1dev-92ffa06.tar.gz pyhello-0.1dev_92ffa06-py2.7.egg
Whenever you want to build a stable release (without any “dev” tags), just set the key to empty in your setup.cfg
, like this:
[egg_info]
tag_build =
RedHat y centOS tienen la fastidiosa dependencia de su gestor de paquetes, yum, con la versión 2.6 de Python desde tiempos inmemoriales. Lo que en tecnología son unos seis o siete años.
Instalar Python 2.7 no es posible con los repositorios instalados por defecto, y si tienes la mala idea de instalar un repositorio donde sí esté y meterlo como paquete que supedita al python por defecto, te acabas de cargar yum (y la posibilidad más sencilla de deshacer tus cambios).
La mejor manera, pese a lo que pueda parecer, es instalar desde fuentes, haciendo lo que se conoce como “altinstall” (instalación alternativa). Esto crea ejecutables llamados python2.7
bajo /usr/local/bin
, que no sobreescriben el comando python
normal del sistema; éste sigue apuntando a un ejecutable bajo /usr/bin
.
$ wget http://www.python.org/ftp/python/2.7.6/Python-2.7.6.tgz
$ tar xvfz Python-2.7.6.tgz
$ cd Python-2.7.6
$ ./configure
$ make
$ sudo make altinstall
Además de esto, es recomendable instalar un easy_install
alternativo también, ya que, si no, todas las librerías de python se instalarán para la 2.6 y no para la 2.7.
$ wget http://pypi.python.org/packages/2.7/s/setuptools/setuptools-0.6c11-py2.7.egg
$ sudo -i
# export PATH=$PATH:/usr/local/bin
# sh setuptools-0.6c11-py2.7.egg
# exit
$ sudo rm /usr/local/bin/easy_install ## remove the symlink that shadows the system easy_install
$ # You may now try the easy_install for 2.7 with e.g.:
$ sudo /usr/local/bin/easy_install-2.7 numpy
Este post es una combinación de dos respuestas en Stack Overflow, y mi propia experiencia con este mismo problema.
¡Por fin he entendido cuál es la diferencia entre Unicode y UTF–8! Y lo que es más importante, cómo se declaran correctamente strings
en Unicode en Python.
Unicode es la tabla de equivalencias entre caracteres de (casi) todos los lenguajes humanos, y un número asignado a ese caracter en concreto.
UTF–8 es la manera de comprimir esos números en uno o dos bytes, en lugar de usar 4 bytes por caracter, aprovechando el hecho de que la mayoría de caracteres habituales están en los números bajos (menores de 128).
Es decir, si el “encodificador” encuentra un número < 128, deja ese número; si encuentra uno mayor, pero menor de X (donde X es un límite que no recuerdo), usa dos bytes para expresar este número. El “decodificador” entonces sabe que cada caracter menor de 128 está “solo”, mientras que si encuentra uno mayor, entonces debe leer también el siguiente byte para tener el número correcto con el que ir a la tabla Unicode y obtener el caracter adecuado.
Se puede crear una cadena Unicode en Python usando una u
delante de la cadena literal, pero esto no siempre es posible, como cuando se lee de un fichero. Para convertir entre distintas codificaciones existe la función unicode
.
La función unicode
no utiliza UTF–8 por defecto, sino, absurdamente, ASCII. Por eso sólo es equivalente a poner una u
delante una cadena si se especifica que el encoding
sea 'utf-8'
.
unicode_string = u"Años"
unicode_str = unicode(open('some.txt', 'r').read(), encoding='utf-8')
Al generar una aplicación para Mac OS X con py2app, a menudo se generan ejecutables muy pesados, por ejemplo 20 MBs para una aplicación de línea de comandos (!).
Uno de los problemas es que py2app tiende a incluir muchos módulos de la librería estándar de Python que en realidad no hacen falta. Se pueden excluir específicamente incluyéndolos en la opción excludes que se pasa a la función setup en el archivo setup.py usado para generar la aplicación.
Con la lista siguiente, el peso baja de 22 MBs a 6 MBs. Probablemente se puede rebajar aún más.
# File: setup.py
from setuptools import setup
APP = ['path/main.py']
Plist = {}
DATA_FILES = []
OPTIONS = {'argv_emulation': True,
#'iconfile': 'Icons/ConverterIcon.icns',
'plist': Plist,
'excludes': [
'aetypes',
'ast',
'bz2',
'calendar',
'codecs',
'collections',
'ctypes',
'distutils',
'doctest',
'email',
'encodings',
'functools',
'gzip',
'inspect',
'itertools',
'locale',
'logging',
'optparse',
'pickle',
'platform',
'pprint',
'random',
're',
'sets',
'shutil',
'socket',
'ssl',
'subprocess',
'tarfile',
'tempfile',
'threading',
'traceback',
'types',
'unittest',
'urllib',
'urllib2',
'urlparse',
'weakref',
'xml',
'zipfile',
]
}
setup(
app=APP,
package_dir={'': 'src'}, # you may not need this
data_files=DATA_FILES,
version="0.1",
description="<Your description>",
author="<Your name>",
author_email="<Your email>",
options={'py2app': OPTIONS},
setup_requires=['py2app'],
)