From 2df1b3caa33d04e2dfd47076ac123aac9fdf840b Mon Sep 17 00:00:00 2001 From: Michael Howitz Date: Fri, 12 Feb 2021 09:37:08 +0100 Subject: [PATCH] Config with zope product (#942) * Configuring for zope-product * Use more f-strings. --- .editorconfig | 5 +- .github/workflows/tests.yml | 54 ++++++++ .gitignore | 51 +++---- .meta.toml | 136 +++++++++++++++++++ .travis.yml | 35 ----- MANIFEST.in | 42 +++--- appveyor.yml | 20 +-- setup.cfg | 61 ++++----- src/App/Management.py | 2 +- src/OFS/Image.py | 10 +- src/OFS/tests/test_event.py | 7 +- src/Products/Five/browser/adding.py | 3 +- src/Products/PageTemplates/PageTemplate.py | 4 +- src/Testing/testbrowser.py | 2 +- src/ZPublisher/BeforeTraverse.py | 4 +- src/ZPublisher/HTTPRequest.py | 6 +- src/ZPublisher/HTTPResponse.py | 7 +- src/ZPublisher/tests/testBeforeTraverse.py | 4 +- src/ZPublisher/tests/testHTTPRequest.py | 2 +- src/ZPublisher/tests/test_WSGIPublisher.py | 8 +- src/ZPublisher/tests/test_pubevents.py | 5 +- src/ZTUtils/Zope.py | 2 +- src/Zope2/Startup/datatypes.py | 4 +- src/Zope2/utilities/tests/test_zconsole.py | 6 +- src/webdav/PropertySheet.py | 5 +- src/webdav/PropertySheets.py | 5 +- tox.ini | 150 +++++++++++---------- 27 files changed, 393 insertions(+), 247 deletions(-) create mode 100644 .github/workflows/tests.yml create mode 100644 .meta.toml delete mode 100644 .travis.yml diff --git a/.editorconfig b/.editorconfig index f6f28c4f57..615323a7f8 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,4 +1,7 @@ -# EditorConfig Configurtaion file, for more details see: +# Generated from: +# https://github.com/zopefoundation/meta/tree/master/config/zope-product +# +# EditorConfig Configuration file, for more details see: # http://EditorConfig.org # EditorConfig is a convention description, that could be interpreted # by multiple editors to enforce common coding conventions for specific diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000000..0c783b84a8 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,54 @@ +# Generated from: +# https://github.com/zopefoundation/meta/tree/master/config/zope-product +name: tests + +on: + push: + branches: [ master ] + pull_request: + schedule: + - cron: '0 12 * * 0' # run once a week on Sunday + +jobs: + build: + strategy: + matrix: + config: + # [Python version, tox env] + - ["3.8", "lint"] + - ["3.6", "py36"] + - ["3.7", "py37"] + - ["3.8", "py38"] + - ["3.9", "py39"] + - ["3.8", "docs"] + - ["3.8", "coverage"] + + runs-on: ubuntu-latest + name: ${{ matrix.config[1] }} + steps: + - uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.config[0] }} + - name: Pip cache + uses: actions/cache@v2 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ matrix.config[0] }}-${{ hashFiles('setup.*', 'tox.ini') }} + restore-keys: | + ${{ runner.os }}-pip-${{ matrix.config[0] }}- + ${{ runner.os }}-pip- + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install tox + - name: Test + run: tox -e ${{ matrix.config[1] }} + - name: Coverage + if: matrix.config[1] == 'coverage' + run: | + pip install coveralls coverage-python-version + coveralls --service=github + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index 97cc0ee141..350f3861f5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,35 +1,28 @@ -*.egg-info -*.py? +# Generated from: +# https://github.com/zopefoundation/meta/tree/master/config/zope-product +*.egg-info/ *.profraw -*.swp -.Python +*.pyc +*.pyo .coverage .coverage.* -.installed*.cfg +.eggs/ +.installed.cfg .mr.developer.cfg -.project -.pydevproject -.tox -.vscode -/bin/ -/build/ -/_build/ -/develop-eggs/ -/develop/ -/dist/ -/docs/.build/ -/docs/_build/ -/eggs/ -/etc/ -/htmlcov/ -/include/ -/lib/ -/lib64 -/log/ -/parts/ -/var/ +.tox/ +__pycache__/ +bin/ +build/ coverage.xml -pip-selfcheck.json -Pipfile -Pipfile.lock +develop-eggs/ +develop/ +dist/ +docs/_build +eggs/ +etc/ +lib/ +lib64 +log/ +parts/ pyvenv.cfg +var/ diff --git a/.meta.toml b/.meta.toml new file mode 100644 index 0000000000..b177ca6262 --- /dev/null +++ b/.meta.toml @@ -0,0 +1,136 @@ +# Generated from: +# https://github.com/zopefoundation/meta/tree/master/config/zope-product +[meta] +template = "zope-product" +commit-id = "211d612c86d6754ebe13fad9b7081533bb603ed9" + +[python] +with-appveyor = true +with-pypy = false +with-legacy-python = false +with-docs = true +with-sphinx-doctests = false + +[coverage] +fail-under = 80 + +[isort] +known_third_party = "ipaddress, PasteDeploy, waitress, chameleon, paste, pkg_resources" +known_zope = "AccessControl, Acquisition, App, DateTime, DocumentTemplate, ExtensionClass, MultiMapping, OFS, Persistence, persistent, Products, RestrictedPython, Shared, Testing, transaction, webdav, ZConfig, zExceptions, zmi, ZODB, zope, Zope2, ZPublisher, ZTUtils" + +[flake8] +additional-config = [ + "# W503 line break before binary operator", + "ignore = W503", + ] + +[tox] +additional-envlist = [ + "pre-commit", + ] +testenv-commands-pre = [ + "{envbindir}/buildout -c {toxinidir}/buildout.cfg buildout:directory={envdir} buildout:develop={toxinidir} install alltests", + ] +testenv-commands = [ + "{envdir}/bin/alltests {posargs:-vc}", + ] +coverage-command = "coverage run {envdir}/bin/alltests {posargs:-vc}" +testenv-additional = [ + "", + "[testenv:pre-commit]", + "basepython = python3", + "description = This env runs all linters configured in .pre-commit-config.yaml", + "skip_install = true", + "deps =", + " pre-commit", + "commands_pre =", + "commands =", + " pre-commit run --all-files --show-diff-on-failure", + "", + "[testenv:autopep8]", + "basepython = python3.6", + "skip_install = true", + "deps =", + " -cconstraints.txt", + " autopep8", + " docformatter", + "commands =", + " autopep8 --verbose --in-place --recursive --aggressive --aggressive {toxinidir}/src setup.py", + " docformatter --in-place --recursive {toxinidir}/src setup.py", + ] + +[manifest] +additional-rules = [ + "include *.py", + "include *.yaml", + "include sources.cfg", + "include versions-prod.cfg", + "include versions.cfg", + "include zope-ecosystem.cfg", + "recursive-include docs *.css", + "recursive-include docs *.jpg", + "recursive-include docs *.png", + "recursive-include docs *.tgz", + "recursive-include src *.css", + "recursive-include src *.dtml", + "recursive-include src *.eot", + "recursive-include src *.gif", + "recursive-include src *.htm", + "recursive-include src *.html", + "recursive-include src *.ico", + "recursive-include src *.in", + "recursive-include src *.js", + "recursive-include src *.map", + "recursive-include src *.md", + "recursive-include src *.pdf", + "recursive-include src *.png", + "recursive-include src *.po", + "recursive-include src *.pot", + "recursive-include src *.svg", + "recursive-include src *.ttf", + "recursive-include src *.webmanifest", + "recursive-include src *.woff", + "recursive-include src *.woff2", + "recursive-include src *.xml", + "recursive-include src *.zpt", + ] + +[check-manifest] +additional-ignores = [ + "docs/_build/html/_images/*", + "docs/_build/html/_sources/migrations/*", + "docs/_build/html/_sources/migrations/zope4/*", + "docs/_build/html/_sources/zdgbook/*", + "docs/_build/html/_sources/zdgbook/includes/*", + "docs/_build/html/_sources/zopebook/*", + "docs/_build/html/_sources/zopebook/includes/*", + "docs/_build/html/_static/*", + "docs/_build/html/_static/css/*", + ] +ignore-bad-ideas = [ + "src/Products/Five/tests/locales/de/LC_MESSAGES/fivetest.mo", + "src/Products/Five/tests/locales/en/LC_MESSAGES/fivetest.mo", + ] + +[appveyor] +replacement = [ + "environment:", + " matrix:", + " - TOXENV: py38", + " - TOXENV: py37", + " - TOXENV: py36", + " - TOXENV: py39", + "install:", + " - python -m pip install -U pip", + " - pip install -U setuptools wheel", + " - pip install -U tox", + "build: false", + "matrix:", + " fast_finish: true", + " allow_failures:", + " - TOXENV: py39", + "test_script:", + " - tox", + "on_success:", + " - echo Build succesful!", + ] diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 611a6c14fa..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,35 +0,0 @@ -language: python - -matrix: - include: - - python: "3.6" - env: TOXENV=lint - after_success: - - python: "3.6" - env: TOXENV=py36 - - python: "3.7" - env: TOXENV=py37 - - python: "3.8" - env: TOXENV=py38 - - python: "3.9" - env: TOXENV=py39 - -install: - - pip install -U pip setuptools - - pip install -U tox coveralls coverage - -script: - - tox - -after_success: - - coverage combine - - coveralls - -notifications: - email: mh@gocept.com - -cache: - pip: true - directories: - - eggs/ - diff --git a/MANIFEST.in b/MANIFEST.in index 00fb88e0b3..b6661ce986 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,32 +1,32 @@ -include *.py +# Generated from: +# https://github.com/zopefoundation/meta/tree/master/config/zope-product include *.rst include *.txt include buildout.cfg +include tox.ini +include appveyor.yml + +recursive-include docs *.bat +recursive-include docs *.py +recursive-include docs *.rst +recursive-include docs *.txt +recursive-include docs Makefile + +recursive-include src *.pt +recursive-include src *.py +recursive-include src *.rst +recursive-include src *.txt +recursive-include src *.zcml +include *.py +include *.yaml include sources.cfg include versions-prod.cfg include versions.cfg include zope-ecosystem.cfg - -include *.yml -exclude *.yml - -include .editorconfig -exclude .editorconfig - -include .gitignore -exclude .gitignore - -exclude MANIFEST.in - -recursive-include docs *.bat recursive-include docs *.css recursive-include docs *.jpg recursive-include docs *.png -recursive-include docs *.py -recursive-include docs *.rst recursive-include docs *.tgz -recursive-include docs *.txt -recursive-include docs Makefile recursive-include src *.css recursive-include src *.dtml recursive-include src *.eot @@ -38,20 +38,14 @@ recursive-include src *.in recursive-include src *.js recursive-include src *.map recursive-include src *.md -recursive-include src *.mo recursive-include src *.pdf recursive-include src *.png recursive-include src *.po recursive-include src *.pot -recursive-include src *.pt -recursive-include src *.py -recursive-include src *.rst recursive-include src *.svg recursive-include src *.ttf -recursive-include src *.txt recursive-include src *.webmanifest recursive-include src *.woff recursive-include src *.woff2 recursive-include src *.xml -recursive-include src *.zcml recursive-include src *.zpt diff --git a/appveyor.yml b/appveyor.yml index 0c8b62f9f8..7cfa302395 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,19 +1,21 @@ -# AppVeyor CI settings (Windows Machine CI Tests) - +# Generated from: +# https://github.com/zopefoundation/meta/tree/master/config/zope-product environment: - WIN_COV: ' ' # some whitespaces to have a trueish value. matrix: - TOXENV: py38 - TOXENV: py37 - TOXENV: py36 - + - TOXENV: py39 install: - - pip install tox - -build: off - + - python -m pip install -U pip + - pip install -U setuptools wheel + - pip install -U tox +build: false matrix: fast_finish: true - + allow_failures: + - TOXENV: py39 test_script: - tox +on_success: + - echo Build succesful! diff --git a/setup.cfg b/setup.cfg index f3810296dd..2057acb7f2 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,11 +1,32 @@ +# Generated from: +# https://github.com/zopefoundation/meta/tree/master/config/zope-product [bdist_wheel] universal = 0 +[flake8] +doctests = 1 +no-accept-encodings = True +htmldir = parts/flake8 +# W503 line break before binary operator +ignore = W503 + [check-manifest] ignore = - update_index.sh - tox.ini - .travis.yml + .editorconfig + .meta.toml + docs/_build/html/_sources/* + docs/_build/html/_images/* + docs/_build/html/_sources/migrations/* + docs/_build/html/_sources/migrations/zope4/* + docs/_build/html/_sources/zdgbook/* + docs/_build/html/_sources/zdgbook/includes/* + docs/_build/html/_sources/zopebook/* + docs/_build/html/_sources/zopebook/includes/* + docs/_build/html/_static/* + docs/_build/html/_static/css/* +ignore-bad-ideas = + src/Products/Five/tests/locales/de/LC_MESSAGES/fivetest.mo + src/Products/Five/tests/locales/en/LC_MESSAGES/fivetest.mo [isort] force_single_line = True @@ -13,39 +34,7 @@ combine_as_imports = True sections = FUTURE,STDLIB,THIRDPARTY,ZOPE,FIRSTPARTY,LOCALFOLDER known_third_party = ipaddress, PasteDeploy, waitress, chameleon, paste, pkg_resources known_zope = AccessControl, Acquisition, App, DateTime, DocumentTemplate, ExtensionClass, MultiMapping, OFS, Persistence, persistent, Products, RestrictedPython, Shared, Testing, transaction, webdav, ZConfig, zExceptions, zmi, ZODB, zope, Zope2, ZPublisher, ZTUtils +known_first_party = default_section = ZOPE line_length = 79 lines_after_imports = 2 - -[flake8] -ignore = - # W503 line break before binary operator: is no longer requested by PEP-8 - W503, - C901, - N801, - N802, - N803, - N805, - N806, - N812, - # We should remove the following ignored check codes: - T000, - C103, -no-accept-encodings = True -doctests = True -exclude = - bootstrap.py - -[coverage:run] -branch = True -source = src -omit = - - -[coverage:report] -precision = 2 -show_missing = False -sort = Name - -[coverage:html] -directory = _build/coverage diff --git a/src/App/Management.py b/src/App/Management.py index 6bb6982cb1..bda79961c2 100644 --- a/src/App/Management.py +++ b/src/App/Management.py @@ -91,7 +91,7 @@ def tabs_path_length(self, REQUEST): def tabs_path_default(self, REQUEST): steps = REQUEST._steps[:-1] script = REQUEST['BASEPATH1'] - linkpat = '{}/manage_workspace' + linkpat = '{0}/manage_workspace' yield {'url': linkpat.format(html.escape(script, True)), 'title': 'Root', 'last': not bool(steps)} diff --git a/src/OFS/Image.py b/src/OFS/Image.py index 00b247e34c..f336671ea3 100644 --- a/src/OFS/Image.py +++ b/src/OFS/Image.py @@ -316,10 +316,8 @@ def _range_request_handler(self, REQUEST, RESPONSE): ) RESPONSE.setHeader( 'Content-Type', - 'multipart/{}byteranges; boundary={}'.format( - draftprefix, - boundary, - ) + f'multipart/{draftprefix}byteranges;' + f' boundary={boundary}' ) RESPONSE.setStatus(206) # Partial content @@ -975,11 +973,11 @@ def tag( if alt is None: alt = getattr(self, 'alt', '') - result = '{} alt="{}"'.format(result, html.escape(alt, True)) + result = f'{result} alt="{html.escape(alt, True)}"' if title is None: title = getattr(self, 'title', '') - result = '{} title="{}"'.format(result, html.escape(title, True)) + result = f'{result} title="{html.escape(title, True)}"' if height: result = f'{result} height="{height}"' diff --git a/src/OFS/tests/test_event.py b/src/OFS/tests/test_event.py index 3d97adb745..6be9aa5274 100644 --- a/src/OFS/tests/test_event.py +++ b/src/OFS/tests/test_event.py @@ -13,10 +13,6 @@ ############################################################################## """Test events """ - -# These classes aren't defined in the doctest because otherwise -# they wouldn't be picklable, and we need that to test copy/paste. - from OFS.Folder import Folder from OFS.OrderedFolder import OrderedFolder from OFS.SimpleItem import SimpleItem @@ -28,6 +24,9 @@ def setUp(test): testing.setUp(test) eventtesting.setUp(test) +# These classes aren't defined in the doctest because otherwise +# they wouldn't be picklable, and we need that to test copy/paste. + class DontComplain: diff --git a/src/Products/Five/browser/adding.py b/src/Products/Five/browser/adding.py index 0df8f7b01d..6d138f92b8 100644 --- a/src/Products/Five/browser/adding.py +++ b/src/Products/Five/browser/adding.py @@ -132,8 +132,7 @@ def action(self, type_name='', id=''): if queryMultiAdapter((self, self.request), name=view_name) is not None: - url = "{}/{}={}".format( - absoluteURL(self, self.request), type_name, id) + url = f"{absoluteURL(self, self.request)}/{type_name}={id}" self.request.response.redirect(url) return diff --git a/src/Products/PageTemplates/PageTemplate.py b/src/Products/PageTemplates/PageTemplate.py index f8dd85162e..55dc528d14 100644 --- a/src/Products/PageTemplates/PageTemplate.py +++ b/src/Products/PageTemplates/PageTemplate.py @@ -61,9 +61,7 @@ def pt_macros(self): __traceback_supplement__ = ( PageTemplateTracebackSupplement, self, {}) raise PTRuntimeError( - 'Page Template {} has errors: {}'.format( - self.id, self._v_errors - )) + f'Page Template {self.id} has errors: {self._v_errors}') return self._v_macros # these methods are reimplemented or duplicated here because of diff --git a/src/Testing/testbrowser.py b/src/Testing/testbrowser.py index a0fbfa019d..f4b20380ed 100644 --- a/src/Testing/testbrowser.py +++ b/src/Testing/testbrowser.py @@ -72,4 +72,4 @@ def login(self, username, password): if not isinstance(password, bytes): password = password.encode('UTF-8') hdr = codecs.encode(b'%s:%s' % (username, password), 'base64') - self.addHeader('Authorization', 'basic {}'.format(hdr.decode('UTF-8'))) + self.addHeader('Authorization', f'basic {hdr.decode("UTF-8")}') diff --git a/src/ZPublisher/BeforeTraverse.py b/src/ZPublisher/BeforeTraverse.py index f401cea422..ae2362d11a 100644 --- a/src/ZPublisher/BeforeTraverse.py +++ b/src/ZPublisher/BeforeTraverse.py @@ -110,8 +110,8 @@ def __call__(self, container, request): try: cob(container, request) except TypeError: - LOG.error('{!r} call {!r} failed.'.format( - self._hookname, cob), exc_info=True) + LOG.error(f'{self._hookname!r} call {cob!r} failed.', + exc_info=True) def add(self, cob): self._list.append(cob) diff --git a/src/ZPublisher/HTTPRequest.py b/src/ZPublisher/HTTPRequest.py index 703196683d..496560a188 100644 --- a/src/ZPublisher/HTTPRequest.py +++ b/src/ZPublisher/HTTPRequest.py @@ -1497,7 +1497,7 @@ def __str__(self): return result + "" def __repr__(self): - return "<{}, URL={}>".format(self.__class__.__name__, self.get('URL')) + return f"<{self.__class__.__name__}, URL={self.get('URL')}>" def text(self): result = "FORM\n\n" @@ -1781,8 +1781,8 @@ def __str__(self): def __repr__(self): # return repr( self.__dict__ ) return '{%s}' % ', '.join( - "'{}': {!r}".format(*item) for item in - sorted(self.__dict__.items())) + f"'{key}': {value!r}" + for key, value in sorted(self.__dict__.items())) def __eq__(self, other): if not isinstance(other, record): diff --git a/src/ZPublisher/HTTPResponse.py b/src/ZPublisher/HTTPResponse.py index 225d34ee55..824490fe81 100644 --- a/src/ZPublisher/HTTPResponse.py +++ b/src/ZPublisher/HTTPResponse.py @@ -334,7 +334,7 @@ def appendCookie(self, name, value): else: cookie = cookies[name] = {} if 'value' in cookie: - cookie['value'] = '{}:{}'.format(cookie['value'], value) + cookie['value'] = f'{cookie["value"]}:{value}' else: cookie['value'] = value @@ -675,10 +675,11 @@ def _cookie_list(self): # quoted cookie attr values, so only the value part # of name=value pairs may be quoted. + v = quote(attrs['value']) if attrs.get('quoted', True): - cookie = '{}="{}"'.format(name, quote(attrs['value'])) + cookie = f'{name}="{v}"' else: - cookie = '{}={}'.format(name, quote(attrs['value'])) + cookie = f'{name}={v}' for name, v in attrs.items(): name = name.lower() if name == 'expires': diff --git a/src/ZPublisher/tests/testBeforeTraverse.py b/src/ZPublisher/tests/testBeforeTraverse.py index 89059e7e29..1e40e7f009 100644 --- a/src/ZPublisher/tests/testBeforeTraverse.py +++ b/src/ZPublisher/tests/testBeforeTraverse.py @@ -81,7 +81,7 @@ def testBeforeTraverse(self): ... TypeError: BrokenHook - Unregister the borken hook: + Unregister the broken hook: >>> _ = BeforeTraverse.unregisterBeforeTraverse(container, 'broken_hook') @@ -117,7 +117,7 @@ def testBeforeTraverse(self): ... TypeError: BrokenHook - Unregister the borken hook: + Unregister the broken hook: >>> _ = BeforeTraverse.unregisterBeforeTraverse( ... container, 'broken_callable') diff --git a/src/ZPublisher/tests/testHTTPRequest.py b/src/ZPublisher/tests/testHTTPRequest.py index dfa927b1be..4dd8f33f01 100644 --- a/src/ZPublisher/tests/testHTTPRequest.py +++ b/src/ZPublisher/tests/testHTTPRequest.py @@ -146,7 +146,7 @@ def _processInputs(self, inputs): query_string = [] add = query_string.append for key, val in inputs: - add("{}={}".format(quote_plus(key), quote_plus(val))) + add(f"{quote_plus(key)}={quote_plus(val)}") query_string = '&'.join(query_string) env = {'SERVER_NAME': 'testingharnas', 'SERVER_PORT': '80'} diff --git a/src/ZPublisher/tests/test_WSGIPublisher.py b/src/ZPublisher/tests/test_WSGIPublisher.py index b129123122..f7a5cf6450 100644 --- a/src/ZPublisher/tests/test_WSGIPublisher.py +++ b/src/ZPublisher/tests/test_WSGIPublisher.py @@ -917,7 +917,7 @@ def test_can_handle_non_ascii_URLs(self): browser = Testing.testbrowser.Browser() browser.login('manager', 'manager_pass') - browser.open('http://localhost/{}'.format(quote('täst'))) + browser.open(f'http://localhost/{quote("täst")}') self.assertEqual(browser.contents.decode('utf-8'), 'çöńtêñt') @@ -988,9 +988,9 @@ def __init__(self, context, request): self.request = request def __call__(self): - return ('Exception View: {}\nContext: {}'.format( - self.context.__class__.__name__, - self.__parent__.__class__.__name__)) + return ( + f'Exception View: {self.context.__class__.__name__}\n' + f'Context: {self.__parent__.__class__.__name__}') def registerExceptionView(for_, factory=CustomExceptionView, diff --git a/src/ZPublisher/tests/test_pubevents.py b/src/ZPublisher/tests/test_pubevents.py index 5848e303f8..fad2f32eca 100644 --- a/src/ZPublisher/tests/test_pubevents.py +++ b/src/ZPublisher/tests/test_pubevents.py @@ -181,8 +181,9 @@ def __init__(self, context, request): def __call__(self): global_request = getRequest() self.request.response.events.append('exc_view') - return ('Exception: {}\nRequest: {!r}'.format( - self.context.__class__, global_request)) + return ( + f'Exception: {self.context.__class__}\n' + f'Request: {global_request!r}') class TestGlobalRequestPubEventsAndExceptionUpgrading(FunctionalTestCase): diff --git a/src/ZTUtils/Zope.py b/src/ZTUtils/Zope.py index 82be5fbc39..81c1a3b21f 100644 --- a/src/ZTUtils/Zope.py +++ b/src/ZTUtils/Zope.py @@ -208,7 +208,7 @@ def make_query(*args, **kwargs): qlist = complex_marshal(list(d.items())) for i in range(len(qlist)): k, m, v = qlist[i] - qlist[i] = '{}{}={}'.format(quote(k), m, quote(str(v))) + qlist[i] = f'{quote(k)}{m}={quote(str(v))}' return '&'.join(qlist) diff --git a/src/Zope2/Startup/datatypes.py b/src/Zope2/Startup/datatypes.py index 1d2ad95025..fb3635f464 100644 --- a/src/Zope2/Startup/datatypes.py +++ b/src/Zope2/Startup/datatypes.py @@ -72,8 +72,8 @@ def importable_name(name): IO = io.StringIO() traceback.print_exc(file=IO) raise ValueError( - 'The object named by "{}" could not be imported\n{}'.format( - name, IO.getvalue())) + f'The object named by {name!r} could not be imported\n' + f'{IO.getvalue()}') class ZDaemonEnvironDict(UserDict): diff --git a/src/Zope2/utilities/tests/test_zconsole.py b/src/Zope2/utilities/tests/test_zconsole.py index 7966a10088..dfa2c3df48 100644 --- a/src/Zope2/utilities/tests/test_zconsole.py +++ b/src/Zope2/utilities/tests/test_zconsole.py @@ -10,7 +10,7 @@ zope_conf_template = """ -%define INSTANCE {} +%define INSTANCE {0} instancehome $INSTANCE @@ -92,6 +92,6 @@ def test_runscript(self): # so we have the raw string in there. expected = ( "42\n" - r"['run', {!r}, {!r}, {!r}, 'baz']" - "\nPropertyManager\n".format(self.zopeconf, script, bar)) + rf"['run', {self.zopeconf!r}, {script!r}, {bar!r}, 'baz']" + "\nPropertyManager\n") self.assertEqual(expected, got) diff --git a/src/webdav/PropertySheet.py b/src/webdav/PropertySheet.py index 652bee68b9..c0f49e2c38 100644 --- a/src/webdav/PropertySheet.py +++ b/src/webdav/PropertySheet.py @@ -115,8 +115,9 @@ def dav__propstat(self, name, result, if not hasattr(self, 'dav__%s' % name): value = xml_escape(value) if xml_id: - prop = '{}\n'.format( - name, attrs, xml_id, value, name) + prop = ( + f'{value}\n' + ) else: prop = f'<{name}{attrs} xmlns="">{value}\n' code = '200 OK' diff --git a/src/webdav/PropertySheets.py b/src/webdav/PropertySheets.py index 21733c1e72..3d8f14bb2c 100644 --- a/src/webdav/PropertySheets.py +++ b/src/webdav/PropertySheets.py @@ -139,10 +139,9 @@ def dav__lockdiscovery(self): else: fake = 1 - out = '{}\n{}'.format( - out, lock.asLockDiscoveryProperty('n', fake=fake)) + out = f'{out}\n{lock.asLockDiscoveryProperty("n", fake=fake)}' - out = '%s\n' % out + out = f'{out}\n' return out diff --git a/tox.ini b/tox.ini index e6b4a280f4..2049700d0c 100644 --- a/tox.ini +++ b/tox.ini @@ -1,58 +1,37 @@ +# Generated from: +# https://github.com/zopefoundation/meta/tree/master/config/zope-product [tox] -# If adding or removing envs here please update the testenv:coverage-report -# section as well: +minversion = 3.18 envlist = - py36, - py37, - py38, - py39, - lint, - pre-commit, - coverage-report + lint + py36 + py37 + py38 + py39 + docs + coverage + pre-commit [testenv] -coverage_run = {env:WIN_COV:coverage run} -commands = - {envbindir}/buildout -c {toxinidir}/buildout.cfg buildout:directory={envdir} buildout:develop={toxinidir} install test alltests - {[testenv]coverage_run} {envdir}/bin/alltests {posargs:-vc} skip_install = true +# We need to pin setuptools until we have zc.buildout 3.0. deps = - -cconstraints.txt - coverage setuptools < 52 - zc.buildout>=2.12 -setenv = - COVERAGE_FILE=.coverage.{envname} - -[testenv:coverage-report] -basepython = python3.6 -depends = - py36, - py37, - py38, - py39, -deps = - -cconstraints.txt - coverage -setenv = - COVERAGE_FILE=.coverage -skip_install = true + zc.buildout +commands_pre = + {envbindir}/buildout -c {toxinidir}/buildout.cfg buildout:directory={envdir} buildout:develop={toxinidir} install alltests commands = - coverage erase - coverage combine - coverage html -i - coverage xml -i - coverage report -i --fail-under=80 + {envdir}/bin/alltests {posargs:-vc} -[testenv:isort-apply] -basepython = python3.6 +[testenv:pre-commit] +basepython = python3 +description = This env runs all linters configured in .pre-commit-config.yaml skip_install = true deps = - -cconstraints.txt - isort - + pre-commit +commands_pre = commands = - isort {toxinidir}/src {toxinidir}/docs setup.py {posargs} + pre-commit run --all-files --show-diff-on-failure [testenv:autopep8] basepython = python3.6 @@ -61,47 +40,82 @@ deps = -cconstraints.txt autopep8 docformatter - commands = autopep8 --verbose --in-place --recursive --aggressive --aggressive {toxinidir}/src setup.py docformatter --in-place --recursive {toxinidir}/src setup.py [testenv:lint] -basepython = python3.6 -skip_install = true - +basepython = python3 +allowlist_externals = + mkdir +commands_pre = + mkdir -p {toxinidir}/parts/flake8 +commands = + isort --check-only --diff {toxinidir}/src {toxinidir}/setup.py + - flake8 --format=html {toxinidir}/src {toxinidir}/setup.py + flake8 {toxinidir}/src {toxinidir}/setup.py + check-manifest + check-python-versions deps = - -cconstraints.txt - isort + check-manifest + check-python-versions flake8 + isort # helper to generate HTML reports: flake8-html # Useful flake8 plugins that are Python and Plone specific: flake8-coding flake8-debugger - flake8-deprecated - flake8-todo mccabe - # Potential flake8 plugins that should be used: # TBD - #flake8-blind-except - #flake8-commas - #flake8-docstrings - #flake8-mypy - #flake8-pep3101 - #flake8-plone-hasattr - #flake8-string-format - #flake8_strict - #flake8-quotes +[testenv:isort-apply] +basepython = python3 +commands_pre = +deps = + isort commands = - isort --check-only --diff {toxinidir}/src setup.py - flake8 src docs setup.py + isort {toxinidir}/src {toxinidir}/setup.py [] -[testenv:pre-commit] -basepython = python3.6 -description = This env runs all linters configured in .pre-commit-config.yaml +[testenv:docs] +basepython = python3 +skip_install = false +deps = +extras = + docs +commands_pre = +commands = + sphinx-build -b html -d docs/_build/doctrees docs docs/_build/html + +[testenv:coverage] +basepython = python3 skip_install = true +allowlist_externals = + mkdir deps = - pre-commit + {[testenv]deps} + coverage + coverage-python-version commands = - pre-commit run --all-files --show-diff-on-failure + mkdir -p {toxinidir}/parts/htmlcov + coverage run {envdir}/bin/alltests {posargs:-vc} + coverage html + coverage report -m --fail-under=80 + +[coverage:run] +branch = True +plugins = coverage_python_version +source = src + +[coverage:report] +precision = 2 +exclude_lines = + pragma: no cover + pragma: nocover + except ImportError: + raise NotImplementedError + if __name__ == '__main__': + self.fail + raise AssertionError + +[coverage:html] +directory = parts/htmlcov