diff --git a/.bumpversion.cfg b/.bumpversion.cfg index bcf97b41..c8aa3d1d 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.31.0 +current_version = 0.32.0 commit = True tag = False message = chore: Bump version from {current_version} to {new_version} diff --git a/.coveragerc.test.ini b/.coveragerc.test.ini new file mode 100644 index 00000000..295b959a --- /dev/null +++ b/.coveragerc.test.ini @@ -0,0 +1,18 @@ +[run] +source = src/ +omit = + src/scripts/* + src/tests/* +branch = True + +[report] +exclude_lines = + pragma: no cover + if __name__ == .__main__. +show_missing = True + +[xml] +output = test-reports/coverage/xml/coverage.xml + +[html] +directory = test-reports/coverage/html diff --git a/.flake8 b/.flake8 new file mode 100644 index 00000000..7b8f6f64 --- /dev/null +++ b/.flake8 @@ -0,0 +1,20 @@ +[flake8] +ignore = + # W503 line break before binary operator + W503 + +exclude = + *.egg-info/, + .git/, + .mypy_cache/, + .pyenvs/, + __pycache__/, + build/, + dist/, + docs/ + +max-line-length = 100 + +doctests = True +show-source = True +statistics = True diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index f4e86776..ba8d588d 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -137,7 +137,7 @@ jobs: - name: Store Artifacts if: ${{ always() }} - uses: actions/upload-artifact@v4.3.4 + uses: actions/upload-artifact@v4.3.6 with: name: test_reports_${{ matrix.python_version }} path: test-reports/ diff --git a/.github/workflows/dependency-review.yaml b/.github/workflows/dependency-review.yaml index 865a3540..2bff4f41 100644 --- a/.github/workflows/dependency-review.yaml +++ b/.github/workflows/dependency-review.yaml @@ -24,6 +24,6 @@ jobs: uses: actions/checkout@v4.1.7 - name: Dependency Review - uses: actions/dependency-review-action@v4.3.3 + uses: actions/dependency-review-action@v4.3.4 with: fail-on-severity: critical diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index a73732aa..4842f76f 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -68,7 +68,7 @@ jobs: make dist - name: Store Artifacts - uses: actions/upload-artifact@v4.3.4 + uses: actions/upload-artifact@v4.3.6 with: name: release path: ${{ env.ARTIFACTS_PATH }}/ diff --git a/HISTORY.md b/HISTORY.md index f588b139..3c83184f 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,23 @@ # History +## 0.32.0 (2024-08-28) + +- (PR #660, 2024-08-23) chore: Bump setuptools from 65.5.1 to 70.3.0 +- (PR #672, 2024-08-23) chore: Bump django from 4.2.14 to 4.2.15 +- (PR #676, 2024-08-23) chore(deps): Update `pip` from 23.3 to 24.2 +- (PR #677, 2024-08-23) chore(deps): Update `wheel` from ≤0.43.0 to 0.44.0 +- (PR #675, 2024-08-23) Replace Setuptools Configuration with Python Project Configuration +- (PR #670, 2024-08-23) chore: Bump jsonschema from 4.22.0 to 4.23.0 +- (PR #678, 2024-08-23) chore: Bump the development-dependencies group across 1 directory with 7 updates +- (PR #679, 2024-08-23) chore: Bump the production-dependencies group across 1 directory with 2 updates +- (PR #680, 2024-08-23) Test coverage broken by migration from `setup.py` to `pyproject.toml` +- (PR #668, 2024-08-23) chore: Bump pyopenssl from 24.1.0 to 24.2.1 +- (PR #673, 2024-08-23) chore(deps): Bump importlib-metadata from 7.1.0 to 8.4.0 +- (PR #681, 2024-08-28) Move Flake8 configuration from `setup.cfg` to its own file +- (PR #682, 2024-08-28) Move Coverage.py configuration from `setup.cfg` to its own file +- (PR #683, 2024-08-28) Replace `setup.py sdist` and `bdist_wheel` with `build` +- (PR #684, 2024-08-28) When running `twine check`, fail on warnings + ## 0.31.0 (2024-07-17) - (PR #661, 2024-07-17) extras: Add `RutFilter` for Django views and DRF views diff --git a/Makefile b/Makefile index 41faa1bd..14542897 100644 --- a/Makefile +++ b/Makefile @@ -101,7 +101,7 @@ test-all: ## run tests on every Python version with tox tox test-coverage: ## run tests and record test coverage - coverage run --rcfile=setup.cfg setup.py test + coverage run --rcfile=.coveragerc.test.ini -m unittest discover -v -c -b -s src -t src test-coverage-report: test-coverage-report-console test-coverage-report: test-coverage-report-xml @@ -109,21 +109,21 @@ test-coverage-report: test-coverage-report-html test-coverage-report: ## Run tests, measure code coverage, and generate reports test-coverage-report-console: ## print test coverage summary - coverage report --rcfile=setup.cfg -m + coverage report --rcfile=.coveragerc.test.ini -m test-coverage-report-xml: ## Generate test coverage XML report - coverage xml --rcfile=setup.cfg + coverage xml --rcfile=.coveragerc.test.ini test-coverage-report-html: ## generate test coverage HTML report - coverage html --rcfile=setup.cfg + coverage html --rcfile=.coveragerc.test.ini build: ## Build Python package $(PYTHON) setup.py build dist: build ## builds source and wheel package - python setup.py sdist - python setup.py bdist_wheel - twine check dist/* + python -m build --sdist + python -m build --wheel + twine check --strict dist/* ls -l dist upload-release: ## upload dist packages diff --git a/pyproject.toml b/pyproject.toml index 18d880de..c6b22efc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,14 +1,94 @@ # Python Project Configuration # # Documentation: +# - https://packaging.python.org/en/latest/specifications/pyproject-toml/ +# (https://github.com/pypa/packaging.python.org/blob/caa20073/source/specifications/pyproject-toml.rst) # - https://pip.pypa.io/en/stable/reference/build-system/pyproject-toml/ -# - https://github.com/pypa/pip/blob/23.2.1/docs/html/reference/build-system/pyproject-toml.md -# - https://packaging.python.org/en/latest/specifications/declaring-project-metadata/ -# - https://github.com/pypa/packaging.python.org/blob/df2c8b22/source/specifications/declaring-project-metadata.rst +# (https://github.com/pypa/pip/blob/24.2/docs/html/reference/build-system/pyproject-toml.md) +# - https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html +# (https://github.com/pypa/setuptools/blob/v70.3.0/docs/userguide/pyproject_config.rst) [build-system] requires = [ - "setuptools==65.5.1", - "wheel==0.41.3", + "setuptools==70.3.0", + "wheel==0.44.0", ] -build-backend = "setuptools.build_meta:__legacy__" +build-backend = "setuptools.build_meta" + +[project] +name = "cl-sii" +dependencies = [ + "cryptography>=38.0.0", + "defusedxml>=0.6.0,<1", + "jsonschema>=3.1.1", + "lxml>=4.6.5,<6", + "marshmallow>=3,<4", + "pydantic>=2.3.0,!=1.7.*,!=1.8.*,!=1.9.*", + "pyOpenSSL>=22.0.0", + "pytz>=2019.3", + "signxml>=3.1.0", +] +requires-python = ">=3.8, <3.11" +authors = [ + {name = "Fyntex TI SpA", email = "no-reply@fyntex.ai"}, +] +description = "Python library for Servicio de Impuestos Internos (SII) of Chile." +readme = "README.md" +license = {text = "MIT"} +classifiers = [ + # See https://pypi.org/classifiers/ + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Natural Language :: English", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", +] +dynamic = ["version"] + +[project.optional-dependencies] +django = ["Django>=2.2.24"] +django-filter = ["django-filter>=24.2"] +djangorestframework = ["djangorestframework>=3.10.3,<3.16"] + +[project.urls] +Homepage = "https://github.com/fyntex/lib-cl-sii-python" +Changelog = "https://github.com/fyntex/lib-cl-sii-python/blob/develop/HISTORY.md" + +[tool.setuptools] +include-package-data = true +zip-safe = false + +[tool.setuptools.packages.find] +where = ["src"] +include = ["*"] +exclude = [ + "scripts", + "tests*", +] +namespaces = true + +[tool.setuptools.package-data] +# note: the "typing information" of this project's packages is not made available to its users +# automatically; it needs to be packaged and distributed. The way to do so is fairly new and +# it is specified in PEP 561 - "Distributing and Packaging Type Information". +# See: +# - https://www.python.org/dev/peps/pep-0561/#packaging-type-information +# - https://github.com/python/typing/issues/84 +# - https://github.com/python/mypy/issues/3930 +# warning: remember to replicate this in the manifest file for source distribution ('MANIFEST.in'). +cl_sii = [ + # Indicates that the "typing information" of the package should be distributed. + "py.typed", + # Data files that are not in a sub-package. + "data/cte/schemas-json/*.schema.json", + "data/ref/factura_electronica/schemas-xml/*.xsd", +] + +[tool.setuptools.dynamic] +version = {attr = "cl_sii.__version__"} + +[tool.distutils.bdist_wheel] +universal = false diff --git a/requirements-dev.in b/requirements-dev.in index 128cfa57..4a3b3e98 100644 --- a/requirements-dev.in +++ b/requirements-dev.in @@ -4,16 +4,17 @@ -c requirements.txt -black==24.4.2 +black==24.8.0 +build==1.0.3 bumpversion==0.5.3 -coverage==7.5.4 -flake8==7.1.0 +coverage==7.6.1 +flake8==7.1.1 isort==5.13.2 -mypy==1.10.1 +mypy==1.11.1 pip-tools==7.4.1 -tox==4.16.0 +tox==4.18.0 twine==5.1.1 -types-jsonschema==4.22.0.20240610 -types-pyOpenSSL==24.1.0.20240425 +types-jsonschema==4.23.0.20240813 +types-pyOpenSSL==24.1.0.20240722 types-pytz==2024.1.0.20240417 -wheel==0.43.0 +wheel==0.44.0 diff --git a/requirements-dev.txt b/requirements-dev.txt index 14bd2108..fa0cd541 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -8,15 +8,17 @@ attrs==23.2.0 # via # -c requirements.txt # referencing -black==24.4.2 +black==24.8.0 # via -r requirements-dev.in bleach==5.0.1 # via readme-renderer build==1.0.3 - # via pip-tools + # via + # -r requirements-dev.in + # pip-tools bumpversion==0.5.3 # via -r requirements-dev.in -cachetools==5.3.3 +cachetools==5.5.0 # via tox certifi==2024.7.4 # via @@ -36,7 +38,7 @@ click==8.0.3 # pip-tools colorama==0.4.6 # via tox -coverage==7.5.4 +coverage==7.6.1 # via -r requirements-dev.in cryptography==42.0.8 # via @@ -51,11 +53,11 @@ filelock==3.15.4 # via # tox # virtualenv -flake8==7.1.0 +flake8==7.1.1 # via -r requirements-dev.in idna==3.7 # via requests -importlib-metadata==7.1.0 +importlib-metadata==8.4.0 # via # -c requirements.txt # build @@ -74,7 +76,7 @@ mccabe==0.7.0 # via flake8 mdurl==0.1.2 # via markdown-it-py -mypy==1.10.1 +mypy==1.11.1 # via -r requirements-dev.in mypy-extensions==1.0.0 # via @@ -151,15 +153,15 @@ tomli==2.0.1 # pyproject-api # pyproject-hooks # tox -tox==4.16.0 +tox==4.18.0 # via -r requirements-dev.in twine==5.1.1 # via -r requirements-dev.in types-cffi==1.16.0.20240331 # via types-pyopenssl -types-jsonschema==4.22.0.20240610 +types-jsonschema==4.23.0.20240813 # via -r requirements-dev.in -types-pyopenssl==24.1.0.20240425 +types-pyopenssl==24.1.0.20240722 # via -r requirements-dev.in types-pytz==2024.1.0.20240417 # via -r requirements-dev.in @@ -179,7 +181,7 @@ virtualenv==20.26.3 # via tox webencodings==0.5.1 # via bleach -wheel==0.43.0 +wheel==0.44.0 # via # -r requirements-dev.in # pip-tools @@ -189,7 +191,7 @@ zipp==3.19.2 # importlib-metadata # The following packages are considered to be unsafe in a requirements file: -pip==23.3 +pip==24.2 # via pip-tools -setuptools==65.5.1 +setuptools==70.3.0 # via pip-tools diff --git a/requirements.in b/requirements.in index 01ed5af9..a514d458 100644 --- a/requirements.in +++ b/requirements.in @@ -11,11 +11,11 @@ defusedxml==0.7.1 django-filter>=24.2 Django>=2.2.24 djangorestframework>=3.10.3,<3.16 -importlib-metadata==7.1.0 -jsonschema==4.22.0 +importlib-metadata==8.4.0 +jsonschema==4.23.0 lxml==5.2.2 marshmallow==3.21.3 pydantic==2.7.2 -pyOpenSSL==24.1.0 +pyOpenSSL==24.2.1 pytz==2024.1 signxml==3.2.2 diff --git a/requirements.txt b/requirements.txt index 0785636d..7996cb6b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -28,7 +28,7 @@ cryptography==42.0.8 # signxml defusedxml==0.7.1 # via -r requirements.in -django==4.2.14 +django==4.2.15 # via # -r requirements.in # django-filter @@ -37,13 +37,13 @@ django-filter==24.2 # via -r requirements.in djangorestframework==3.15.2 # via -r requirements.in -importlib-metadata==7.1.0 +importlib-metadata==8.4.0 # via -r requirements.in importlib-resources==6.4.0 # via # jsonschema # jsonschema-specifications -jsonschema==4.22.0 +jsonschema==4.23.0 # via -r requirements.in jsonschema-specifications==2023.12.1 # via jsonschema @@ -63,7 +63,7 @@ pydantic==2.7.2 # via -r requirements.in pydantic-core==2.18.3 # via pydantic -pyopenssl==24.1.0 +pyopenssl==24.2.1 # via # -r requirements.in # signxml diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 3746bf09..00000000 --- a/setup.cfg +++ /dev/null @@ -1,42 +0,0 @@ -[bdist_wheel] -universal = 0 - -[coverage:run] -source = src/ -omit = - src/scripts/* - src/tests/* -branch = True - -[coverage:report] -exclude_lines = - pragma: no cover - if __name__ == .__main__. -show_missing = True - -[coverage:xml] -output = test-reports/coverage/xml/coverage.xml - -[coverage:html] -directory = test-reports/coverage/html - -[flake8] -ignore = - # W503 line break before binary operator - W503 - -exclude = - *.egg-info/, - .git/, - .mypy_cache/, - .pyenvs/, - __pycache__/, - build/, - dist/, - docs/ - -max-line-length = 100 - -doctests = True -show-source = True -statistics = True diff --git a/setup.py b/setup.py index d39ae3e5..dd4e63e4 100644 --- a/setup.py +++ b/setup.py @@ -1,98 +1,6 @@ #!/usr/bin/env python -import os -import re -from typing import Sequence -from setuptools import find_packages, setup +from setuptools import setup -def get_version(*file_paths: str) -> str: - filename = os.path.join(os.path.dirname(__file__), *file_paths) - version_file = open(filename).read() - version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", version_file, re.M) - if version_match: - return version_match.group(1) - raise RuntimeError('Unable to find version string.') - - -version = get_version('src', 'cl_sii', '__init__.py') - -readme = open('README.md').read() -history = open('HISTORY.md').read() - -requirements = [ - 'cryptography>=38.0.0', - 'defusedxml>=0.6.0,<1', - 'jsonschema>=3.1.1', - 'lxml>=4.6.5,<6', - 'marshmallow>=3,<4', - 'pydantic>=2.3.0,!=1.7.*,!=1.8.*,!=1.9.*', - 'pyOpenSSL>=22.0.0', - 'pytz>=2019.3', - 'signxml>=3.1.0', -] - -extras_requirements = { - 'django': ['Django>=2.2.24'], - 'django-filter': ['django-filter>=24.2'], - 'djangorestframework': ['djangorestframework>=3.10.3,<3.16'], -} - -setup_requirements: Sequence[str] = [] - -test_requirements: Sequence[str] = [ - # note: include here only packages **imported** in test code (e.g. 'requests-mock'), NOT those - # like 'coverage' or 'tox'. -] - -# note: the "typing information" of this project's packages is not made available to its users -# automatically; it needs to be packaged and distributed. The way to do so is fairly new and -# it is specified in PEP 561 - "Distributing and Packaging Type Information". -# See: -# - https://www.python.org/dev/peps/pep-0561/#packaging-type-information -# - https://github.com/python/typing/issues/84 -# - https://github.com/python/mypy/issues/3930 -# warning: remember to replicate this in the manifest file for source distribution ('MANIFEST.in'). -_package_data = { - 'cl_sii': [ - # Indicates that the "typing information" of the package should be distributed. - 'py.typed', - # Data files that are not in a sub-package. - 'data/cte/schemas-json/*.schema.json', - 'data/ref/factura_electronica/schemas-xml/*.xsd', - ], -} - -setup( - author='Fyntex TI SpA', - author_email='no-reply@fyntex.ai', - classifiers=[ - # See https://pypi.org/classifiers/ - 'Development Status :: 3 - Alpha', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: MIT License', - 'Natural Language :: English', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', - 'Programming Language :: Python :: 3.10', - ], - description="""Python library for Servicio de Impuestos Internos (SII) of Chile.""", - extras_require=extras_requirements, - install_requires=requirements, - license="MIT", - long_description=readme + '\n\n' + history, - long_description_content_type='text/markdown', # for reStructuredText: 'text/x-rst' - include_package_data=True, - name='cl-sii', - package_data=_package_data, - package_dir={'': 'src'}, - packages=find_packages(where='src', exclude=['scripts', 'tests*']), - python_requires='>=3.8, <3.11', - setup_requires=setup_requirements, - test_suite='tests', - tests_require=test_requirements, - url='https://github.com/fyntex/lib-cl-sii-python', - version=version, - zip_safe=False, -) +setup() diff --git a/src/cl_sii/__init__.py b/src/cl_sii/__init__.py index 67546f89..2826ea58 100644 --- a/src/cl_sii/__init__.py +++ b/src/cl_sii/__init__.py @@ -4,4 +4,4 @@ """ -__version__ = '0.31.0' +__version__ = '0.32.0' diff --git a/src/scripts/clean_dte_xml_file.py b/src/scripts/clean_dte_xml_file.py index 3f846902..cb1f3ca9 100755 --- a/src/scripts/clean_dte_xml_file.py +++ b/src/scripts/clean_dte_xml_file.py @@ -62,17 +62,16 @@ def clean_dte_xml_file(input_file_path: str, output_file_path: str) -> Iterable[ # note: another way to compute the difference in a similar format is # `diff -Naur $input_file_path $output_file_path` file_bytes_diff_gen = difflib.diff_bytes( - dfunc=difflib.unified_diff, - a=file_bytes.splitlines(), - b=file_bytes_rewritten.splitlines()) + dfunc=difflib.unified_diff, a=file_bytes.splitlines(), b=file_bytes_rewritten.splitlines() + ) return file_bytes_diff_gen def main_single_file(input_file_path: str, output_file_path: str) -> None: file_bytes_diff_gen = clean_dte_xml_file( - input_file_path=input_file_path, - output_file_path=output_file_path) + input_file_path=input_file_path, output_file_path=output_file_path + ) for diff_line in file_bytes_diff_gen: print(diff_line) @@ -89,8 +88,8 @@ def main_dir_files(input_files_dir_path: str) -> None: print(f"\n\nWill clean file '{input_file_path}' and save it to '{output_file_path}'.") file_bytes_diff_gen = clean_dte_xml_file( - input_file_path=input_file_path, - output_file_path=output_file_path) + input_file_path=input_file_path, output_file_path=output_file_path + ) print("Difference between input and output files:") diff_line = None @@ -102,11 +101,8 @@ def main_dir_files(input_files_dir_path: str) -> None: if __name__ == '__main__': if sys.argv[1] == 'file': - main_single_file( - input_file_path=sys.argv[2], - output_file_path=sys.argv[3]) + main_single_file(input_file_path=sys.argv[2], output_file_path=sys.argv[3]) elif sys.argv[1] == 'dir': - main_dir_files( - input_files_dir_path=sys.argv[2]) + main_dir_files(input_files_dir_path=sys.argv[2]) else: raise ValueError(f"Invalid option: '{sys.argv[1]}'") diff --git a/src/scripts/example.py b/src/scripts/example.py index 8c4259af..5c88cf19 100755 --- a/src/scripts/example.py +++ b/src/scripts/example.py @@ -49,6 +49,7 @@ # script ############################################################################### + def main(args: Sequence[str]) -> None: start_ts = datetime.now() @@ -57,8 +58,7 @@ def main(args: Sequence[str]) -> None: try: print("Action: do something") except FileNotFoundError: - logger.exception( - "Process aborted: a file could not be opened.", exc_info=True) + logger.exception("Process aborted: a file could not be opened.", exc_info=True) except KeyboardInterrupt: logger.error("Process interrupted by user.") except Exception: diff --git a/tox.ini b/tox.ini index 1fe875ad..779afe35 100644 --- a/tox.ini +++ b/tox.ini @@ -7,7 +7,7 @@ envlist = [testenv] setenv = PYTHONPATH = {toxinidir}:{toxinidir}/cl_sii -commands = coverage run --rcfile=setup.cfg setup.py test +commands = coverage run --rcfile=.coveragerc.test.ini -m unittest discover -v -c -b -s src -t src deps = -r{toxinidir}/requirements.txt -r{toxinidir}/requirements-dev.txt