Skip to content

Commit a059f3c

Browse files
committed
Se estandarizó gran parte del código. Se reestructuró la carpeta tests y sus archivos. Se modificó algunos tests, reduciendo la cantidad de variables de entorno necesarias. Se modificó el script de Makefile para ejecutar los tests. Se añadió scrutinizer.yml.
1 parent b0bf2b2 commit a059f3c

69 files changed

Lines changed: 2316 additions & 757 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,7 @@ jobs:
3535
APIGATEWAY_API_TOKEN: ${{ secrets.APIGATEWAY_API_TOKEN }}
3636
TEST_CONTRIBUYENTE_RUT: ${{ vars.TEST_CONTRIBUYENTE_IDENTIFICADOR }} # Variable necesaria para test_contribuyentes.
3737
run: |
38-
python3 tests/run.py sii.test_actividades_economicas
39-
python3 tests/run.py sii.test_contribuyentes
40-
python3 tests/run.py sii.test_indicadores
38+
make tests_readonly
4139
4240
- name: Upload pytest result report
4341
if: failure()

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@ tests/*.json
2323
tests/*.csv
2424
tests/*.pdf
2525
tests/*.html
26+
tests/archivos/sii/*

.scrutinizer.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
checks:
2+
python: true
3+
4+
build:
5+
nodes:
6+
analysis:
7+
tests:
8+
override:
9+
- python-scrutinizer-run
10+
- command: make tests_readonly
11+
coverage:
12+
file: var/tests-coverage.xml
13+
format: clover
14+
environment:
15+
python:
16+
version: 3.11.10
17+
dependencies:
18+
before:
19+
- pip install -r requirements.txt
20+
21+
filter:
22+
paths:
23+
- apigatewaycl/*
24+
excluded_paths:
25+
- resources/*
26+
- tests/*
27+
- tools/*
28+
- var/*
29+
- vendor/*

Makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ install-dev:
1212
tests: install-dev
1313
python tests/run.py
1414

15+
tests_readonly:
16+
python3 tests/run.py sii.actividades.test_listar_actividades_economicas
17+
python3 tests/run.py sii.contribuyentes.test_obtener_situacion_tributaria
18+
python3 tests/run.py sii.indicadores_uf.test_obtener_uf_anual
19+
python3 tests/run.py sii.indicadores_uf.test_obtener_uf_mensual
20+
python3 tests/run.py sii.indicadores_uf.test_obtener_uf_diario
21+
1522
docs:
1623
sphinx-apidoc -o docs apigatewaycl && sphinx-build -b html docs docs/_build/html
1724

apigatewaycl/api_client/__init__.py

Lines changed: 77 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,29 @@
1717
# <http://www.gnu.org/licenses/lgpl.html>.
1818
#
1919

20-
from os import getenv
2120
from requests.exceptions import Timeout, ConnectionError, RequestException, HTTPError
21+
from os import getenv
2222
from abc import ABC
23+
2324
import urllib.parse
2425
import urllib
2526
import requests
2627
import base64
2728
import json
28-
import time
2929
import re
3030

3131
class ApiClient:
3232
'''
3333
Cliente para interactuar con la API de API Gateway.
3434
35-
:param str token: Token de autenticación del usuario. Si no se proporciona, se intentará obtener de una variable de entorno.
36-
:param str url: URL base de la API. Si no se proporciona, se usará una URL por defecto.
37-
:param str version: Versión de la API. Si no se proporciona, se usará una versión por defecto.
38-
:param bool raise_for_status: Si se debe lanzar una excepción automáticamente para respuestas de error HTTP. Por defecto es True.
35+
:param str token: Token de autenticación del usuario. Si no se proporciona,
36+
se intentará obtener de una variable de entorno.
37+
:param str url: URL base de la API. Si no se proporciona, se usará una
38+
URL por defecto.
39+
:param str version: Versión de la API. Si no se proporciona, se usará
40+
una versión por defecto.
41+
:param bool raise_for_status: Si se debe lanzar una excepción automáticamente
42+
para respuestas de error HTTP. Por defecto es True.
3943
'''
4044

4145
__DEFAULT_URL = 'https://apigateway.cl'
@@ -71,7 +75,9 @@ def __validate_url(self, url):
7175
:rtype: str
7276
:raises ApiException: Si la URL no es válida o está ausente.
7377
'''
74-
return str(url).strip() if url else getenv('APIGATEWAY_API_URL', self.__DEFAULT_URL).strip()
78+
return str(url).strip() if url else getenv(
79+
'APIGATEWAY_API_URL',
80+
self.__DEFAULT_URL).strip()
7581

7682
def __generate_headers(self):
7783
'''
@@ -97,9 +103,12 @@ def __request(self, method, resource, data = None, headers = None):
97103
:param dict headers: Cabeceras adicionales para la solicitud (opcional).
98104
:return: Respuesta de la solicitud.
99105
:rtype: requests.Response
100-
:raises ApiException: Si el método HTTP no es soportado o si hay un error de conexión.
106+
:raises ApiException: Si el método HTTP no es soportado o si hay
107+
un error de conexión.
101108
'''
102-
api_path = '/api/%(version)s%(resource)s' % {'version': self.version, 'resource': resource}
109+
api_path = '/api/%(version)s%(resource)s' % {
110+
'version': self.version, 'resource': resource
111+
}
103112
full_url = urllib.parse.urljoin(self.url + '/', api_path.lstrip('/'))
104113
headers = headers or {}
105114
headers = {**self.headers, **headers}
@@ -109,11 +118,17 @@ def __request(self, method, resource, data = None, headers = None):
109118
response = requests.request(method, full_url, data = data, headers = headers)
110119
return self.__check_and_return_response(response)
111120
except ConnectionError as error:
112-
raise ApiException('Error de conexión: %(error)s' % {'error': error})
121+
raise ApiException('Error de conexión: %(error)s' % {
122+
'error': error
123+
})
113124
except Timeout as error:
114-
raise ApiException('Error de timeout: %(error)s' % {'error': error})
125+
raise ApiException('Error de timeout: %(error)s' % {
126+
'error': error
127+
})
115128
except RequestException as error:
116-
raise ApiException('Error en la solicitud: %(error)s' % {'error': error})
129+
raise ApiException('Error en la solicitud: %(error)s' % {
130+
'error': error
131+
})
117132

118133
def __check_and_return_response(self, response):
119134
'''
@@ -130,10 +145,18 @@ def __check_and_return_response(self, response):
130145
except HTTPError as error:
131146
try:
132147
error = response.json()
133-
message = error.get('message', '') or error.get('exception', '') or 'Error desconocido.'
148+
message = error.get(
149+
'message', ''
150+
) or error.get(
151+
'exception', ''
152+
) or 'Error desconocido.'
134153
except json.decoder.JSONDecodeError:
135-
message = 'Error al decodificar los datos en JSON: %(response)s' % {'response': response.text}
136-
raise ApiException('Error HTTP: %(message)s' % {'message': message})
154+
message = 'Error al decodificar los datos en JSON: %(response)s' % {
155+
'response': response.text
156+
}
157+
raise ApiException('Error HTTP: %(message)s' % {
158+
'message': message
159+
})
137160
return response
138161

139162
def get(self, resource, headers = None):
@@ -212,9 +235,14 @@ def __str__(self):
212235
:return: Una cadena que representa el error de una manera clara y concisa.
213236
'''
214237
if self.code is not None:
215-
return "[API Gateway] Error %(code)s: %(message)s" % {'code': self.code, 'message': self.message}
238+
return "[API Gateway] Error %(code)s: %(message)s" % {
239+
'code': self.code,
240+
'message': self.message
241+
}
216242
else:
217-
return "[API Gateway] %(message)s" % {'message': self.message}
243+
return "[API Gateway] %(message)s" % {
244+
'message': self.message
245+
}
218246

219247
class ApiBase(ABC):
220248
'''
@@ -229,8 +257,20 @@ class ApiBase(ABC):
229257

230258
auth = {}
231259

232-
def __init__(self, api_token = None, api_url = None, api_version = None, api_raise_for_status = True, **kwargs):
233-
self.client = ApiClient(api_token, api_url, api_version, api_raise_for_status)
260+
def __init__(
261+
self,
262+
api_token = None,
263+
api_url = None,
264+
api_version = None,
265+
api_raise_for_status = True,
266+
**kwargs
267+
):
268+
self.client = ApiClient(
269+
api_token,
270+
api_url,
271+
api_version,
272+
api_raise_for_status
273+
)
234274
self.__setup_auth(kwargs)
235275

236276
def __setup_auth(self, kwargs):
@@ -243,11 +283,26 @@ def __setup_auth(self, kwargs):
243283
clave = kwargs.get('clave')
244284
if identificador and clave:
245285
if self.__is_auth_pass(identificador):
246-
self.auth = {'pass': {'rut': identificador, 'clave': clave}}
286+
self.auth = {
287+
'pass': {
288+
'rut': identificador,
289+
'clave': clave
290+
}
291+
}
247292
elif self.__is_auth_cert_data(identificador):
248-
self.auth = {'cert': {'cert-data': identificador, 'pkey-data': clave}}
293+
self.auth = {
294+
'cert': {
295+
'cert-data': identificador,
296+
'pkey-data': clave
297+
}
298+
}
249299
elif self.__is_auth_file_data(identificador):
250-
self.auth = {'cert': {'file-data': identificador, 'file-pass': clave}}
300+
self.auth = {
301+
'cert': {
302+
'file-data': identificador,
303+
'file-pass': clave
304+
}
305+
}
251306
else:
252307
raise ApiException('No se han proporcionado las credenciales de autentificación.')
253308

@@ -382,4 +437,3 @@ def _get_auth_pass(self):
382437
else:
383438
raise ApiException('auth.pass or auth.cert missing.')
384439
return self.auth
385-

apigatewaycl/api_client/sii/actividades_economicas.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,19 @@
2020
'''
2121
Módulo para obtener las actividades económicas del SII.
2222
23-
Para más información sobre la API, consulte la `documentación completa de Actividades Económicas <https://developers.apigateway.cl/#e64eb128-173a-48c7-ab0b-b6152e59c327>`_.
23+
Para más información sobre la API, consulte la `documentación completa de
24+
Actividades Económicas <https://developers.apigateway.cl/#e64eb128-173a-48c7-ab0b-b6152e59c327>`_.
2425
'''
2526

2627
from .. import ApiBase
2728

2829
class ActividadesEconomicas(ApiBase):
2930
'''
30-
Cliente específico para interactuar con los endpoints de actividades económicas de la API de API Gateway.
31+
Cliente específico para interactuar con los endpoints de actividades
32+
económicas de la API de API Gateway.
3133
32-
Provee métodos para obtener listados de actividades económicas, tanto de primera como de segunda categoría.
34+
Provee métodos para obtener listados de actividades económicas, tanto
35+
de primera como de segunda categoría.
3336
'''
3437

3538
def listado(self, categoria = None):

apigatewaycl/api_client/sii/bhe.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@
1818
#
1919

2020
'''
21-
Módulo para interactuar con Boletas de Honorarios Electrónicas, tanto emitidas como recibidas, del SII.
21+
Módulo para interactuar con Boletas de Honorarios Electrónicas, tanto
22+
emitidas como recibidas, del SII.
2223
23-
Para más información sobre la API, consulte la `documentación completa de las BHE <https://developers.apigateway.cl/#4df9775f-2cd3-4b35-80a5-373f2501230c>`_.
24+
Para más información sobre la API, consulte la `documentación completa de las
25+
BHE <https://developers.apigateway.cl/#4df9775f-2cd3-4b35-80a5-373f2501230c>`_.
2426
'''
2527

2628
from .. import ApiBase

apigatewaycl/api_client/sii/bte.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
'''
2121
Módulo para la emisión de Boletas de Terceros Electrónicas del SII.
2222
23-
Para más información sobre la API, consulte la `documentación completa de las BTE <https://developers.apigateway.cl/#e08f50ab-5509-48ab-81ab-63fc8e5985e1>`_.
23+
Para más información sobre la API, consulte la `documentación completa de las
24+
BTE <https://developers.apigateway.cl/#e08f50ab-5509-48ab-81ab-63fc8e5985e1>`_.
2425
'''
2526

2627
from .. import ApiBase
@@ -48,7 +49,9 @@ def documentos(self, emisor, periodo, pagina = None):
4849
:return: Respuesta JSON con los documentos BTE.
4950
:rtype: list[dict]
5051
'''
51-
url = '/sii/bte/emitidas/documentos/%(emisor)s/%(periodo)s' % {'emisor': emisor, 'periodo': periodo}
52+
url = '/sii/bte/emitidas/documentos/%(emisor)s/%(periodo)s' % {
53+
'emisor': emisor, 'periodo': periodo
54+
}
5255
if pagina is not None:
5356
url += '?pagina=%(pagina)s' % {
5457
'pagina': pagina,
@@ -124,7 +127,9 @@ def receptor_tasa(self, emisor, receptor, periodo = None):
124127
body = {
125128
'auth': self._get_auth_pass()
126129
}
127-
url = '/sii/bte/emitidas/receptor_tasa/%(emisor)s/%(receptor)s' % {'emisor': emisor, 'receptor': receptor}
130+
url = '/sii/bte/emitidas/receptor_tasa/%(emisor)s/%(receptor)s' % {
131+
'emisor': emisor, 'receptor': receptor
132+
}
128133
if periodo:
129134
url += '?periodo=%(periodo)s' % {'periodo': periodo}
130135
response = self.client.post(url, data = body)

apigatewaycl/api_client/sii/contribuyentes.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,16 @@
2020
'''
2121
Módulo para obtener datos de los contribuyentes a través del SII.
2222
23-
Para más información sobre la API, consulte la `documentación completa de los Contribuyentes <https://developers.apigateway.cl/#c88f90b6-36bb-4dc2-ba93-6e418ff42098>`_.
23+
Para más información sobre la API, consulte la `documentación completa de los
24+
Contribuyentes <https://developers.apigateway.cl/#c88f90b6-36bb-4dc2-ba93-6e418ff42098>`_.
2425
'''
2526

2627
from .. import ApiBase
2728

2829
class Contribuyentes(ApiBase):
2930
'''
30-
Cliente específico para interactuar con los endpoints de contribuyentes de la API de API Gateway.
31+
Cliente específico para interactuar con los endpoints de contribuyentes
32+
de la API de API Gateway.
3133
3234
Hereda de ApiBase y utiliza su funcionalidad para realizar solicitudes a la API.
3335
'''
@@ -40,7 +42,9 @@ def situacion_tributaria(self, rut):
4042
:return: Respuesta JSON con la situación tributaria del contribuyente.
4143
:rtype: dict
4244
'''
43-
url = '/sii/contribuyentes/situacion_tributaria/tercero/%(rut)s' % {'rut': rut}
45+
url = '/sii/contribuyentes/situacion_tributaria/tercero/%(rut)s' % {
46+
'rut': rut
47+
}
4448
response = self.client.get(url)
4549
return response.json()
4650

@@ -52,6 +56,8 @@ def verificar_rut(self, serie):
5256
:return: Respuesta JSON con la verificación del RUT.
5357
:rtype: dict
5458
'''
55-
url = '/sii/contribuyentes/rut/verificar/%(serie)s' % {'serie': serie}
59+
url = '/sii/contribuyentes/rut/verificar/%(serie)s' % {
60+
'serie': serie
61+
}
5662
response = self.client.get(url)
5763
return response.json()

0 commit comments

Comments
 (0)