Skip to content

Commit cee9080

Browse files
authored
Merge pull request #451 from fyntex/develop
Deploy release v0.22.0
2 parents 73bc445 + f3f54bb commit cee9080

17 files changed

+459
-54
lines changed

.bumpversion.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[bumpversion]
2-
current_version = 0.21.0
2+
current_version = 0.22.0
33
commit = True
44
tag = False
55
message = chore: Bump version from {current_version} to {new_version}

.github/workflows/ci.yaml

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ jobs:
2828
strategy:
2929
matrix:
3030
python_version:
31-
- "3.7.15"
3231
- "3.8.13"
3332
- "3.9.16"
3433
- "3.10.9"
@@ -46,7 +45,7 @@ jobs:
4645
run: make python-virtualenv PYTHON_VIRTUALENV_DIR="venv"
4746

4847
- name: Restoring/Saving Cache
49-
uses: actions/[email protected].5
48+
uses: actions/[email protected].6
5049
with:
5150
path: "venv"
5251
key: py-v1-deps-${{ runner.os }}-${{ matrix.python_version }}-${{ hashFiles('requirements.txt') }}-${{ hashFiles('requirements-dev.txt') }}-${{ hashFiles('Makefile', 'make/**.mk') }}
@@ -70,7 +69,6 @@ jobs:
7069
strategy:
7170
matrix:
7271
python_version:
73-
- "3.7.15"
7472
- "3.8.13"
7573
- "3.9.16"
7674
- "3.10.9"
@@ -85,7 +83,7 @@ jobs:
8583
python-version: "${{ matrix.python_version }}"
8684

8785
- name: Restoring/Saving Cache
88-
uses: actions/[email protected].5
86+
uses: actions/[email protected].6
8987
with:
9088
path: "venv"
9189
key: py-v1-deps-${{ runner.os }}-${{ matrix.python_version }}-${{ hashFiles('requirements.txt') }}-${{ hashFiles('requirements-dev.txt') }}-${{ hashFiles('Makefile', 'make/**.mk') }}
@@ -126,7 +124,7 @@ jobs:
126124
127125
- name: Check that compiled Python dependency manifests are up-to-date with their sources
128126
# FIXME: There are issues related to testing with multiple Python versions.
129-
if: ${{ startsWith(matrix.python_version, '3.7.') }}
127+
if: ${{ startsWith(matrix.python_version, '3.8.') }}
130128
run: |
131129
source "$PYTHON_VIRTUALENV_ACTIVATE"
132130
make python-deps-sync-check

.github/workflows/deploy.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ jobs:
4747
python-version: "3.10.9"
4848

4949
- name: Restoring/Saving Cache
50-
uses: actions/[email protected].5
50+
uses: actions/[email protected].6
5151
with:
5252
path: "venv"
5353
key: py-v1-deps-${{ runner.os }}-${{ steps.set_up_python.outputs.python-version }}-${{ hashFiles('requirements.txt') }}-${{ hashFiles('requirements-dev.txt') }}-${{ hashFiles('Makefile', 'make/**.mk') }}

.github/workflows/release.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ jobs:
4747
run: make python-virtualenv PYTHON_VIRTUALENV_DIR="venv"
4848

4949
- name: Restoring/Saving Cache
50-
uses: actions/[email protected].5
50+
uses: actions/[email protected].6
5151
with:
5252
path: "venv"
5353
key: py-v1-deps-${{ runner.os }}-${{ steps.set_up_python.outputs.python-version }}-${{ hashFiles('requirements.txt') }}-${{ hashFiles('requirements-dev.txt') }}-${{ hashFiles('Makefile', 'make/**.mk') }}

HISTORY.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# History
22

3+
## 0.22.0 (2023-03-09)
4+
5+
- (PR #446, 2023-03-07) chore(deps-dev): Bump mypy from 0.991 to 1.0.1
6+
- (PR #449, 2023-03-08) Drop support for Python 3.7
7+
- (PR #442, 2023-03-09) chore: Bump actions/cache from 3.2.5 to 3.2.6
8+
- (PR #440, 2023-03-09) fix(cte): Add default values for known missing codes in SII CTE Form 29
9+
310
## 0.21.0 (2023-02-28)
411

512
- (PR #441, 2023-03-01) Switch CI/CD from CircleCI to GitHub Actions

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ The full documentation is at <https://lib-cl-sii-python.readthedocs.io>.
3131

3232
## Supported Python versions
3333

34-
Only Python 3.7, 3.8, 3.9 and 3.10. Python 3.6 and below will not work because we use some features
35-
introduced in Python 3.7.
34+
Only Python 3.8, 3.9 and 3.10. Python 3.7 and below will not work because we use some features
35+
introduced in Python 3.8.
3636

3737
## Quickstart
3838

cl_sii/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@
55
"""
66

77

8-
__version__ = '0.21.0'
8+
__version__ = '0.22.0'

cl_sii/cte/f29/parse_datos_obj.py

Lines changed: 99 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from __future__ import annotations
22

3+
import copy
4+
import json
35
from datetime import datetime
46
from decimal import Decimal
57
from pathlib import Path
@@ -23,10 +25,17 @@
2325
)
2426
CTE_F29_DATOS_OBJ_SCHEMA = read_json_schema(_CTE_F29_DATOS_OBJ_SCHEMA_PATH)
2527

28+
_CTE_F29_DATOS_OBJ_MISSING_KEY_FIXES_PATH = (
29+
Path(__file__).parent.parent.parent / 'data' / 'cte' / 'f29_datos_obj_missing_key_fixes.json'
30+
)
31+
CTE_F29_DATOS_OBJ_MISSING_KEY_FIXES: SiiCteF29DatosObjType = json.load(
32+
open(_CTE_F29_DATOS_OBJ_MISSING_KEY_FIXES_PATH)
33+
)
34+
2635

2736
def parse_sii_cte_f29_datos_obj(
2837
datos_obj: SiiCteF29DatosObjType,
29-
schema_validator: Optional[Callable[[SiiCteF29DatosObjType], None]] = None,
38+
schema_validator: Optional[Callable[[SiiCteF29DatosObjType], SiiCteF29DatosObjType]] = None,
3039
campo_deserializer: Optional[Callable[[object, str], object]] = None,
3140
) -> CteForm29:
3241
"""
@@ -55,7 +64,7 @@ def parse_sii_cte_f29_datos_obj(
5564

5665
def _parse_sii_cte_f29_datos_obj_to_dict(
5766
datos_obj: SiiCteF29DatosObjType,
58-
schema_validator: Callable[[SiiCteF29DatosObjType], None],
67+
schema_validator: Callable[[SiiCteF29DatosObjType], SiiCteF29DatosObjType],
5968
campo_deserializer: Callable[[object, str], object],
6069
) -> Mapping[str, object]:
6170
"""
@@ -67,17 +76,17 @@ def _parse_sii_cte_f29_datos_obj_to_dict(
6776
:param campo_deserializer:
6877
:raises JsonSchemaValidationError: If schema validation fails.
6978
"""
70-
schema_validator(datos_obj)
79+
validated_datos_obj = schema_validator(datos_obj)
7180

7281
datos_obj_campos: Mapping[int, str] = {
73-
int(code): str(value) for code, value in datos_obj['campos'].items()
82+
int(code): str(value) for code, value in validated_datos_obj['campos'].items()
7483
}
75-
datos_obj_extras: Mapping[str, object] = datos_obj['extras']
84+
datos_obj_extras: Mapping[str, object] = validated_datos_obj['extras']
7685
datos_obj_glosa: Mapping[int, str] = { # noqa: F841
77-
int(code): str(value) for code, value in datos_obj['glosa'].items()
86+
int(code): str(value) for code, value in validated_datos_obj['glosa'].items()
7887
}
7988
datos_obj_tipos: Mapping[int, str] = {
80-
int(code): str(value) for code, value in datos_obj['tipos'].items()
89+
int(code): str(value) for code, value in validated_datos_obj['tipos'].items()
8190
}
8291

8392
deserialized_datos_obj_campos = {
@@ -156,12 +165,14 @@ def cte_f29_datos_obj_campo_best_effort_deserializer(campo_value: object, tipo:
156165
return deserialized_value
157166

158167

159-
def cte_f29_datos_schema_default_validator(datos_obj: SiiCteF29DatosObjType) -> None:
168+
def cte_f29_datos_schema_default_validator(
169+
datos_obj: SiiCteF29DatosObjType,
170+
) -> SiiCteF29DatosObjType:
160171
"""
161172
Validate the ``datos`` object against the schema.
162173
163174
:raises JsonSchemaValidationError: If schema validation fails.
164-
:returns: ``None`` if schema validation passed.
175+
:returns: Validated ``datos`` object if schema validation passed.
165176
"""
166177
try:
167178
jsonschema.validate(datos_obj, schema=CTE_F29_DATOS_OBJ_SCHEMA)
@@ -172,3 +183,82 @@ def cte_f29_datos_schema_default_validator(datos_obj: SiiCteF29DatosObjType) ->
172183
raise JsonSchemaValidationError("The keys of 'campos' and 'tipos' are not exactly the same")
173184
if datos_obj['campos'].keys() != datos_obj['glosa'].keys():
174185
raise JsonSchemaValidationError("The keys of 'campos' and 'tipos' are not exactly the same")
186+
187+
return datos_obj
188+
189+
190+
def cte_f29_datos_schema_best_effort_validator(
191+
datos_obj: SiiCteF29DatosObjType,
192+
) -> SiiCteF29DatosObjType:
193+
"""
194+
Validate the ``datos`` object against the schema.
195+
196+
If there are missing keys in the `tipos` or `glosa` dicts, it will try to get them
197+
from a list of default values.
198+
199+
:raises JsonSchemaValidationError: If schema validation fails.
200+
:returns: Validated ``datos`` object if schema validation passed.
201+
"""
202+
try:
203+
validated_datos_obj = cte_f29_datos_schema_default_validator(datos_obj)
204+
except JsonSchemaValidationError as exc:
205+
if exc.__cause__ is jsonschema.exceptions.ValidationError:
206+
# We will not try to fix this kind of error.
207+
raise
208+
elif exc.__cause__ is None:
209+
# Let's try to fix this.
210+
new_datos_obj = try_fix_cte_f29_datos(datos_obj)
211+
212+
# Let's try again.
213+
cte_f29_datos_schema_default_validator(new_datos_obj)
214+
return new_datos_obj
215+
else:
216+
raise
217+
else:
218+
return validated_datos_obj
219+
220+
221+
def try_fix_cte_f29_datos(datos_obj: SiiCteF29DatosObjType) -> SiiCteF29DatosObjType:
222+
"""
223+
Try to fix the ``datos`` object.
224+
225+
If there are missing keys in the `tipos` or `glosa` dicts, it will try to get them
226+
from a list of default values.
227+
228+
:raises JsonSchemaValidationError: If an unfixable issue is found.
229+
:returns: A possibly fixed ``datos`` object.
230+
"""
231+
new_datos_obj: Mapping[str, MutableMapping[str, object]]
232+
new_datos_obj = copy.deepcopy(datos_obj) # type: ignore[arg-type]
233+
234+
campos_tipos_keys_diff = datos_obj['campos'].keys() - datos_obj['tipos'].keys()
235+
remaining_campos_tipos_diff = (
236+
campos_tipos_keys_diff - CTE_F29_DATOS_OBJ_MISSING_KEY_FIXES['tipos'].keys()
237+
)
238+
if remaining_campos_tipos_diff:
239+
raise JsonSchemaValidationError(
240+
"The keys of 'campos' and 'tipos' differ for the following codes: "
241+
f"{remaining_campos_tipos_diff}"
242+
)
243+
else:
244+
for missing_key in campos_tipos_keys_diff:
245+
new_datos_obj['tipos'][missing_key] = CTE_F29_DATOS_OBJ_MISSING_KEY_FIXES['tipos'][
246+
missing_key
247+
]
248+
249+
campos_glosa_keys_diff = datos_obj['campos'].keys() - datos_obj['glosa'].keys()
250+
remaining_campos_glosa_diff = (
251+
campos_glosa_keys_diff - CTE_F29_DATOS_OBJ_MISSING_KEY_FIXES['glosa'].keys()
252+
)
253+
if remaining_campos_glosa_diff:
254+
raise JsonSchemaValidationError(
255+
"The keys of 'campos' and 'glosa' differ for the following codes: "
256+
f"{remaining_campos_glosa_diff}"
257+
)
258+
else:
259+
for missing_key in campos_glosa_keys_diff:
260+
new_datos_obj['glosa'][missing_key] = CTE_F29_DATOS_OBJ_MISSING_KEY_FIXES['glosa'][
261+
missing_key
262+
]
263+
264+
return new_datos_obj
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"glosa": {
3+
"049": "(Desconocido)"
4+
},
5+
"tipos": {
6+
"049": "M"
7+
}
8+
}

mypy.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[mypy]
2-
python_version = 3.7
2+
python_version = 3.8
33
platform = linux
44
files =
55
cl_sii,

0 commit comments

Comments
 (0)