From 25c0ba1d9a6f1a00ae5657c23638464a5a1b27f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20St=C3=ADskala?= Date: Wed, 5 Apr 2023 15:14:47 +0200 Subject: [PATCH] Flake test and black code formatting (#10) * Files formatting using black * Added ruff for flake tests * Added pre-commit hooks * Dropped support for Python 3.7 --- .editorconfig | 3 +- .github/workflows/main.yml | 8 +- .gitignore | 3 +- .pre-commit-config.yaml | 10 ++ README.md | 5 + poetry.lock | 316 ++++++++++++++++++++++++++++++++++--- pyproject.toml | 18 ++- qrplatba/__init__.py | 2 + qrplatba/spayd.py | 85 ++++++---- qrplatba/svg.py | 53 ++++--- tests/test_svg.py | 36 ++--- 11 files changed, 430 insertions(+), 109 deletions(-) create mode 100644 .pre-commit-config.yaml diff --git a/.editorconfig b/.editorconfig index dfcd4e9..9d1205d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,8 +7,9 @@ indent_style = space indent_size = 4 insert_final_newline = true trim_trailing_whitespace = true +max_line_length = 120 -[*.yml] +[{*.yml,*.yaml}] indent_size = 2 [Makefile] diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 28bf416..64ac2ca 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -26,7 +26,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [ "3.7", "3.8", "3.9", "3.10", "3.11" ] + python-version: [ "3.8", "3.9", "3.10", "3.11" ] defaults: run: shell: bash @@ -75,6 +75,12 @@ jobs: - name: Run pytest run: poetry run pytest -v + - name: Run ruff + run: poetry run ruff . + + - name: Run black + run: poetry run black --check . + - name: Check for clean working tree run: | git diff --exit-code --stat HEAD diff --git a/.gitignore b/.gitignore index b573ab0..682d2fb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ -__pycache__ +__pycache__/ *.pyc dist/ .idea/ qrplatba.egg-info/ +.*_cache/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..9496e87 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,10 @@ +repos: + - repo: https://github.com/psf/black + rev: 23.3.0 + hooks: + - id: black + language_version: python3.11 + - repo: https://github.com/charliermarsh/ruff-pre-commit + rev: 'v0.0.260' + hooks: + - id: ruff diff --git a/README.md b/README.md index ac26ef2..7dd7fc1 100644 --- a/README.md +++ b/README.md @@ -63,5 +63,10 @@ This software is licensed under [MIT license](https://opensource.org/license/mit - Changed license to MIT - Added unit tests +### `1.1.0` (5 April 2023) + +- Dropped support for Python 3.7 +- Added pre-commit, black and ruff for code formatting + diff --git a/poetry.lock b/poetry.lock index 01e3c31..5d6be83 100644 --- a/poetry.lock +++ b/poetry.lock @@ -19,6 +19,83 @@ docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib- tests = ["attrs[tests-no-zope]", "zope.interface"] tests-no-zope = ["cloudpickle", "cloudpickle", "hypothesis", "hypothesis", "mypy (>=0.971,<0.990)", "mypy (>=0.971,<0.990)", "pympler", "pympler", "pytest (>=4.3.0)", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-mypy-plugins", "pytest-xdist[psutil]", "pytest-xdist[psutil]"] +[[package]] +name = "black" +version = "23.3.0" +description = "The uncompromising code formatter." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "black-23.3.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:0945e13506be58bf7db93ee5853243eb368ace1c08a24c65ce108986eac65915"}, + {file = "black-23.3.0-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:67de8d0c209eb5b330cce2469503de11bca4085880d62f1628bd9972cc3366b9"}, + {file = "black-23.3.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:7c3eb7cea23904399866c55826b31c1f55bbcd3890ce22ff70466b907b6775c2"}, + {file = "black-23.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32daa9783106c28815d05b724238e30718f34155653d4d6e125dc7daec8e260c"}, + {file = "black-23.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:35d1381d7a22cc5b2be2f72c7dfdae4072a3336060635718cc7e1ede24221d6c"}, + {file = "black-23.3.0-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:a8a968125d0a6a404842fa1bf0b349a568634f856aa08ffaff40ae0dfa52e7c6"}, + {file = "black-23.3.0-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:c7ab5790333c448903c4b721b59c0d80b11fe5e9803d8703e84dcb8da56fec1b"}, + {file = "black-23.3.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:a6f6886c9869d4daae2d1715ce34a19bbc4b95006d20ed785ca00fa03cba312d"}, + {file = "black-23.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f3c333ea1dd6771b2d3777482429864f8e258899f6ff05826c3a4fcc5ce3f70"}, + {file = "black-23.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:11c410f71b876f961d1de77b9699ad19f939094c3a677323f43d7a29855fe326"}, + {file = "black-23.3.0-cp37-cp37m-macosx_10_16_x86_64.whl", hash = "sha256:1d06691f1eb8de91cd1b322f21e3bfc9efe0c7ca1f0e1eb1db44ea367dff656b"}, + {file = "black-23.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50cb33cac881766a5cd9913e10ff75b1e8eb71babf4c7104f2e9c52da1fb7de2"}, + {file = "black-23.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:e114420bf26b90d4b9daa597351337762b63039752bdf72bf361364c1aa05925"}, + {file = "black-23.3.0-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:48f9d345675bb7fbc3dd85821b12487e1b9a75242028adad0333ce36ed2a6d27"}, + {file = "black-23.3.0-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:714290490c18fb0126baa0fca0a54ee795f7502b44177e1ce7624ba1c00f2331"}, + {file = "black-23.3.0-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:064101748afa12ad2291c2b91c960be28b817c0c7eaa35bec09cc63aa56493c5"}, + {file = "black-23.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:562bd3a70495facf56814293149e51aa1be9931567474993c7942ff7d3533961"}, + {file = "black-23.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:e198cf27888ad6f4ff331ca1c48ffc038848ea9f031a3b40ba36aced7e22f2c8"}, + {file = "black-23.3.0-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:3238f2aacf827d18d26db07524e44741233ae09a584273aa059066d644ca7b30"}, + {file = "black-23.3.0-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:f0bd2f4a58d6666500542b26354978218a9babcdc972722f4bf90779524515f3"}, + {file = "black-23.3.0-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:92c543f6854c28a3c7f39f4d9b7694f9a6eb9d3c5e2ece488c327b6e7ea9b266"}, + {file = "black-23.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a150542a204124ed00683f0db1f5cf1c2aaaa9cc3495b7a3b5976fb136090ab"}, + {file = "black-23.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:6b39abdfb402002b8a7d030ccc85cf5afff64ee90fa4c5aebc531e3ad0175ddb"}, + {file = "black-23.3.0-py3-none-any.whl", hash = "sha256:ec751418022185b0c1bb7d7736e6933d40bbb14c14a0abcf9123d1b159f98dd4"}, + {file = "black-23.3.0.tar.gz", hash = "sha256:1c7b8d606e728a41ea1ccbd7264677e494e87cf630e399262ced92d4a8dac940"}, +] + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +packaging = ">=22.0" +pathspec = ">=0.9.0" +platformdirs = ">=2" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.7.4)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "cfgv" +version = "3.3.1" +description = "Validate configuration and produce human readable error messages." +category = "dev" +optional = false +python-versions = ">=3.6.1" +files = [ + {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"}, + {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"}, +] + +[[package]] +name = "click" +version = "8.1.3" +description = "Composable command line interface toolkit" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, + {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + [[package]] name = "colorama" version = "0.4.6" @@ -31,6 +108,18 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +[[package]] +name = "distlib" +version = "0.3.6" +description = "Distribution utilities" +category = "dev" +optional = false +python-versions = "*" +files = [ + {file = "distlib-0.3.6-py2.py3-none-any.whl", hash = "sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e"}, + {file = "distlib-0.3.6.tar.gz", hash = "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46"}, +] + [[package]] name = "exceptiongroup" version = "1.1.1" @@ -47,25 +136,35 @@ files = [ test = ["pytest (>=6)"] [[package]] -name = "importlib-metadata" -version = "6.1.0" -description = "Read metadata from Python packages" +name = "filelock" +version = "3.10.7" +description = "A platform independent file lock." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "importlib_metadata-6.1.0-py3-none-any.whl", hash = "sha256:ff80f3b5394912eb1b108fcfd444dc78b7f1f3e16b16188054bd01cb9cb86f09"}, - {file = "importlib_metadata-6.1.0.tar.gz", hash = "sha256:43ce9281e097583d758c2c708c4376371261a02c34682491a8e98352365aad20"}, + {file = "filelock-3.10.7-py3-none-any.whl", hash = "sha256:bde48477b15fde2c7e5a0713cbe72721cb5a5ad32ee0b8f419907960b9d75536"}, + {file = "filelock-3.10.7.tar.gz", hash = "sha256:892be14aa8efc01673b5ed6589dbccb95f9a8596f0507e232626155495c18105"}, ] -[package.dependencies] -typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} -zipp = ">=0.5" +[package.extras] +docs = ["furo (>=2022.12.7)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.22,!=1.23.4)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.2.2)", "diff-cover (>=7.5)", "pytest (>=7.2.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] + +[[package]] +name = "identify" +version = "2.5.22" +description = "File identification library for Python" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "identify-2.5.22-py2.py3-none-any.whl", hash = "sha256:f0faad595a4687053669c112004178149f6c326db71ee999ae4636685753ad2f"}, + {file = "identify-2.5.22.tar.gz", hash = "sha256:f7a93d6cf98e29bd07663c60728e7a4057615068d7a639d132dc883b2d54d31e"}, +] [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -perf = ["ipython"] -testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] +license = ["ukkonen"] [[package]] name = "iniconfig" @@ -79,6 +178,33 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +category = "dev" +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "nodeenv" +version = "1.7.0" +description = "Node.js virtual environment builder" +category = "dev" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" +files = [ + {file = "nodeenv-1.7.0-py2.py3-none-any.whl", hash = "sha256:27083a7b96a25f2f5e1d8cb4b6317ee8aeda3bdd121394e5ac54e498028a042e"}, + {file = "nodeenv-1.7.0.tar.gz", hash = "sha256:e0e7f7dfb85fc5394c6fe1e8fa98131a2473e04311a45afb6508f7cf1836fa2b"}, +] + +[package.dependencies] +setuptools = "*" + [[package]] name = "packaging" version = "23.0" @@ -91,6 +217,34 @@ files = [ {file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"}, ] +[[package]] +name = "pathspec" +version = "0.11.1" +description = "Utility library for gitignore style pattern matching of file paths." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pathspec-0.11.1-py3-none-any.whl", hash = "sha256:d8af70af76652554bd134c22b3e8a1cc46ed7d91edcdd721ef1a0c51a84a5293"}, + {file = "pathspec-0.11.1.tar.gz", hash = "sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687"}, +] + +[[package]] +name = "platformdirs" +version = "3.2.0" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "platformdirs-3.2.0-py3-none-any.whl", hash = "sha256:ebe11c0d7a805086e99506aa331612429a72ca7cd52a1f0d277dc4adc20cb10e"}, + {file = "platformdirs-3.2.0.tar.gz", hash = "sha256:d5b638ca397f25f979350ff789db335903d7ea010ab28903f57b27e1b16c2b08"}, +] + +[package.extras] +docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.22,!=1.23.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.2.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] + [[package]] name = "pluggy" version = "1.0.0" @@ -103,13 +257,29 @@ files = [ {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, ] -[package.dependencies] -importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} - [package.extras] dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] +[[package]] +name = "pre-commit" +version = "3.2.2" +description = "A framework for managing and maintaining multi-language pre-commit hooks." +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pre_commit-3.2.2-py2.py3-none-any.whl", hash = "sha256:0b4210aea813fe81144e87c5a291f09ea66f199f367fa1df41b55e1d26e1e2b4"}, + {file = "pre_commit-3.2.2.tar.gz", hash = "sha256:5b808fcbda4afbccf6d6633a56663fed35b6c2bc08096fd3d47ce197ac351d9d"}, +] + +[package.dependencies] +cfgv = ">=2.0.0" +identify = ">=1.0.0" +nodeenv = ">=0.11.1" +pyyaml = ">=5.1" +virtualenv = ">=20.10.0" + [[package]] name = "pypng" version = "0.20220715.0" @@ -138,7 +308,6 @@ files = [ attrs = ">=19.2.0" colorama = {version = "*", markers = "sys_platform == \"win32\""} exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} -importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} iniconfig = "*" packaging = "*" pluggy = ">=0.12,<2.0" @@ -162,6 +331,56 @@ files = [ [package.dependencies] pytest = ">=4.0.0" +[[package]] +name = "pyyaml" +version = "6.0" +description = "YAML parser and emitter for Python" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, + {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, + {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, + {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, + {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"}, + {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"}, + {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"}, + {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"}, + {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, + {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, + {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, + {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, + {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, + {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, + {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, + {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, + {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, + {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, + {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, + {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, + {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, + {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, +] + [[package]] name = "qrcode" version = "7.4.2" @@ -186,6 +405,50 @@ maintainer = ["zest.releaser[recommended]"] pil = ["pillow (>=9.1.0)"] test = ["coverage", "pytest"] +[[package]] +name = "ruff" +version = "0.0.261" +description = "An extremely fast Python linter, written in Rust." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruff-0.0.261-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:6624a966c4a21110cee6780333e2216522a831364896f3d98f13120936eff40a"}, + {file = "ruff-0.0.261-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:2dba68a9e558ab33e6dd5d280af798a2d9d3c80c913ad9c8b8e97d7b287f1cc9"}, + {file = "ruff-0.0.261-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8dbd0cee5a81b0785dc0feeb2640c1e31abe93f0d77c5233507ac59731a626f1"}, + {file = "ruff-0.0.261-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:581e64fa1518df495ca890a605ee65065101a86db56b6858f848bade69fc6489"}, + {file = "ruff-0.0.261-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cc970f6ece0b4950e419f0252895ee42e9e8e5689c6494d18f5dc2c6ebb7f798"}, + {file = "ruff-0.0.261-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:8fa98e747e0fe185d65a40b0ea13f55c492f3b5f9a032a1097e82edaddb9e52e"}, + {file = "ruff-0.0.261-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f268d52a71bf410aa45c232870c17049df322a7d20e871cfe622c9fc784aab7b"}, + {file = "ruff-0.0.261-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1293acc64eba16a11109678dc4743df08c207ed2edbeaf38b3e10eb2597321b"}, + {file = "ruff-0.0.261-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d95596e2f4cafead19a6d1ec0b86f8fda45ba66fe934de3956d71146a87959b3"}, + {file = "ruff-0.0.261-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:4bcec45abdf65c1328a269cf6cc193f7ff85b777fa2865c64cf2c96b80148a2c"}, + {file = "ruff-0.0.261-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:6c5f397ec0af42a434ad4b6f86565027406c5d0d0ebeea0d5b3f90c4bf55bc82"}, + {file = "ruff-0.0.261-py3-none-musllinux_1_2_i686.whl", hash = "sha256:39abd02342cec0c131b2ddcaace08b2eae9700cab3ca7dba64ae5fd4f4881bd0"}, + {file = "ruff-0.0.261-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:aaa4f52a6e513f8daa450dac4859e80390d947052f592f0d8e796baab24df2fc"}, + {file = "ruff-0.0.261-py3-none-win32.whl", hash = "sha256:daff64b4e86e42ce69e6367d63aab9562fc213cd4db0e146859df8abc283dba0"}, + {file = "ruff-0.0.261-py3-none-win_amd64.whl", hash = "sha256:0fbc689c23609edda36169c8708bb91bab111d8f44cb4a88330541757770ab30"}, + {file = "ruff-0.0.261-py3-none-win_arm64.whl", hash = "sha256:d2eddc60ae75fc87f8bb8fd6e8d5339cf884cd6de81e82a50287424309c187ba"}, + {file = "ruff-0.0.261.tar.gz", hash = "sha256:c1c715b0d1e18f9c509d7c411ca61da3543a4aa459325b1b1e52b8301d65c6d2"}, +] + +[[package]] +name = "setuptools" +version = "67.6.1" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "setuptools-67.6.1-py3-none-any.whl", hash = "sha256:e728ca814a823bf7bf60162daf9db95b93d532948c4c0bea762ce62f60189078"}, + {file = "setuptools-67.6.1.tar.gz", hash = "sha256:257de92a9d50a60b8e22abfcbb771571fde0dbf3ec234463212027a4eeecbe9a"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] + [[package]] name = "tomli" version = "2.0.1" @@ -211,22 +474,27 @@ files = [ ] [[package]] -name = "zipp" -version = "3.15.0" -description = "Backport of pathlib-compatible object wrapper for zip files" +name = "virtualenv" +version = "20.21.0" +description = "Virtual Python Environment builder" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "zipp-3.15.0-py3-none-any.whl", hash = "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556"}, - {file = "zipp-3.15.0.tar.gz", hash = "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b"}, + {file = "virtualenv-20.21.0-py3-none-any.whl", hash = "sha256:31712f8f2a17bd06234fa97fdf19609e789dd4e3e4bf108c3da71d710651adbc"}, + {file = "virtualenv-20.21.0.tar.gz", hash = "sha256:f50e3e60f990a0757c9b68333c9fdaa72d7188caa417f96af9e52407831a3b68"}, ] +[package.dependencies] +distlib = ">=0.3.6,<1" +filelock = ">=3.4.1,<4" +platformdirs = ">=2.4,<4" + [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] +docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=22.12)"] +test = ["covdefaults (>=2.2.2)", "coverage (>=7.1)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23)", "pytest (>=7.2.1)", "pytest-env (>=0.8.1)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.10)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)"] [metadata] lock-version = "2.0" -python-versions = "^3.7" -content-hash = "8a9c39a1aa9360100d298be9cc350a82a1ae02262dcb40f37b32e5781a785d69" +python-versions = "^3.8" +content-hash = "8f83be87a044a2e37239ae98d848534271abd12e805eb46c1e1235fecf071bbf" diff --git a/pyproject.toml b/pyproject.toml index aaa6add..29be5b7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "qrplatba" -version = "1.0.0" +version = "1.1.0" description = "QR platba SVG QR code and SPAYD string generator." authors = ["Viktor Stískala "] repository = "https://github.com/ViktorStiskala/python-qrplatba" @@ -8,7 +8,6 @@ classifiers=[ 'Intended Audience :: Developers', 'Operating System :: OS Independent', 'Programming Language :: Python', - 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', @@ -20,18 +19,25 @@ license = "MIT" readme = "README.md" [tool.poetry.dependencies] -python = "^3.7" +python = "^3.8" qrcode = "^7.4" -[tool.poetry.dev-dependencies] - [tool.poetry.group.test] optional = true - [tool.poetry.group.test.dependencies] pytest = "^7.2" pytest-github-actions-annotate-failures = "^0.1.8" +ruff = "^0.0.261" +black = "^23.3.0" + +[tool.poetry.group.dev.dependencies] +pre-commit = "^3.2.2" + +[tool.ruff] +line-length = 120 +[tool.black] +line-length = 120 [build-system] requires = ["poetry-core>=1.0.0"] diff --git a/qrplatba/__init__.py b/qrplatba/__init__.py index 4f77c2b..01f5d38 100644 --- a/qrplatba/__init__.py +++ b/qrplatba/__init__.py @@ -1 +1,3 @@ from .spayd import QRPlatbaGenerator + +__all__ = ["QRPlatbaGenerator"] diff --git a/qrplatba/spayd.py b/qrplatba/spayd.py index 581e68d..0d7e134 100644 --- a/qrplatba/spayd.py +++ b/qrplatba/spayd.py @@ -5,15 +5,32 @@ class QRPlatbaGenerator: - RE_ACCOUNT = re.compile(r'((?P\d+(?=-))-)?(?P\d+)/(?P\d{4})') - - def __init__(self, account, amount=None, currency=None, x_vs=None, x_ss=None, x_ks=None, alternate_accounts=None, recipient_name=None, - due_date=None, payment_type=None, message=None, notification_type=None, notification_address=None, x_per=None, x_id=None, - x_url=None, reference=None): + RE_ACCOUNT = re.compile(r"((?P\d+(?=-))-)?(?P\d+)/(?P\d{4})") + + def __init__( + self, + account, + amount=None, + currency=None, + x_vs=None, + x_ss=None, + x_ks=None, + alternate_accounts=None, + recipient_name=None, + due_date=None, + payment_type=None, + message=None, + notification_type=None, + notification_address=None, + x_per=None, + x_id=None, + x_url=None, + reference=None, + ): """ http://qr-platba.cz/pro-vyvojare/specifikace-formatu/ - :param account: ACC account number, can be specified either as IBAN or in CZ commonly used format 12-123456789/0300 + :param account: ACC account number, can be specified either as IBAN or in CZ format 12-123456789/0300 :param amount: AM payment amount :param currency: CC currency (3 digits) :param x_vs: X-VS @@ -54,14 +71,14 @@ def _convert_to_iban(self, account): Convert czech account number to IBAN """ acc = self.RE_ACCOUNT.match(account) - iban = 'CZ00{b}{ba:0>6}{a:0>10}'.format( - ba=acc.group('ba') or 0, - a=acc.group('a'), - b=acc.group('b'), + iban = "CZ00{b}{ba:0>6}{a:0>10}".format( + ba=acc.group("ba") or 0, + a=acc.group("a"), + b=acc.group("b"), ) # convert IBAN letters into numbers - crc = re.sub(r'[A-Z]', lambda m: str(ord(m.group(0)) - 55), iban[4:] + iban[:4]) + crc = re.sub(r"[A-Z]", lambda m: str(ord(m.group(0)) - 55), iban[4:] + iban[:4]) # compute control digits digits = "{:0>2}".format(98 - int(crc) % 97) @@ -71,7 +88,7 @@ def _convert_to_iban(self, account): @property def _account(self): if self.account is not None: - out = 'ACC:{}*' + out = "ACC:{}*" if self.RE_ACCOUNT.match(self.account): return out.format(self._convert_to_iban(self.account)) @@ -87,8 +104,8 @@ def _alternate_accounts(self): formatted.append(self._convert_to_iban(account)) else: formatted.append(account) - return "ALT-ACC:{}*".format(','.join(formatted)) - return '' + return "ALT-ACC:{}*".format(",".join(formatted)) + return "" @property def _amount(self): @@ -99,39 +116,39 @@ def _amount(self): @property def _due_date(self): if self.due_date is not None: - str_part = 'DT:{}*' + str_part = "DT:{}*" if isinstance(self.due_date, datetime): - return str_part.format(self.due_date.date().isoformat()).replace('-', '') + return str_part.format(self.due_date.date().isoformat()).replace("-", "") if isinstance(self.due_date, date): - return str_part.format(self.due_date.isoformat()).replace('-', '') + return str_part.format(self.due_date.isoformat()).replace("-", "") return str_part.format(self.due_date) - return '' + return "" def _format_item_string(self, item, name): if item: return "{name}:{value}*".format(name=name, value=item) - return '' + return "" def get_text(self): return "SPD*1.0*{ACC}{ALTACC}{AM}{CC}{RF}{RN}{DT}{PT}{MSG}{NT}{NTA}{XPER}{XVS}{XSS}{XKS}{XID}{XURL}".format( ACC=self._account, ALTACC=self._alternate_accounts, AM=self._amount, - CC=self._format_item_string(self.currency, 'CC'), - RF=self._format_item_string(self.reference, 'RF'), - RN=self._format_item_string(self.recipient_name, 'RN'), + CC=self._format_item_string(self.currency, "CC"), + RF=self._format_item_string(self.reference, "RF"), + RN=self._format_item_string(self.recipient_name, "RN"), DT=self._due_date, - PT=self._format_item_string(self.payment_type, 'PT'), - MSG=self._format_item_string(self.message, 'MSG'), - NT=self._format_item_string(self.notification_type, 'NT'), - NTA=self._format_item_string(self.notification_address, 'NTA'), - XPER=self._format_item_string(self.x_per, 'X-PER'), - XVS=self._format_item_string(self.x_vs, 'X-VS'), - XSS=self._format_item_string(self.x_ss, 'X-SS'), - XKS=self._format_item_string(self.x_ks, 'X-KS'), - XID=self._format_item_string(self.x_id, 'X-ID'), - XURL=self._format_item_string(self.x_url, 'X-URL') - ).rstrip('*') + PT=self._format_item_string(self.payment_type, "PT"), + MSG=self._format_item_string(self.message, "MSG"), + NT=self._format_item_string(self.notification_type, "NT"), + NTA=self._format_item_string(self.notification_address, "NTA"), + XPER=self._format_item_string(self.x_per, "X-PER"), + XVS=self._format_item_string(self.x_vs, "X-VS"), + XSS=self._format_item_string(self.x_ss, "X-SS"), + XKS=self._format_item_string(self.x_ks, "X-KS"), + XID=self._format_item_string(self.x_id, "X-ID"), + XURL=self._format_item_string(self.x_url, "X-URL"), + ).rstrip("*") def make_image(self, border=2, box_size=12, error_correction=qrcode.constants.ERROR_CORRECT_M): qr = qrcode.QRCode( @@ -139,7 +156,7 @@ def make_image(self, border=2, box_size=12, error_correction=qrcode.constants.ER error_correction=error_correction, image_factory=QRPlatbaSVGImage, border=border, - box_size=box_size + box_size=box_size, ) qr.add_data(self.get_text()) qr.make(fit=True) diff --git a/qrplatba/svg.py b/qrplatba/svg.py index 6c396c5..16deb55 100644 --- a/qrplatba/svg.py +++ b/qrplatba/svg.py @@ -21,11 +21,11 @@ class QRPlatbaSVGImage(svg.SvgPathImage): text size is computed to achieve width of 16 QR points. """ - QR_TEXT_STYLE = 'font-size:{size}px;font-weight:bold;fill:#000000;font-family:Arial;' - FONT_SIZE = Decimal('3.5') - FONT_HEIGHT = Decimal('8') + QR_TEXT_STYLE = "font-size:{size}px;font-weight:bold;fill:#000000;font-family:Arial;" + FONT_SIZE = Decimal("3.5") + FONT_HEIGHT = Decimal("8") - LINE_SIZE = Decimal('0.25') + LINE_SIZE = Decimal("0.25") INSIDE_BORDER = 4 BOTTOM_LINE_SEGMENTS = (2, 22) @@ -41,25 +41,25 @@ def _get_scaled_sizes(self): scale_ratio = self.units(self.box_size, text=False) def strip_zeros(value): - return Decimal(str(value).rstrip('0').rstrip('.')) if '.' in str(value) else value + return Decimal(str(value).rstrip("0").rstrip(".")) if "." in str(value) else value return ScaledSizes( inside_border=strip_zeros(self.INSIDE_BORDER * scale_ratio), outside_border=strip_zeros(self.outside_border * scale_ratio), width=strip_zeros(self.width * scale_ratio), line_size=strip_zeros(self.LINE_SIZE * scale_ratio), - ratio=scale_ratio + ratio=scale_ratio, ) def make_border(self): """Creates black thin border around QR code""" scaled = self._get_scaled_sizes() - def sizes(o, i, w, l): # size helper - return o * scaled.outside_border + i * scaled.inside_border + w * scaled.width + l * scaled.line_size + def sizes(ob, ib, wd, ln): # size helper + return ob * scaled.outside_border + ib * scaled.inside_border + wd * scaled.width + ln * scaled.line_size - horizontal_line = 'M{x0},{y0}h{length}v{width}h-{length}z' - vertical_line = 'M{x0},{y0}v{length}h{width}v-{length}z' + horizontal_line = "M{x0},{y0}h{length}v{width}h-{length}z" + vertical_line = "M{x0},{y0}v{length}h{width}v-{length}z" def get_subpaths(): # top line @@ -67,7 +67,7 @@ def get_subpaths(): x0=scaled.outside_border, y0=scaled.outside_border, length=sizes(0, 2, 1, 2), - width=scaled.line_size + width=scaled.line_size, ) b_first, b_second = self.BOTTOM_LINE_SEGMENTS @@ -77,7 +77,7 @@ def get_subpaths(): x0=scaled.outside_border, y0=sizes(1, 2, 1, 1), length=b_first * scaled.ratio, - width=scaled.line_size + width=scaled.line_size, ) # bottom line - second segment @@ -85,7 +85,7 @@ def get_subpaths(): x0=scaled.outside_border + b_second * scaled.ratio, y0=sizes(1, 2, 1, 1), length=sizes(0, 2, 1, 2) - b_second * scaled.ratio, - width=scaled.line_size + width=scaled.line_size, ) # left line @@ -93,7 +93,7 @@ def get_subpaths(): x0=scaled.outside_border, y0=scaled.outside_border + scaled.line_size, length=scaled.width + 2 * scaled.inside_border, - width=scaled.line_size + width=scaled.line_size, ) # right line @@ -101,22 +101,28 @@ def get_subpaths(): x0=sizes(1, 2, 1, 1), y0=sizes(1, 0, 0, 1), length=sizes(0, 2, 1, 0), - width=scaled.line_size + width=scaled.line_size, ) - subpaths = ' '.join(get_subpaths()) - return ET.Element('path', d=subpaths, id="qrplatba-border", **self.QR_PATH_STYLE) + subpaths = " ".join(get_subpaths()) + return ET.Element("path", d=subpaths, id="qrplatba-border", **self.QR_PATH_STYLE) def make_text(self): """Creates "QR platba" text element""" scaled = self._get_scaled_sizes() - text_style = self.QR_TEXT_STYLE.format(size=(self.FONT_SIZE * scaled.ratio).quantize(Decimal('0.01'))) + text_style = self.QR_TEXT_STYLE.format(size=(self.FONT_SIZE * scaled.ratio).quantize(Decimal("0.01"))) x_pos = str(scaled.outside_border + scaled.line_size + 4 * scaled.ratio) - y_pos = str(scaled.outside_border + scaled.line_size + 2 * scaled.inside_border + scaled.width + (self.FONT_HEIGHT / 4) * scaled.ratio) + y_pos = str( + scaled.outside_border + + scaled.line_size + + 2 * scaled.inside_border + + scaled.width + + (self.FONT_HEIGHT / 4) * scaled.ratio + ) - text_el = ET.Element('text', style=text_style, x=x_pos, y=y_pos, id="qrplatba-text") - text_el.text = 'QR platba' + text_el = ET.Element("text", style=text_style, x=x_pos, y=y_pos, id="qrplatba-text") + text_el.text = "QR platba" return text_el @@ -126,14 +132,13 @@ def _svg(self, viewBox=None, **kwargs): box = "0 0 {w} {h}".format( w=self.units(self.pixel_size, text=False), - h=self.units(h_pixels, text=False) + h=self.units(h_pixels, text=False), ) svg_el = super()._svg(viewBox=box, **kwargs) svg_el.append(self.make_border()) svg_el.append(self.make_text()) # update size of the SVG element - svg_el.attrib['height'] = str(self.units(h_pixels)) + svg_el.attrib["height"] = str(self.units(h_pixels)) return svg_el - diff --git a/tests/test_svg.py b/tests/test_svg.py index 70771d9..6a75a7b 100644 --- a/tests/test_svg.py +++ b/tests/test_svg.py @@ -7,35 +7,35 @@ class TestSVGImage: data = { - 'account': '123456789/0123', - 'amount': 400.56, - 'x_vs': 2034456, - 'message': 'text', - 'due_date': datetime.now() + timedelta(days=14) + "account": "123456789/0123", + "amount": 400.56, + "x_vs": 2034456, + "message": "text", + "due_date": datetime.now() + timedelta(days=14), } def make_image(self, **kwargs): generator = QRPlatbaGenerator(**self.data) img = generator.make_image(**kwargs) - return img.to_string(encoding='unicode') + return img.to_string(encoding="unicode") def test_svg_content(self): svg_data = self.make_image() - assert 'http://www.w3.org/2000/svg' in svg_data + assert "http://www.w3.org/2000/svg" in svg_data root = ET.fromstring(svg_data) - text = root.find('.//{http://www.w3.org/2000/svg}text') + text = root.find(".//{http://www.w3.org/2000/svg}text") assert text is not None - assert text.text == 'QR platba' + assert text.text == "QR platba" - paths = root.findall('.//{http://www.w3.org/2000/svg}path') + paths = root.findall(".//{http://www.w3.org/2000/svg}path") assert len(paths) == 2 for path in paths: - assert path.get('id') is not None - assert path.get('id') in ('qr-path', 'qrplatba-border') + assert path.get("id") is not None + assert path.get("id") in ("qr-path", "qrplatba-border") def test_svg_scaling(self): svg_data = self.make_image(box_size=40) @@ -43,22 +43,22 @@ def test_svg_scaling(self): root = ET.fromstring(svg_data) assert root is not None - assert root.get('width') == '198mm' - assert root.get('height') == '201.2mm' + assert root.get("width") == "198mm" + assert root.get("height") == "201.2mm" def test_file_save(self, tmp_path): generator = QRPlatbaGenerator(**self.data) img = generator.make_image() - filename = tmp_path / 'example.svg' + filename = tmp_path / "example.svg" img.save(filename) assert filename.exists() root = ET.parse(filename).getroot() assert root is not None - viewbox = root.get('viewBox') + viewbox = root.get("viewBox") assert viewbox is not None - data = map(Decimal, viewbox.split(' ')) - assert list(data) == [Decimal(0), Decimal(0), Decimal('59.4'), Decimal('60.36')] + data = map(Decimal, viewbox.split(" ")) + assert list(data) == [Decimal(0), Decimal(0), Decimal("59.4"), Decimal("60.36")]