martes, 15 de febrero de 2011

Novedades PyAfipWs -Factura Electrónica- (instalador nsis, pythoncom, soap)

Recientemente liberé una nueva actualización de la biblioteca PyAfipWs, con varias mejoras:
http://www.pyafipws.com.ar/anuncios/nuevoinstalador106ayejemplosparawsfev1
A continuación se detallan los temas técnicos:

Extension a py2exe para generar un instalador NSIS:

Inicialmente usaba un .BAT para generar el instalador (7-zip autoextraible), para simplificar y mejorar el proceso (detectar archivos en uso, desinstalar copia previa, mostrar licencia, elegir directorio, internacionalización), desarrollé nsis.py, una extensión para py2exe, que agregando dos lineas a un setup.py crea un paquete unico con todo incluido, usando Nullsoft Scriptable Install System:

from nsis import build_installer
setup(
...
cmdclass = {"py2exe": build_installer}
)

Más info en:
http://code.google.com/p/pyafipws/source/browse/setup_wsfev1.py
http://code.google.com/p/pyafipws/source/browse/nsis.py

El código está adaptado de una ejemplo de py2exe para Inno Setup. 

PythonCOM y la ruta de instalación

Para poder acceder a archivos locales en un ambiente empaquetado con py2exe, en general es trivial salvo que el script sea una DLL, ya que el interprete Python se "embebe" dentro del programa anfitrión, y los métodos estándard para determinar donde está ubicado el script fallan.
La solución mas simple fue usar:

  • sys.executable para cuando el script es un .EXE
  • win32api.GetModuleFileName(sys.frozendllhandle) para cuando el script es un .DLL
  • __file__ cuando se ejecuta directamente el .PY

Más info en:
http://code.google.com/p/pyafipws/source/browse/wsfev1.py#129

Type Library y PythonCOM:

Algunos lenguajes de tipado estático (C#, versiones de Cobol) necesitan para las interfaces COM una librería de tipos (mejor conocidas como .TLB) para referenciar y determinar los métodos, parámetros y valores devueltos, ya que Python es un lenguaje dinámico que no ofrece dicha información.
Para mi sorpresa, las implementaciones en lenguajes de tipado estático tampoco parecen ofrecerla, y es necesario en todos los casos usar un compilador de un lenguaje especial de MS (IDL):
http://code.google.com/p/pyafipws/source/browse/pyafipws.idl
Para que lo reconozca hay que agregar al objeto python los atributos _typelib_guid_, _typelib_version_, _com_interfaces_
http://code.google.com/p/pyafipws/source/browse/pyafipws.py#57

Igualmente todo este tema esta deshabilitado ya que el tipado estático ocasiona más problemas que los que resuelve (sobre todo con el registro, DLL hell, falta de flexibilidad, etc.), y hay métodos alternativos más simples para acceder a PythonCOM desde C# y lenguajes similares.

Mi agradecimiento a Mark Hammond (el creador de python-win32) por señalar al ejemplo "pippo" en el directorio win32com\test, como muestra de una asociación entre un objeto Python COM y su TLB.

Mejorando la performance SOAP WSDL:

El protocolo SOAP es complejo, y analizar el XML de la descripción de un webservice (WSDL) para poder comunicarse con el, es un proceso un poco costoso.
Gracias a Python la solución se simplificó bastante, ya que permite guardar y recuperar las estructuras de datos ya procesadas, sin necesidad de artefactos o código generado como en otros lenguajes (.NET, Java, etc.):
http://code.google.com/p/pysimplesoap/source/browse/pysimplesoap/client.py#244

Con el módulo cPickle de la librería estándar (implementado en C) se mejoro el tiempo para cargar un WSDL de 0.4 segundos a aproximadamente a 0.001 segundos, ~ 400 veces más rápido. Con pickle nativo (implementado en python) la mejora era un poco menos significativa (~ 40 veces más rápido).
Los test fueron realizados en una netbook para un webservice medianamente complejo, YMMV

Licencia y Aviso Legal

CC BY-SACopyright (C) 2009 - 2013 Mariano Reingart reingart@gmail.com - Visite el sitio http://reingart.blogspot.com/ para novedades. Salvo indicación contraria, el texto de esta página está disponible bajo la Licencia Creative Commons Atribución Compartir Igual 3.0 Unported; podrían ser aplicables cláusulas adicionales.

Se solicita mantener el aviso de copyright (enlazando al texto original), compartir las obras derivadas bajo la misma licencia, y si es, posible comunicando al autor cualquier mejora. No utilizar logotipos ni marcas sin la debida autorización de sus titulares.

Toda información es proporcionada a Titulo Informativo y se entrega como está, sin garantías explícitas ni implicitas de ningún tipo, incluyendo sin limitación, pérdida de ganancias, interrupción de negocios, pérdida de programas u otros datos en sistemas de computación o cualquier otro reclamo. Al usarla acepta hacerlo bajo su propia responsabilidad, conociendo la normativa y reglamentaciones existentes. En caso de controversias respecto del presente, usted acepta presentarlas y resolverlas exclusivamente en la jurisdicción de los Tribunales Ordinarios Civiles y Comerciales del Departamento Judicial de Morón, Provincia de Buenos Aires, Argentina, renunciando expresamente a cualquier otro fuero que pudiere corresponder.