From fd04fa6e4168200d408dce2d38e0648b08f84f03 Mon Sep 17 00:00:00 2001 From: Luis Felipe Mileo Date: Wed, 3 Feb 2021 23:24:06 -0300 Subject: [PATCH 1/5] [FIX] CI --- .appveyor.yml | 65 +++++----------------- .travis.yml | 30 +++++----- ci/appveyor-bootstrap.py | 111 +++++++++++++++++++++++++++++++++++++ ci/appveyor-download.py | 109 ++++++++++++++++++++++++++++++++++++ ci/bootstrap.py | 57 +++++-------------- ci/requirements.txt | 1 - ci/templates/.appveyor.yml | 12 ++-- ci/templates/.travis.yml | 11 ++-- ci/templates/appveyor.yml | 53 ++++++++++++++++++ setup.cfg | 39 +++++++------ setup.py | 4 +- 11 files changed, 345 insertions(+), 147 deletions(-) create mode 100644 ci/appveyor-bootstrap.py create mode 100755 ci/appveyor-download.py create mode 100644 ci/templates/appveyor.yml diff --git a/.appveyor.yml b/.appveyor.yml index a504f35..00e9fae 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,80 +1,45 @@ version: '{branch}-{build}' build: off +cache: + - '%LOCALAPPDATA%\pip\Cache' environment: global: - COVERALLS_EXTRAS: '-v' - COVERALLS_REPO_TOKEN: [Required for Appveyor, take it from https://coveralls.io/github/erpbrasil/erpbrasil.edoc.pdf] + WITH_COMPILER: 'cmd /E:ON /V:ON /C .\ci\appveyor-with-compiler.cmd' matrix: - TOXENV: check - TOXPYTHON: C:\Python36\python.exe - PYTHON_HOME: C:\Python36 - PYTHON_VERSION: '3.6' - PYTHON_ARCH: '32' - - TOXENV: py27,codecov,coveralls - TOXPYTHON: C:\Python27\python.exe - PYTHON_HOME: C:\Python27 - PYTHON_VERSION: '2.7' - PYTHON_ARCH: '32' - - TOXENV: py27,codecov,coveralls - TOXPYTHON: C:\Python27-x64\python.exe - PYTHON_HOME: C:\Python27-x64 - PYTHON_VERSION: '2.7' - PYTHON_ARCH: '64' - WINDOWS_SDK_VERSION: v7.0 - - TOXENV: py35,codecov,coveralls - TOXPYTHON: C:\Python35\python.exe - PYTHON_HOME: C:\Python35 - PYTHON_VERSION: '3.5' - PYTHON_ARCH: '32' - - TOXENV: py35,codecov,coveralls - TOXPYTHON: C:\Python35-x64\python.exe - PYTHON_HOME: C:\Python35-x64 - PYTHON_VERSION: '3.5' - PYTHON_ARCH: '64' - - TOXENV: py36,codecov,coveralls - TOXPYTHON: C:\Python36\python.exe - PYTHON_HOME: C:\Python36 - PYTHON_VERSION: '3.6' + TOXPYTHON: C:\Python37\python.exe + PYTHON_HOME: C:\Python37 + PYTHON_VERSION: '3.7' PYTHON_ARCH: '32' - - TOXENV: py36,codecov,coveralls - TOXPYTHON: C:\Python36-x64\python.exe - PYTHON_HOME: C:\Python36-x64 - PYTHON_VERSION: '3.6' - PYTHON_ARCH: '64' - - TOXENV: py37,codecov,coveralls + - TOXENV: 'py37,codecov' TOXPYTHON: C:\Python37\python.exe PYTHON_HOME: C:\Python37 PYTHON_VERSION: '3.7' PYTHON_ARCH: '32' - - TOXENV: py37,codecov,coveralls + - TOXENV: 'py37,codecov' TOXPYTHON: C:\Python37-x64\python.exe PYTHON_HOME: C:\Python37-x64 PYTHON_VERSION: '3.7' PYTHON_ARCH: '64' - - TOXENV: py38,codecov,coveralls - TOXPYTHON: C:\Python38\python.exe - PYTHON_HOME: C:\Python38 - PYTHON_VERSION: '3.8' - PYTHON_ARCH: '32' - - TOXENV: py38,codecov,coveralls - TOXPYTHON: C:\Python38-x64\python.exe - PYTHON_HOME: C:\Python38-x64 - PYTHON_VERSION: '3.8' - PYTHON_ARCH: '64' init: - ps: echo $env:TOXENV - ps: ls C:\Python* install: - - '%PYTHON_HOME%\python -mpip install --progress-bar=off tox -rci/requirements.txt' + - python -u ci\appveyor-bootstrap.py + - python -m pip install -U pip - '%PYTHON_HOME%\Scripts\virtualenv --version' - '%PYTHON_HOME%\Scripts\easy_install --version' - '%PYTHON_HOME%\Scripts\pip --version' - '%PYTHON_HOME%\Scripts\tox --version' + - choco install -r -y swig test_script: - - cmd /E:ON /V:ON /C .\ci\appveyor-with-compiler.cmd %PYTHON_HOME%\Scripts\tox + - '%WITH_COMPILER% %PYTHON_HOME%\Scripts\tox' + on_failure: - ps: dir "env:" - ps: get-content .tox\*\log\* +artifacts: + - path: dist\* ### To enable remote debugging uncomment this (also, see: http://www.appveyor.com/docs/how-to/rdp-to-build-worker): # on_finish: diff --git a/.travis.yml b/.travis.yml index 0d4f349..59d673f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,15 @@ language: python dist: xenial cache: false + +addons: + apt: + packages: + - expect-dev # provides unbuffer utility + - python-lxml # because pip installation is slow + - pdftk + - libreoffice + - graphviz env: global: - LD_PRELOAD=/lib/x86_64-linux-gnu/libSegFault.so @@ -10,31 +19,18 @@ matrix: - python: '3.6' env: - TOXENV=check - - python: '3.6' + - python: '3.8' env: - TOXENV=docs - env: - - TOXENV=py27,codecov,coveralls - python: '2.7' - - env: - - TOXENV=py35,codecov,coveralls - python: '3.5' - - env: - - TOXENV=py36,codecov,coveralls + - TOXENV=py36,codecov python: '3.6' - env: - - TOXENV=py37,codecov,coveralls + - TOXENV=py37,codecov python: '3.7' - env: - - TOXENV=py38,codecov,coveralls + - TOXENV=py38,codecov python: '3.8' - - env: - - TOXENV=pypy,codecov,coveralls - python: 'pypy' - - env: - - TOXENV=pypy3,codecov,coveralls - - TOXPYTHON=pypy3 - python: 'pypy3' before_install: - python --version - uname -a diff --git a/ci/appveyor-bootstrap.py b/ci/appveyor-bootstrap.py new file mode 100644 index 0000000..dd76230 --- /dev/null +++ b/ci/appveyor-bootstrap.py @@ -0,0 +1,111 @@ +""" +AppVeyor will at least have few Pythons around so there's no point of implementing a bootstrapper in PowerShell. + +This is a port of https://github.com/pypa/python-packaging-user-guide/blob/master/source/code/install.ps1 +with various fixes and improvements that just weren't feasible to implement in PowerShell. +""" +from __future__ import print_function +from os import environ +from os.path import exists +from subprocess import check_call + +try: + from urllib.request import urlretrieve +except ImportError: + from urllib import urlretrieve + +BASE_URL = "https://www.python.org/ftp/python/" +GET_PIP_URL = "https://bootstrap.pypa.io/get-pip.py" +GET_PIP_PATH = "C:\get-pip.py" +URLS = { + ("2.7", "64"): BASE_URL + "2.7.13/python-2.7.13.amd64.msi", + ("2.7", "32"): BASE_URL + "2.7.13/python-2.7.13.msi", + ("3.4", "64"): BASE_URL + "3.4.4/python-3.4.4.amd64.msi", + ("3.4", "32"): BASE_URL + "3.4.4/python-3.4.4.msi", + ("3.5", "64"): BASE_URL + "3.5.4/python-3.5.4-amd64.exe", + ("3.5", "32"): BASE_URL + "3.5.4/python-3.5.4.exe", + ("3.6", "64"): BASE_URL + "3.6.2/python-3.6.2-amd64.exe", + ("3.6", "32"): BASE_URL + "3.6.2/python-3.6.2.exe", +} +INSTALL_CMD = { + # Commands are allowed to fail only if they are not the last command. Eg: uninstall (/x) allowed to fail. + "2.7": [["msiexec.exe", "/L*+!", "install.log", "/qn", "/x", "{path}"], + ["msiexec.exe", "/L*+!", "install.log", "/qn", "/i", "{path}", "TARGETDIR={home}"]], + "3.4": [["msiexec.exe", "/L*+!", "install.log", "/qn", "/x", "{path}"], + ["msiexec.exe", "/L*+!", "install.log", "/qn", "/i", "{path}", "TARGETDIR={home}"]], + "3.5": [["{path}", "/quiet", "TargetDir={home}"]], + "3.6": [["{path}", "/quiet", "TargetDir={home}"]], +} + + +def download_file(url, path): + print("Downloading: {} (into {})".format(url, path)) + progress = [0, 0] + + def report(count, size, total): + progress[0] = count * size + if progress[0] - progress[1] > 1000000: + progress[1] = progress[0] + print("Downloaded {:,}/{:,} ...".format(progress[1], total)) + + dest, _ = urlretrieve(url, path, reporthook=report) + return dest + + +def install_python(version, arch, home): + print("Installing Python", version, "for", arch, "bit architecture to", home) + if exists(home): + return + + path = download_python(version, arch) + print("Installing", path, "to", home) + success = False + for cmd in INSTALL_CMD[version]: + cmd = [part.format(home=home, path=path) for part in cmd] + print("Running:", " ".join(cmd)) + try: + check_call(cmd) + except Exception as exc: + print("Failed command", cmd, "with:", exc) + if exists("install.log"): + with open("install.log") as fh: + print(fh.read()) + else: + success = True + if success: + print("Installation complete!") + else: + print("Installation failed") + + +def download_python(version, arch): + for _ in range(3): + try: + return download_file(URLS[version, arch], "installer.exe") + except Exception as exc: + print("Failed to download:", exc) + print("Retrying ...") + + +def install_pip(home): + pip_path = home + "/Scripts/pip.exe" + python_path = home + "/python.exe" + if exists(pip_path): + print("pip already installed.") + else: + print("Installing pip...") + download_file(GET_PIP_URL, GET_PIP_PATH) + print("Executing:", python_path, GET_PIP_PATH) + check_call([python_path, GET_PIP_PATH]) + + +def install_packages(home, *packages): + cmd = [home + "/Scripts/pip.exe", "install"] + cmd.extend(packages) + check_call(cmd) + + +if __name__ == "__main__": + install_python(environ['PYTHON_VERSION'], environ['PYTHON_ARCH'], environ['PYTHON_HOME']) + install_pip(environ['PYTHON_HOME']) + install_packages(environ['PYTHON_HOME'], "setuptools>=18.0.1", "wheel", "tox", "virtualenv>=13.1.0") diff --git a/ci/appveyor-download.py b/ci/appveyor-download.py new file mode 100755 index 0000000..399967b --- /dev/null +++ b/ci/appveyor-download.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python +""" +Use the AppVeyor API to download Windows artifacts. + +Taken from: https://bitbucket.org/ned/coveragepy/src/tip/ci/download_appveyor.py +# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 +# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt +""" +from __future__ import unicode_literals + +import argparse +import os +import zipfile + +import requests + + +def make_auth_headers(): + """Make the authentication headers needed to use the Appveyor API.""" + path = os.path.expanduser("~/.appveyor.token") + if not os.path.exists(path): + raise RuntimeError( + "Please create a file named `.appveyor.token` in your home directory. " + "You can get the token from https://ci.appveyor.com/api-token" + ) + with open(path) as f: + token = f.read().strip() + + headers = { + 'Authorization': 'Bearer {}'.format(token), + } + return headers + + +def download_latest_artifacts(account_project, build_id): + """Download all the artifacts from the latest build.""" + if build_id is None: + url = "https://ci.appveyor.com/api/projects/{}".format(account_project) + else: + url = "https://ci.appveyor.com/api/projects/{}/build/{}".format(account_project, build_id) + build = requests.get(url, headers=make_auth_headers()).json() + jobs = build['build']['jobs'] + print(u"Build {0[build][version]}, {1} jobs: {0[build][message]}".format(build, len(jobs))) + + for job in jobs: + name = job['name'] + print(u" {0}: {1[status]}, {1[artifactsCount]} artifacts".format(name, job)) + + url = "https://ci.appveyor.com/api/buildjobs/{}/artifacts".format(job['jobId']) + response = requests.get(url, headers=make_auth_headers()) + artifacts = response.json() + + for artifact in artifacts: + is_zip = artifact['type'] == "Zip" + filename = artifact['fileName'] + print(u" {0}, {1} bytes".format(filename, artifact['size'])) + + url = "https://ci.appveyor.com/api/buildjobs/{}/artifacts/{}".format(job['jobId'], filename) + download_url(url, filename, make_auth_headers()) + + if is_zip: + unpack_zipfile(filename) + os.remove(filename) + + +def ensure_dirs(filename): + """Make sure the directories exist for `filename`.""" + dirname = os.path.dirname(filename) + if dirname and not os.path.exists(dirname): + os.makedirs(dirname) + + +def download_url(url, filename, headers): + """Download a file from `url` to `filename`.""" + ensure_dirs(filename) + response = requests.get(url, headers=headers, stream=True) + if response.status_code == 200: + with open(filename, 'wb') as f: + for chunk in response.iter_content(16 * 1024): + f.write(chunk) + else: + print(u" Error downloading {}: {}".format(url, response)) + + +def unpack_zipfile(filename): + """Unpack a zipfile, using the names in the zip.""" + with open(filename, 'rb') as fzip: + z = zipfile.ZipFile(fzip) + for name in z.namelist(): + print(u" extracting {}".format(name)) + ensure_dirs(name) + z.extract(name) + + +parser = argparse.ArgumentParser(description='Download artifacts from AppVeyor.') +parser.add_argument('--id', + metavar='PROJECT_ID', + default='erpbrasil/erpbrasil.edoc.pdf', + help='Project ID in AppVeyor.') +parser.add_argument('build', + nargs='?', + metavar='BUILD_ID', + help='Build ID in AppVeyor. Eg: master-123') + +if __name__ == "__main__": + # import logging + # logging.basicConfig(level="DEBUG") + args = parser.parse_args() + download_latest_artifacts(args.id, args.build) diff --git a/ci/bootstrap.py b/ci/bootstrap.py index 2597983..80bdf47 100755 --- a/ci/bootstrap.py +++ b/ci/bootstrap.py @@ -1,26 +1,18 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -from __future__ import absolute_import -from __future__ import print_function -from __future__ import unicode_literals +from __future__ import absolute_import, print_function, unicode_literals import os -import subprocess import sys from os.path import abspath from os.path import dirname from os.path import exists from os.path import join -base_path = dirname(dirname(abspath(__file__))) - -def check_call(args): - print("+", *args) - subprocess.check_call(args) - - -def exec_in_env(): +if __name__ == "__main__": + base_path = dirname(dirname(abspath(__file__))) + print("Project path: {0}".format(base_path)) env_path = join(base_path, ".tox", "bootstrap") if sys.platform == "win32": bin_path = join(env_path, "Scripts") @@ -31,26 +23,19 @@ def exec_in_env(): print("Making bootstrap env in: {0} ...".format(env_path)) try: - check_call([sys.executable, "-m", "venv", env_path]) + subprocess.check_call(["virtualenv", env_path]) except subprocess.CalledProcessError: - try: - check_call([sys.executable, "-m", "virtualenv", env_path]) - except subprocess.CalledProcessError: - check_call(["virtualenv", env_path]) + subprocess.check_call([sys.executable, "-m", "virtualenv", env_path]) print("Installing `jinja2` into bootstrap environment...") - check_call([join(bin_path, "pip"), "install", "jinja2", "tox"]) + subprocess.check_call([join(bin_path, "pip"), "install", "jinja2"]) python_executable = join(bin_path, "python") - if not os.path.exists(python_executable): - python_executable += '.exe' - - print("Re-executing with: {0}".format(python_executable)) - print("+ exec", python_executable, __file__, "--no-env") - os.execv(python_executable, [python_executable, __file__, "--no-env"]) + if not os.path.samefile(python_executable, sys.executable): + print("Re-executing with: {0}".format(python_executable)) + os.execv(python_executable, [python_executable, __file__]) -def main(): import jinja2 - print("Project path: {0}".format(base_path)) + import subprocess jinja = jinja2.Environment( loader=jinja2.FileSystemLoader(join(base_path, "ci", "templates")), @@ -61,12 +46,8 @@ def main(): tox_environments = [ line.strip() - # 'tox' need not be installed globally, but must be importable - # by the Python that is running this script. - # This uses sys.executable the same way that the call in - # cookiecutter-pylibrary/hooks/post_gen_project.py - # invokes this bootstrap.py itself. - for line in subprocess.check_output([sys.executable, '-m', 'tox', '--listenvs'], universal_newlines=True).splitlines() + # WARNING: 'tox' must be installed globally or in the project's virtualenv + for line in subprocess.check_output(['tox', '--listenvs'], universal_newlines=True).splitlines() ] tox_environments = [line for line in tox_environments if line.startswith('py')] @@ -75,15 +56,3 @@ def main(): fh.write(jinja.get_template(name).render(tox_environments=tox_environments)) print("Wrote {}".format(name)) print("DONE.") - - -if __name__ == "__main__": - args = sys.argv[1:] - if args == ["--no-env"]: - main() - elif not args: - exec_in_env() - else: - print("Unexpected arguments {0}".format(args), file=sys.stderr) - sys.exit(1) - diff --git a/ci/requirements.txt b/ci/requirements.txt index b2a21e5..1c8d385 100644 --- a/ci/requirements.txt +++ b/ci/requirements.txt @@ -1,4 +1,3 @@ virtualenv>=16.6.0 pip>=19.1.1 setuptools>=18.0.1 -six>=1.12.0 diff --git a/ci/templates/.appveyor.yml b/ci/templates/.appveyor.yml index 51fe7ab..f1dd02f 100644 --- a/ci/templates/.appveyor.yml +++ b/ci/templates/.appveyor.yml @@ -2,8 +2,6 @@ version: '{branch}-{build}' build: off environment: global: - COVERALLS_EXTRAS: '-v' - COVERALLS_REPO_TOKEN: [Required for Appveyor, take it from https://coveralls.io/github/erpbrasil/erpbrasil.edoc.pdf] matrix: - TOXENV: check TOXPYTHON: C:\Python36\python.exe @@ -12,7 +10,8 @@ environment: PYTHON_ARCH: '32' {% for env in tox_environments %} {% if env.startswith(('py2', 'py3')) %} - - TOXENV: {{ env }},codecov,coveralls{{ "" }} + - TOXENV: {{ env }},codecov + TOXPYTHON: C:\Python{{ env[2:4] }}\python.exe PYTHON_HOME: C:\Python{{ env[2:4] }} PYTHON_VERSION: '{{ env[2] }}.{{ env[3] }}' @@ -20,7 +19,8 @@ environment: {% if 'nocov' in env %} WHEEL_PATH: .tox/dist {% endif %} - - TOXENV: {{ env }},codecov,coveralls{{ "" }} + - TOXENV: {{ env }},codecov + TOXPYTHON: C:\Python{{ env[2:4] }}-x64\python.exe PYTHON_HOME: C:\Python{{ env[2:4] }}-x64 PYTHON_VERSION: '{{ env[2] }}.{{ env[3] }}' @@ -28,8 +28,8 @@ environment: {% if 'nocov' in env %} WHEEL_PATH: .tox/dist {% endif %} -{% if env.startswith('py2') %} - WINDOWS_SDK_VERSION: v7.0 +{% if env.startswith(('py2', 'py34')) %} + WINDOWS_SDK_VERSION: v7.{{ '1' if env.startswith('py3') else '0' }} {% endif %} {% endif %}{% endfor %} init: diff --git a/ci/templates/.travis.yml b/ci/templates/.travis.yml index af7c95c..be81589 100644 --- a/ci/templates/.travis.yml +++ b/ci/templates/.travis.yml @@ -1,6 +1,5 @@ language: python dist: xenial -cache: false env: global: - LD_PRELOAD=/lib/x86_64-linux-gnu/libSegFault.so @@ -15,12 +14,12 @@ matrix: - TOXENV=docs {%- for env in tox_environments %}{{ '' }} - env: - - TOXENV={{ env }},codecov,coveralls + - TOXENV={{ env }},codecov {%- if env.startswith('pypy3') %}{{ '' }} - TOXPYTHON=pypy3 - python: 'pypy3' + python: 'pypy3.5-6.0' {%- elif env.startswith('pypy') %}{{ '' }} - python: 'pypy' + python: 'pypy2.7-6.0' {%- else %}{{ '' }} python: '{{ '{0[2]}.{0[3]}'.format(env) }}' {%- endif %} @@ -28,9 +27,9 @@ matrix: before_install: - python --version - uname -a - - lsb_release -a || true + - lsb_release -a install: - - python -mpip install --progress-bar=off tox -rci/requirements.txt + - pip install tox - virtualenv --version - easy_install --version - pip --version diff --git a/ci/templates/appveyor.yml b/ci/templates/appveyor.yml new file mode 100644 index 0000000..f8c2c69 --- /dev/null +++ b/ci/templates/appveyor.yml @@ -0,0 +1,53 @@ +version: '{branch}-{build}' +build: off +cache: + - '%LOCALAPPDATA%\pip\Cache' +environment: + global: + WITH_COMPILER: 'cmd /E:ON /V:ON /C .\ci\appveyor-with-compiler.cmd' + matrix: + - TOXENV: check + TOXPYTHON: C:\Python36\python.exe + PYTHON_HOME: C:\Python36 + PYTHON_VERSION: '3.6' + PYTHON_ARCH: '32' +{% for env in tox_environments %} +{% if env.startswith(('py2', 'py3')) %} + - TOXENV: '{{ env }},codecov' + TOXPYTHON: C:\Python{{ env[2:4] }}\python.exe + PYTHON_HOME: C:\Python{{ env[2:4] }} + PYTHON_VERSION: '{{ env[2] }}.{{ env[3] }}' + PYTHON_ARCH: '32' +{% if env.startswith(('py2', 'py34')) %} + WINDOWS_SDK_VERSION: v7.{{ '1' if env.startswith('py3') else '0' }} +{% endif %} + - TOXENV: '{{ env }},codecov' + TOXPYTHON: C:\Python{{ env[2:4] }}-x64\python.exe + PYTHON_HOME: C:\Python{{ env[2:4] }}-x64 + PYTHON_VERSION: '{{ env[2] }}.{{ env[3] }}' + PYTHON_ARCH: '64' +{% if env.startswith(('py2', 'py34')) %} + WINDOWS_SDK_VERSION: v7.{{ '1' if env.startswith('py3') else '0' }} +{% endif %} +{% endif %}{% endfor %} +init: + - ps: echo $env:TOXENV + - ps: ls C:\Python* +install: + - python -u ci\appveyor-bootstrap.py + - '%PYTHON_HOME%\Scripts\virtualenv --version' + - '%PYTHON_HOME%\Scripts\easy_install --version' + - '%PYTHON_HOME%\Scripts\pip --version' + - '%PYTHON_HOME%\Scripts\tox --version' +test_script: + - '%WITH_COMPILER% %PYTHON_HOME%\Scripts\tox' + +on_failure: + - ps: dir "env:" + - ps: get-content .tox\*\log\* +artifacts: + - path: dist\* + +### To enable remote debugging uncomment this (also, see: http://www.appveyor.com/docs/how-to/rdp-to-build-worker): +# on_finish: +# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) diff --git a/setup.cfg b/setup.cfg index 3918d9a..7657435 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,22 +4,26 @@ universal = 1 [flake8] max-line-length = 140 exclude = */migrations/* - [tool:pytest] -norecursedirs = - migrations -python_files = - test_*.py - *_test.py - tests.py -addopts = - -ra - --strict - --doctest-modules - --doctest-glob=\*.rst - --tb=short -testpaths = - tests +# If a pytest section is found in one of the possible config files +# (pytest.ini, tox.ini or setup.cfg), then pytest will not look for any others, +# so if you add a pytest config section elsewhere, +# you will need to delete this section from setup.cfg. +norecursedirs = + migrations + +python_files = + test_*.py + *_test.py + tests.py +addopts = + -ra + --strict + --doctest-modules + --doctest-glob=\*.rst + --tb=short +testpaths = + tests [tool:isort] force_single_line = True @@ -29,8 +33,3 @@ default_section = THIRDPARTY forced_separate = test_erpbrasil.edoc.pdf not_skip = __init__.py skip = migrations - -[egg_info] -tag_build = -tag_date = 0 - diff --git a/setup.py b/setup.py index efec00b..4b1d476 100644 --- a/setup.py +++ b/setup.py @@ -50,12 +50,10 @@ def read(*names, **kwargs): 'Operating System :: POSIX', 'Operating System :: Microsoft :: Windows', 'Programming Language :: Python', - 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', # uncomment if you test on these interpreters: @@ -72,7 +70,7 @@ def read(*names, **kwargs): keywords=[ # eg: 'keyword1', 'keyword2', 'keyword3', ], - python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*', + python_requires='>=3.5, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*', install_requires=[ 'click', 'erpbrasil.base', From 0bc84f396a4f49f7a014a31125cfe4e2f52a466c Mon Sep 17 00:00:00 2001 From: Luis Felipe Mileo Date: Wed, 3 Feb 2021 23:33:23 -0300 Subject: [PATCH 2/5] [REF] Flake8 --- src/erpbrasil/edoc/pdf/__init__.py | 3 -- src/erpbrasil/edoc/pdf/danfe_formata.py | 64 +++++++++++++++---------- src/erpbrasil/edoc/pdf/nfe.py | 3 +- tests/test_xml.py | 3 +- 4 files changed, 40 insertions(+), 33 deletions(-) diff --git a/src/erpbrasil/edoc/pdf/__init__.py b/src/erpbrasil/edoc/pdf/__init__.py index ec81f51..c89fe99 100644 --- a/src/erpbrasil/edoc/pdf/__init__.py +++ b/src/erpbrasil/edoc/pdf/__init__.py @@ -6,6 +6,3 @@ objectify.ObjectifyElementClassLookup()) parser = etree.XMLParser() parser.set_element_class_lookup(lookup) - -from erpbrasil.edoc.pdf import nfe -from erpbrasil.edoc.pdf.base import ImprimirXml diff --git a/src/erpbrasil/edoc/pdf/danfe_formata.py b/src/erpbrasil/edoc/pdf/danfe_formata.py index 64dc785..eb1817f 100644 --- a/src/erpbrasil/edoc/pdf/danfe_formata.py +++ b/src/erpbrasil/edoc/pdf/danfe_formata.py @@ -23,29 +23,41 @@ def formata_decimal(numero, digitos): return locale.format(formato, numero, grouping=True) -formata_vBC = lambda valor: formata_decimal(valor, 2) -formata_vICMS = lambda valor: formata_decimal(valor, 2) -formata_vBCST = lambda valor: formata_decimal(valor, 2) -formata_vST = lambda valor: formata_decimal(valor, 2) -formata_vTotTrib = lambda valor: formata_decimal(valor, 2) -formata_vProd = lambda valor: formata_decimal(valor, 2) -formata_vFrete = lambda valor: formata_decimal(valor, 2) -formata_vSeg = lambda valor: formata_decimal(valor, 2) -formata_vDesc = lambda valor: formata_decimal(valor, 2) -formata_vOutro = lambda valor: formata_decimal(valor, 2) -formata_vIPI = lambda valor: formata_decimal(valor, 2) -formata_vNF = lambda valor: formata_decimal(valor, 2) -formata_qCom = lambda valor: formata_decimal(valor, 3) -formata_vUnCom = lambda valor: formata_decimal(valor, 5) -formata_vProd = lambda valor: formata_decimal(valor, 2) -formata_pIPI = lambda valor: formata_decimal(valor, 2) -formata_vOrig = lambda valor: formata_decimal(valor, 2) -formata_vDesc = lambda valor: formata_decimal(valor, 2) -formata_vLiq = lambda valor: formata_decimal(valor, 2) -formata_vDup = lambda valor: formata_decimal(valor, 2) -formata_pesoB = lambda valor: formata_decimal(valor, 2) -formata_pesoL = lambda valor: formata_decimal(valor, 2) -formata_pICMS = lambda valor: formata_decimal(valor, 2) +def formata_duas_casas(valor): + return formata_decimal(valor, 2) + + +def formata_tres_casas(valor): + return formata_decimal(valor, 3) + + +def formata_cinco_casas(valor): + return formata_decimal(valor, 5) + + +formata_vBC = formata_duas_casas +formata_vICMS = formata_duas_casas +formata_vBCST = formata_duas_casas +formata_vST = formata_duas_casas +formata_vTotTrib = formata_duas_casas +formata_vProd = formata_duas_casas +formata_vFrete = formata_duas_casas +formata_vSeg = formata_duas_casas +formata_vDesc = formata_duas_casas +formata_vOutro = formata_duas_casas +formata_vIPI = formata_duas_casas +formata_vNF = formata_duas_casas +formata_qCom = formata_tres_casas +formata_vUnCom = formata_cinco_casas +formata_vProd = formata_duas_casas +formata_pIPI = formata_duas_casas +formata_vOrig = formata_duas_casas +formata_vDesc = formata_duas_casas +formata_vLiq = formata_duas_casas +formata_vDup = formata_duas_casas +formata_pesoB = formata_duas_casas +formata_pesoL = formata_duas_casas +formata_pICMS = formata_duas_casas def formata_fone(fone): @@ -359,9 +371,9 @@ def fatura_a_prazo(NFe): len(str(NFe.infNFe.cobr.dup)) > 1 or ((len(str(NFe.infNFe.cobr.dup)) == 1) and (datetime.strptime(str(NFe.infNFe.cobr.dup[0].dVenc), - '%Y-%m-%d').toordinal() > datetime.strptime( - str(NFe.infNFe.ide.dEmi.toordinal()), - '%Y-%m-%d').toordinal()))): + '%Y-%m-%d').toordinal() > datetime.strptime( + str(NFe.infNFe.ide.dEmi.toordinal()), + '%Y-%m-%d').toordinal()))): return True return False diff --git a/src/erpbrasil/edoc/pdf/nfe.py b/src/erpbrasil/edoc/pdf/nfe.py index 6a6f723..376c481 100644 --- a/src/erpbrasil/edoc/pdf/nfe.py +++ b/src/erpbrasil/edoc/pdf/nfe.py @@ -1,5 +1,5 @@ import re -from lxml import objectify, etree +from lxml import objectify from erpbrasil.edoc.pdf.base import VoidElement from erpbrasil.edoc.pdf import lookup @@ -84,7 +84,6 @@ def __getattribute__(*args): tag = search.group(1) method = ('formata_%s' % tag) if hasattr(danfe_formata, method): - result = eval( 'danfe_formata.' + method + '(\'' + str(result.text) + '\')') diff --git a/tests/test_xml.py b/tests/test_xml.py index 93743dd..cf6ed9e 100644 --- a/tests/test_xml.py +++ b/tests/test_xml.py @@ -11,5 +11,4 @@ output = path.join(OUTPUT, file) print('XML: ' + file) - print (base.ImprimirXml.imprimir(caminho_xml=arquivo, output_dir=output)) - + print(base.ImprimirXml.imprimir(caminho_xml=arquivo, output_dir=output)) From 8cf924b1aabeb72793183a760c14f0e67dbe4494 Mon Sep 17 00:00:00 2001 From: Luis Felipe Mileo Date: Wed, 3 Feb 2021 23:34:52 -0300 Subject: [PATCH 3/5] [REF] isort --- src/erpbrasil/edoc/pdf/__init__.py | 3 ++- src/erpbrasil/edoc/pdf/base.py | 3 ++- src/erpbrasil/edoc/pdf/danfe_formata.py | 12 +++++------- src/erpbrasil/edoc/pdf/nfe.py | 6 +++--- tests/test_xml.py | 4 +++- 5 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/erpbrasil/edoc/pdf/__init__.py b/src/erpbrasil/edoc/pdf/__init__.py index c89fe99..78e391e 100644 --- a/src/erpbrasil/edoc/pdf/__init__.py +++ b/src/erpbrasil/edoc/pdf/__init__.py @@ -1,4 +1,5 @@ -from lxml import objectify, etree +from lxml import etree +from lxml import objectify __version__ = '0.1.1' diff --git a/src/erpbrasil/edoc/pdf/base.py b/src/erpbrasil/edoc/pdf/base.py index 998b5f2..9608cee 100644 --- a/src/erpbrasil/edoc/pdf/base.py +++ b/src/erpbrasil/edoc/pdf/base.py @@ -1,11 +1,12 @@ # -*- coding: utf-8 -*- import os import re -import sh import tempfile +import sh from lxml import objectify from py3o.template import Template + from erpbrasil.edoc.pdf import parser # cte_namespace = lookup.get_namespace('http://www.portalfiscal.inf.br/cte') diff --git a/src/erpbrasil/edoc/pdf/danfe_formata.py b/src/erpbrasil/edoc/pdf/danfe_formata.py index eb1817f..3078984 100644 --- a/src/erpbrasil/edoc/pdf/danfe_formata.py +++ b/src/erpbrasil/edoc/pdf/danfe_formata.py @@ -1,17 +1,15 @@ # -*- coding: utf-8 -*- -import locale -import pytz import base64 - -from genshi import Markup -from reportlab.graphics.barcode import createBarcodeDrawing +import locale from datetime import datetime -from dateutil.parser import parse +import pytz +from dateutil.parser import parse from erpbrasil.base.fiscal.cnpj_cpf import formata as formata_CNPJ from erpbrasil.base.fiscal.cnpj_cpf import formata as formata_CPF - from erpbrasil.base.misc import format_zipcode +from genshi import Markup +from reportlab.graphics.barcode import createBarcodeDrawing def formata_decimal(numero, digitos): diff --git a/src/erpbrasil/edoc/pdf/nfe.py b/src/erpbrasil/edoc/pdf/nfe.py index 376c481..3c64791 100644 --- a/src/erpbrasil/edoc/pdf/nfe.py +++ b/src/erpbrasil/edoc/pdf/nfe.py @@ -1,10 +1,10 @@ import re -from lxml import objectify -from erpbrasil.edoc.pdf.base import VoidElement -from erpbrasil.edoc.pdf import lookup +from lxml import objectify from erpbrasil.edoc.pdf import danfe_formata +from erpbrasil.edoc.pdf import lookup +from erpbrasil.edoc.pdf.base import VoidElement nfe_namespace = lookup.get_namespace('http://www.portalfiscal.inf.br/nfe') diff --git a/tests/test_xml.py b/tests/test_xml.py index cf6ed9e..a26d3ab 100644 --- a/tests/test_xml.py +++ b/tests/test_xml.py @@ -1,4 +1,6 @@ -from os import walk, path +from os import path +from os import walk + from erpbrasil.edoc.pdf import base PATH = 'xml' From d5338ee0b69001b217928c9679f8cb2d8739c050 Mon Sep 17 00:00:00 2001 From: Luis Felipe Mileo Date: Wed, 3 Feb 2021 23:55:25 -0300 Subject: [PATCH 4/5] [FIX] Readme and setup --- README.rst | 9 +-------- setup.py | 10 +++++----- tox.ini | 29 ++++++++++++++++------------- 3 files changed, 22 insertions(+), 26 deletions(-) diff --git a/README.rst b/README.rst index fb24aac..308ec79 100644 --- a/README.rst +++ b/README.rst @@ -7,17 +7,12 @@ Overview .. list-table:: :stub-columns: 1 - * - docs - - |docs| * - tests - | |travis| |appveyor| |requires| | |coveralls| |codecov| * - package - | |version| |wheel| |supported-versions| |supported-implementations| | |commits-since| -.. |docs| image:: https://readthedocs.org/projects/erpbrasil.edoc.pdf/badge/?style=flat - :target: https://readthedocs.org/projects/erpbrasiledocpdf - :alt: Documentation Status .. |travis| image:: https://api.travis-ci.org/erpbrasil/erpbrasil.edoc.pdf.svg?branch=master :alt: Travis-CI Build Status @@ -82,9 +77,7 @@ You can also install the in-development version with:: Documentation ============= - -https://erpbrasiledocpdf.readthedocs.io/ - +https://erpbrasil.github.io/docs/ Development =========== diff --git a/setup.py b/setup.py index 4b1d476..1d7b863 100644 --- a/setup.py +++ b/setup.py @@ -62,11 +62,11 @@ def read(*names, **kwargs): # 'Programming Language :: Python :: Implementation :: Stackless', 'Topic :: Utilities', ], - project_urls={ - 'Documentation': 'https://erpbrasiledocpdf.readthedocs.io/', - 'Changelog': 'https://erpbrasiledocpdf.readthedocs.io/en/latest/changelog.html', - 'Issue Tracker': 'https://github.com/erpbrasil/erpbrasil.edoc.pdf/issues', - }, + # project_urls={ + # 'Documentation': 'https://erpbrasiledocpdf.readthedocs.io/', + # 'Changelog': 'https://erpbrasiledocpdf.readthedocs.io/en/latest/changelog.html', + # 'Issue Tracker': 'https://github.com/erpbrasil/erpbrasil.edoc.pdf/issues', + # }, keywords=[ # eg: 'keyword1', 'keyword2', 'keyword3', ], diff --git a/tox.ini b/tox.ini index b76f4be..bf53832 100644 --- a/tox.ini +++ b/tox.ini @@ -5,7 +5,7 @@ deps = tox skip_install = true commands = - python ci/bootstrap.py --no-env + python ci/bootstrap.py passenv = * ; a generative tox configuration, see: https://tox.readthedocs.io/en/latest/config.html#generative-envlist @@ -15,7 +15,7 @@ envlist = clean, check, docs, - {py27,py35,py36,py37,py38,pypy,pypy3}, + {py36,py37,py38,pypy,pypy3}, report ignore_basepython_conflict = true @@ -23,12 +23,11 @@ ignore_basepython_conflict = true basepython = pypy: {env:TOXPYTHON:pypy} pypy3: {env:TOXPYTHON:pypy3} - py27: {env:TOXPYTHON:python2.7} - py35: {env:TOXPYTHON:python3.5} - {py36,docs}: {env:TOXPYTHON:python3.6} + py36: {env:TOXPYTHON:python3.6} + {py38,docs,spell}: {env:TOXPYTHON:python3.8} py37: {env:TOXPYTHON:python3.7} py38: {env:TOXPYTHON:python3.8} - {bootstrap,clean,check,report,codecov,coveralls}: {env:TOXPYTHON:python3} + {bootstrap,clean,check,report,codecov}: {env:TOXPYTHON:python3} setenv = PYTHONPATH={toxinidir}/tests PYTHONUNBUFFERED=yes @@ -57,6 +56,17 @@ commands = flake8 src tests setup.py isort --verbose --check-only --diff --recursive src tests setup.py +[testenv:spell] +setenv = + SPELLCHECK=1 +commands = + sphinx-build -b spelling docs dist/docs +skip_install = true +deps = + -r{toxinidir}/docs/requirements.txt + sphinxcontrib-spelling + pyenchant + [testenv:docs] usedevelop = true deps = @@ -65,13 +75,6 @@ commands = sphinx-build {posargs:-E} -b html docs dist/docs sphinx-build -b linkcheck docs dist/docs -[testenv:coveralls] -deps = - coveralls -skip_install = true -commands = - coveralls [] - [testenv:codecov] deps = codecov From de5d0aff2b6d1a9fc524ae1d64d79f715665e202 Mon Sep 17 00:00:00 2001 From: Luis Felipe Mileo Date: Thu, 4 Feb 2021 00:05:12 -0300 Subject: [PATCH 5/5] [FIX] Tests --- setup.cfg | 2 +- .../{test_erpbrasil.edoc.pdf.py => test_erpbrasil_edoc_pdf.py} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename tests/{test_erpbrasil.edoc.pdf.py => test_erpbrasil_edoc_pdf.py} (100%) diff --git a/setup.cfg b/setup.cfg index 7657435..639d250 100644 --- a/setup.cfg +++ b/setup.cfg @@ -30,6 +30,6 @@ force_single_line = True line_length = 120 known_first_party = erpbrasil.edoc.pdf default_section = THIRDPARTY -forced_separate = test_erpbrasil.edoc.pdf +forced_separate = test_erpbrasil_edoc_pdf.py not_skip = __init__.py skip = migrations diff --git a/tests/test_erpbrasil.edoc.pdf.py b/tests/test_erpbrasil_edoc_pdf.py similarity index 100% rename from tests/test_erpbrasil.edoc.pdf.py rename to tests/test_erpbrasil_edoc_pdf.py