Parseit

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 dato 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:

Con esta configuración al invocar parseit sifere.dat o eventualmente python parseit.py 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?

Algunos puntos claves de este proyecto:

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.

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 el 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 lo abre 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:

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:

Notas adicionales:

Formatos

Changelog:

Version 1.4.3 - 2017-08-23

Version 1.4.2 - 2017-05-04

Version 1.4.1 - 2017-01-05

Version 1.4 - 2016-11-02

Version 1.3 - 2016-10-17

Version 1.2 - 2016-10-11

Version 1.1

Version 0.1