Reduce el tamaño de un pdf con páginas escaneadas

Un fichero pdf puede ser muy útil y ligero, siemre y cuando el contenido no sean imágenes escaneadas, es necesario recomprimir esas imágenes y volver a montar el pdf.

Como solución sorprendente he usado este par de comandos que unidos reducen el tamaño una proporción brutal. En un ejemplo real de 35 Mb a 1,8Mb y de 59Mb a 2,3Mb

Tan solo cambia el fichero de input.pdf con el nombre de tu fichero, se generara un fichero medium.pdf y un fichero small.pdf. Elije al gusto.

gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=/screen -dNOPAUSE -dQUIET -dBATCH -sOutputFile=medium.pdf input.pdf
ps2pdf medium.pdf small.pdf

15 estrategias de éxito para timeboxing

Por decirlo simplemente, timeboxing es la herramienta de gestión del tiempo más efectiva que conozco. Incluso si ya la conoces y la usas hasta cierto punto, hay una buena posibilidad de que aún puedas hacerlo mejor con algunos de los siguientes consejos.

Para quienes son nuevos, “timeboxing” es simplemente fijar un período de tiempo para trabajar en una tarea o grupo de tareas . En lugar de trabajar en una tarea hasta que finalice, te comprometes a trabajar en ella durante un período de tiempo específico.

Pero no dejes que la simplicidad del concepto te engañe, hay mucho más en esta herramienta de lo que parece.

Mucha gente ya escribió sobre esto (revisa a Dave Cheong para un buen comienzo, así como a JD Meier[1] y Steve Pavlina[2]). Aunque estos chicos hicieron un gran trabajo al presentarlo, el “timeboxingme ha ayudado tanto que decidí compartir 15 formas específicas en que puede ayudarlo a ser más productivo. Aquí están:

1. Atrévete con tareas grandes

El uso más obvio de un ‘timebox es avanzar en tareas grandes. Por un lado, te permite progresar continuamente en estas tareas intimidantes. Por otro lado, te asegura que trabajar en estas tareas no sobrecargará el resto del día.

2. Desházte de ‘Tareas de mosquitos’

Los ‘timeboxes son una gran manera de abordar esas molestas y pequeñas tareas que siguen molestandote. El problema con estas pequeñas tareas molestas es que cada una de ellas, por sí sola, puede considerarse lo suficientemente insignificante como para ser aplazada. Después de un tiempo, sin embargo, hay suficientes para drenar una cantidad significativa de tu energía mental. Una buena estrategia para recuperar esa energía es crear un ‘timeboxy abordarlas a todas de una sóla vez.

3. Superar la procrastinación

Si te estás escaqueando de una tarea, olvídate de completarla: simplemente colócala en un ‘timebox. Así superas tu resistencia hacia la tarea y es probable que cuando se acabe el tiempo hayas desarrollado el impulso suficiente para seguir trabajando en ella durante más tiempo.

Así es, si la pereza es tu problema, no dudes en ignorar el temporizador cuando suene. Eso es lo que yo llamo ‘open timebox: establece un período mínimo de trabajo, que puedes extender a tu gusto. Para este tipo de ‘timebox’, me gusta configurar mi temporizador con una ronda de aplausos[3] como un pequeño incentivo para seguir adelante.

4. Conquista el perfeccionismo

El perfeccionismo es la otra cara de la procrastinación. En lugar de evitar una tarea, la dedicas tanto tiempo que cuando te das cuenta, todo tu tiempo se ha ido. Para evitar el perfeccionismo y los efectos de los rendimientos decrecientes, tener una hora de corte definida para una tarea es una de las mejores estrategias que puede usar.

Lidiar con el perfeccionismo exige lo que yo llamo ‘closed timebox’: establecer un período máximo de trabajo . Cuando se trata de estos ‘timebox’, me gusta configurar mi temporizador con un zumbido perturbador y molesto[4] para recordarme que deje la tarea inmediatamente.

5. Define tu enfoque

El ‘timebox’ de una tarea en particular ayuda a excluir otras tareas y pensamientos no relacionados de tu radar durante el tiempo que dura el ‘timebox’. Reducir el desorden mental es esencial si quieres ser completamente productivo.

Además, al organizar tu trabajo en ‘timeboxes’ tienes la estructura que necesitas para prepararte adecuadamente para tus tareas. Evitar distracciones de antemano, maximiza tus posibilidades de obtener ‘flow’.

6. Aumentar la eficiencia

¿No es verdad que obtienes mucho más en uno de esos viernes previos a vacaciones que en cualquier otro día normal de trabajo? Por alguna razón, parece que nuestro trabajo más eficiente generalmente se realiza al final de un período de tiempo cuando hay un ‘deadline’ muy bien definido.

Los ‘timeboxes’ te presionan de lo suficiente de una forma saludable, lo que te permite aprovechar al máximo este ‘efecto entrega‘, así que asegúrate de que el temporizador está visible y de que puedes ver el tiempo mientras trabajas en tu tarea.

7. Impulsa la motivación

Las grandes tareas, sin importar cuán importantes sean, pueden ser desmotivantes: simplemente necesitas trabajar durante demasiado tiempo para ver los resultados. Es posible que prefiramos retrasar tareas importantes, de modo que trabajemos en muchas tareas rápidas y sencillas, sólo por la falsa percepción de logro.

Pero al igual que el simple hecho de tachar los elementos de tu lista de tareas puede ser motivador, por lo que se completa con éxito un ‘timebox’. Completar un ‘timebox’ funciona como un signo visible de progreso.

Otra idea sobre cómo usar los ‘timeboxes’ para aumentar la motivación es hacer un juego o desafío: ¿Cuántos logros puede alcanzar durante una hora? ¿Por qué no intentar batir tu propio récord?

8. Trabajar en ‘Fuzzy Goals’

Aunque algunas personas quieran criticarme por esto, no estoy de acuerdo en que deberíamos tener objetivos SMART[5] para todo. SMART del ingles, que significa «Specífic (específico, concreto), Mesaurable (se puede medir), Achievable (se puede lograr), Realist (genera el impacto deseado)  y Timed (limitado en el tiempo).

A veces disfruto la libertad de un resultado abierto. A veces solo quiero mejorar algo, no hay un objetivo específico y preciso en mente. Este ha sido especialmente el caso desde que empecé a experimentar con objetivos más pequeños y graduales). Creo que es saludable no ser 100% objetivo todo el tiempo.

Dicho esto, no puedes permitirte que estos relaxed goals superen tu plan diario; ya sabes, cuando realmente necesites estar completamente concentrado y tienes plazos usa SMART. Define tus ‘fuzzy goals’ en un ‘timebox’ y obtén lo mejor de ambos mundos.

9. Exploraciones creativas iniciales

Los proyectos que requieren una gran cantidad de creatividad no se abordan mejor de principio a fin. La manera más efectiva de lidiar con un proyecto como este es tener una fase inicial de inmersión, un período en el que generas una ráfaga de ideas, y luego olvidarte de ellas por un tiempo. Dejándolo ir, le da tiempo a la mente subconsciente para trabajar en el problema.

Esta fase inicial de lluvia de ideas ‘brainstroming’ es un candidato perfecto para el ‘timeboxing’ ya que generalmente no hay un resultado preciso para él. (A menos que defina un resultado preciso para el proceso creativo, como en una Lista de 100[6] o Cuota de idea[7] ).

10. Aumentar la conciencia del tiempo

¿Cuántas veces te has preguntado al final del día a dónde se fue todo tu tiempo? Como el lector Iain Hamp[8] sugirió en un comentario[9], realizar auditorías de tiempo es una actividad extremadamente valiosa para diagnosticar su tiempo, así como para alinear su tiempo y valores. La estructuración de ‘timeboxes’ diarias hace que estas auditorías sean súper fáciles de hacer.

Además, ser más consciente de cuánto puedes hacer en tu espacio de tiempo es liberador, ya que le ayuda a decir «no» a cosas sin importancia con más frecuencia.

11. Crea un ritmo de trabajo

Solo obtienes la máxima eficacia si equilibras adecuadamente los períodos de trabajo y descanso. Los ‘timebox’ proporcionan un gran marco para permitir que este equilibrio suceda. La clave es encontrar tu propio ritmo.

Alternar entre diferentes tipos de ‘timeboxes’ (como trabajo / descanso o tareas difíciles / sencillas) maximiza el uso de energía y le permite lograr mucho más.

Mi ritmo de trabajo favorito es alternar entre bloques de 50 minutos de trabajo y 10 minutos de descanso[10]. Para sprints rápidos, Merlin Mann es notablemente efectivo (10 + 2) * 5 hack[11] es también una gran opción.

Si está interesado en una discusión más profunda sobre diferentes patrones de ráfagas de tiempo, recomiendo el libro de Mark Forster Get Everything Done y Still Have Time to Play[12].

12. Enfócate en finalizar una tarea significativa

Trabajar en tus proyectos más importantes a primera hora de la mañana es un consejo clásico para garantizar que finalizarás un trabajo significativo ese día. Crea un ‘timebox’ para dedicar a tus sueños todos los días, antes de que el mundo tenga la oportunidad de interrumpir sus planes.

Si no planeas utilizar ‘timebox’ para nada más, considera aplicar sólo este consejo. Esto es quizás lo único y más efectivo que puedes hacer para conseguir tus sueños.

13. Equilibra tu vida

Es común enfocarse demasiado en un área específica de nuestras vidas a expensas de los demás.

Recuerda, que no necesitas usar el ‘timebox’ sólo para tareas relacionadas con el trabajo: puedes bloquear el tiempo para cualquier cosa que te importe: ocio, familia, pasatiempos, cualquier cosa.

La planificación previa de ‘timeboxes’ para las cosas que más te importan es una excelente estrategia para llevar a vida equilibrada. De hecho, estos ‘timeboxes’ pre-planificados son el corazón del sistema de priorización que uso. Planeo explorarlo más profundamente en un nuevo artículo.

14. Evita que se te vaya el tiempo

Ya sabes de lo que estoy hablando: foros, navegar por la web, juegos, noticia, correo electrónico, todo el mundo parece estar perdiendo el tiempo en su vida. StumbleUpon[13] , ¿alguien? 🙂

Deja de perjudicarte a tí mismo; todo lo que necesitas hacer es colocar un ‘timebox’ a tu alrededor para recuperar el tiempo perdido.

15. Recompénsate

Si relacionas tus recompensas con la finalización de las tareas, es posible que te encuentres realizando sólo tareas rápidas y sencillas, y evitas las más importantes. ¿Por qué no obtener una pequeña recompensa después de completar un ‘timebox’?

Un ejemplo personal: revisar el correo electrónico varias veces al día es una vieja costumbre que todavía no he logrado curar. Si bien la solución ideal sería la tarea de verificar el correo electrónico en un ‘timebox’, ahora lo uso como una recompensa por completar ‘timebox’: ¡un incentivo adicional que funciona de maravilla!

Las recompensas pueden ser tan pequeñas como un vaso de agua o una respiración profunda en la ventana (para obtener más información sobre pequeñas recompensas y su poderoso efecto, recomiendo el capítulo «Otorgar pequeñas recompensas» en un pequeño paso que puede cambiar tu vida[14] – ver el libro completo resumen[15]).

¿Que pasa contigo?

Si aún no usas ‘timebox’, pruébalo.

Si no tiene un temporizador, puedo recomendarte algunos: dado que paso la mayor parte del día en el ordenador, uso principalmente la minúscula y superfuncional aplicación en mi escritorio Egg[16] y Timekeeper[17] en mi PDA cuando estoy fuera del ordenador. Para una solución gratuita, multiplataforma y basada en navegador, puede usar Virtual StopWatch[18] . También puedes usar temporizadores de cocina regulares[19], he visto que el modelo Ultrak T-2 se recomienda en alguna parte.

¿Y tú, ya usas ‘timebox’? ¿Cuál es tu experiencia? ¿Tienes algún otro uso específico? ¿Tienes algún temporizador específico para recomendar? ¿Estás tan entusiasmado con ‘timeboxing’ como yo? ¡Por favor comparte sus pensamientos en los comentarios!

Fuentes y enlaces

Traducción de fuente original: https://litemind.com/time-boxing/

Solucionar problema de módulo no encontrado

Esto me ha vuelto a pasar hoy , tengo un módulo en desarollo y quiero importar el módulo fuera de un directorio donde tengo acceso directo al módulo. Pues una opción es instalar el módulo para que el interprete sepa que hay un módulo con ese nombre, y la otra es agregar la ruta desde la que se puede acceder a ese módulo en la lista de sys.path

import os
import sys
self_path = os.path.dirname(os.path.realpath(__file__))
sys.path.append("{}/../../".format(self_path))

Funciona bien bien

python requirements using git

En algunos proyectos actualmente estoy usando un repo de git como dependencia, ya sea por que es un repo privado o por que no está disponible en pypi.

Cómo se indica una dependencia en requirements.txt:

git+https://github.com/jsenin/pythondependency.git#egg=module
git+https://github.com/jsenin/pythondependency.git@<branch>#egg=module
git+https://github.com/jsenin/pythondependency.git@<commit_hash>#egg=module

Hay que tener en cuenta que si es una dependencia que vamos a editar tenemos que instalarla con ‘-e’

-e git+https://github.com/jsenin/pythondependency.git#egg=module

Para instalar las dependencias usamos pip

pip install -r requirements.txt

Otra forma de instalar estos paquetes es usando setup.py y dependencias. Bien, hay que tener en cuenta que usando el típico script setup.py que usa setuptools (distutils están obsoletas)  instala dependencias y tiene dos modos: python setup.py install y python setup.py develop. La diferencia es que install instala los paquetes sin que sean editables y con develop sí son editables. Además no se genera el wheell ( paquete de instalación ) cosa que con pip sí se hace, con lo que la desintalación es sencilla usando el propio pip. Por otro lado las setuptools generan directorios egg que habrá que borrar a mano si queremos desinstalar. 

Existe una opción de borrar los paquetes instalados con setuptools en modo develop

python setup.py develop --uninstall

blueman.bluez.errors.DBusFailedError: Protocol not available

Al intentar vincular por bluethooth un dispostivo de audio aparece el error

blueman.bluez.errors.DBusFailedError: Protocol not available

Seguramente necesitas instalar un paquete de pulseaudio


sudo apt-get install pulseaudio-module-bluetooth

Necesitarás reiniciar el servicio de pulseaudio

pulseaudio -k

Debería arrancar de nuevo automáticamente el servicio y comenzar a usar el módulo bluetooth

Refernecias: https://github.com/blueman-project/blueman/issues/547

json pretty print en consola

En mi día a día manejo bastantes cadenas de json o diccionarios de python como tantos otros y muchas veces necesito tener una visualización más agradable a la vista y acabo complicándome la vida copiando, pegando, etc… El otro día incluso me instalé un paquete ‘aeson-pretty’ para printear jsons, peeeero esta solución es mucho más sencilla y me gusta más

echo "alias j='python -m json.tool'" >> ~/.bash_aliases
source ~/.bashrc
echo '{ "element0" : "lorem", "element1" : "ipsum" }' | j
{
"element0": "lorem",
"element1": "ipsum"
}

Unused variable ‘__class__’ (unused-variable)

Si usas pylint como linter para python puede que lo estés flipando al ver errores como este :


Unused variable '__class__' (unused-variable)

Al parecer el paquete  astroid en su versión 1.6.x introduce por algún motivo este comportamiento. Para solucionarlo basta con instalar la version astroid==1.5.3

Actualizando el paquete con pip debería ser suficiente y recuerda actualizar tu requirements.txt

pip install astroid==1.5.3

Referencias: https://github.com/ahitrin/SiebenApp/commit/ea063d143f140554aaa08606d9c8d58121e8a52c

supervivencia en python usando xml con namespaces

En python hay dos librerías que se usan extensamente xml que viene en el core de python y lxml una librería externa que provee de algunas cosas que xml no.

Vamos a manejar tres clases o conceptons ElementTree, Element y ElemenPath y vamos a jugar siempre con que nuestro xml tiene namespaces ya que tooooodo el uso actual de xml de servicios soap se hace con namespaces, excepto los ficheros de configuración de java

<tag attributo=»value»>texto</tag>

Elment, es un tag, y tiene nombre ( tag, tagname o como quieras llamarlo ), attributos y texto

En estos ejemplos se realiza una acción y se dumpea la salida para comprobar lo que estamos haciendo

import xml.etree.ElementTree as ET

# crear nodos <root><body></body></root>
>>> root = ET.Element('root')
>>> body = ET.SubElement(a, 'body')
>>> ET.dump(root)

# asignar atributos a un tag
# <root><body env=»devel»></body></root>
>>> root = ET.Element('root')
>>> body = ET.SubElement(root, 'body', {'env':'devel'})
>>> ET.dump(body)
<root><body env="devel" /></root>

# otras formas de manejar los attributos
>>> body.attrib['env']
'devel'
>>> body.attrib['env'] = 'foo'
>>> body.attrib['env']
'foo'

# texto dentro de un Element
>>> body.text = 'this is the text'
>>> ET.dump(body)
<body env="foo">this is the text</body>

# importar de fichero
>>> import xml.etree.ElementTree as ET
>>> tree = ET.parse('country_data.xml')
>>> root = tree.getroot()

# importar de string
>>> xml_string = "<root><body></body></root>"
>>> root = ET.fromstring(xml_string)
>>> ET.dump(root)
<root><body /></root>

# namespaces

source = """<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:cwmp="urn:dslforum-org:cwmp-1-2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap-enc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Header>
<cwmp:ID soap:mustUnderstand="1">irrelevant_request_id</cwmp:ID>
<cwmp:HoldRequests soap:mustUnderstand="1">0</cwmp:HoldRequests>
</soap:Header>
<soap:Body>
</soap:Body>
</soap:Envelope>"""

>>> xml = ET.fromstring(source)
>>> xml
<Element ‘{http://schemas.xmlsoap.org/soap/envelope/}Envelope’ at 0x7f8ddb53d950>

Dos cosas a tener en cuenta, NO puede haber un salto de linea de en el «»»<?xml…» genera una excepción «XML or text declaration not at start of entity»

source = """
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:cwmp="urn:dslforum-org:cwmp-1-2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap-enc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Header>
<cwmp:ID soap:mustUnderstand="1">irrelevant_request_id</cwmp:ID>
<cwmp:HoldRequests soap:mustUnderstand="1">0</cwmp:HoldRequests>
</soap:Header>
<soap:Body>
</soap:Body>
</soap:Envelope>"""

>>> import xml.etree.ElementTree as ET
>>> xml = ET.fromstring(source)
>>> xml = ET.fromstring(source)
Traceback (most recent call last):
File «<stdin>», line 1, in <module>
File «/usr/lib/python2.7/xml/etree/ElementTree.py», line 1311, in XML
parser.feed(text)
File «/usr/lib/python2.7/xml/etree/ElementTree.py», line 1653, in feed
self._raiseerror(v)
File «/usr/lib/python2.7/xml/etree/ElementTree.py», line 1517, in _raiseerror
raise err
xml.etree.ElementTree.ParseError: XML or text declaration not at start of entity: line 2, column 0
#Usando namespaces los tags se nombran así
{url}TagName

Con lo que las busquedas xpath se hace buscando por {url}TagName. Para buscar <cwmp:ID> lo tendremos que hacer de la siguiente manera, pero antes hay que registar las urls

Podemos usar find o findall para buscar uno o todos los nodos que cumplan un pattern xpath

source = """<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:cwmp="urn:dslforum-org:cwmp-1-2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap-enc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Header>
<cwmp:ID soap:mustUnderstand="1">irrelevant_request_id</cwmp:ID>
<cwmp:HoldRequests soap:mustUnderstand="1">0</cwmp:HoldRequests>
</soap:Header>
<soap:Body>
</soap:Body>
</soap:Envelope>"""

>>> xml = ET.fromstring(source)
# como tenemos namespaces esta consulta no funcionará
>>> xml.find('ID')
# esta debería funcionar, pero tampoco funciona por que find busca desde la raiz y no desde cualquier nodo
>>> xml.find('{urn:dslforum-org:cwmp-1-2}ID')
# buscamos con find desde cualquier nodo con una busqueda al estilo xpath
>>> xml.findall('.//{urn:dslforum-org:cwmp-1-2}ID')
<Element '{urn:dslforum-org:cwmp-1-2}ID' at 0x7f234c675c50>

# es posible usar etiquetas para los namespaces
>>> ns = {'cwmp': 'urn:dslforum-org:cwmp-1-2',
'soap': 'http://schemas.xmlsoap.org/soap/envelope/'}
>>> xml.find('.//{urn:dslforum-org:cwmp-1-2}ID', ns)
<Element '{urn:dslforum-org:cwmp-1-2}ID' at 0x7f234c675c50>

# findall devolerá una lista con los resultados, o una lista vacía si no hay resultado
>>> xml.findall('.//{urn:dslforum-org:cwmp-1-2}ID', ns)
[<Element '{urn:dslforum-org:cwmp-1-2}ID' at 0x7f234c675c50>]

# pip install lxml
# from lxml import etree

# crear nodos <root><body></body></root>
>>> root = etree.Element('root')
>>> root.append(etree.Element('body'))
>>> etree.tostring(root)
'<root><body/></root>'
>>> etree.tostring(root, pretty_print=True)
'<root>\n <body/>\n</root>\n'

# asignar atributos a un tag

>>> root = etree.Element('root')
>>> root.append(etree.Element('body', env='devel'))
>>> etree.tostring(root)
'<root><body/><body env="devel"/></root>'
>>> etree.tostring(root, pretty_print=True)
'<root>\n <body/>\n <body env="devel"/>\n</root>\n'

# manejar attributes de forma comoda
>>> root = etree.Element('root')
>>> root.append(etree.Element('body', my_attribute='my_value'))
>>> attributes = root[0].attrib
>>> attributes['new_attr'] = '12345'
>>> etree.tostring(root)
'<root><body my_attribute="my_value" new_attr="12345"/></root>'

# manejar texto
>>> from lxml import etree
>>> root = etree.Element('root')
>>> root.append(etree.Element('body', my_attribute='my_value'))
>>> root.text = 'this is the text'
>>> etree.tostring(root)
'<root>this is the text<body my_attribute="my_value"/></root>'

# importar de fichero

>>> from lxml import etree
>>> tree = ET.parse('country_data.xml')
>>> root = tree.getroot()

# importar de string
>>> xml_string = "<root><body></body></root>"
>>> root = ET.fromstring(xml_string)
>>> ET.dump(root)
<root><body /></root>

# namespaces

>>> source = """<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:cwmp="urn:dslforum-org:cwmp-1-2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap-enc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Header>
<cwmp:ID soap:mustUnderstand="1">irrelevant_request_id</cwmp:ID>
<cwmp:HoldRequests soap:mustUnderstand="1">0</cwmp:HoldRequests>
</soap:Header>
<soap:Body>
</soap:Body>
</soap:Envelope>"""
>>> root = ET.fromstring(source)

#Buscando nodos, como el xml hay que poner {<namespace}Tag

# nótese que el {namespace} debe ser exacto al encabezado o no funcionará la búsqueda
>>> print(root.findall('{http://schemas.xmlsoap.org/soap/envelope}Header'))
[]
>>> print(root.findall('{http://schemas.xmlsoap.org/soap/envelope/}Header'))
[<Element '{http://schemas.xmlsoap.org/soap/envelope/}Header' at 0x7f234c675e90>]

# para poder obtener los nsmap de un xml debemos usar objectify, hay dos Element

http://lxml.de/api/xml.etree.ElementTree.Element-class.html
http://lxml.de/api/lxml.etree.ElementBase-class.html

>>> root = objectify.fromstring(source)
>>> root.nsmap
{'cwmp': 'urn:dslforum-org:cwmp-1-2', 'soap-enc': 'http://schemas.xmlsoap.org/soap/encoding/', 'xsi': 'http://www.w3.org/2001/XMLSchema-instance', 'soap': 'http://schemas.xmlsoap.org/soap/envelope/', 'xsd': 'http://www.w3.org/2001/XMLSchema'}

# printea con cabecera xml usando xml_declaration=True
root = etree.Element('root')
etree.tostring(root, encoding="utf-8" , xml_declaration=True)
"<?xml version='1.0' encoding='utf-8'?>\n<root/>"

# Se pueden crear a mano elmentos de namespaces con ElementMarker pero el trabajo es muy extenso y el código no es muy legible, mi recomendación es usar templates de string importarlos y usarlos en vez de generarlos a mano.

from lxml import etree
from lxml.builder import ElementMaker
soap = ElementMaker(namespace=»http://schemas.xmlsoap.org/soap/envelope/», nsmap={‘soap’ : «http://schemas.xmlsoap.org/soap/envelope/»})

# Extras : xmlwitch
xmlwitch sólo lee y no escribe, pero lo hace de manera muy cómodo

entornos virtuales en python

Las aplicaciones cada vez son más complejas y por suerte más estructuradas, por ello los pequeños bloques de código reutilizable se extraen y se paquetizan, con uno u otro nombre dependiendo de cada lenguaje. El siguiente paso necesario es una herramienta que gestione los paquetes, instalar, listar, eliminar, instalar desde una fuente remota, etc… Bien pues aquí es donde llega la necesidad de usar un entorno virutal. ¿Por qué? Por varios motivos, uno es que cada aplicación puede requerir una serie de paquetes con versiones concretas que no son necesarias con otras aplicaciones o que incluso que sean incopatibles entre sí.
Usando un entorno virtual podemos instalar estas dependencias en una ruta exclusiva para nuestra aplicación y no tenemos que instalarlas en el sistema. Esto es genial ya que no necesitaremos permisos elevados para instalar los paquetes ni tendremos que andar instalando o desinstalando paquetes para poder desarrollar o instalar una aplicación. Además podemos deshacernos fácilmente de estos paquetes eliminando la ruta donde se almacenan y volver a instalarlos para probar el despliegue o simplemente por si sospechamos que hay ‘algo’ que no está correcto en nuestras dependencias.

En el caso de python hay dos entornos virtuales que se usan extensivamente: virtualenvwrapper y virtuaenv.

La primera vez que empecé a leer sobre esto me resultó muy confuso por que parecía que se hablaba de un sólo software para crear el entorno virutal y no de dos. El uso de estos dos nombres muy parecidos favorece la confusión, pero son dos proyectos que al fin y al cabo hacen lo mismo: proveernos de un entorno virtual.

A grandes rasgos las características principales de virtualenvwrapper vs virtualenv en Debian son:
* virtualenvwrapper sólo soporta python2.x ( ojo, en paquete Debian, ver READE.debian) y virutalenv soporta 2.x y 3.x
* virtualenvwrapper centraliza el almacenamiento de dependencias en $WORKON_HOME Y virutalenv no, debes especificar el directorio cada vez que creas el entorno.

Ahora, como comenzar a usar un entorno virtual en python:

Virtualenvwrapper


sudo apt-get install virtualenvwrapper
mkvirtualenv my_project
workon my_project
...
deactivate

Se crea por defecto en `~/.virtualenvs`

 Virtualenv

Puedes preparar el entorno para la version de python que quieras siempre que la tengas instalada en el systema ( -p <ruta_a_bin_python> )

sudo apt-get install python-virtualenv
virtualenv -p /usr/bin/python2 venv
source venv/bin/activate
...
deactivate

instalar dependencias: pip

El gestor de dependencias por defecto en python es pip, y con el puedes instalar, desintalar, instalar desde remoto, etc…
Con estos entornos ya puedes instalar tus ficheros requirements.txt o requirements-dev.txt de pip sin tener que usar poderes de supervaca. La manera ‘standard’ para instalar las dependencias de un proyecto:


pip install pip --upgrade
pip install -r acs/requirements-dev.txt --upgrade
pip install -r acs/requirements.txt --upgrade

Finalmente podrías configurar cada paquete que disponga de setup.py

for package in $(ls -d */); do pushd $package; if [ -e setup.py ]; then python setup.py develop; fi; popd; done