Parseit

19 mins

Parseit es una herramienta de linea de comandos para “interpretar” archivos de texto con formato (Con o sin delimitador).

Para entender que es parseit nada mejor que un ejemplo práctico:

Para el intercambio de información con el Afip (Agencia federal de ingresos públicos), se suele trabajar con este tipo de archivos. En particular los contribuyentes grandes, que suelen generar gran cantidad de información, y a los que les resulta más óptimo trabajar mediante la importación de archivos directamente en los aplicativos del mencionado organismo. Veamos un caso típico de una aplicación, la del Sistema federal de información más conocido como SIFERE que permite importar masivamente la información de retenciones y percepciones. El archivo de importación (texto, con campos de longitud fija y caracteres de fin de linea) tiene un formato ya definido como el siguiente:

90130-00000000-901/01/200612341234567891234560FA0000000000010000123500000125,20
90130-00000000-901/01/200612341234567891234560FA0000000000010000123500000125,20
90130-00000000-901/01/200612341234567891234560FA0000000000010000123500000125,20

Leer un archivo así tiene sus complicaciones, si bien los datos están en texto claro resulta complicado analizarlo, y aquí es dónde entra Parseit. Para poder interpretar este archivo de una forma más conveniente, y usando la documentación que oportunamente publica el Afip, podemos definir dicho formato en una archivo JSON, por ejemplo de la siguiente forma:

		"sifere-retenciones": {
			"category": "Afip.Sifere",
			"delimiter": "",
			"fields": {
				"Código de Jurisdicción":         [ 3, "table", "sifere-jurisdicciones", ""],
				"CUIT del Agente de Retención":   [13, "string", "", ""],
				"Fecha de la Retención":          [10, "date", "%d/%m/%Y", "%d-%m-%Y"],
				"Número de Sucursal":             [ 4, "string", "", ""],
				"Número de constancia":           [16, "string", "", ""],
				"Tipo de Comprobante":            [ 1, "table", "sifere-tipo-comprobantes", ""],
				"Letra del Comprobante":          [ 1, "string", "", ""],
				"Número de Comprobante Original": [20, "string", "", ""],
				"Importe Retenido":               [11, "amount", "", ""]
			}
		},

Nótese que además de definir la longitud de cada campo y el orden, definimos el tipo de datos y particularmente algunos de los campos son “tablas”, dónde el dato en sí hace referencia a una tabla de valores ya definida también en el archivo, por ejemplo algo así:

	"sifere-jurisdicciones": {
		"901": "Capital Federal",
		"902": "Buenos Aires",
		"903": "Catamarca",
		"904": "Córdoba",
		"905": "Corrientes",
		"906": "Chaco",
		"907": "Chubut",
		"908": "Entre Ríos",
		"909": "Formosa",
		"910": "Jujuy",
		"911": "La Pampa",
		"912": "La Rioja",
		"913": "Mendoza",
		"914": "Misiones",
		"915": "Neuquén",
		"916": "Río Negro",
		"917": "Salta",
		"918": "San Juan",
		"919": "San Luis",
		"920": "Santa Cruz",
		"921": "Santa Fe",
		"922": "Santiago del Estero",
		"923": "Tierra del Fuego",
		"924": "Tucumán"
	},
	"sifere-tipo-comprobantes": {
		"F": "Factura",
		"R": "Recibo", 
		"D": "Nota de Débito",
		"C": "Nota de Crédito",
		"O": "Otro"
	},

De esta forma tenemos:

  • Un archivo de texto con información en campos de longitud fija, por ejemplo: sifere.dat
  • Una definición JSON del formato, en un archivo de nombre parseit.fmt (puede ser cualquier nombre, pero esto se lee automáticamente)
  • La herramienta parseit o parseit.exe

Con esta configuración al invocar parseit sifere.dat o eventualmente python parseit sifere.dat obtendremos en la línea de comandos una salida como está:

+----------+--------------------------+--------------------------------+-------------------------+----------------------+------------------------+-----------------------+-------------------------+----------------------------------+--------------------+
|   # Reg. | Código de Jurisdicción   | CUIT del Agente de Retención   | Fecha de la Retención   |   Número de Sucursal |   Número de constancia | Tipo de Comprobante   | Letra del Comprobante   |   Número de Comprobante Original |   Importe Retenido |
|----------+--------------------------+--------------------------------+-------------------------+----------------------+------------------------+-----------------------+-------------------------+----------------------------------+--------------------|
|        1 | 901 - Capital Federal    | 30-00000000-9                  | 01-01-2006              |                 1234 |       1234567891234560 | F - Factura           | A                       |             00000000000100001235 |             125.20 |
|        2 | 901 - Capital Federal    | 30-00000000-9                  | 01-01-2006              |                 1234 |       1234567891234560 | F - Factura           | A                       |             00000000000100001235 |             125.20 |
|        3 | 901 - Capital Federal    | 30-00000000-9                  | 01-01-2006              |                 1234 |       1234567891234560 | F - Factura           | A                       |             00000000000100001235 |             125.20 |
+----------+--------------------------+--------------------------------+-------------------------+----------------------+------------------------+-----------------------+-------------------------+----------------------------------+--------------------+

Que hizo parseit?

  • Identificó y relacionó automáticamente al archivo de entrada con el formato definido anteriormente
  • Extrajo los campos del archivo original y los separo y formateo convenientemente
  • Agregó un titulo a cada columna según lo definido en el archivo de configuración JSON
  • Completó la información en los campos tipo “tabla” de la forma código - valor para mejorar la legibilidad
  • Formateo también los campos fecha para mejorar la lectura
  • Agregó una útil columna # Reg

Algunos puntos claves de este proyecto:

  • Herramienta de línea de comandos
  • Interpretación de archivos de texto de formato especifico, con caractér de fin de línea.
  • Interpretación de archivos CSV (valores separados por delimitadores).
  • Uso de archivos JSON para la definición del formato (consultar parseit.json)
    • Definición de campos, longitudes y formatos varios
    • Definición de valores tipo tabla (código: valor) para reemplazo al mostrar de los mismos
  • Especificación de un formato determinado o por defecto el archivo “parseit.fmt” que estuviera en la misma carpeta de ejecutable
  • Varios formatos de exportación de los datos, entre otros:
    • psql
    • csv
    • html
    • etc.
  • Definir que filas y que columnas mostrar
  • Útil visualización o “transposición” de la tabla al modo “horizontal”
  • Poder incorporar un hoja de estilos cuando los datos los exportamos a html
  • Poder exportar a un archivo determinado y apertura automática del mismo.
  • Con la distribución se agregan los formatos para interpretar los archivos de texto para el Siap / Afip:
    • ARCIBA: débitos y créditos
    • RG3685: Compras: comprobantes y alícuotas, Ventas: comprobantes y alicuotas
    • SIFERE: Retenciones y percepciones
    • SICORE: Retenciones y percepciones
    • IIBB: Padrones de alto riesgo y régimen general

Requerimientos e instalación:

En Windows, nada en particular ya que se distribuye la herramienta “congelada” mediante Pyinstaller. Descargarla y copiarla en alguna carpeta del sistema, idealmente que esté apuntada al path.

  • Para descargar y descomprimir Parseit, hacer click aqui
  • El proyecto en Github

Ejemplos de Uso:

Invocación sin parámetros o con `–help

uso: parseit [-h] [-v] [-f "path o archivo"] [-u "formato"] [-t] [-s] [-i]
             [-o "archivo"] [-x] [-e "formato"] [-c "columnas"] [-r "filas"]
             [-n] [-z] [-a] [-l "archivo css"]
             ["archivo a interpretar"]

Parseador de archivos
2016, Patricio Moracho <pmoracho@gmail.com>

argumentos posicionales:
  "archivo a interpretar"          Archivo de input

argumentos opcionales:
  -h, --help                       mostrar esta ayuda y salir
  -v, --version                    show program's version number and exit
  -f "path o archivo", --format "path o archivo"
                                   Definir path o archivo FMT a utilizar
  -u "formato", --useformat "formato"
                                   Forzar el uso de un determinado formato para porcesar el archivo
  -t, --dontusetables              No usar traducción por tablas y mostrar los datos nativos
  -s, --showformat                 Mostrar información de un formato (--format) en particular o todos los definidos
  -i, --ignorefmterror             Ignorar errores al cargar archivos de formatos
  -o "archivo", --outputfile "archivo"
                                   Exportar a un archivo
  -x, --openfile                   abrir automáticamente el archivo
  -e "formato", --exportformat "formato"
                                   Exportar en un formato específico
  -c "columnas", --showcols "columnas"
                                   Números de las columnas a mostrar
  -r "filas", --showrows "filas"   Números de las filas a mostrar
  -n, --dontshowrecordnumber       No mostrar los números de cada registro
  -z, --horizontalmode             Modo de visualización horizontal
  -a, --addtotals                  Agregar una última fila con los totales de los campos númericos
  -l "archivo css", --css-file "archivo css"
                                   Archivo de estilos (.Css) para la salida Html

Ejemplos de uso:

- Interpretar un archivo infiriendo el formato:
  parseit [opciones] <archivo a interpretar>

- Mostrar todos los formatos disponibles y sus definiciones:
  parseit [opciones] -s [opciones]

- Mostrar esta ayuda:
  parseit -h  

parseit sample/padron.txt -r 4-9,12 -c 1-10,13

Filtra los registros 4 al 9 y el 12, y muestra las columnas 1 a 10 y la 13

+----------+---------------+---------------+---------------+-------------+--------------+--------------+------------------+--------------+-------------+-----------------------------------+
|   # Reg. | Fecha Publ.   | Fecha Desde   | Fecha Hasta   |        CUIT | Tipo         | Marca Alta   | Marca Alícuota   |   Percepción |   Retención | Razón Social                      |
|----------+---------------+---------------+---------------+-------------+--------------+--------------+------------------+--------------+-------------+-----------------------------------|
|        4 | 27-06-2016    | 01-11-2016    | 30-11-2016    | 20044290775 | D - Directo  | S            | N                |         1.50 |        1.50 | LADEDA HORACIO JOSE               |
|        5 | 23-09-2016    | 01-10-2016    | 31-12-2016    | 20004226039 | C - Convenio | S            | N                |         6.00 |        4.50 | MIGUENS JOSE ENRIQUE C            |
|        6 | 23-09-2016    | 01-10-2016    | 31-12-2016    | 20004228635 | D - Directo  | S            | N                |         6.00 |        4.50 | LATUGAYE JOSE JORGE               |
|        7 | 23-09-2016    | 01-10-2016    | 31-12-2016    | 20004234597 | D - Directo  | S            | N                |         6.00 |        4.50 | PREPELITCHI PEDRO                 |
|        8 | 23-09-2016    | 01-10-2016    | 31-12-2016    | 20004234813 | D - Directo  | S            | N                |         6.00 |        4.50 | SUCESION DE SPOTA ALBERTO ANTONIO |
|        9 | 23-09-2016    | 01-10-2016    | 31-12-2016    | 20004237375 | D - Directo  | S            | N                |         6.00 |        4.50 | ZAMORA JOSE MAXIMO                |
|       12 | 23-09-2016    | 01-10-2016    | 31-12-2016    | 20004246846 | D - Directo  | S            | N                |         6.00 |        4.50 | ROMANELLA EDUARDO EDGAR           |
+----------+---------------+---------------+---------------+-------------+--------------+--------------+------------------+--------------+-------------+-----------------------------------+

parseit sample/padron.txt -r 4,11 -z

Muestra solo los registros 4 y 11 y los muestra en le modo horizontal.

+---------------------+---------------------+
|               Campo | Valor               |
|---------------------+---------------------|
|              # Reg. | 4                   |
|         Fecha Publ. | 27-06-2016          |
|         Fecha Desde | 01-11-2016          |
|         Fecha Hasta | 30-11-2016          |
|                CUIT | 20044290775         |
|                Tipo | D - Directo         |
|          Marca Alta | S                   |
|      Marca Alícuota | N                   |
|          Percepción | 1.5                 |
|           Retención | 1.5                 |
|       Grupo Percep. | 16                  |
|    Grupo Retención. | 16                  |
|        Razón Social | LADEDA HORACIO JOSE |
| ------------------- | ------------------- |
|              # Reg. | 11                  |
|         Fecha Publ. | 23-09-2016          |
|         Fecha Desde | 01-10-2016          |
|         Fecha Hasta | 31-12-2016          |
|                CUIT | 20004242042         |
|                Tipo | D - Directo         |
|          Marca Alta | S                   |
|      Marca Alícuota | N                   |
|          Percepción | 6.0                 |
|           Retención | 4.5                 |
|       Grupo Percep. | 00                  |
|    Grupo Retención. | 00                  |
|        Razón Social | PEQA JUAN CARLOS    |
| ------------------- | ------------------- |
+---------------------+---------------------+

parseit sample/padron.txt -r 4,11 -e csv

Muestra solo los registros 4 y 11 y los exporta en la forma tradicional CSV, por ejemplo para importar a un Excel.

"# Reg.";"Fecha Publ.";"Fecha Desde";"Fecha Hasta";"CUIT";"Tipo";"Marca Alta";"Marca Alícuota";"Percepción";"Retención";"Grupo Percep.";"Grupo Retención.";"Razón Social"
"4";"27-06-2016";"01-11-2016";"30-11-2016";"20044290775";"D - Directo";"S";"N";"    1.50";"    1.50";"16";"16";"LADEDA HORACIO JOSE"
"11";"23-09-2016";"01-10-2016";"31-12-2016";"20004242042";"D - Directo";"S";"N";"    6.00";"    4.50";"00";"00";"PEQA JUAN CARLOS"

parseit sample/padron.txt -r 4,11 -e html

Generar una salida html de los registros 4 y 11

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="description" content="parseit - Parseador de archivos">
<meta name="author" content="2016, Patricio Moracho <pmoracho@gmail.com>">
<style type="text/css">

                        table.tabulate {
                                font-family: Verdana, Geneva, sans-serif;
                                font-size:10px;
                                color:#000000;
                                border-width: 1px;
                                border-color: #eeeeee;
                                border-collapse: collapse;
                                background-color: #ffffff;
                                width: 100%;
                                table-layout: auto;
                        }
                        table.tabulate th {
                                border-width: 1px;
                                padding: 1px;
                                border-style: solid;
                                border-color: #eeeeee;
                                background-color: #004f6f;
                                color:#fff;
                                text-align: left;
                        }
                        table.tabulate td {
                                border-width   : 1px;
                                padding            : 1px;
                                border-style   : solid;
                                border-color   : #eeeeee;
                                vertical-align : top;
                        }
                        table.tabulate tr:nth-of-type(even) {
                                background-color:#D2E4FC;
                        }
                        table.tabulate tr:nth-of-type(odd) {
                                background-color:#F7FDFA;
                        }
                        p {
                                font-family: Verdana, Geneva, sans-serif;
                                font-size:14px;
                                width: 100%;
                                padding: 0px;
                                margin: 0px;
                                text-align: center;
                        }

</style>
<title>Archivo: sample/padron.txt (Padron-iibb-general)</title>
</head>
<body>
<p><b>Archivo: sample/padron.txt (Padron-iibb-general)</b></p><p>Cantidad de registros visualizados: 2</p><p></br></p><table class=tabulate>
<thead>
<tr><th style="text-align: right;"># Reg.</th><th>Fecha Publ.</th><th>Fecha Desde</th><th>Fecha Hasta</th><th style="text-align: right;">CUIT</th><th>Tipo</th><th>Marca Alta</th><th>Marca Al&iacute;cuota</th><th style="text-align: right;">Percepci&oacute;n</th><th style="text-align: right;">Retenci&oacute;n</th><th style="text-align: right;">Grupo Percep.</th><th style="text-align: right;">Grupo Retenci&oacute;n.</th><th>Raz&oacute;n Social</th></tr>
</thead>
<tbody>
<tr><td style="text-align: right;">4</td><td>27-06-2016</td><td>01-11-2016</td><td>30-11-2016</td><td style="text-align: right;">20044290775</td><td>D - Directo</td><td>S</td><td>N</td><td style="text-align: right;">1.50</td><td style="text-align: right;">1.50</td><td style="text-align: right;">16</td><td style="text-align: right;">16</td><td>LADEDA HORACIO JOSE</td></tr>
<tr><td style="text-align: right;">11</td><td>23-09-2016</td><td>01-10-2016</td><td>31-12-2016</td><td style="text-align: right;">20004242042</td><td>D - Directo</td><td>S</td><td>N</td><td style="text-align: right;">6.00</td><td style="text-align: right;">4.50</td><td style="text-align: right;">00</td><td style="text-align: right;">00</td><td>PEQA JUAN CARLOS</td></tr>
</tbody>
</table></body>
</html>

parseit sample/padron.txt -e html -o salida.html -x

Exportar a html directo al archivo salida.html y abrirlo automáticamente con el navegador asociado

Captura de pantalla de un Chrome

Notas para el desarrollador:

Requisitos iniciales

El proyecto parseit esta construido usando el lenguaje python, a la fecha no se usan librerías adicionales a las propias de python, pero de todas formas es recomendable preparar antes que nada, un entorno de desarrollo. A continuación expondremos en detalle cuales son los pasos para tener preparado el entorno de desarrollo. Este detalle esta orientado a la implementación sobre Windows 32 bits, los pasos para versiones de 64 bits son sustancialmente distintos, en particular por algunos de los “paquetes” que se construyen a partir de módulos en C o C++, de igual forma la instalación sobre Linux tiene sus grandes diferencias. Eventualmente profundizaremos sobre estos entornos, pero en principio volvemos a señalar que el siguiente detalle aplica a los ambientes Windows de 32 bits:

  • Obviamente en primer lugar necesitaremos Python, por ahora únicamente la versión 3.4. La correcta instalación se debe verificar desde la línea de comandos: python --version. Si todo se instaló correctamente se debe ver algo como esto Python 3.4.0, sino verificar que Python.exe se encuentre correctamente apuntado en el PATH.

  • Es conveniente pero no mandatorio hacer upgrade de la herramienta pip: python -m pip install --upgrade pip

  • Virutalenv. Es la herramienta estándar para crear entornos “aislados” de python. Para no tener conflictos de desarrollo lo que haremos mediante esta herramienta es crear un “entorno virtual” de python en una carpeta del proyecto (venv). Este “entorno virtual” contendrá una copia completa de Python, al activarlo se modifica el PATH al python.exe que apuntará ahora a nuestra carpeta del entorno, evitando cualquier tipo de conflicto con un entorno Python ya existente. La instalación de virtualenv se hara mediante pip install virtualenv

  • Descargar el proyecto desde Github, se puede descargar desde la página el proyecto como un archivo Zip, o si contamos con Git sencillamente haremos un git clone https://github.com/pmoracho/parseit.

  • El proyecto una vez descomprimido o luego del clonado del repositorio tendrá una estructura de directorios similar a la siguiente:

parseit.git
   |-dist
   |-tests
   |-tools

Preparación del entorno virtual local

Para poder ejecutar, o crear la distribución de la herramientas, lo primero que deberemos hacer es armar un entorno python “virtual” que alojaremos en una subcarpeta del directorio principal que llamaremos “venv”. En el proyecto incorporamos una herramienta de automatización de algunas tareas básicas. Se trata de make.py, la forma de ejecutarlo es la siguiente: python tools\make.py <comando> la ejecución si parámetros o mediante el parámetro --help arrojará una salida como lo que sigue:

Automatización de tareas para el proyecto Paresit
(c) 2016, Patricio Moracho <pmoracho@gmail.com>

Uso: make <command> [<args>]

Los comandos más usados:
   devcheck   Hace una verificación del entorno de desarrollo
   devinstall Realiza la instalación del entorno de desarrollo virtual e instala los requerimientos
   docinstall Intalación de Sphinx
   clear      Elimina archivos innecesarios
   test       Ejecuta todos los tests definidos del proyecto
   build      Construye la distribución binaria de las herramientas del proyecto

argumentos posicionales:
  command     Comando a ejecutar

argumentos opcionales:
  -h, --help  mostrar esta ayuda y salir

Para preparar el entorno virtual simplemente haremos python tools\make.py devinstall, este proceso si resulta exitoso deberá haber realizado las siguientes tareas:

  • Creación de un entorno pyhton virtual en la carpeta “venv”, invocable mediante venv\Scripts\activate.bat en Windows o source venv/Scripts/activate en entornos Linux o Cygwin/Mingw (en Windows)
  • Instalado todas las dependencias necesarias

Notas adicionales:

  • Es recomendable y cómodo, pero entiendo que no es mandatorio, contar con un entorno estilo “Linux”, por ejemplo MinGW, tal como dice la página del proyecto: “MinGW provides a complete Open Source programming tool set which is suitable for the development of native MS-Windows applications, and which do not depend on any 3rd-party C-Runtime DLLs. (It does depend on a number of DLLs provided by Microsoft themselves, as components of the operating system; most notable among these is MSVCRT.DLL, the Microsoft C runtime library. Additionally, threaded applications must ship with a freely distributable thread support DLL, provided as part of MinGW itself).” De este entorno requerimos algunas herramientas de desarrollo: Bash para la línea de comandos y Make para la automatización de varias tareas del proyecto.

  • Usar “soft tabs”: Con cualquier editor que usemos configurar el uso del en vez de los espacios, yo prefiero el puro al espacio, entiendo que es válido el otro criterio pero ya los fuentes están con esta configuración, por lo que para evitar problemas al compilar los .py recomiendo seguir usando este criterio. Asimismo configurar en 4 posiciones estos .

Formatos

  • Los formatos se definen en uno o más archivos .FMT que no son más que archivos JSON
  • JSON Editor Online Para validar la edición del archivo de formatos

Changelog:

Version 1.4.1 - 2017-01-05

  • El tipo “amounts” permite procesar montos al estilo “0000-45.34”

Version 1.4 - 2016-11-02

  • Corrección de bug, estaba filtrando un registro del total

Version 1.3 - 2016-10-17

  • Primera funcionalidad para la busqueda de registros por texto

Version 1.2 - 2016-10-11

  • Primera funcionalidad para el manejo de archivos CSV (separado por delimitador)
  • Notas varias para el desarrollador

Version 1.1

  • Primer release oficial de la herramienta
  • Se distribuyen varios formatos para interpretar archivos de Afip / Siap

Version 0.1

  • Versión inicial

@pmoracho QR code
https://pmoracho.github.io/blog/2016/10/11/Parseit/
11-Oct-16
BY-NC-SA 4.0 https://pmoracho.github.io/disclosure
https://pmoracho.github.io/blog/2016/10/11/Parseit/