Archivo de la etiqueta: version

Solucionar: RuntimeWarning: Python C API version mismatch for module en CentOS 5.5 con cPanel

Si utilizas CenOS y por ejemplo has decidido hacer una actualización de tu versión de Python ya que puede que estuvieras usando la versión 2.4 o 2.6 y quieres actualizar a 2.6 o 2.7 respectivamente, puede ser que te encuentres el error siguiente al ejecutar yum:

# yum
/usr/lib/python2.6/site-packages/rpm/__init__.py:7: RuntimeWarning: Python C API version mismatch for module _rpm: This Python has API version 1013, module _rpm has version 1012.
  from _rpm import *
There was a problem importing one of the Python modules
required to run yum. The error leading to this problem was:
   No module named sqlitecachec
Please install a package which provides this module, or
verify that the module is installed correctly.
It's possible that the above module doesn't match the
current version of Python, which is:
2.6.5 (r265:79063, Jun  4 2010, 21:43:07)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-48)]
If you cannot solve this problem yourself, please go to
the yum faq at:
  http://wiki.linux.duke.edu/YumFaq

Este error se debe, a que yum, esta buscando sus bibliotecas para ejecutarse y no las encuentra. Posiblemente por que tu versión de yum esta instalada en otra versión de python anterior y la nueva no tiene dicha versión.

Existen varias formas de solucionar esto, pero en CentOS no esta documentada y a fecha de hoy en google no puedes encontrar ninguna solución. Es más acudiendo al IRC de centos pidiendo ayuda, su respuesta liberal en ingles fue “Date una bofetada o directamente disparate en la cabeza por lo que has hecho“.

Esta respuesta me indigno mucho, sobre todo porque me pareció pésimo el soporte, que sin darme solución, encima me respondía de esa forma, aparte el problema realmente reside en que ellos no son capaces de solucionártelo y puesto que no actualizan la versión de python en años “para que sea estable“, los usuarios y sysadmin deben ingeniárselas solucionando los problemas.

Luego después de experimentar mis soluciones fueron las siguientes:

Reinstalar yum a traves de rpm: esto probablemente funcionaría, pero no, ya que se instalaría incorrectamente con la nueva versión de python y no conseguí hacer nada, quizás hice mal algún paso.

– Reinstalar el paquete yum-metadata-parser que contiene las dependencias de yum. Igualmente al reinstalarlo no tuvo efecto ya que estaría cogiendo una mezcla de paths.

– Modificar la variable de entorno PYTHONPATH. De igual forma no funciono ni poniendo versiones más antiguas.

La solución final, que aunque fue cutre, conseguí hacerlo funcionar, fue la siguiente:

Buscar el binario de yum:

# which yum

En mi caso la salida fue:

# which yum
/usr/bin/yum

Luego tras comprobar que el tipo del archivo era un script en python:

# file /usr/bin/yum
/usr/bin/yum: python script text executable

Me fije en el archivo para editarlo:

# cat /usr/bin/yum
#!/usr/bin/python
import sys
try:
 import yum
except ImportError:
 print >> sys.stderr, """\
There was a problem importing one of the Python modules
required to run yum. The error leading to this problem was:

 %s

Please install a package which provides this module, or
verify that the module is installed correctly.

It's possible that the above module doesn't match the
current version of Python, which is:
%s

If you cannot solve this problem yourself, please go to 
the yum faq at:
 http://wiki.linux.duke.edu/YumFaq
 
""" % (sys.exc_value, sys.version)
 sys.exit(1)

sys.path.insert(0, '/usr/share/yum-cli')
try:
 import yummain
 yummain.user_main(sys.argv[1:], exit_code=True)
except KeyboardInterrupt, e:
 print >> sys.stderr, "\n\nExiting on user cancel."
 sys.exit(1)

Si os fijáis, nuestro error se da en este preciso archivo, ya que falla una excepción con el ImportError. Y en la primera línea tenemos un:

#!/usr/bin/python

Basta con cambiar esa línea para decirle al script que ejecute una versión antigua de python (la que funcionaba) de nuestro sistema. Es decir, cambiar (en mi caso a python 2.4):

#!/usr/bin/python2.4

Y listo, yum funcionará sin problemas. Obviamente, con un mejor análisis de la situación, se podría hacer que yum cogiera realmente la última versión de python y sus bibliotecas (probablemente por el path), pero eso requiere de mayor trabajo y tiempo y para mí esta solución fue valida. Sin embargo, si alguien esta dispuesto a comentar una mejor solución, estaré agradecido.

Auto channel updater for Tivion

I am working on the next version of Tivion (called Nepiron), that for the moment it’s a bugfix release with some interesting features.

The release is dated for some months ago, but I am a little busy with the homework from university, participating on new CULS5 (with a new project, still unrevealed), developing my own game with my friends, collaborating as main developer on some open source projects and managing my own hosting company. So patience, I am working on my spare time (mostly on lately night, when the normal people sleep).

On previous nights, I worked on real support for maverick release on Ubuntu (it works on development version, but need a .deb binary), add/modify some channels, and the most important feature, doing a auto channel updater for Tivion.

On previous releases, I update the list channel each time, but honestly my releases are not very often. So I get some emails requesting updates for channels, or making a automatic updater.

That’s was easy with Python, I use the bazaar repository with the last url commited. Then, I get the last channels commited when I want, for release only the new channels at time. So, Tivion only check the url with a timestamp (Unix formatted date) and if the timestamp is more recent, just grab the new channels.

If you get the development version of Tivion, each time that you start Tivion, you get the last list of channels avaliable. But not all it’s party. I still need refresh the channels on the GUI, show a popup notification or make a option on preferences for enable/disable the auto channel updater, manual updater (some ideas more are welcome).

So stay tuned for updates, the fun is coming!

Como usar bibliotecas de C en Python

Para determinadas aplicaciones, la eficiencia y el rendimiento es clave. Python es un buen lenguaje para programar rápido y mucho en pocas líneas, pero a veces queremos bajar más de nivel para ofrecer mejores prestaciones.

Pero esta decisión no debe implicar, perder nuestra comodidad que tenemos con Python. Existe una biblioteca incluida nativamente desde Python 2.5 llamada ctypes que nos permite utilizar funciones y bibliotecas compartidas de C (en cualquier sistema operativo) obteniendo la eficiencia del lenguaje C pero sin renunciar a las bondades de sintaxis de Python.

Ejemplo práctico y sencillo

Veamos un ejemplo sencillo para ilustrar esta gran funcionalidad. Para empezar podemos crear un simple archivo de código fuente en C y por ejemplo llamarlo ‘libtest.c’.

Por ejemplo, en esta biblioteca C, haremos una simple función que multiplique enteros:

int multiply(int num1, int num2)
{
    return num1 * num2;
}

Ahora necesitaremos compilar nuestra biblioteca ‘libtest.c’ en una biblioteca válida, para ello utilizaremos los siguientes comandos de compilación:

gcc -c -fPIC libtest.c
gcc -shared libtest.o -o libtest.so

Ello creara una versión final de la biblioteca para GNU/Linux llamada libtest.so que podamos usar en Python.

Ahora probemos nuestra biblioteca (debes poner el path o camino de libtest.so en el código para que funcione o incluirlo en las rutas donde GNU/Linux buscara las bibliotecas comunes):

# A partir de Python >= 2.5 se incluye la libreria *ctypes* en el core, comprobar si esta disponible
import sys
try:
    from ctypes import *
except ImportError:
    print 'ERROR! La biblioteca *ctypes* para Python no esta disponible.'
    sys.exit(-1)

libtest = cdll.LoadLibrary('ruta_a_la_biblioteca/libtest.so')
print 'La multiplicación de 2 * 2 es:', libtest.multiply(2, 2)

Este ejemplo imprimirá 4 si todo ha ido correctamente. Como se aprecia, no es nada complicado usar código C nativo en Python.

Ejemplo con parámetros

Podemos crear ejemplos más complejos, incluso con funciones que tengan argumentos como punteros o pasados por referencia. Por ejemplo una lista donde se sumen todos los valores, su media:

/* suma de una lista de valores */
double sum(double *data, int n)
{
    int i=0;
    double sum=0.0;

    for (i=0; i < n; i++)
        sum += data[i];
    return sum;
}

/* media de una lista de valores */
double mean(double *data, int n)
{
    double s = sum(data, n);
    return s/((double)n);
}

Lo compilamos de nuevo con:t:

$ gcc -shared -fPIC liblist.c -o liblist.so

Y en python de nuevo usamos ctypes:

from ctypes import *
so = CDLL("liblist.so")

# Establecemos las interfaces con los argumentos

# y los valores que devuelven
so.mean.argtypes= [POINTER(c_double), c_int]
so.mean.restype = c_double
so.sum.argtypes = [POINTER(c_double), c_int]
so.sum.restype = c_double

# Llamamos a las funciones
def cmean(self, dlist):
    doubleArray = c_double*len(dlist) # Tipo de dato (double[n])
    cx = doubleArray(*dlist) # Array actual
    n = len(cx) # Longitud del dato

    result = so.mean(cx, n)
    return float(result)

def csum(self, dlist):
    doubleArray = c_double*len(dlist)
    cx = doubleArray(*dlist)
    n = len(cx)

    result = so.sum(cx, n)
    return float(result)

# Ahora podemos usar estas funciones como si fuera python puro!
data = [1,2,3,4,5,6]
print cmean(data)
print csum(data)

Con ctypes podemos crear un wrapper (envoltura o adaptador) para una biblioteca matemática u otras funciones que nos interesen.

Ejemplo con MPI

Otro ejemplo práctico sería poder escribir MPI en python desde C, como el ejemplo que escribí hace unos días. Notad que ya existen implementaciones python de MPI, pero nunca esta demás saber como funcionan y que principios siguen, por ejemplo para iniciarse en openMPI desde python, podríamos hacer:

#!/usr/bin/python

import sys

try:
from ctypes import CDLL, pythonapi, c_int, POINTER, c_char_p, byref, RTLD_GLOBAL
from ctypes.util import find_library
except ImportError:
print 'ERROR! La biblioteca *ctypes* para Python no esta disponible!'
sys.exit(-1)

libc = CDLL('libc.so.6')

print libc._handle, libc._name

f = pythonapi.Py_GetArgcArgv
argc = c_int()
argv = POINTER(c_char_p)()
f(byref(argc), byref(argv))

mpi = CDLL(find_library('mpi'), RTLD_GLOBAL)
print mpi._handle, mpi._name

libc.printf("Hola mundo");

mpi.MPI_Finalize()

En este ejemplo, utilizo el método find_library() de ctypes que me permite olvidarme de localizar la ruta de una biblioteca y así buscar por si mismo el programa su ruta. Se importa la biblioteca de C y la de MPI y se hace un simple hola mundo mostrando algunos datos sobre las bibliotecas también. Para ctypes únicamente he importando las funciones necesarias, evitando que se cargue toda la biblioteca.

En definitiva ctypes es una potente herramienta que todo desarrollador Python debería tener en cuenta cuando quiera realizar desarrollos más eficientes y aprovechar implementaciones de otras bibliotecas compartidas.