diff --git a/.editorconfig b/.editorconfig index a83363b..5b3c112 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,15 +1,56 @@ +# Generated from: +# https://github.com/plone/meta/tree/main/config/default +# See the inline comments on how to expand/tweak this configuration file +# +# 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 +# file types + +# top-most EditorConfig file: +# Will ignore other EditorConfig files in Home directory or upper tree level. +root = true + + [*] -indent_style = space +# Default settings for all files. +# Unix-style newlines with a newline ending every file end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true +# Set default charset charset = utf-8 +# Indent style default +indent_style = space +# Max Line Length - a hard line wrap, should be disabled +max_line_length = off -[{*.py,*.cfg}] +[*.{py,cfg,ini}] +# 4 space indentation indent_size = 4 -[{*.html,*.dtml,*.pt,*.zpt,*.xml,*.zcml,*.js}] +[*.{yml,zpt,pt,dtml,zcml,html,xml}] +# 2 space indentation indent_size = 2 -[Makefile] +[*.{json,jsonl,js,jsx,ts,tsx,css,less,scss}] +# Frontend development +# 2 space indentation +indent_size = 2 +max_line_length = 80 + +[{Makefile,.gitmodules}] +# Tab indentation (no size specified, but view as 4 spaces) indent_style = tab +indent_size = unset +tab_width = unset + + +## +# Add extra configuration options in .meta.toml: +# [editorconfig] +# extra_lines = """ +# _your own configuration lines_ +# """ +## diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..38918f4 --- /dev/null +++ b/.flake8 @@ -0,0 +1,22 @@ +# Generated from: +# https://github.com/plone/meta/tree/main/config/default +# See the inline comments on how to expand/tweak this configuration file +[flake8] +doctests = 1 +ignore = + # black takes care of line length + E501, + # black takes care of where to break lines + W503, + # black takes care of spaces within slicing (list[:]) + E203, + # black takes care of spaces after commas + E231, + +## +# Add extra configuration options in .meta.toml: +# [flake8] +# extra_lines = """ +# _your own configuration lines_ +# """ +## diff --git a/.github/workflows/black.yml b/.github/workflows/black.yml deleted file mode 100644 index f5fb8c5..0000000 --- a/.github/workflows/black.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: Black -on: [push] -jobs: - build: - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - python-version: [3.8] - - steps: - # git checkout - - uses: actions/checkout@v2 - - # python setup - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v1 - with: - python-version: ${{ matrix.python-version }} - - # python cache - - uses: actions/cache@v1 - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} - restore-keys: | - ${{ runner.os }}-pip- - - # install black (extract version from versions.cfg) - - name: install black - run: pip install black - - # run black - - name: run black - run: black src/ --check --diff diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml new file mode 100644 index 0000000..99aca9c --- /dev/null +++ b/.github/workflows/codecov.yml @@ -0,0 +1,53 @@ +# Generated from: +# https://github.com/plone/meta/tree/main/config/default +# See the inline comments on how to expand/tweak this configuration file +name: Codecov +on: + push: + branches: + - master + - main + pull_request: + branches: + - master + - main + workflow_dispatch: + +jobs: + coveralls: + name: Codecov + runs-on: ${{ matrix.os }} + strategy: + matrix: + python-version: ["3.11"] + os: ["ubuntu-latest"] + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: install OS packages + if: inputs.os-packages != '' + run: sudo apt-get install -y ${{ inputs.os-packages }} + - name: Cache packages + uses: actions/cache@v4 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ matrix.python-version }}-${{ hashFiles('tox.ini') }} + restore-keys: | + ${{ runner.os }}-pip-${{ matrix.python-version }}- + ${{ runner.os }}-pip- + - name: Install dependencies + run: python -m pip install tox + - name: Initialize tox + run: | + if [ `tox list --no-desc -f init|wc -l` = 1 ]; then tox -e init;else true; fi + - name: Run coverage + run: | + tox -q -e coverage >> $GITHUB_STEP_SUMMARY + - uses: codecov/codecov-action@v4 + with: + fail_ci_if_error: true + verbose: true + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/flake8.yml b/.github/workflows/flake8.yml deleted file mode 100644 index 73f73f0..0000000 --- a/.github/workflows/flake8.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: Flake 8 -on: [push] -jobs: - build: - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - python-version: [3.8] - - steps: - # git checkout - - uses: actions/checkout@v2 - - # python setup - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v1 - with: - python-version: ${{ matrix.python-version }} - - # python cache - - uses: actions/cache@v1 - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} - restore-keys: | - ${{ runner.os }}-pip- - - # install flake8 - - name: install flake8 - run: pip install flake8 - - # run black - - name: run flake8 - run: flake8 src/ setup.py diff --git a/.github/workflows/meta.yml b/.github/workflows/meta.yml new file mode 100644 index 0000000..0309990 --- /dev/null +++ b/.github/workflows/meta.yml @@ -0,0 +1,70 @@ +# Generated from: +# https://github.com/plone/meta/tree/main/config/default +# See the inline comments on how to expand/tweak this configuration file +name: Meta +on: + push: + branches: + - master + - main + pull_request: + branches: + - master + - main + workflow_dispatch: + +## +# To set environment variables for all jobs, add in .meta.toml: +# [github] +# env = """ +# debug: 1 +# image-name: 'org/image' +# image-tag: 'latest' +# """ +## + +jobs: + qa: + uses: plone/meta/.github/workflows/qa.yml@main + test: + uses: plone/meta/.github/workflows/test.yml@main + coverage: + uses: plone/meta/.github/workflows/coverage.yml@main + dependencies: + uses: plone/meta/.github/workflows/dependencies.yml@main + release_ready: + uses: plone/meta/.github/workflows/release_ready.yml@main + circular: + uses: plone/meta/.github/workflows/circular.yml@main + +## +# To modify the list of default jobs being created add in .meta.toml: +# [github] +# jobs = [ +# "qa", +# "test", +# "coverage", +# "dependencies", +# "release_ready", +# "circular", +# ] +## + +## +# To request that some OS level dependencies get installed +# when running tests/coverage jobs, add in .meta.toml: +# [github] +# os_dependencies = "git libxml2 libxslt" +## + + plonetests: + uses: collective/workflow-plonematrix/.github/workflows/plonetest-matrix.yml@main + +## +# Specify additional jobs in .meta.toml: +# [github] +# extra_lines = """ +# another: +# uses: org/repo/.github/workflows/file.yml@main +# """ +## diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml deleted file mode 100644 index 74a04e9..0000000 --- a/.github/workflows/tests.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: Build and test - -on: [push] - -jobs: - build: - strategy: - fail-fast: false - matrix: - include: - - plone-version: "52" - python-version: 3.7 - - plone-version: "52" - python-version: 3.8 - - plone-version: "60" - python-version: 3.7 - - plone-version: "60" - python-version: 3.8 - - plone-version: "60" - python-version: 3.9 - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions/cache@v2 - with: - path: | - ~/.cache/pip - ~/buildout-cache/eggs - ~/extends - webpack/node_modules - key: ${{ runner.os }}-tox-${{ matrix.python-version }}-${{ matrix.plone-version }}-${{ hashFiles('**/setup.py') }}-${{ hashFiles('**/requirements.txt') }}-${{ hashFiles('**/*.cfg') }}-${{ hashFiles('**/constraints.txt') }}-${{ hashFiles('**/tox.ini') }} - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install system libraries - run: sudo apt-get install libxml2-dev libxslt1-dev libjpeg-dev - - name: Install dependencies - run: | - python -m pip install --upgrade pip virtualenv - - name: setup buildout cache - env: - PLONE_VERSION: ${{ matrix.plone-version }} - run: | - virtualenv . - mkdir -p ~/buildout-cache/{eggs,downloads} - mkdir ~/.buildout - echo "[buildout]" > $HOME/.buildout/default.cfg - echo "download-cache = $HOME/buildout-cache/downloads" >> $HOME/.buildout/default.cfg - echo "eggs-directory = $HOME/buildout-cache/eggs" >> $HOME/.buildout/default.cfg - bin/pip install -r requirements_plone$PLONE_VERSION.txt -c constraints_plone$PLONE_VERSION.txt - cp test_plone$PLONE_VERSION.cfg buildout.cfg - - name: Run buildout - run: | - bin/buildout -N -t 3 code-analysis:return-status-codes=True annotate - bin/buildout -N -t 3 code-analysis:return-status-codes=True - - - name: Tests - env: - PLONE_VERSION: ${{ matrix.plone-version }} - PYTHON_VERSION: ${{ matrix.python-version }} - run: | - bin/test --all diff --git a/.gitignore b/.gitignore index d47d72c..a98115e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,49 +1,58 @@ -.coverage +# Generated from: +# https://github.com/plone/meta/tree/main/config/default +# See the inline comments on how to expand/tweak this configuration file +# python related *.egg-info -*.log +*.pyc +*.pyo + +# translation related *.mo -*.py? -*.swp -.coverage* -.python-version -# dirs + +# tools related +build/ +.coverage +.*project +coverage.xml +dist/ +docs/_build +__pycache__/ +.tox +.vscode/ +node_modules/ + +# venv / buildout related bin/ -buildout-cache/ develop-eggs/ eggs/ -htmlcov/ +.eggs/ +etc/ +.installed.cfg include/ lib/ -local/ -node_modules/ -parts/ -src/* -test.plone_addon/ -var/ -# files -.installed.cfg -.mr.developer.cfg -Gruntfile.js lib64 -log.html -output.xml -package.json -pip-selfcheck.json +.mr.developer.cfg +parts/ pyvenv.cfg -report.html +var/ local.cfg -.vscode/ -# excludes -!.coveragerc -!.editorconfig -!.gitattributes -!.gitignore -!.gitkeep -!.travis.yml -!src/collective -/.coverage.py37-Plone52 -/.tox -/reports -/share -/src-mrd -/downloads + +# mxdev +/instance/ +/.make-sentinels/ +/*-mxdev.txt +/reports/ +/sources/ +/venv/ +.installed.txt + +forest.dot +forest.json + +## +# Add extra configuration options in .meta.toml: +# [gitignore] +# extra_lines = """ +# _your own configuration lines_ +# """ +## diff --git a/.meta.toml b/.meta.toml new file mode 100644 index 0000000..cb78044 --- /dev/null +++ b/.meta.toml @@ -0,0 +1,30 @@ +# Generated from: +# https://github.com/plone/meta/tree/main/config/default +# See the inline comments on how to expand/tweak this configuration file +[meta] +template = "default" +commit-id = "1c2155e4" + +[github] +extra_lines = """ + plonetests: + uses: collective/workflow-plonematrix/.github/workflows/plonetest-matrix.yml@main +""" + +[tox] +use_mxdev = true +config_lines = """ +[gh-actions] +python = + 3.8: py38 + 3.9: py39 + 3.10: py310 + 3.11: py311 + 3.12: py312 +""" + +[gitignore] +extra_lines = """ +forest.dot +forest.json +""" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..0a5e9d0 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,94 @@ +# Generated from: +# https://github.com/plone/meta/tree/main/config/default +# See the inline comments on how to expand/tweak this configuration file +ci: + autofix_prs: false + autoupdate_schedule: monthly + +repos: +- repo: https://github.com/asottile/pyupgrade + rev: v3.15.2 + hooks: + - id: pyupgrade + args: [--py38-plus] +- repo: https://github.com/pycqa/isort + rev: 5.13.2 + hooks: + - id: isort +- repo: https://github.com/psf/black + rev: 24.3.0 + hooks: + - id: black +- repo: https://github.com/collective/zpretty + rev: 3.1.0 + hooks: + - id: zpretty + +## +# Add extra configuration options in .meta.toml: +# [pre_commit] +# zpretty_extra_lines = """ +# _your own configuration lines_ +# """ +## +- repo: https://github.com/PyCQA/flake8 + rev: 7.0.0 + hooks: + - id: flake8 + +## +# Add extra configuration options in .meta.toml: +# [pre_commit] +# flake8_extra_lines = """ +# _your own configuration lines_ +# """ +## +- repo: https://github.com/codespell-project/codespell + rev: v2.2.6 + hooks: + - id: codespell + additional_dependencies: + - tomli + +## +# Add extra configuration options in .meta.toml: +# [pre_commit] +# codespell_extra_lines = """ +# _your own configuration lines_ +# """ +## +- repo: https://github.com/mgedmin/check-manifest + rev: "0.49" + hooks: + - id: check-manifest +- repo: https://github.com/regebro/pyroma + rev: "4.2" + hooks: + - id: pyroma +- repo: https://github.com/mgedmin/check-python-versions + rev: "0.22.0" + hooks: + - id: check-python-versions + args: ['--only', 'setup.py,pyproject.toml'] +- repo: https://github.com/collective/i18ndude + rev: "6.1.0" + hooks: + - id: i18ndude + + +## +# Add extra configuration options in .meta.toml: +# [pre_commit] +# i18ndude_extra_lines = """ +# _your own configuration lines_ +# """ +## + + +## +# Add extra configuration options in .meta.toml: +# [pre_commit] +# extra_lines = """ +# _your own configuration lines_ +# """ +## diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index cd8ac53..0000000 --- a/.travis.yml +++ /dev/null @@ -1,60 +0,0 @@ -language: python -sudo: false -cache: - pip: true - directories: - - eggs - - downloads -python: - - "2.7" -matrix: - include: - - python: "3.7" - env: - - TOXENV=py37-lint - - PLONE_VERSION=52 - - python: "2.7" - env: PLONE_VERSION=43 - - python: "2.7" - env: PLONE_VERSION=51 - - python: "2.7" - env: PLONE_VERSION=52 - - python: "3.7" - env: PLONE_VERSION=52 - dist: xenial - sudo: true - fast_finish: true -before_install: - - virtualenv -p `which python` . - - mkdir -p $HOME/buildout-cache/{eggs,downloads} - - mkdir $HOME/.buildout - - echo "[buildout]" > $HOME/.buildout/default.cfg - - echo "download-cache = $HOME/buildout-cache/downloads" >> $HOME/.buildout/default.cfg - - echo "eggs-directory = $HOME/buildout-cache/eggs" >> $HOME/.buildout/default.cfg - - bin/pip install -r requirements.txt -c constraints_plone$PLONE_VERSION.txt -# - bin/buildout -N out:download-cache=downloads code-analysis:return-status-codes=True annotate -# - bin/buildout -N buildout:download-cache=downloads code-analysis:return-status-codes=True - - cp test_plone$PLONE_VERSION.cfg buildout.cfg - -install: - - bin/buildout -N -t 3 code-analysis:return-status-codes=True annotate - - bin/buildout -N -t 3 code-analysis:return-status-codes=True - -before_script: -- 'export DISPLAY=:99.0' -- Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & -- sleep 3 -- firefox -v - -script: -# do code-analysis only on latest plone because there's -# a strange error with configparser in version < 5.1 - - echo $PLONE_VERSION | grep -v 5.2.x || bin/code-analysis - - bin/test --all - -after_success: - - echo $PLONE_VERSION | grep -v 5.2.x || bin/createcoverage --output-dir=parts/test/coverage - - echo $PLONE_VERSION | grep -v 5.2.x || bin/pip install coverage - - echo $PLONE_VERSION | grep -v 5.2.x || bin/python -m coverage.pickle2json - - echo $PLONE_VERSION | grep -v 5.2.x || bin/pip install -q coveralls - - echo $PLONE_VERSION | grep -v 5.2.x || coveralls diff --git a/CHANGES.rst b/CHANGES.rst index 8c4fb7b..156ee3d 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,10 +1,14 @@ Changelog ------------ -2.2 (unreleased) +3.0 (unreleased) ~~~~~~~~~~~~~~~~ -- Nothing changed yet. +- refactoring package to pip based installation +- update configuration via plone/meta +- refactor norobots widget to bootstrap5 formcontrol with floating labels +- add tests + [1letter] 2.1 (2022-08-18) diff --git a/MANIFEST.in b/MANIFEST.in index 07a60db..a470f0b 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,11 @@ graft src/collective graft docs include *.rst +include .coveragerc +include constraints.txt +include requirements.txt +include .gitlab-ci.yml +include instance.yml +exclude *.txt global-exclude *.pyc + diff --git a/README.rst b/README.rst index 1c94f0e..2076369 100644 --- a/README.rst +++ b/README.rst @@ -1,9 +1,9 @@ -.. image:: https://travis-ci.org/collective/collective.z3cform.norobots.svg?branch=master - :target: https://travis-ci.org/collective/collective.z3cform.norobots +.. image:: https://github.com/collective/collective.outputfilters.tinymceaccordion/actions/workflows/meta.yml/badge.svg + :target: https://github.com/collective/collective.outputfilters.tinymceaccordion/actions/workflows/meta.yml + :alt: Plone Meta Workflow -.. image:: https://coveralls.io/repos/github/collective/collective.z3cform.norobots/badge.svg?branch=master - :target: https://coveralls.io/github/collective/collective.z3cform.norobots?branch=master - :alt: Coveralls +.. image:: https://codecov.io/gh/collective/collective.z3cform.norobots/graph/badge.svg?token=DgZ7MzmVMr + :target: https://codecov.io/gh/collective/collective.z3cform.norobots .. image:: https://img.shields.io/pypi/v/collective.z3cform.norobots.svg :target: https://pypi.python.org/pypi/collective.z3cform.norobots/ @@ -59,9 +59,12 @@ See previous releases for old Plone versions. Screenshot ------------ -.. image:: https://github.com/sylvainb/collective.z3cform.norobots/raw/master/docs/collective-z3cform-norobots-screenshot.png - :height: 324px - :width: 499px +.. image:: https://raw.githubusercontent.com/collective/collective.z3cform.norobots/dev/docs/collective.z3cform.norobots-screenshot-1.png + :scale: 100 % + :alt: Screenshot + :align: center + +.. image:: https://raw.githubusercontent.com/collective/collective.z3cform.norobots/dev/docs/collective.z3cform.norobots-screenshot-2.png :scale: 100 % :alt: Screenshot :align: center @@ -69,8 +72,12 @@ Screenshot Installation ------------ -Getting the module -~~~~~~~~~~~~~~~~~~~~ +Getting the module - pip based + +Add ``collective.z3cform.norobots`` to your ``requirements.txt`` + +Getting the module - buildout based +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Add ``collective.z3cform.norobots`` to your ``plone.recipe.zope2instance`` buildout section e.g.:: @@ -119,32 +126,28 @@ Answer can contain multiple values delimited by semicolon: Quickly test ? ~~~~~~~~~~~~~~~~~~~~ -Download ``collective.z3cform.norobots`` and use ``virtualenv`` and ``buildout`` to test the module:: +Checkout ``collective.z3cform.norobots`` and use ``venv`` and ``pip`` to test the module:: - easy_install virtualenv - cd collective.z3cform.norobots - virtualenv . - source bin/activate - (collective.z3cform.norobots) easy_install zc.buildout - !!! check the buildout config file ``test-plone-base.cfg`` before running !!! - (collective.z3cform.norobots) ln -s test-plone-5.0.x.cfg buildout.cfg - (collective.z3cform.norobots) python bootstrap.py - (collective.z3cform.norobots) bin/buildout - [...] be patient... [...] - (collective.z3cform.norobots) ./bin/instance fg + python3 -m venv ./venv + source venv/bin/activate + (venv) pip install mxdev + (venv) pip install -r requirements-mxdev.txt + (venv) pip install cookiecutter + (venv) cookiecutter -f --no-input --config-file instance.yml https://github.com/plone/cookiecutter-zope-instance + (venv) runwsgi -v instance/etc/zope.ini Go to http://localhost:8080, add a new Plone Site and install collective.z3cform.norobots (see above). Launch tests:: - (collective.z3cform.norobots) pip install unittest2 - (collective.z3cform.norobots) ./bin/test -s collective.z3cform.norobots + (venv) pip install tox + (venv) tox Launch code coverage:: - (collective.z3cform.norobots) bin/coverage - (collective.z3cform.norobots) bin/report - And open with a browser htmlcov/index.html + (venv) tox -e coverage + +and open with a browser htmlcov/index.html Usage as a ``plone.app.discussion`` (Plone Discussions) captcha plugin ---------------------------------------------------------------------- @@ -161,7 +164,7 @@ You can use this widget setting the "widgetFactory" property of a form field: from zope import interface, schema from z3c.form import interfaces, form, field, button, validator - from plone.app.z3cform.layout import wrap_form + from plone.z3cform.layout import wrap_form from collective.z3cform.norobots.i18n import MessageFactory as _ from collective.z3cform.norobots.widget import NorobotsFieldWidget @@ -176,10 +179,10 @@ You can use this widget setting the "widgetFactory" property of a form field: fields = field.Fields(INorobotsForm) fields['norobots'].widgetFactory = NorobotsFieldWidget - # wrap the form with plone.app.z3cform's Form wrapper + # wrap the form with plone.z3cform's Form wrapper NorobotsFormView = wrap_form(NorobotsForm) - # Register Norobots validator for the correponding field in the IContactInfo interface + # Register Norobots validator for the corresponding field in the IContactInfo interface validator.WidgetValidatorDiscriminators(NorobotsValidator, field=INorobotsForm['norobots']) In your configure.zcml you have to add the following adapter, to make the validation work. @@ -217,12 +220,12 @@ Credits Source code ----------- -`Source code `_ is hosted on Github. +`Source code `_ is hosted on Github. How to contribute and submit a patch ? -------------------------------------- -`Source code `_ and an `issue tracker `_ is hosted on Github. +`Source code `_ and an `issue tracker `_ is hosted on Github. Contributors ----------------- @@ -237,5 +240,6 @@ Contributors * Luca Fabbri [keul] * Andrea Cecchi [cekk] * [serge73] +* [1letter] .. _`collective.pfg.norobots`: http://pypi.python.org/pypi/collective.pfg.norobots diff --git a/base.cfg b/base.cfg deleted file mode 100644 index a0d6215..0000000 --- a/base.cfg +++ /dev/null @@ -1,103 +0,0 @@ -[buildout] -show-picked-versions = true -extensions = - mr.developer - -index = https://pypi.python.org/simple/ - -parts = - instance - test - code-analysis - coverage - test-coverage - createcoverage - releaser - i18ndude - omelette - robot - plone-helper-scripts -develop = . - - -[instance] -recipe = plone.recipe.zope2instance -user = admin:admin -http-address = 8080 -environment-vars = - zope_i18n_compile_mo_files true -eggs = - Plone - Pillow - collective.z3cform.norobots [test] - - -[code-analysis] -recipe = - -[omelette] -recipe = collective.recipe.omelette -eggs = ${instance:eggs} - - -[test] -recipe = zc.recipe.testrunner -eggs = ${instance:eggs} -initialization = - os.environ['TZ'] = 'UTC' -defaults = ['-s', 'collective.z3cform.norobots', '--auto-color', '--auto-progress'] - - -[coverage] -recipe = zc.recipe.egg -eggs = coverage - - -[test-coverage] -recipe = collective.recipe.template -input = inline: - #!/bin/bash - export TZ=UTC - ${buildout:directory}/bin/coverage run bin/test $* - ${buildout:directory}/bin/coverage html - ${buildout:directory}/bin/coverage report -m --fail-under=90 - # Fail (exit status 1) if coverage returns exit status 2 (this happens - # when test coverage is below 100%. -output = ${buildout:directory}/bin/test-coverage -mode = 755 - - -[createcoverage] -recipe = zc.recipe.egg -eggs = createcoverage - - -[robot] -recipe = zc.recipe.egg -eggs = - ${test:eggs} - plone.app.robotframework[debug,reload] - - -[releaser] -recipe = zc.recipe.egg -eggs = zest.releaser - - -[i18ndude] -recipe = zc.recipe.egg -eggs = i18ndude - -[plone-helper-scripts] -recipe = zc.recipe.egg -eggs = - Products.CMFPlone - ${instance:eggs} -interpreter = zopepy -scripts = - zopepy - plone-compile-resources - -[versions] -# Don't use a released version of collective.z3cform.norobots -collective.z3cform.norobots = diff --git a/bobtemplate.cfg b/bobtemplate.cfg deleted file mode 100644 index 16211ef..0000000 --- a/bobtemplate.cfg +++ /dev/null @@ -1,4 +0,0 @@ -[main] -version = 5.1 -template = plone_addon -git_init = True diff --git a/buildout.cfg b/buildout.cfg deleted file mode 100644 index 7e6e66e..0000000 --- a/buildout.cfg +++ /dev/null @@ -1,8 +0,0 @@ -[buildout] -# use this extend one of the buildout configuration: -extends = -# -*- mrbob: extra extends -*- -# test_plone43.cfg -# test_plone51.cfg -# test_plone52.cfg - test_plone60.cfg \ No newline at end of file diff --git a/constraints.txt b/constraints.txt index c1fb3a1..228b6cc 100644 --- a/constraints.txt +++ b/constraints.txt @@ -1 +1 @@ --c constraints_plone60.txt +-c https://dist.plone.org/release/6.0-latest/constraints.txt diff --git a/constraints_plone52.txt b/constraints_plone52.txt deleted file mode 100644 index d96fee0..0000000 --- a/constraints_plone52.txt +++ /dev/null @@ -1,3 +0,0 @@ --c https://dist.plone.org/release/5.2-latest/requirements.txt -# setuptools==40.2.0 -# zc.buildout==2.12.2 diff --git a/constraints_plone60.txt b/constraints_plone60.txt deleted file mode 100644 index a88edf2..0000000 --- a/constraints_plone60.txt +++ /dev/null @@ -1,4 +0,0 @@ --c https://dist.plone.org/release/6.0-dev/requirements.txt - -isort>=5 -black>=22.3.0 \ No newline at end of file diff --git a/dependabot.yml b/dependabot.yml new file mode 100644 index 0000000..bbd3ab0 --- /dev/null +++ b/dependabot.yml @@ -0,0 +1,11 @@ +# Generated from: +# https://github.com/plone/meta/tree/main/config/default +# See the inline comments on how to expand/tweak this configuration file +version: 2 +updates: + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + # Check for updates to GitHub Actions every week + interval: "weekly" diff --git a/docs/collective-z3cform-norobots-screenshot.png b/docs/collective-z3cform-norobots-screenshot.png deleted file mode 100644 index f0186ef..0000000 Binary files a/docs/collective-z3cform-norobots-screenshot.png and /dev/null differ diff --git a/docs/collective.z3cform.norobots-screenshot-1.png b/docs/collective.z3cform.norobots-screenshot-1.png new file mode 100644 index 0000000..2d78506 Binary files /dev/null and b/docs/collective.z3cform.norobots-screenshot-1.png differ diff --git a/docs/collective.z3cform.norobots-screenshot-2.png b/docs/collective.z3cform.norobots-screenshot-2.png new file mode 100644 index 0000000..27686e4 Binary files /dev/null and b/docs/collective.z3cform.norobots-screenshot-2.png differ diff --git a/instance.yml b/instance.yml new file mode 100644 index 0000000..c705db0 --- /dev/null +++ b/instance.yml @@ -0,0 +1,8 @@ +default_context: + initial_user_name: "admin" + initial_user_password: "admin" + wsgi_listen: "localhost:8080" + zcml_package_includes: collective.z3cform.norobots + db_storage: direct + debug_mode: true + verbose_security: true \ No newline at end of file diff --git a/mx.ini b/mx.ini new file mode 100644 index 0000000..24b7933 --- /dev/null +++ b/mx.ini @@ -0,0 +1,4 @@ +[settings] +main-package = -e .[test] +version-overrides = + zope.testrunner==6.4 \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..e0717ba --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,130 @@ +# Generated from: +# https://github.com/plone/meta/tree/main/config/default +# See the inline comments on how to expand/tweak this configuration file +[build-system] +requires = ["setuptools>=68.2"] + +## +# Add extra configuration options in .meta.toml: +# [pyproject] +# towncrier_extra_lines = """ +# extra_configuration +# """ +## + +[tool.isort] +profile = "plone" + +## +# Add extra configuration options in .meta.toml: +# [pyproject] +# isort_extra_lines = """ +# extra_configuration +# """ +## + +[tool.black] +target-version = ["py38"] + +## +# Add extra configuration options in .meta.toml: +# [pyproject] +# black_extra_lines = """ +# extra_configuration +# """ +## + +[tool.codespell] +ignore-words-list = "discreet," +skip = "*.po," +## +# Add extra configuration options in .meta.toml: +# [pyproject] +# codespell_ignores = "foo,bar" +# codespell_skip = "*.po,*.map,package-lock.json" +## + +[tool.dependencychecker] +Zope = [ + # Zope own provided namespaces + 'App', 'OFS', 'Products.Five', 'Products.OFSP', 'Products.PageTemplates', + 'Products.SiteAccess', 'Shared', 'Testing', 'ZPublisher', 'ZTUtils', + 'Zope2', 'webdav', 'zmi', + # ExtensionClass own provided namespaces + 'ExtensionClass', 'ComputedAttribute', 'MethodObject', + # Zope dependencies + 'AccessControl', 'Acquisition', 'AuthEncoding', 'beautifulsoup4', 'BTrees', + 'cffi', 'Chameleon', 'DateTime', 'DocumentTemplate', + 'MultiMapping', 'multipart', 'PasteDeploy', 'Persistence', 'persistent', + 'pycparser', 'python-gettext', 'pytz', 'RestrictedPython', 'roman', + 'soupsieve', 'transaction', 'waitress', 'WebOb', 'WebTest', 'WSGIProxy2', + 'z3c.pt', 'zc.lockfile', 'ZConfig', 'zExceptions', 'ZODB', 'zodbpickle', + 'zope.annotation', 'zope.browser', 'zope.browsermenu', 'zope.browserpage', + 'zope.browserresource', 'zope.cachedescriptors', 'zope.component', + 'zope.configuration', 'zope.container', 'zope.contentprovider', + 'zope.contenttype', 'zope.datetime', 'zope.deferredimport', + 'zope.deprecation', 'zope.dottedname', 'zope.event', 'zope.exceptions', + 'zope.filerepresentation', 'zope.globalrequest', 'zope.hookable', + 'zope.i18n', 'zope.i18nmessageid', 'zope.interface', 'zope.lifecycleevent', + 'zope.location', 'zope.pagetemplate', 'zope.processlifetime', 'zope.proxy', + 'zope.ptresource', 'zope.publisher', 'zope.schema', 'zope.security', + 'zope.sequencesort', 'zope.site', 'zope.size', 'zope.structuredtext', + 'zope.tal', 'zope.tales', 'zope.testbrowser', 'zope.testing', + 'zope.traversing', 'zope.viewlet' +] +'Products.CMFCore' = [ + 'docutils', 'five.localsitemanager', 'Missing', 'Products.BTreeFolder2', + 'Products.GenericSetup', 'Products.MailHost', 'Products.PythonScripts', + 'Products.StandardCacheManagers', 'Products.ZCatalog', 'Record', + 'zope.sendmail', 'Zope' +] +'plone.base' = [ + 'plone.batching', 'plone.registry', 'plone.schema','plone.z3cform', + 'Products.CMFCore', 'Products.CMFDynamicViewFTI', +] +python-dateutil = ['dateutil'] + +## +# Add extra configuration options in .meta.toml: +# [pyproject] +# dependencies_ignores = "['zestreleaser.towncrier']" +# dependencies_mappings = [ +# "gitpython = ['git']", +# "pygithub = ['github']", +# ] +## + +[tool.check-manifest] +ignore = [ + ".editorconfig", + ".flake8", + ".meta.toml", + ".pre-commit-config.yaml", + "dependabot.yml", + "mx.ini", + "tox.ini", + +] + +## +# Add extra configuration options in .meta.toml: +# [pyproject] +# check_manifest_ignores = """ +# "*.map.js", +# "*.pyc", +# """ +# check_manifest_extra_lines = """ +# ignore-bad-ideas = [ +# "some/test/file/PKG-INFO", +# ] +# """ +## + + +## +# Add extra configuration options in .meta.toml: +# [pyproject] +# extra_lines = """ +# _your own configuration lines_ +# """ +## diff --git a/pyvenv.cfg b/pyvenv.cfg deleted file mode 100644 index 9f5cf86..0000000 --- a/pyvenv.cfg +++ /dev/null @@ -1,3 +0,0 @@ -home = /usr/local/bin -include-system-site-packages = false -version = 3.7.3 diff --git a/requirements.txt b/requirements.txt index 2d6efa1..163ba4b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ --r requirements_plone60.txt \ No newline at end of file +-c constraints.txt +-e .[test] diff --git a/requirements_plone52.txt b/requirements_plone52.txt deleted file mode 100644 index 67682a2..0000000 --- a/requirements_plone52.txt +++ /dev/null @@ -1,4 +0,0 @@ --c constraints_plone52.txt -setuptools -zc.buildout -tox \ No newline at end of file diff --git a/requirements_plone60.txt b/requirements_plone60.txt deleted file mode 100644 index f187a3d..0000000 --- a/requirements_plone60.txt +++ /dev/null @@ -1,7 +0,0 @@ --c constraints_plone60.txt -setuptools -zc.buildout -tox -isort -flake8 -black \ No newline at end of file diff --git a/setup.cfg b/setup.cfg index a3c7aef..54bf953 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,29 +1,3 @@ -[check-manifest] -ignore = - *.cfg - .coveragerc - .editorconfig - .gitattributes - [isort] # black compatible isort rules: profile = plone -force_alphabetical_sort=True -force_single_line=True -lines_after_imports=2 - -[flake8] -# black compatible flake8 rules: -ignore = - W503, - C812, - E501 - T001 - C813 -# E203, E266 -exclude = bootstrap.py,docs,*.egg.,omelette -max-line-length = 88 -max-complexity = 18 -select = B,C,E,F,W,T4,B9 - -builtins = unicode,basestring diff --git a/setup.py b/setup.py index 526920a..506a712 100644 --- a/setup.py +++ b/setup.py @@ -1,11 +1,10 @@ -# -*- coding: utf-8 -*- from setuptools import find_packages from setuptools import setup import os -version = "2.2.dev0" +version = "3.0.dev0" def read(*rnames): @@ -14,28 +13,27 @@ def read(*rnames): long_description = "\n\n".join([read("README.rst"), read("CHANGES.rst")]) -tests_require = ["plone.app.testing"] - -classifiers = [ - "Framework :: Plone", - "Framework :: Plone :: 6.0", - "Framework :: Plone :: 5.2", - "Framework :: Plone :: 5.1", - "Framework :: Plone :: 4.3", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 2.7", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Topic :: Software Development :: Libraries :: Python Modules", -] - setup( name="collective.z3cform.norobots", version=version, description="Human readable captcha for z3cform", long_description=long_description, - classifiers=classifiers, + long_description_content_type="text/x-rst", + classifiers=[ + "Development Status :: 5 - Production/Stable", + "Framework :: Plone", + "Framework :: Plone :: Addon", + "Framework :: Plone :: 6.0", + "Framework :: Plone :: 6.1", + "Programming Language :: Python", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Topic :: Software Development :: Libraries :: Python Modules", + "License :: OSI Approved :: GNU General Public License (GPL)", + ], keywords="plone z3cform captcha", author="Sylvain Boureliou", author_email="sylvain.boureliou@makina-corpus.com", @@ -46,15 +44,30 @@ def read(*rnames): namespace_packages=["collective", "collective.z3cform"], include_package_data=True, zip_safe=False, + python_requires=">=3.8", install_requires=[ "setuptools", - "plone.app.z3cform", "plone.app.registry", - "plone.api", + "plone.registry", + "plone.restapi", + "Zope", + "Products.CMFPlone", + "Products.GenericSetup", + "z3c.form", + "plone.base", ], - tests_require=tests_require, + extras_require={ + "test": [ + "plone.app.testing", + "plone.api", + "plone.app.testing", + "plone.browserlayer", + "plone.testing>=5.0.0", + "six", + "lxml", + ] + }, test_suite="collective.z3cform.norobots.tests.test_docs.test_suite", - extras_require={"test": tests_require}, # define there your console scripts entry_points={"z3c.autoinclude.plugin": "target = plone"}, ) diff --git a/src/collective/__init__.py b/src/collective/__init__.py index 03d08ff..5284146 100644 --- a/src/collective/__init__.py +++ b/src/collective/__init__.py @@ -1,2 +1 @@ -# -*- coding: utf-8 -*- __import__("pkg_resources").declare_namespace(__name__) diff --git a/src/collective/z3cform/__init__.py b/src/collective/z3cform/__init__.py index 03d08ff..5284146 100644 --- a/src/collective/z3cform/__init__.py +++ b/src/collective/z3cform/__init__.py @@ -1,2 +1 @@ -# -*- coding: utf-8 -*- __import__("pkg_resources").declare_namespace(__name__) diff --git a/src/collective/z3cform/norobots/__init__.py b/src/collective/z3cform/norobots/__init__.py index e33e948..eb4c8a5 100644 --- a/src/collective/z3cform/norobots/__init__.py +++ b/src/collective/z3cform/norobots/__init__.py @@ -1,2 +1 @@ -# -*- coding: utf-8 -*- from collective.z3cform.norobots.widget import NorobotsFieldWidget # NOQA:F401 diff --git a/src/collective/z3cform/norobots/browser/configure.zcml b/src/collective/z3cform/norobots/browser/configure.zcml index 262c176..5815258 100644 --- a/src/collective/z3cform/norobots/browser/configure.zcml +++ b/src/collective/z3cform/norobots/browser/configure.zcml @@ -9,17 +9,17 @@ @@ -27,8 +27,8 @@ diff --git a/src/collective/z3cform/norobots/browser/controlpanel.py b/src/collective/z3cform/norobots/browser/controlpanel.py index ba42eab..8ad7718 100644 --- a/src/collective/z3cform/norobots/browser/controlpanel.py +++ b/src/collective/z3cform/norobots/browser/controlpanel.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from collective.z3cform.norobots.browser.interfaces import INorobotsWidgetSettings from collective.z3cform.norobots.i18n import norobotsMessageFactory as _ from plone.app.registry.browser.controlpanel import ControlPanelFormWrapper diff --git a/src/collective/z3cform/norobots/browser/interfaces.py b/src/collective/z3cform/norobots/browser/interfaces.py index ca8bf52..32ced1b 100644 --- a/src/collective/z3cform/norobots/browser/interfaces.py +++ b/src/collective/z3cform/norobots/browser/interfaces.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from collective.z3cform.norobots.i18n import norobotsMessageFactory as _ from zope import schema from zope.interface import Interface diff --git a/src/collective/z3cform/norobots/browser/norobots.py b/src/collective/z3cform/norobots/browser/norobots.py index 0573125..94dd0b1 100644 --- a/src/collective/z3cform/norobots/browser/norobots.py +++ b/src/collective/z3cform/norobots/browser/norobots.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from collective.z3cform.norobots.browser.interfaces import INorobotsView from collective.z3cform.norobots.browser.interfaces import INorobotsWidgetSettings from hashlib import md5 diff --git a/src/collective/z3cform/norobots/browser/norobots_macro.pt b/src/collective/z3cform/norobots/browser/norobots_macro.pt index f6b5deb..0f7d50f 100644 --- a/src/collective/z3cform/norobots/browser/norobots_macro.pt +++ b/src/collective/z3cform/norobots/browser/norobots_macro.pt @@ -15,32 +15,41 @@ " i18n:domain="collective.z3cform.norobots" > - - (Required) -
- - In order to avoid spam, please answer the question below. - -
- Question: -
+ +
- Your answer: + - + +
+
In order to avoid spam, please answer the question below.
+ + diff --git a/src/collective/z3cform/norobots/configure.zcml b/src/collective/z3cform/norobots/configure.zcml index 51425f1..d8494ba 100644 --- a/src/collective/z3cform/norobots/configure.zcml +++ b/src/collective/z3cform/norobots/configure.zcml @@ -1,20 +1,24 @@ + xmlns="http://namespaces.zope.org/zope" + xmlns:browser="http://namespaces.zope.org/browser" + xmlns:five="http://namespaces.zope.org/five" + xmlns:genericsetup="http://namespaces.zope.org/genericsetup" + xmlns:i18n="http://namespaces.zope.org/i18n" + xmlns:meta="http://namespaces.zope.org/meta" + xmlns:z3c="http://namespaces.zope.org/z3c" + xmlns:zcml="http://namespaces.zope.org/zcml" + i18n_domain="collective.z3cform.norobots" + > - + - + @@ -23,21 +27,24 @@ + permission="zope.Public" + interface="collective.z3cform.norobots.widget.INorobotsWidget" + /> + widget="collective.z3cform.norobots.widget.INorobotsWidget" + template="norobots_input.pt" + layer="z3c.form.interfaces.IFormLayer" + mode="input" + /> + name="collective.z3cform.norobots" + directory="static" + /> diff --git a/src/collective/z3cform/norobots/i18n.py b/src/collective/z3cform/norobots/i18n.py index ea84ef4..ff4fdec 100644 --- a/src/collective/z3cform/norobots/i18n.py +++ b/src/collective/z3cform/norobots/i18n.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from zope.i18nmessageid import MessageFactory diff --git a/src/collective/z3cform/norobots/interfaces.py b/src/collective/z3cform/norobots/interfaces.py new file mode 100644 index 0000000..5f5f605 --- /dev/null +++ b/src/collective/z3cform/norobots/interfaces.py @@ -0,0 +1,7 @@ +"""Module where all interfaces, events and exceptions live.""" + +from zope.publisher.interfaces.browser import IDefaultBrowserLayer + + +class ICollectiveZ3CFormNorobotsBrowserlayer(IDefaultBrowserLayer): + """Marker interface that defines a browser layer.""" diff --git a/src/collective/z3cform/norobots/norobots_input.pt b/src/collective/z3cform/norobots/norobots_input.pt index e39039c..c99fcb6 100644 --- a/src/collective/z3cform/norobots/norobots_input.pt +++ b/src/collective/z3cform/norobots/norobots_input.pt @@ -1,45 +1,56 @@ - - Question: -
- - Your answer: - - +
+ + + +
+ -
+ diff --git a/src/collective/z3cform/norobots/plone_forms/configure.zcml b/src/collective/z3cform/norobots/plone_forms/configure.zcml index a0672b2..95de19b 100644 --- a/src/collective/z3cform/norobots/plone_forms/configure.zcml +++ b/src/collective/z3cform/norobots/plone_forms/configure.zcml @@ -6,9 +6,16 @@ + + diff --git a/src/collective/z3cform/norobots/plone_forms/constraints.py b/src/collective/z3cform/norobots/plone_forms/constraints.py index cdfe209..dc8c00b 100644 --- a/src/collective/z3cform/norobots/plone_forms/constraints.py +++ b/src/collective/z3cform/norobots/plone_forms/constraints.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Helper functions for fields validation from collective.z3cform.norobots.i18n import norobotsMessageFactory as _ diff --git a/src/collective/z3cform/norobots/plone_forms/contact_info.py b/src/collective/z3cform/norobots/plone_forms/contact_info.py index 347fe13..459a767 100644 --- a/src/collective/z3cform/norobots/plone_forms/contact_info.py +++ b/src/collective/z3cform/norobots/plone_forms/contact_info.py @@ -1,9 +1,8 @@ -# -*- coding: utf-8 -*- from collective.z3cform.norobots.i18n import norobotsMessageFactory as _ from collective.z3cform.norobots.plone_forms import constraints from collective.z3cform.norobots.validator import NorobotsValidator from collective.z3cform.norobots.widget import NorobotsFieldWidget -from plone.app.z3cform.layout import wrap_form +from plone.z3cform.layout import wrap_form from Products.CMFCore.utils import getToolByName from z3c.form import button from z3c.form import field @@ -99,10 +98,10 @@ def handle_send(self, action): plone_utils.addPortalMessage("[FAKE] %s" % _("Mail sent.")) -# wrap the form with plone.app.z3cform's Form wrapper +# wrap the form with plone.z3cform's Form wrapper ContactInfoView = wrap_form(ContactInfoForm) -# Register Norobots validator for the correponding field in the IContactInfo interface +# Register Norobots validator for the corresponding field in the IContactInfo interface validator.WidgetValidatorDiscriminators( NorobotsValidator, field=IContactInfo["norobots"] ) diff --git a/src/collective/z3cform/norobots/plone_forms/simpleform-with-macro.pt b/src/collective/z3cform/norobots/plone_forms/simpleform-with-macro.pt new file mode 100644 index 0000000..4d11e83 --- /dev/null +++ b/src/collective/z3cform/norobots/plone_forms/simpleform-with-macro.pt @@ -0,0 +1,59 @@ + + + + + + + + +
+ +
+ +
+ +
+ Norobots Macro goes here +
+ +
+ + + +
+ + + + + + + +
+ + + +
+ + + diff --git a/src/collective/z3cform/norobots/plone_forms/simpleform.py b/src/collective/z3cform/norobots/plone_forms/simpleform.py new file mode 100644 index 0000000..957e7b1 --- /dev/null +++ b/src/collective/z3cform/norobots/plone_forms/simpleform.py @@ -0,0 +1,33 @@ +from collective.z3cform.norobots.i18n import norobotsMessageFactory as _ +from plone.z3cform.layout import FormWrapper +from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile +from z3c.form import button +from z3c.form import field +from z3c.form import form +from zope import schema +from zope.interface import Interface + + +class ISimpleForm(Interface): + fullname = schema.TextLine( + title=_("Name"), + description=_("Please enter your full name."), + required=False, + ) + + +class SimpleForm(form.Form): + fields = field.Fields(ISimpleForm) + ignoreContext = True # don't use context to get widget data + id = "simpleform" + + @button.buttonAndHandler(_("Send")) + def handle_send(self, action): + data, errors = self.extractData() + + +class SimpleFormView(FormWrapper): + + form = SimpleForm + + index = ViewPageTemplateFile("simpleform-with-macro.pt") diff --git a/src/collective/z3cform/norobots/profiles.zcml b/src/collective/z3cform/norobots/profiles.zcml index fd82c47..89796f9 100644 --- a/src/collective/z3cform/norobots/profiles.zcml +++ b/src/collective/z3cform/norobots/profiles.zcml @@ -1,31 +1,35 @@ + xmlns="http://namespaces.zope.org/zope" + xmlns:browser="http://namespaces.zope.org/browser" + xmlns:five="http://namespaces.zope.org/five" + xmlns:genericsetup="http://namespaces.zope.org/genericsetup" + xmlns:i18n="http://namespaces.zope.org/i18n" + xmlns:meta="http://namespaces.zope.org/meta" + xmlns:z3c="http://namespaces.zope.org/z3c" + i18n_domain="collective.z3cform.norobots" + > + name="default" + title="Norobots captcha field (collective.z3cform.norobots)" + description="Provides a human captcha widget based on a list of questions/answers." + provides="Products.GenericSetup.interfaces.EXTENSION" + directory="profiles/default" + /> + name="uninstall" + title="Norobots captcha field UNINSTALLATION" + description="Removes the human usable captcha widget based on a list of questions/answers." + provides="Products.GenericSetup.interfaces.EXTENSION" + directory="profiles/uninstall" + post_handler=".setuphandlers.uninstall" + /> + factory=".setuphandlers.HiddenProfiles" + name="collective.z3cform.norobots-hiddenprofiles" + /> - \ No newline at end of file +
diff --git a/src/collective/z3cform/norobots/profiles/default/browserlayer.xml b/src/collective/z3cform/norobots/profiles/default/browserlayer.xml new file mode 100644 index 0000000..5cb1d70 --- /dev/null +++ b/src/collective/z3cform/norobots/profiles/default/browserlayer.xml @@ -0,0 +1,6 @@ + + + + diff --git a/src/collective/z3cform/norobots/profiles/default/controlpanel.xml b/src/collective/z3cform/norobots/profiles/default/controlpanel.xml index 5a3e29b..199e3ea 100644 --- a/src/collective/z3cform/norobots/profiles/default/controlpanel.xml +++ b/src/collective/z3cform/norobots/profiles/default/controlpanel.xml @@ -1,4 +1,4 @@ - + + 2 diff --git a/src/collective/z3cform/norobots/profiles/default/registry.xml b/src/collective/z3cform/norobots/profiles/default/registry.xml index 515acad..e35f309 100644 --- a/src/collective/z3cform/norobots/profiles/default/registry.xml +++ b/src/collective/z3cform/norobots/profiles/default/registry.xml @@ -1,3 +1,4 @@ + diff --git a/src/collective/z3cform/norobots/profiles/uninstall/browserlayer.xml b/src/collective/z3cform/norobots/profiles/uninstall/browserlayer.xml new file mode 100644 index 0000000..53e9ab9 --- /dev/null +++ b/src/collective/z3cform/norobots/profiles/uninstall/browserlayer.xml @@ -0,0 +1,6 @@ + + + + diff --git a/src/collective/z3cform/norobots/profiles/uninstall/controlpanel.xml b/src/collective/z3cform/norobots/profiles/uninstall/controlpanel.xml index c7d9d78..9204aba 100644 --- a/src/collective/z3cform/norobots/profiles/uninstall/controlpanel.xml +++ b/src/collective/z3cform/norobots/profiles/uninstall/controlpanel.xml @@ -1,9 +1,9 @@ - + - - \ No newline at end of file + + diff --git a/src/collective/z3cform/norobots/profiles/uninstall/registry.xml b/src/collective/z3cform/norobots/profiles/uninstall/registry.xml index 8125e90..46021ba 100644 --- a/src/collective/z3cform/norobots/profiles/uninstall/registry.xml +++ b/src/collective/z3cform/norobots/profiles/uninstall/registry.xml @@ -1,6 +1,6 @@ - + - - \ No newline at end of file + + diff --git a/src/collective/z3cform/norobots/restapi/__init__.py b/src/collective/z3cform/norobots/restapi/__init__.py index 40a96af..e69de29 100644 --- a/src/collective/z3cform/norobots/restapi/__init__.py +++ b/src/collective/z3cform/norobots/restapi/__init__.py @@ -1 +0,0 @@ -# -*- coding: utf-8 -*- diff --git a/src/collective/z3cform/norobots/restapi/configure.zcml b/src/collective/z3cform/norobots/restapi/configure.zcml index 6e3eb30..21df485 100644 --- a/src/collective/z3cform/norobots/restapi/configure.zcml +++ b/src/collective/z3cform/norobots/restapi/configure.zcml @@ -3,12 +3,14 @@ xmlns:browser="http://namespaces.zope.org/browser" xmlns:i18n="http://namespaces.zope.org/i18n" xmlns:plone="http://namespaces.plone.org/plone" - i18n_domain="collective.z3cform.norobots"> + i18n_domain="collective.z3cform.norobots" + > - + + factory=".controlpanel.NoRobotsSettingsConfigletPanel" + name="collective.z3cform.norobots.settings" + /> diff --git a/src/collective/z3cform/norobots/restapi/controlpanel.py b/src/collective/z3cform/norobots/restapi/controlpanel.py index 1238f1d..4ec9d06 100644 --- a/src/collective/z3cform/norobots/restapi/controlpanel.py +++ b/src/collective/z3cform/norobots/restapi/controlpanel.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from collective.z3cform.norobots.browser.interfaces import INorobotsWidgetSettings from collective.z3cform.norobots.i18n import _ from plone.restapi.controlpanels import RegistryConfigletPanel diff --git a/src/collective/z3cform/norobots/setuphandlers.py b/src/collective/z3cform/norobots/setuphandlers.py index 3fabf7c..067254d 100644 --- a/src/collective/z3cform/norobots/setuphandlers.py +++ b/src/collective/z3cform/norobots/setuphandlers.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Products.CMFPlone.interfaces import INonInstallable from zope.interface import implementer diff --git a/src/collective/z3cform/norobots/testing.py b/src/collective/z3cform/norobots/testing.py index 672e639..0271bdb 100644 --- a/src/collective/z3cform/norobots/testing.py +++ b/src/collective/z3cform/norobots/testing.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.app.testing import applyProfile from plone.app.testing import FunctionalTesting from plone.app.testing import IntegrationTesting @@ -16,7 +15,7 @@ def setUpZope(self, app, configurationContext): # Load ZCML for this package import collective.z3cform.norobots - self.loadZCML(package=collective.z3cform.norobots) + self.loadZCML(name="testing.zcml", package=collective.z3cform.norobots) def setUpPloneSite(self, portal): applyProfile(portal, "collective.z3cform.norobots:default") @@ -35,5 +34,5 @@ def tearDownZope(self, app): ) NOROBOTS_FUNCTIONNAL_TESTING = FunctionalTesting( bases=(NOROBOTS_FIXTURE,), - name="collective.z3cform.norobots:Integration", + name="collective.z3cform.norobots:Functional", ) diff --git a/src/collective/z3cform/norobots/testing.zcml b/src/collective/z3cform/norobots/testing.zcml new file mode 100644 index 0000000..d2f02b3 --- /dev/null +++ b/src/collective/z3cform/norobots/testing.zcml @@ -0,0 +1,18 @@ + + + + + + + + diff --git a/src/collective/z3cform/norobots/tests/doctests.rst b/src/collective/z3cform/norobots/tests/doctests.rst index 3db7bc1..1bae984 100644 --- a/src/collective/z3cform/norobots/tests/doctests.rst +++ b/src/collective/z3cform/norobots/tests/doctests.rst @@ -48,7 +48,7 @@ NorobotsWidget factory ('NorobotsFieldWidget') as the field's widgetFactory: >>> from zope.annotation.interfaces import IAttributeAnnotatable >>> from z3c.form import form, field, validator - >>> from plone.app.z3cform.layout import wrap_form + >>> from plone.z3cform.layout import wrap_form >>> class FooForm(form.Form): ... fields = field.Fields(IFooForm) @@ -56,7 +56,7 @@ NorobotsWidget factory ('NorobotsFieldWidget') as the field's widgetFactory: ... ignoreContext = True ... label = u'Foo form' -Register Norobots validator for the correponding field in the IFooForm interface: +Register Norobots validator for the corresponding field in the IFooForm interface: >>> from zope.component import provideAdapter >>> validator.WidgetValidatorDiscriminators(NorobotsValidator, field=IFooForm['norobots']) diff --git a/src/collective/z3cform/norobots/tests/test_controlpanel.py b/src/collective/z3cform/norobots/tests/test_controlpanel.py new file mode 100644 index 0000000..5316195 --- /dev/null +++ b/src/collective/z3cform/norobots/tests/test_controlpanel.py @@ -0,0 +1,46 @@ +from collective.z3cform.norobots.testing import NOROBOTS_FUNCTIONNAL_TESTING +from plone.app.testing import setRoles +from plone.app.testing import SITE_OWNER_NAME +from plone.app.testing import SITE_OWNER_PASSWORD +from plone.app.testing import TEST_USER_ID +from plone.testing.zope import Browser + +import transaction +import unittest + + +class TestFunctionalControlpanel(unittest.TestCase): + + layer = NOROBOTS_FUNCTIONNAL_TESTING + + def _manager_browser(self): + transaction.commit() + # Set up browser + browser = Browser(self.layer["app"]) + browser.handleErrors = False + browser.addHeader( + "Authorization", + "Basic {}:{}".format( + SITE_OWNER_NAME, + SITE_OWNER_PASSWORD, + ), + ) + return browser + + def setUp(self): + self.portal = self.layer["portal"] + setRoles(self.portal, TEST_USER_ID, ["Manager"]) + + def test_controlpanel_textarea(self): + from io import StringIO + from lxml import etree + + browser = self._manager_browser() + browser.open(f"{self.portal.absolute_url()}/@@norobots-controlpanel") + tree = etree.parse(StringIO(browser.contents), etree.HTMLParser()) + + result = tree.xpath("//textarea[@id='form-widgets-questions']/@rows") + self.assertEqual("15", result[0], "The textarea should be have 15 lines") + + +5 diff --git a/src/collective/z3cform/norobots/tests/test_docs.py b/src/collective/z3cform/norobots/tests/test_docs.py index ca035a2..8c275a4 100644 --- a/src/collective/z3cform/norobots/tests/test_docs.py +++ b/src/collective/z3cform/norobots/tests/test_docs.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from collective.z3cform.norobots.testing import NOROBOTS_INTEGRATION_TESTING from plone.testing import layered diff --git a/src/collective/z3cform/norobots/tests/test_install.py b/src/collective/z3cform/norobots/tests/test_install.py index 7170953..55ffee4 100644 --- a/src/collective/z3cform/norobots/tests/test_install.py +++ b/src/collective/z3cform/norobots/tests/test_install.py @@ -1,6 +1,6 @@ -# -*- coding: utf-8 -*- from collective.z3cform.norobots.testing import NOROBOTS_INTEGRATION_TESTING from plone import api +from plone.base.utils import get_installer from plone.registry.interfaces import IRegistry from Products.CMFCore.utils import getToolByName from zope.component import getUtility @@ -8,12 +8,6 @@ import unittest -try: - from Products.CMFPlone.utils import get_installer -except ImportError: - # BBB for Plone 5.0 and lower. - get_installer = None - PROJECTNAME = "collective.z3cform.norobots" @@ -24,10 +18,7 @@ class TestInstall(unittest.TestCase): def setUp(self): """Custom shared utility setup for tests.""" self.portal = self.layer["portal"] - if get_installer: - self.installer = get_installer(self.portal, self.layer["request"]) - else: - self.installer = api.portal.get_tool("portal_quickinstaller") + self.installer = get_installer(self.portal, self.layer["request"]) def test_product_is_installed(self): """Test if collective.z3cform.norobots is installed.""" @@ -37,6 +28,15 @@ def test_product_is_installed(self): ) ) + def test_browserlayer(self): + """Test that ICollectiveZ3CFormNorobotsBrowserlayer is registered.""" + from collective.z3cform.norobots.interfaces import ( + ICollectiveZ3CFormNorobotsBrowserlayer, + ) + from plone.browserlayer import utils + + self.assertIn(ICollectiveZ3CFormNorobotsBrowserlayer, utils.registered_layers()) + def test_registry(self): registry = getUtility(IRegistry) # Check 'question' entry is in the registry @@ -62,10 +62,7 @@ def setUp(self): self.app = self.layer["app"] self.portal = self.layer["portal"] self.request = self.layer["request"] - if get_installer: - self.installer = get_installer(self.portal, self.request) - else: - self.installer = api.portal.get_tool("portal_quickinstaller") + self.installer = get_installer(self.portal, self.request) self.installer.uninstall_product("collective.z3cform.norobots") def test_product_is_not_installed(self): @@ -74,6 +71,17 @@ def test_product_is_not_installed(self): self.installer.is_product_installed("collective.z3cform.norobots"), ) + def test_browserlayer_removed(self): + """Test that ICollectiveZ3CFormNorobotsBrowserlayer is removed.""" + from collective.z3cform.norobots.interfaces import ( + ICollectiveZ3CFormNorobotsBrowserlayer, + ) + from plone.browserlayer import utils + + self.assertNotIn( + ICollectiveZ3CFormNorobotsBrowserlayer, utils.registered_layers() + ) + def test_registry(self): registry = getUtility(IRegistry) self.assertNotIn( diff --git a/src/collective/z3cform/norobots/tests/test_sample_package.py b/src/collective/z3cform/norobots/tests/test_sample_package.py new file mode 100644 index 0000000..96877a2 --- /dev/null +++ b/src/collective/z3cform/norobots/tests/test_sample_package.py @@ -0,0 +1,120 @@ +from collective.z3cform.norobots.testing import NOROBOTS_FUNCTIONNAL_TESTING +from collective.z3cform.norobots.testing import NOROBOTS_INTEGRATION_TESTING +from plone.app.testing import setRoles +from plone.app.testing import SITE_OWNER_NAME +from plone.app.testing import SITE_OWNER_PASSWORD +from plone.app.testing import TEST_USER_ID +from plone.testing.zope import Browser + +import transaction +import unittest + + +class TestIntegrationSamplePackage(unittest.TestCase): + layer = NOROBOTS_INTEGRATION_TESTING + + def test_constraints_isValidEmail(self): + from collective.z3cform.norobots.plone_forms.constraints import isEmail + + self.assertTrue(isEmail("john.doe@plone.org")) + + def test_constraints_isNotValidEmail(self): + from collective.z3cform.norobots.plone_forms.constraints import isEmail + from collective.z3cform.norobots.plone_forms.constraints import IsEmailError + + with self.assertRaises(IsEmailError): + isEmail("i'm not a valid email") + + +class TestFunctionalSamplePackage(unittest.TestCase): + + layer = NOROBOTS_FUNCTIONNAL_TESTING + + def _manager_browser(self): + transaction.commit() + # Set up browser + browser = Browser(self.layer["app"]) + browser.handleErrors = False + browser.addHeader( + "Authorization", + "Basic {}:{}".format( + SITE_OWNER_NAME, + SITE_OWNER_PASSWORD, + ), + ) + return browser + + def setUp(self): + self.portal = self.layer["portal"] + setRoles(self.portal, TEST_USER_ID, ["Manager"]) + + def test_sample_package(self): + from io import StringIO + from lxml import etree + + browser = self._manager_browser() + browser.open(f"{self.portal.absolute_url()}/z3cform-contact-info") + tree = etree.parse(StringIO(browser.contents), etree.HTMLParser()) + + result = tree.xpath("//form[@id='z3cform_contact_info_form']") + self.assertEqual(1, len(result), "the sample form is not present") + + result = tree.xpath("//input[@name='form.widgets.fullname']") + self.assertEqual(1, len(result), "fullname widget is not present") + + result = tree.xpath("//input[@name='form.widgets.email']") + self.assertEqual(1, len(result), "email widget is not present") + + result = tree.xpath("//input[@name='form.widgets.subject']") + self.assertEqual(1, len(result), "subject widget is not present") + + result = tree.xpath("//textarea[@name='form.widgets.message']") + self.assertEqual(1, len(result), "message widget is not present") + + result = tree.xpath("//input[@name='form.widgets.norobots']") + self.assertEqual(1, len(result), "norobots widget is not present") + + # send the form + browser.getControl("Send").click() + self.assertIn( + "Please correct the indicated errors and don't forget to fill in the field 'Are you a human ?'.", + browser.contents, + "the error message is missing!", + ) + + +class TestFunctionalMacroView(unittest.TestCase): + + layer = NOROBOTS_FUNCTIONNAL_TESTING + + def _manager_browser(self): + transaction.commit() + # Set up browser + browser = Browser(self.layer["app"]) + browser.handleErrors = False + browser.addHeader( + "Authorization", + "Basic {}:{}".format( + SITE_OWNER_NAME, + SITE_OWNER_PASSWORD, + ), + ) + return browser + + def setUp(self): + self.portal = self.layer["portal"] + setRoles(self.portal, TEST_USER_ID, ["Manager"]) + + def test_sample_package(self): + from io import StringIO + from lxml import etree + + browser = self._manager_browser() + browser.open(f"{self.portal.absolute_url()}/simple-form-with-macro-view") + tree = etree.parse(StringIO(browser.contents), etree.HTMLParser()) + + result = tree.xpath("//input[@name='form.widgets.fullname']") + self.assertEqual(1, len(result), "fullname widget is not present") + + result = tree.xpath("//input[@name='norobots']") + self.assertEqual(1, len(result), "norobots widget is not present") diff --git a/src/collective/z3cform/norobots/tests/utils.py b/src/collective/z3cform/norobots/tests/utils.py deleted file mode 100644 index 1166f70..0000000 --- a/src/collective/z3cform/norobots/tests/utils.py +++ /dev/null @@ -1,5 +0,0 @@ -# -*- coding: utf-8 -*- -from pkg_resources import get_distribution - - -PLONE_VERSION = get_distribution("Products.CMFPlone").version diff --git a/src/collective/z3cform/norobots/upgrades/__init__.py b/src/collective/z3cform/norobots/upgrades/__init__.py index 40a96af..e69de29 100644 --- a/src/collective/z3cform/norobots/upgrades/__init__.py +++ b/src/collective/z3cform/norobots/upgrades/__init__.py @@ -1 +0,0 @@ -# -*- coding: utf-8 -*- diff --git a/src/collective/z3cform/norobots/upgrades/configure.zcml b/src/collective/z3cform/norobots/upgrades/configure.zcml index 38f903c..11923b5 100644 --- a/src/collective/z3cform/norobots/upgrades/configure.zcml +++ b/src/collective/z3cform/norobots/upgrades/configure.zcml @@ -6,10 +6,10 @@ diff --git a/src/collective/z3cform/norobots/upgrades/upgrades.py b/src/collective/z3cform/norobots/upgrades/upgrades.py index 44b146d..c0036e3 100644 --- a/src/collective/z3cform/norobots/upgrades/upgrades.py +++ b/src/collective/z3cform/norobots/upgrades/upgrades.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from collective.z3cform.norobots.browser.interfaces import INorobotsWidgetSettings from plone.registry.interfaces import IRegistry from Products.CMFCore.utils import getToolByName diff --git a/src/collective/z3cform/norobots/validator.py b/src/collective/z3cform/norobots/validator.py index 7955eec..e20073d 100644 --- a/src/collective/z3cform/norobots/validator.py +++ b/src/collective/z3cform/norobots/validator.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Acquisition import aq_inner from collective.z3cform.norobots.i18n import norobotsMessageFactory as _ from z3c.form import validator diff --git a/src/collective/z3cform/norobots/widget.py b/src/collective/z3cform/norobots/widget.py index 44a360c..8e00bc0 100644 --- a/src/collective/z3cform/norobots/widget.py +++ b/src/collective/z3cform/norobots/widget.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Acquisition import aq_inner from z3c.form.browser.text import TextWidget from z3c.form.interfaces import IFieldWidget diff --git a/test-coverage.sh b/test-coverage.sh deleted file mode 100755 index 19a1f46..0000000 --- a/test-coverage.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -# ./test-coverage.sh - -bin/coverage -bin/report -open htmlcov/index.html \ No newline at end of file diff --git a/test_plone52.cfg b/test_plone52.cfg deleted file mode 100644 index de4273c..0000000 --- a/test_plone52.cfg +++ /dev/null @@ -1,59 +0,0 @@ -[buildout] - -extends = - https://raw.github.com/collective/buildout.plonetest/master/test-5.2.x.cfg - https://raw.githubusercontent.com/collective/buildout.plonetest/master/qa.cfg - base.cfg - -update-versions-file = test_plone52.cfg - -[versions] - -# Added by buildout at 2020-04-02 09:34:04.990371 -SecretStorage = 3.1.2 -createcoverage = 1.5 -entrypoints = 0.3 -flake8 = 3.7.9 -flake8-blind-except = 0.1.1 -flake8-coding = 1.3.2 -flake8-commas = 2.0.0 -flake8-debugger = 3.2.1 -flake8-deprecated = 1.3 -flake8-isort = 2.9.1 -flake8-pep3101 = 1.3.0 -flake8-plone-api = 1.4 -flake8-plone-hasattr = 0.2.post0 -flake8-print = 3.1.4 -flake8-quotes = 3.0.0 -flake8-string-format = 0.3.0 -flake8-todo = 0.7 -isort = 4.3.21 -jeepney = 0.4.3 -keyring = 21.2.0 -mccabe = 0.6.1 -pathtools = 0.1.2 -plone.recipe.codeanalysis = 3.0.1 -prompt-toolkit = 1.0.18 -pycodestyle = 2.5.0 -pyflakes = 2.1.1 -watchdog = 0.10.2 - -# Required by: -# plone.recipe.codeanalysis==3.0.1 -check-manifest = 0.41 - -# Required by: -# SecretStorage==3.1.2 -cryptography = 2.8 - -# Required by: -# check-manifest==0.41 -pep517 = 0.8.2 - -# Required by: -# flake8-isort==2.9.1 -testfixtures = 6.14.0 - -# Required by: -# prompt-toolkit==1.0.18 -wcwidth = 0.1.9 diff --git a/test_plone60.cfg b/test_plone60.cfg deleted file mode 100644 index 7982bd5..0000000 --- a/test_plone60.cfg +++ /dev/null @@ -1,37 +0,0 @@ -[buildout] - -extends = - https://raw.githubusercontent.com/collective/buildout.plonetest/master/test-6.0.x.cfg - https://raw.githubusercontent.com/collective/buildout.plonetest/master/qa.cfg - base.cfg - -update-versions-file = test_plone60.cfg - -[versions] -createcoverage = 1.5 -watchdog = 2.1.6 -# Added by buildout at 2021-12-06 10:38:47.973784 -flake8 = 4.0.1 -flake8-blind-except = 0.2.0 -flake8-coding = 1.3.2 -flake8-commas = 2.1.0 -flake8-debugger = 4.0.0 -flake8-deprecated = 1.3 -flake8-isort = 4.1.1 -flake8-pep3101 = 1.3.0 -flake8-plone-api = 1.4 -flake8-plone-hasattr = 0.2.post0 -flake8-print = 4.0.0 -flake8-quotes = 3.3.1 -flake8-string-format = 0.3.0 -flake8-todo = 0.7 -isort = 5.10.1 -mccabe = 0.6.1 -plone.recipe.codeanalysis = 3.0.1 -pyflakes = 2.4.0 -testfixtures = 6.18.3 - -# Required by: -# flake8-debugger==4.0.0 -# flake8-print==4.0.0 -pycodestyle = 2.8.0 diff --git a/tox.ini b/tox.ini index d42a613..2ecf646 100644 --- a/tox.ini +++ b/tox.ini @@ -1,206 +1,225 @@ +# Generated from: +# https://github.com/plone/meta/tree/main/config/default +# See the inline comments on how to expand/tweak this configuration file [tox] +# We need 4.4.0 for constrain_package_deps. +min_version = 4.4.0 envlist = - py37-lint, - py38-lint, - py39-lint, - black-check, - py{38,37}-Plone{52}, - py{39}-Plone{60}, -# docs, -# coverage-report, - -skip_missing_interpreters = True + lint + test + dependencies [gh-actions] python = - 3.7: py37 3.8: py38 3.9: py39 - -[gh-actions:env] -PLONE-VERSION = - Plone52: Plone52 - Plone60: Plone60 + 3.10: py310 + 3.11: py311 + 3.12: py312 + +## +# Add extra configuration options in .meta.toml: +# [tox] +# envlist_lines = """ +# my_other_environment +# """ +# config_lines = """ +# my_extra_top_level_tox_configuration_lines +# """ +## [testenv] skip_install = true - -passenv=* - -extras = - develop - test - +allowlist_externals = + echo + false +# Make sure typos like `tox -e formaat` are caught instead of silently doing nothing. +# See https://github.com/tox-dev/tox/issues/2858. commands = - {envbindir}/buildout -c {env:version_file} buildout:directory={envdir} buildout:develop={toxinidir} bootstrap - {envbindir}/buildout -c {env:version_file} buildout:directory={envdir} buildout:develop={toxinidir} annotate - {envbindir}/buildout -c {env:version_file} buildout:directory={envdir} buildout:develop={toxinidir} install test robot code-analysis - coverage run {envbindir}/test -v1 --auto-color {posargs} - # coverage run {envbindir}/test -v --all -t robot {posargs} - -setenv = - COVERAGE_FILE=.coverage.{envname} - version_file = {toxinidir}/test_plone60.cfg - Plone52: version_file={toxinidir}/test_plone52.cfg - Plone60: version_file={toxinidir}/test_plone60.cfg - -deps = - Plone52: -rrequirements_plone52.txt - Plone52: -cconstraints_plone52.txt - Plone60: -rrequirements_plone60.txt - Plone60: -cconstraints_plone60.txt - coverage - -[testenv:coverage-report] + echo "Unrecognized environment name {envname}" + false + +## +# Add extra configuration options in .meta.toml: +# [tox] +# testenv_options = """ +# basepython = /usr/bin/python3.8 +# """ +## + +[testenv:init] +description = Prepare environment skip_install = true -usedevelop = True -basepython = python3.9 - deps = - coverage - -cconstraints_plone60.txt - -setenv = - COVERAGE_FILE=.coverage - + mxdev commands = - coverage erase - coverage combine - coverage html - coverage xml - coverage report + mxdev -c mx.ini + echo "Initial setup for mxdev" -[lint] +[testenv:format] +description = automatically reformat code skip_install = true - deps = - -cconstraints.txt - isort - flake8 - # helper to generate HTML reports: - flake8-html - # Useful flake8 plugins that are Python and Plone specific: - flake8-coding - flake8-debugger - flake8-deprecated - flake8-print - #flake8-pytest - 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 - #flake8-polyfill - + pre-commit commands = - mkdir -p {toxinidir}/reports/flake8 - - flake8 --format=html --htmldir={toxinidir}/reports/flake8 --doctests {toxinidir}/src {toxinidir}/setup.py - flake8 --doctests {toxinidir}/src {toxinidir}/setup.py - isort --check-only {toxinidir}/src {toxinidir}/setup.py - # black --check --diff -v {toxinidir}/src {toxinidir}/setup.py - -whitelist_externals = - mkdir + pre-commit run -a pyupgrade + pre-commit run -a isort + pre-commit run -a black + pre-commit run -a zpretty - -[testenv:isort-apply] +[testenv:lint] +description = run linters that will help improve the code style skip_install = true - deps = - -cconstraints.txt - isort - + pre-commit commands = - isort {toxinidir}/src {toxinidir}/setup.py - + pre-commit run -a -[testenv:black-check] -basepython = python3.9 -skip_install = True +[testenv:dependencies] +description = check if the package defines all its dependencies +skip_install = true deps = - -cconstraints.txt - black - + build + z3c.dependencychecker==2.14.3 commands = - black --check --diff -v src setup.py - - -[testenv:black-enforce] -basepython = python3.9 -skip_install = True + python -m build --sdist + dependencychecker + +[testenv:dependencies-graph] +description = generate a graph out of the dependencies of the package +skip_install = false +allowlist_externals = + sh deps = - -cconstraints.txt - black - + pipdeptree==2.5.1 + graphviz # optional dependency of pipdeptree commands = - black -v src setup.py - - -[testenv:py37-lint] -basepython = python3.7 -skip_install = true -deps = {[lint]deps} -commands = {[lint]commands} -whitelist_externals = {[lint]whitelist_externals} - -[testenv:py38-lint] -basepython = python3.8 -skip_install = true -deps = {[lint]deps} -commands = {[lint]commands} -whitelist_externals = {[lint]whitelist_externals} - -[testenv:py39-lint] -basepython = python3.9 -skip_install = true -deps = {[lint]deps} -commands = {[lint]commands} -whitelist_externals = {[lint]whitelist_externals} - -[testenv:docs] -skip_install = true - + sh -c 'pipdeptree --exclude setuptools,wheel,pipdeptree,zope.interface,zope.component --graph-output svg > dependencies.svg' + +[testenv:test] +description = run the distribution tests +use_develop = true +skip_install = false +constrain_package_deps = false +set_env = + ROBOT_BROWSER=headlesschrome + +## +# Specify extra test environment variables in .meta.toml: +# [tox] +# test_environment_variables = """ +# PIP_EXTRA_INDEX_URL=https://my-pypi.my-server.com/ +# """ +# +# Set constrain_package_deps .meta.toml: +# [tox] +# constrain_package_deps = "false" +## deps = - Sphinx - + zope.testrunner + -c constraints-mxdev.txt + +## +# Specify additional deps in .meta.toml: +# [tox] +# test_deps_additional = "-esources/plonegovbr.portal_base[test]" +# +# Specify a custom constraints file in .meta.toml: +# [tox] +# constraints_file = "https://my-server.com/constraints.txt" +## commands = - sphinx-build -b html -d _build/docs/doctrees docs _build/docs/html - -[testenv:update_translation] -skip_install = true + zope-testrunner --all --test-path={toxinidir}/src -s collective.z3cform.norobots {posargs} +extras = + test +## +# Add extra configuration options in .meta.toml: +# [tox] +# test_extras = """ +# tests +# widgets +# """ +## + +[testenv:coverage] +description = get a test coverage report +use_develop = true +skip_install = false +constrain_package_deps = false +set_env = + ROBOT_BROWSER=headlesschrome + +## +# Specify extra test environment variables in .meta.toml: +# [tox] +# test_environment_variables = """ +# PIP_EXTRA_INDEX_URL=https://my-pypi.my-server.com/ +# """ +## deps = - i18ndude + coverage + zope.testrunner + -c constraints-mxdev.txt commands = - i18ndude find-untranslated - i18ndude rebuild-pot - i18ndude merge - i18ndude sync - i18ndude list + coverage run --branch --source collective.z3cform.norobots {envbindir}/zope-testrunner --quiet --all --test-path={toxinidir}/src -s collective.z3cform.norobots {posargs} + coverage report -m --format markdown + coverage xml + coverage html +extras = + test -[testenv:release] -skip_install = true +[testenv:release-check] +description = ensure that the distribution is ready to release +skip_install = true deps = - zest.releaser[recommended] + twine + build + -c constraints-mxdev.txt commands = - fullrelease --no-input -v - -[testenv:build_instance] -basepython = python2.7 -skip_install = true + python -m build --sdist + twine check dist/* + +[testenv:circular] +description = ensure there are no cyclic dependencies +use_develop = true +skip_install = false +# Here we must always constrain the package deps to what is already installed, +# otherwise we simply get the latest from PyPI, which may not work. +constrain_package_deps = true +set_env = + +## +# Specify extra test environment variables in .meta.toml: +# [tox] +# test_environment_variables = """ +# PIP_EXTRA_INDEX_URL=https://my-pypi.my-server.com/ +# """ +## +allowlist_externals = + sh +deps = + pipdeptree + pipforester + -c constraints-mxdev.txt commands = - {envbindir}/buildout -c {env:version_file} buildout:directory={toxinidir} bootstrap - {envbindir}/buildout -c {env:version_file} buildout:directory={toxinidir} annotate - {envbindir}/buildout -c {env:version_file} buildout:directory={toxinidir} + # Generate the full dependency tree + sh -c 'pipdeptree -j > forest.json' + # Generate a DOT graph with the circular dependencies, if any + pipforester -i forest.json -o forest.dot --cycles + # Report if there are any circular dependencies, i.e. error if there are any + pipforester -i forest.json --check-cycles -o /dev/null + + +## +# Add extra configuration options in .meta.toml: +# [tox] +# extra_lines = """ +# _your own configuration lines_ +# """ +##