Latest entries

Testear WebServices Restful con curl

written by uve

29 October 2012

Para un proyecto que estoy desarrollando ahora mismo, he necesitado montar unos WebServices con Rest, usando JSON. La forma más rápida de testearlo es utilizando curl. Para ello podemos utilizar el siguiente comando para simular una petición GET. Esto nos mostrará algo parecido a lo siguiente:

$ curl -v -H "Content-Type: application/json" -H "Accept: application/json" -X GET  http://localhost:8888
* About to connect() to localhost port 8888 (#0)
*   Trying 127.0.0.1... connected
> GET / HTTP/1.1
> User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
> Host: localhost:8888
> Content-Type: application/json
> Accept: application/json
>
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Date: Mon, 29 Oct 2012 21:48:49 GMT
< Server: WSGIServer/0.2 Python/3.2.3
< Content-Type: application/json; charset=utf-8
< Content-Length: 159
<
* Closing connection #0
{"respuesta": "en json"}

Ahora vamos a suponer un WebService que cree un usuario. Para ello, recibe 'username', 'password' y 'email'. Para la creación se va a utilizar el método POST. Y esto debe mostrarnos algo similar:

$ curl -v -H "Content-Type: application/json" -H "Accept: application/json" -X POST -d '{"username":"myuser", "password":"mypwd", "email":"myemail@mytest.com"}' http://localhost:8888
* About to connect() to localhost port 8888 (#0)
*   Trying 127.0.0.1... connected
> POST / HTTP/1.1
> User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
> Host: localhost:8888
> Content-Type: application/json
> Accept: application/json
> Content-Length: 69
>
* upload completely sent off: 69out of 69 bytes
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Date: Mon, 29 Oct 2012 21:52:47 GMT
< Server: WSGIServer/0.2 Python/3.2.3
< Content-Type: application/json; charset=utf-8
< Content-Length: 43
<
* Closing connection #0
{"respuesta": "en json"}

Además, podemos aprovechar para testear métodos HTTP que no estén implementados. Supongamos que PUT no está implementado, entonces el resultado deberá ser 'Method not allowed':

$ curl -v -H "Content-Type: application/json" -H "Accept: application/json" -X PUT -d '{"...":"..."}' http://localhost:8888
* About to connect() to localhost port 8888 (#0)
*   Trying 127.0.0.1... connected
> PUT / HTTP/1.1
> User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
> Host: localhost:8888
> Content-Type: application/json
> Accept: application/json
> Content-Length: 69
>
* upload completely sent off: 69out of 69 bytes
* HTTP 1.0, assume close after body
< HTTP/1.0 405 METHOD NOT ALLOWED
< Date: Mon, 29 Oct 2012 21:55:36 GMT
< Server: WSGIServer/0.2 Python/3.2.3
< Content-Type: text/html; charset=utf-8
< Allow: GET, POST
< Content-Length: 0
<
* Closing connection #0

Por otro lado, también podemos probar que no se soporta una respuesta en algo que no sea json, por ejemplo text/html. Y como resultado obtendremos un 'Unsoported media type':

$ curl -v -H "Content-Type: application/json" -H "Accept: text/html" -X GET  http://localhost:8888
* About to connect() to localhost port 8888 (#0)
* Trying 127.0.0.1... connected
> GET / HTTP/1.1
> User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
> Host: localhost:8888
> Content-Type: application/json
> Accept: text/html
>
* HTTP 1.0, assume close after body
< HTTP/1.0 415 UNSUPPORTED MEDIA TYPE
< Date: Mon, 29 Oct 2012 22:00:34 GMT
< Server: WSGIServer/0.2 Python/3.2.3
< Content-Type: text/html; charset=utf-8
< Content-Length: 0
<
* Closing connection #0

 

Full entry >>

Preparar un sitio en construcción con Apache2

written by uve

28 October 2012

Cuando tenemos un sitio en construcción, en el cuál sólo tenemos una pantalla de presentación, puede interesarnos que todas las peticiones redirijan a la página principal.

Para ello podemos utilizar mod_rewrite, el cuál ya se ha comentado antes en este blog. En principio se puede pensar que bastaría con:

RewriteEngine on
RewriteRule ^/(.+)$ / [R=302,L]

Con esto estamos indicando a Apache2 que cualquier cosa que no sea la raíz, ^/(.+)$, debe ser redirigido a , /, usando el código de redirección 302. El problema es que si enlazamos con algún estático: css, javascript, imágenes, ..., también será redirigido a la raíz.

Este comportamiento no nos interesa, así que vamos a añadir una condición. Suponiendo que todos nuestros estáticos están en /static/, bastará con añadir lo siguiente:

RewriteEngine on
RewriteCond %{REQUEST_URI} !^/static/
RewriteRule ^/(.+)$ / [R=302,L]

Full entry >>

Exportar el código fuente de Eclipse a PDF

written by uve

17 October 2012

Hoy me ha llamado un cliente que quiere exportar todo el código fuente de una aplicación Android, desarrollada con Eclipse, a un fichero PDF.

La primera opción que puede venir a la cabeza es imprimir cada uno de los archivos fuente y después concatenarlos todos, pero comprenderéis el proceso es demasiado repetitivo.

Así que me he puesto manos a la obra y de forma breve podemos hacer todo el proceso. Lo primero que necesitamos es instalar la utilidad enscript:

$ sudo apt-get install enscript

Una vez tenemos el comando listo, vamos a exportar todos los ficheros .java:

$ cd /directorio/del/proyecto/eclipse/
$ enscript -r -2 --file-align=2 --highlight --line-numbers -o - `find . -name '*.java'` | ps2pdf - files.java.pdf

Además, para proyectos Android es importante exportar las interfaces y los permisos (el manifiesto):

$ enscript -r -2 --file-align=2 --highlight --line-numbers -o - `find . -name '*.xml'` | ps2pdf - files.xml.pdf

De este modo tenemos dos ficheros con los fuentes java, files.java.pdf, y otro con los archivos xml, files.xml.java. Podemos unirlos de la siguiente forma:

$ gs -q -dNOPAUSE -sDEVICE=pdfwrite  -dBATCH -sOutputFile=files.pdf files.java.pdf files.xml.pdf

Full entry >>

Catalog "SA" cannot be resolved for table xxx

written by uve

2 August 2012

Utilizando JPA en Eclipse para almacenar en HSQLDB me he encontrado con el siguiente error:

Catalog "SA" cannot be resolved for table xxx

Para solucionarlo, vamos a las Propiedades de nuestro proyecto, en el apartado JPA y sobreescribimos el catálogo de la conexión activa. En HSQLDB es PUBLIC.

Full entry >>

Patrón Singleton en Python3

written by uve

17 July 2012

Existen distintas alternativas para implementar este patrón en Python. Una de ellas consiste en el uso de metaclass, que es la que vamos a ver a continuación. Para ello, es necesario definirnos un nuevo tipo:

class SingletonMetaClass(type):
    def __init__(cls,name,bases,dic):
        super(SingletonMetaClass, cls).__init__(name, bases, dic)
        cls._singleton_instance = None

    def __call__(cls,*args,**kw):
        if cls._singleton_instance is None:
            cls._singleton_instance = \
                super(SingletonMetaClass, cls).__call__(*args, **kw)
        return cls._singleton_instance

Así, nuestra clase SingletonMetaClass será un nuevo tipo, hereda de type, por lo que podemos utilizarlo para la construcción de nuestras clases, como por ejemplo:

class Singleton(metaclass=SingletonMetaClass):
    pass

Así, la construcción de objetos del tipo Singleton están controlados por SingletonMetaClass. A partir de este punto, todas aquellas clases que tengamos interés en que sigan este patrón heredarán de la clase Singleton.

Veamos un ejemplo:

>>> class ExampleNoSingleton(): pass
...
>>> ExampleNoSingleton()
<__main__.ExampleNoSingleton object at 0x7fec6bf2f110>
>>> ExampleNoSingleton()
<__main__.ExampleNoSingleton object at 0x7fec6bf2f1d0>
>>> ExampleNoSingleton()
<__main__.ExampleNoSingleton object at 0x7fec6bf2f110>
>>>
>>> class ExampleSingleton(Singleton): pass
...
>>> ExampleSingleton()
<__main__.ExampleSingleton object at 0x7fec6bf2f210>
>>> ExampleSingleton()
<__main__.ExampleSingleton object at 0x7fec6bf2f210>
>>> ExampleSingleton()
<__main__.ExampleSingleton object at 0x7fec6bf2f210>
>>>

Full entry >>

Cómo simular un módulo en Python

written by uve

16 July 2012

Ahora mismo estoy diseñando unos tests para el Trabajo Fin de Máster y me he visto en la necesidad de hacer que un objeto simule un módulo Python, para que valide el método ismodule de inspect. Por ejemplo:

>>> import sys
>>> import inspect
>>> inspect.ismodule(sys)
True
>>>

Para conseguir pasar esta validación, necesitamos que nuestro objeto herede de types.ModuleType:

>>> import types
>>> class Module(types.ModuleType):
...  pass
...
>>> m = Module('ModuleName')
>>> inspect.ismodule(m)
True
>>>

Full entry >>

Python re: bad character range

written by uve

12 July 2012

Trabajando con expresiones regulares, acabamos de encontrarnos con un "bad character range". Queremos una expresión que sea capaz de reconocer secuencias de letras, guiones y '+'. Así se podrían reconocer patrones como 'xhtml+xml', 'html' ó 'x-dvi'.

Supongamos la siguiente expresión r'[\w-\+]+', que parece completamente válida. Pues este es el resultado:

>>> re.compile('[\w-\+]+')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.2/re.py", line 206, in compile
    return _compile(pattern, flags)
  File "/usr/lib/python3.2/re.py", line 255, in _compile
    return _compile_typed(type(pattern), pattern, flags)
  File "/usr/lib/python3.2/functools.py", line 184, in wrapper
    result = user_function(*args, **kwds)
  File "/usr/lib/python3.2/re.py", line 267, in _compile_typed
    return sre_compile.compile(pattern, flags)
  File "/usr/lib/python3.2/sre_compile.py", line 491, in compile
    p = sre_parse.parse(p, flags)
  File "/usr/lib/python3.2/sre_parse.py", line 692, in parse
    p = _parse_sub(source, pattern, 0)
  File "/usr/lib/python3.2/sre_parse.py", line 315, in _parse_sub
    itemsappend(_parse(source, state))
  File "/usr/lib/python3.2/sre_parse.py", line 457, in _parse
    raise error("bad character range")
sre_constants.error: bad character range

El caracter '-' se puede utilizar dentro de los corchetes [ ], como carácter a reconocer. El problema es que si está separando dos caracteres, \w y \+, asume que es un rango.

Distintas soluciones:

>>> re.compile('[\w\+-]')
<_sre.SRE_Pattern object at 0x7fd793a5daf8>
>>> re.compile('[-\w\+]')
<_sre.SRE_Pattern object at 0x7fd793a5dd20>
>>> re.compile('[\w\-\+]')
<_sre.SRE_Pattern object at 0x7fd793a5ddd8>
>>>

Full entry >>

Simular enumeraciones en Python

written by uve

14 May 2012

Estoy ahora mismo trabajando con Python y me acabo de encontrar que disponer de una enumeración me vendría muy bien. Así que, después de investigar un rato, he encontrado dos formas distintas y muy prácticas para hacer enumeraciones.

Estilo C

La primera opción, es hacerlas como se hacen en C. Variables enteras globales:

(GATEWAY_CLASS, FORWARDING_CLASS, PARSE_CLASS) = range(1, 4)

El problema de esta solución, es que en cualquier momento se puede modificar el valor de cualquiera de estas variables, con las consecuencias que esto conlleva.

Estilo Java

En Java, cuando declaramos una enumeración, debemos acceder a través del nombre de la enumeración. Por tanto, para simular este comportamiento en Python, necesitamos una clase:

class RoutingClassType(type):
    (GATEWAY_CLASS,
        FORWARDING_CLASS,
        PARSE_CLASS) = range(1, 4)

Así, ahora tendríamos que acceder así:

RoutingClassType.GATEWAY_CLASS

Aunque esta solución sigue presentando el mismo problema que la solución anterior, lo podemos solucionar creando un nuevo tipo que impida modificar sus atributos:

class EnumType(type):
    def __setattr__(self, name, value):
        raise ValueError

Y ahora bastará con definir nuestra enumeración de la siguiente forma:

class RoutingClassType(type):
    __metaclass__ = EnumType
   
    (GATEWAY_CLASS,
        FORWARDING_CLASS,
        PARSE_CLASS) = range(1, 4)

Full entry >>

SystemError: error return without exception set

written by uve

11 April 2012

Esto se puede deber a que se ha devuelto NULL en una función en la que se debería devolver algo (None por ejemplo):

static PyObject*
example(PyObject *self, PyObject* args, PyObject* kwargs)
{
    // do something
    return NULL;
}

se corrige de la siguiente forma:

static PyObject*
example(PyObject *self, PyObject* args, PyObject* kwargs)
{
    // do something
    Py_RETURN_NONE;
}

o porque al lazar una excepción, no hemos indicado de que excepción se trata:

static PyObject*
example(PyObject *self, PyObject* args, PyObject* kwargs)
{
    PyObject* var;
    // ...
    if(!PyBool_Check(var))
    {
        return NULL;
    }
}

y se corrige:

static PyObject*
example(PyObject *self, PyObject* args, PyObject* kwargs)
{
    PyObject* var;
    // ...
    if(!PyBool_Check(var))
    {
        PyErr_SetString(PyExc_TypeError, "Not boolean");
        return NULL;
    }
}

Full entry >>

npm: Error: Required package: options(latest) not found. (Found: ["0.0.3"])

written by uve

7 April 2012

Hace unos días que descubrí substance.io y estos días me he decidido a instalarlo. A la hora de instalar unos módulos para Node.js con el comando npm me he encontrado con este error:

npm ERR! install failed Error: Required package: options(latest) not found. (Found: ["0.0.3"])
npm ERR! install failed (required by: ws@0.4.12)
npm ERR! install failed     at /usr/share/npm/lib/build.js:192:19
npm ERR! install failed     at cb (/usr/share/npm/lib/utils/graceful-fs.js:32:9)
npm ERR! Error: Required package: options(latest) not found. (Found: ["0.0.3"])
npm ERR! (required by: ws@0.4.12)
npm ERR!     at /usr/share/npm/lib/build.js:192:19
npm ERR!     at cb (/usr/share/npm/lib/utils/graceful-fs.js:32:9)
npm ERR! Report this *entire* log at <http://github.com/isaacs/npm/issues>
npm ERR! or email it to <npm-@googlegroups.com>
npm ERR! Just tweeting a tiny part of the error will not be helpful.
npm not ok

Parece que el problema está en la versión de npm que viene instalada en Ubuntu, que está desactualizada. Así que hay que desinstalar el que viene en repositorios e instalarlo directamente.

Para simplificar el proceso podemos usar este script. Es necesario tener instalado curl.

Full entry >>

¿Cómo utilizar TCP_NODELAY?

written by uve

2 April 2012

Llevaba cerca de dos días con un problema implementando el subscriptor MQTT. Aún no está hecho el diagrama de flujo ya que de momento estoy probando que las llamadas de la biblioteca funcionan. El escenario es el siguiente:

  1. mqtt_connect
  2. mqtt_subscribe
  3. mqtt_unsubscribe
  4. mqtt_disconnect

Conectamos el cliente, nos subscribimos a un topic, nos desubscribimos y desconectamos el cliente. Algo que a priori es sencillamente elemental.

Para comprobar que todo esto funciona he hecho uso del script para Wireshark que ya comenté. Pero el caso es que estaba encontrando errores en Wireshark que no eran lógicos. Yo mandaba un paquete de 17bytes y Wireshark decía que el paquete tenía 19bytes. ¿Qué estaba pasando aquí?

Full entry >>

Synaptic: No se pudieron analizar o abrir las listas de paquetes o el archivo de estado

written by uve

1 April 2012

Al abrir Synaptic me he encontrado con el siguiete error:

E: Encountered a section with no Package: header
E: Problem with MergeList /var/lib/apt/lists/archive.ubuntu.com_ubuntu_dists_precise-security_main_binary-i386_Packages
E: No se pudieron analizar o abrir las listas de paquetes o el archivo de estado.
E: _cache->open() failed, please report.

La solución:

$ sudo rm /var/lib/apt/lists/archive.ubuntu.com_ubuntu_dists_precise-security_main_binary-i386_Packages

Full entry >>

Bindings Python para bibliotecas C: Argumentos (Parte 4)

written by uve

28 March 2012

Continuando con el ejemplo de ayer, hoy voy a explicar cómo podemos parsear los parámetros de entrada. El estado actual es que hemos definido unos prototipos y los hemos añadido al módulo. Ahora vamos a darle contenido a las funciones add y hello.

Ejemplo en GitHub: mema_methods.

Full entry >>

Argumentos en Python

written by uve

28 March 2012

Para los programadores de C, C++, Java, ... puede resultar un tanto extraño la forma de gestionar los parámetros que tiene Python.

Voy a explicar en esta entrada los tipos de parámetros y cómo podemos hacer uso de ellos.

Full entry >>

Bindings Python para bibliotecas C: Métodos (Parte 3)

written by uve

27 March 2012

Ayer explicaba cómo se monta una estructura básica para crear un módulo. Pero para que el módulo sirva para algo, tendremos que añadir funciones.

Ahora vamos a ver cómo podemos crear nuevas funciones y cómo integrarlas al módulo mema. El objetivo para hoy será crear dos funciones: hello y add.

El resultado debería ser algo similar a lo siguiente:

>>> import mema
>>> mema.hello()
Hello mema!
>>> mema.hello('Vicente')
Hello Vicente!
>>>
>>> from mema import add
>>> add(1, 2)
3
>>> add(400, 4)
404
>>>

Ejemplo en GitHub: mema_methods.

Full entry >>

La teoría es cuando crees saber algo, pero no funciona.
La práctica es cuando algo funciona, pero no sabes por qué.
Los programadores combinan la teoría y la práctica:
Nada funciona y no saben por qué.