diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..d054af1 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,56 @@ +# Generated from: +# https://github.com/plone/meta/tree/main/src/plone/meta/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 + + +[*] +# 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,ini}] +# 4 space indentation +indent_size = 4 + +[*.{yml,zpt,pt,dtml,zcml,html,xml}] +# 2 space indentation +indent_size = 2 + +[*.{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..3e2d35f --- /dev/null +++ b/.flake8 @@ -0,0 +1,22 @@ +# Generated from: +# https://github.com/plone/meta/tree/main/src/plone/meta/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/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..e5e4522 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +# Generated from: +# https://github.com/plone/meta/tree/main/src/plone/meta/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/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index 4e11ba7..0000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: tests - -on: - push: - branches: [ main ] - pull_request: - -jobs: - build: - strategy: - matrix: - config: - # [Python version, tox env] - - ["3.7", "plone52-py37"] - - ["3.8", "plone52-py38"] - - ["3.9", "plone52-py39"] - - ["3.7", "plone60-py37"] - - ["3.8", "plone60-py38"] - - ["3.9", "plone60-py39"] - 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] }} diff --git a/.github/workflows/meta.yml b/.github/workflows/meta.yml new file mode 100644 index 0000000..f9a346f --- /dev/null +++ b/.github/workflows/meta.yml @@ -0,0 +1,65 @@ +# Generated from: +# https://github.com/plone/meta/tree/main/src/plone/meta/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@2.x + coverage: + uses: plone/meta/.github/workflows/coverage.yml@2.x + dependencies: + uses: plone/meta/.github/workflows/dependencies.yml@2.x + release_ready: + uses: plone/meta/.github/workflows/release_ready.yml@2.x + circular: + uses: plone/meta/.github/workflows/circular.yml@2.x + +## +# To modify the list of default jobs being created add in .meta.toml: +# [github] +# jobs = [ +# "qa", +# "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" +## + + +## +# Specify additional jobs in .meta.toml: +# [github] +# extra_lines = """ +# another: +# uses: org/repo/.github/workflows/file.yml@main +# """ +## diff --git a/.github/workflows/test-matrix.yml b/.github/workflows/test-matrix.yml new file mode 100644 index 0000000..05872b5 --- /dev/null +++ b/.github/workflows/test-matrix.yml @@ -0,0 +1,72 @@ +# Generated from: +# https://github.com/plone/meta/tree/main/src/plone/meta/default +# See the inline comments on how to expand/tweak this configuration file +name: Tests + +on: + push: + +jobs: + build: + permissions: + contents: read + pull-requests: write + strategy: + # We want to see all failures: + fail-fast: false + matrix: + os: + - ["ubuntu", "ubuntu-latest"] + config: + # [Python version, visual name, tox env] + - ["3.13", "6.2 on py3.13", "py313-plone62"] + - ["3.10", "6.2 on py3.10", "py310-plone62"] + + runs-on: ${{ matrix.os[1] }} + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name + name: ${{ matrix.config[1] }} + steps: + - uses: actions/checkout@v6 + with: + persist-credentials: false + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: ${{ matrix.config[0] }} + allow-prereleases: true + +## +# Add extra configuration options in .meta.toml: +# [github] +# extra_lines_after_os_dependencies = """ +# _your own configuration lines_ +# """ +## + - name: Pip cache + uses: actions/cache@v5 + 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: Initialize tox + # the bash one-liner below does not work on Windows + if: contains(matrix.os, 'ubuntu') + run: | + if [ `tox list --no-desc -f init|wc -l` = 1 ]; then tox -e init;else true; fi + - name: Test + run: tox -e ${{ matrix.config[2] }} + + +## +# Add extra configuration options in .meta.toml: +# [github] +# extra_lines = """ +# _your own configuration lines_ +# """ +## diff --git a/.gitignore b/.gitignore index a44a7ac..a602abe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,37 +1,58 @@ -*.EGG -*.EGG-INFO -*.egg +# Generated from: +# https://github.com/plone/meta/tree/main/src/plone/meta/default +# See the inline comments on how to expand/tweak this configuration file +# python related *.egg-info -*.map -*.mo *.pyc *.pyo -*.js.map -*.tmp* -.*.cfg -.DS_Store -.idea -/bin/ -/build/ -/develop-eggs/ -/devsrc/ -/dist/ -/docs/_screenshots/*.png -/downloads/ -/eggs/ -/extras/ -/fake-eggs/ -/html/ -/include/ -/lib/ -/local/ -/parts/ -/resources/theme/ -/result -/var/ -components -node_modules -!.isort.cfg -pip-selfcheck.json -src/* -.python-version + +# translation related +*.mo + +# tools related +build/ +.coverage +.*project +coverage.xml +dist/ +docs/_build +__pycache__/ +.tox +.vscode/ +node_modules/ +forest.dot +forest.json + +# venv / buildout related +bin/ +develop-eggs/ +eggs/ +.eggs/ +etc/ +.installed.cfg +include/ +lib/ +lib64 +.mr.developer.cfg +parts/ +pyvenv.cfg +var/ +local.cfg + +# mxdev +/instance/ +/.make-sentinels/ +/*-mxdev.txt +/reports/ +/sources/ +/venv/ +.installed.txt + + +## +# 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..f462a34 --- /dev/null +++ b/.meta.toml @@ -0,0 +1,9 @@ +# Generated from: +# https://github.com/plone/meta/tree/main/src/plone/meta/default +# See the inline comments on how to expand/tweak this configuration file +[meta] +template = "default" +commit-id = "2.3.1" + +[tox] +test_matrix = {"6.2" = ["*"]} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..b3e6370 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,94 @@ +# Generated from: +# https://github.com/plone/meta/tree/main/src/plone/meta/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.21.2 + hooks: + - id: pyupgrade + args: [--py38-plus] +- repo: https://github.com/pycqa/isort + rev: 7.0.0 + hooks: + - id: isort +- repo: https://github.com/psf/black-pre-commit-mirror + rev: 25.11.0 + hooks: + - id: black +- repo: https://github.com/collective/zpretty + rev: 3.1.1 + 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.3.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.4.1 + 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.51" + hooks: + - id: check-manifest +- repo: https://github.com/regebro/pyroma + rev: "5.0" + hooks: + - id: pyroma +- repo: https://github.com/mgedmin/check-python-versions + rev: "0.24.0" + hooks: + - id: check-python-versions + args: ['--only', 'setup.py,pyproject.toml'] +- repo: https://github.com/collective/i18ndude + rev: "6.3.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/CHANGES.rst b/CHANGES.rst index 31daeaf..bcf82af 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,11 +1,12 @@ Changelog ========= -2.0.1 (unreleased) ------------------- - -- Nothing changed yet. +.. You should *NOT* be adding new change log entries to this file. + You should create a file in the news directory instead. + For helpful instructions, please see: + https://github.com/plone/plone.releaser/blob/master/ADD-A-NEWS-ITEM.rst +.. towncrier release notes start 2.0.0 (2022-07-22) ------------------ @@ -25,7 +26,7 @@ Changelog 1.1.2 (2017-07-03) ------------------ -- Fix issue where draft sync failed because draft might have been withotu aq wrapper +- Fix issue where draft sync failed because draft might have been without aq wrapper [datakurre] 1.1.1 (2016-09-09) diff --git a/MANIFEST.in b/MANIFEST.in index e8ed5a3..83ef884 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,9 +1,10 @@ include *.rst recursive-include docs * -recursive-include plone * +recursive-include src * global-exclude *pyc exclude bootstrap.py exclude *.cfg .coveragerc .github *.ini +recursive-exclude news * diff --git a/README.rst b/README.rst index 7486e3d..a29f0b4 100644 --- a/README.rst +++ b/README.rst @@ -1,14 +1,6 @@ Introduction ============ -.. image:: https://secure.travis-ci.org/plone/plone.app.drafts.png?branch=master - :alt: Travis CI badge - :target: http://travis-ci.org/plone/plone.app.drafts - -.. image:: https://coveralls.io/repos/plone/plone.app.drafts/badge.png?branch=master - :alt: Coveralls badge - :target: https://coveralls.io/r/plone/plone.app.drafts - plone.app.drafts implements services for managing auto-saved content drafts in Plone. This addresses two problems: diff --git a/buildout.cfg b/buildout.cfg deleted file mode 100644 index e257ee2..0000000 --- a/buildout.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[buildout] -extends = test-4.x.cfg diff --git a/plone/app/drafts/browser/__init__.py b/news/.gitkeep similarity index 100% rename from plone/app/drafts/browser/__init__.py rename to news/.gitkeep diff --git a/news/3928.breaking b/news/3928.breaking new file mode 100644 index 0000000..4fb7ad4 --- /dev/null +++ b/news/3928.breaking @@ -0,0 +1,2 @@ +Replace ``pkg_resources`` namespace with PEP 420 native namespace. +Support only Plone 6.2 and Python 3.10+. diff --git a/plone/__init__.py b/plone/__init__.py deleted file mode 100644 index 03d08ff..0000000 --- a/plone/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# -*- coding: utf-8 -*- -__import__("pkg_resources").declare_namespace(__name__) diff --git a/plone/app/__init__.py b/plone/app/__init__.py deleted file mode 100644 index 03d08ff..0000000 --- a/plone/app/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# -*- coding: utf-8 -*- -__import__("pkg_resources").declare_namespace(__name__) diff --git a/plone/app/drafts/behaviors.zcml b/plone/app/drafts/behaviors.zcml deleted file mode 100644 index 4d4dd8a..0000000 --- a/plone/app/drafts/behaviors.zcml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - diff --git a/plone/app/drafts/browser/configure.zcml b/plone/app/drafts/browser/configure.zcml deleted file mode 100644 index 5ff09e0..0000000 --- a/plone/app/drafts/browser/configure.zcml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - diff --git a/plone/app/drafts/browser/drafts.pt b/plone/app/drafts/browser/drafts.pt deleted file mode 100644 index 6500b2c..0000000 --- a/plone/app/drafts/browser/drafts.pt +++ /dev/null @@ -1,60 +0,0 @@ - - -
-
- -

Drafts

- -

- Drafts are created when a page is edited and has not yet been saved. - A draft found here represents either a content item currently being - edited, an item that has been abandoned, e.g. because of a browser crash. -

- -Return to overview - - - No drafts found - - - - -

Drafts for - on

- -

- The following drafts are in progress. -

- -
- - - - -
- - - - Last modified: - - -
- -
 
- -
- -
-
- -
- -
- - diff --git a/plone/app/drafts/browser/overview.pt b/plone/app/drafts/browser/overview.pt deleted file mode 100644 index 372424c..0000000 --- a/plone/app/drafts/browser/overview.pt +++ /dev/null @@ -1,47 +0,0 @@ - - -
-
- -

Drafts

- -

- Drafts are created when a page is edited and has not yet been saved. - A draft found here represents either a content item currently being - edited, an item that has been abandoned, e.g. because of a browser crash. -

- - - No drafts found - - - - -

Users

- -

- Drafts are managed per user. Click on a user id below to find drafts for - that user. -

- -
- -
- - -
- -
 
- -
- -
- - -
- -
- - diff --git a/plone/app/drafts/browser/targets.pt b/plone/app/drafts/browser/targets.pt deleted file mode 100644 index 6df6665..0000000 --- a/plone/app/drafts/browser/targets.pt +++ /dev/null @@ -1,69 +0,0 @@ - - -
-
- -

Drafts

- -

- Drafts are created when a page is edited and has not yet been saved. - A draft found here represents either a content item currently being - edited, an item that has been abandoned, e.g. because of a browser crash. -

- -
Return to overview - - - No drafts found - - - - -

Drafts for

- -

- Drafts are organised by the target object. Click on a key below to - view drafts for this item. -

- -
- -
- - - - Object of type - being added to - - - - - — - - - View drafts - - - - | - View content object - - -
- -
 
- -
- -
-
- -
- -
- - diff --git a/plone/app/drafts/configure.zcml b/plone/app/drafts/configure.zcml deleted file mode 100644 index 44ac090..0000000 --- a/plone/app/drafts/configure.zcml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/plone/app/drafts/profiles/default/componentregistry.xml b/plone/app/drafts/profiles/default/componentregistry.xml deleted file mode 100644 index 557a538..0000000 --- a/plone/app/drafts/profiles/default/componentregistry.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/plone/app/drafts/profiles/default/metadata.xml b/plone/app/drafts/profiles/default/metadata.xml deleted file mode 100644 index 8be2512..0000000 --- a/plone/app/drafts/profiles/default/metadata.xml +++ /dev/null @@ -1,5 +0,0 @@ - - 1 - - - diff --git a/plone/app/drafts/profiles/default/toolset.xml b/plone/app/drafts/profiles/default/toolset.xml deleted file mode 100644 index 29a1ce6..0000000 --- a/plone/app/drafts/profiles/default/toolset.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..c20adb6 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,167 @@ +# Generated from: +# https://github.com/plone/meta/tree/main/src/plone/meta/default +# See the inline comments on how to expand/tweak this configuration file +[build-system] +requires = ["setuptools>=68.2,<80", "wheel"] + +[tool.towncrier] +directory = "news/" +filename = "CHANGES.rst" +title_format = "{version} ({project_date})" +underlines = ["-", ""] + +[[tool.towncrier.type]] +directory = "breaking" +name = "Breaking changes:" +showcontent = true + +[[tool.towncrier.type]] +directory = "feature" +name = "New features:" +showcontent = true + +[[tool.towncrier.type]] +directory = "bugfix" +name = "Bug fixes:" +showcontent = true + +[[tool.towncrier.type]] +directory = "internal" +name = "Internal:" +showcontent = true + +[[tool.towncrier.type]] +directory = "documentation" +name = "Documentation:" +showcontent = true + +[[tool.towncrier.type]] +directory = "tests" +name = "Tests:" +showcontent = true + +## +# 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,assertin,thet," +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'] +pytest-plone = ['pytest', 'zope.pytestlayer', 'plone.testing', 'plone.app.testing'] + +## +# 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/setup.cfg b/setup.cfg deleted file mode 100644 index caafa66..0000000 --- a/setup.cfg +++ /dev/null @@ -1,6 +0,0 @@ -[isort] -force_alphabetical_sort = True -force_single_line = True -lines_after_imports = 2 -line_length = 200 -not_skip = __init__.py \ No newline at end of file diff --git a/setup.py b/setup.py index 646dc56..d001ce7 100644 --- a/setup.py +++ b/setup.py @@ -1,11 +1,7 @@ -# -*- coding: utf-8 -*- -from setuptools import find_packages from setuptools import setup -import os - -version = "2.0.1.dev0" +version = "3.0.0.dev0" setup( name="plone.app.drafts", @@ -18,14 +14,13 @@ "Development Status :: 4 - Beta", "Environment :: Web Environment", "Framework :: Plone", - "Framework :: Plone :: 5.2", - "Framework :: Plone :: 6.0", + "Framework :: Plone :: 6.2", "License :: OSI Approved :: GNU General Public License v2 (GPLv2)", "Programming Language :: Python", - "Programming Language :: Python :: 3.7", - "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", + "Programming Language :: Python :: 3.13", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Software Development :: Libraries :: Python Modules", @@ -35,25 +30,31 @@ author_email="plone-developers@lists.sourceforge.net", url="http://plone.org", license="GPL", - packages=find_packages(exclude=["ez_setup"]), - namespace_packages=["plone", "plone.app"], include_package_data=True, zip_safe=False, + python_requires=">=3.10", install_requires=[ - "setuptools", - "ZODB3", - "zope.interface", - "zope.component", - "zope.schema", - "zope.annotation", "plone.app.uuid", + "plone.autoform", "plone.behavior>=1.1", - "Zope2", + "plone.dexterity", + "plone.protect", + "plone.uuid", + "Products.CMFCore", + "Products.GenericSetup", + "z3c.form", + "zope.annotation", + "zope.component", + "zope.interface", + "zope.schema", + "Zope", ], extras_require={ "test": [ + "plone.app.contenttypes", "plone.app.testing", "plone.app.dexterity", + "plone.testing", ], }, entry_points=""" diff --git a/plone/app/drafts/__init__.py b/src/plone/app/drafts/__init__.py similarity index 97% rename from plone/app/drafts/__init__.py rename to src/plone/app/drafts/__init__.py index 4616980..d49fdc4 100644 --- a/plone/app/drafts/__init__.py +++ b/src/plone/app/drafts/__init__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.app.drafts.interfaces import ICurrentDraftManagement from plone.app.drafts.interfaces import IDrafting from plone.app.drafts.lifecycle import syncDraftOnSave diff --git a/src/plone/app/drafts/behaviors.zcml b/src/plone/app/drafts/behaviors.zcml new file mode 100644 index 0000000..4948039 --- /dev/null +++ b/src/plone/app/drafts/behaviors.zcml @@ -0,0 +1,20 @@ + + + + + + + diff --git a/src/plone/app/drafts/browser/__init__.py b/src/plone/app/drafts/browser/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/plone/app/drafts/browser/configure.zcml b/src/plone/app/drafts/browser/configure.zcml new file mode 100644 index 0000000..a4f0f54 --- /dev/null +++ b/src/plone/app/drafts/browser/configure.zcml @@ -0,0 +1,39 @@ + + + + + + + + + + + diff --git a/src/plone/app/drafts/browser/drafts.pt b/src/plone/app/drafts/browser/drafts.pt new file mode 100644 index 0000000..8f49d60 --- /dev/null +++ b/src/plone/app/drafts/browser/drafts.pt @@ -0,0 +1,103 @@ + + +
+
+ +

Drafts

+ +

+ Drafts are created when a page is edited and has not yet been saved. + A draft found here represents either a content item currently being + edited, an item that has been abandoned, e.g. because of a browser crash. +

+ + Return to overview + + + No drafts found + + + + +

Drafts for + + on +

+ +

+ The following drafts are in progress. +

+ +
+ + + + +
+ + + + Last modified: + + + +
+ +
 
+ +
+ +
+
+ +
+ +
+ +
diff --git a/src/plone/app/drafts/browser/overview.pt b/src/plone/app/drafts/browser/overview.pt new file mode 100644 index 0000000..cad1060 --- /dev/null +++ b/src/plone/app/drafts/browser/overview.pt @@ -0,0 +1,64 @@ + + +
+
+ +

Drafts

+ +

+ Drafts are created when a page is edited and has not yet been saved. + A draft found here represents either a content item currently being + edited, an item that has been abandoned, e.g. because of a browser crash. +

+ + + No drafts found + + + + +

Users

+ +

+ Drafts are managed per user. Click on a user id below to find drafts for + that user. +

+ +
+ +
+ + +
+ +
 
+ +
+ +
+
+ +
+ +
+ +
diff --git a/src/plone/app/drafts/browser/targets.pt b/src/plone/app/drafts/browser/targets.pt new file mode 100644 index 0000000..8e84aa2 --- /dev/null +++ b/src/plone/app/drafts/browser/targets.pt @@ -0,0 +1,118 @@ + + +
+
+ +

Drafts

+ +

+ Drafts are created when a page is edited and has not yet been saved. + A draft found here represents either a content item currently being + edited, an item that has been abandoned, e.g. because of a browser crash. +

+ + Return to overview + + + No drafts found + + + + +

Drafts for +

+ +

+ Drafts are organised by the target object. Click on a key below to + view drafts for this item. +

+ +
+ +
+ + + + Object of type + + being added to + + + + + — + + + View drafts + + + + | + View content object + + +
+ +
 
+ +
+ +
+
+ +
+ +
+ +
diff --git a/plone/app/drafts/browser/tool.gif b/src/plone/app/drafts/browser/tool.gif similarity index 100% rename from plone/app/drafts/browser/tool.gif rename to src/plone/app/drafts/browser/tool.gif diff --git a/plone/app/drafts/browser/view.py b/src/plone/app/drafts/browser/view.py similarity index 98% rename from plone/app/drafts/browser/view.py rename to src/plone/app/drafts/browser/view.py index 79c769b..8a550f3 100644 --- a/plone/app/drafts/browser/view.py +++ b/src/plone/app/drafts/browser/view.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from datetime import datetime from plone.app.uuid.utils import uuidToObject @@ -9,7 +8,7 @@ from urllib.parse import quote -class View(object): +class View: """A shared view class that is used for each of the three views. They each use a different template. """ diff --git a/src/plone/app/drafts/configure.zcml b/src/plone/app/drafts/configure.zcml new file mode 100644 index 0000000..f5abff9 --- /dev/null +++ b/src/plone/app/drafts/configure.zcml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/plone/app/drafts/current.py b/src/plone/app/drafts/current.py similarity index 98% rename from plone/app/drafts/current.py rename to src/plone/app/drafts/current.py index 02b3e6f..76b0517 100644 --- a/plone/app/drafts/current.py +++ b/src/plone/app/drafts/current.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.app.drafts.interfaces import DRAFT_KEY from plone.app.drafts.interfaces import DRAFT_NAME_KEY from plone.app.drafts.interfaces import ICurrentDraftManagement @@ -18,7 +17,7 @@ @adapter(IRequest) @implementer(ICurrentDraftManagement) -class DefaultCurrentDraftManagement(object): +class DefaultCurrentDraftManagement: def __init__(self, request): self.request = request self.annotations = IAnnotations(request) diff --git a/plone/app/drafts/dexterity.py b/src/plone/app/drafts/dexterity.py similarity index 88% rename from plone/app/drafts/dexterity.py rename to src/plone/app/drafts/dexterity.py index f37c5bb..13968cb 100644 --- a/plone/app/drafts/dexterity.py +++ b/src/plone/app/drafts/dexterity.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Acquisition import aq_base from plone.app.drafts.interfaces import ICurrentDraftManagement from plone.app.drafts.interfaces import IDraftable @@ -76,10 +75,10 @@ def __init__(self, form, request, context): if isDraftable(fti): current = ICurrentDraftManagement(request) - if current.targetKey != "++add++{0}".format(form.portal_type): + if current.targetKey != f"++add++{form.portal_type}": beginDrafting(context, None) current.path = "/".join(context.getPhysicalPath()) - current.targetKey = "++add++{0}".format(form.portal_type) + current.targetKey = f"++add++{form.portal_type}" current.save() else: current.mark() @@ -89,12 +88,12 @@ def __init__(self, form, request, context): context = DraftProxy(current.draft, target.__of__(context)) alsoProvides(request, IAddFormDrafting) - super(DefaultAddFormFieldWidgets, self).__init__(form, request, context) # noqa + super().__init__(form, request, context) # noqa def update(self): if IAddFormDrafting.providedBy(self.request): self.ignoreContext = False - super(DefaultAddFormFieldWidgets, self).update() + super().update() @adapter(IGroup, IAddFormDrafting, Interface) @@ -104,13 +103,11 @@ def __init__(self, form, request, context): draft = getCurrentDraft(request) target = getattr(draft, "_draftAddFormTarget") context = DraftProxy(draft, target.__of__(context)) - super(DefaultAddFormGroupFieldWidgets, self).__init__( - form, request, context - ) # noqa + super().__init__(form, request, context) # noqa def update(self): self.ignoreContext = False - super(DefaultAddFormGroupFieldWidgets, self).update() + super().update() @adapter(DefaultEditForm, IFormLayer, IDexterityContent) @@ -133,9 +130,7 @@ def __init__(self, form, request, context): context = DraftProxy(current.draft, context) alsoProvides(request, IEditFormDrafting) - super(DefaultEditFormFieldWidgets, self).__init__( - form, request, context - ) # noqa + super().__init__(form, request, context) # noqa @adapter(IGroup, IEditFormDrafting, Interface) @@ -144,9 +139,7 @@ class DefaultEditFormGroupFieldWidgets(FieldWidgetsBase): def __init__(self, form, request, context): draft = getCurrentDraft(request) context = DraftProxy(draft, context) - super(DefaultEditFormGroupFieldWidgets, self).__init__( - form, request, context - ) # noqa + super().__init__(form, request, context) # noqa @adapter(WidgetsView, IDisplayFormDrafting, IDexterityContent) @@ -163,9 +156,7 @@ def __init__(self, form, request, context): if current.draft: context = DraftProxy(current.draft, context) - super(DefaultDisplayFormFieldWidgets, self).__init__( - form, request, context - ) # noqa + super().__init__(form, request, context) # noqa @adapter(IGroup, IDisplayFormDrafting, Interface) @@ -174,9 +165,7 @@ class DefaultDisplayFormGroupFieldWidgets(FieldWidgetsBase): def __init__(self, form, request, context): draft = getCurrentDraft(request) context = DraftProxy(draft, context) - super(DefaultDisplayFormGroupFieldWidgets, self).__init__( - form, request, context - ) # noqa + super().__init__(form, request, context) # noqa def autosave(event): # noqa @@ -201,7 +190,7 @@ def autosave(event): # noqa if target is None: target = createContent(form.portal_type) target.id = "" - IMutableUUID(target).set("++add++{0}".format(form.portal_type)) + IMutableUUID(target).set(f"++add++{form.portal_type}") draft._draftAddFormTarget = target target = target.__of__(context) @@ -225,9 +214,7 @@ def autosave(event): # noqa content = DraftProxy(draft, target) # Drop known non-draftable values - data = dict( - [(k, v) for k, v in data.items() if k not in AUTOSAVE_BLACKLIST] - ) # noqa + data = {k: v for k, v in data.items() if k not in AUTOSAVE_BLACKLIST} # noqa # Values are applied within savepoint to allow revert of any # unexpected side-effects from setting field values diff --git a/plone/app/drafts/dexterity.zcml b/src/plone/app/drafts/dexterity.zcml similarity index 95% rename from plone/app/drafts/dexterity.zcml rename to src/plone/app/drafts/dexterity.zcml index 07a7b0e..de6de94 100644 --- a/plone/app/drafts/dexterity.zcml +++ b/src/plone/app/drafts/dexterity.zcml @@ -1,6 +1,7 @@ + i18n_domain="plone.app.drafts" + > diff --git a/plone/app/drafts/draft.py b/src/plone/app/drafts/draft.py similarity index 95% rename from plone/app/drafts/draft.py rename to src/plone/app/drafts/draft.py index 3cdb5e9..828d118 100644 --- a/plone/app/drafts/draft.py +++ b/src/plone/app/drafts/draft.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from persistent import Persistent from plone.app.drafts.interfaces import IDraft from zope.annotation.interfaces import IAttributeAnnotatable diff --git a/plone/app/drafts/interfaces.py b/src/plone/app/drafts/interfaces.py similarity index 79% rename from plone/app/drafts/interfaces.py rename to src/plone/app/drafts/interfaces.py index 47d232c..210fb8d 100644 --- a/plone/app/drafts/interfaces.py +++ b/src/plone/app/drafts/interfaces.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from zope import schema from zope.interface import Interface @@ -17,9 +16,9 @@ class IDraft(Interface): to it as required. """ - _draftUserId = schema.TextLine(title=u"User id") - _draftTargetKey = schema.TextLine(title=u"Target object key") - __name__ = schema.TextLine(title=u"Unique draft name") + _draftUserId = schema.TextLine(title="User id") + _draftTargetKey = schema.TextLine(title="Target object key") + __name__ = schema.TextLine(title="Unique draft name") class IDraftStorage(Interface): @@ -29,18 +28,18 @@ class IDraftStorage(Interface): """ enabled = schema.Bool( - title=u"Whether drafting is enabled", + title="Whether drafting is enabled", default=True, ) drafts = schema.Dict( - title=u"Drafts", - description=u"Use the methods below to inspect and manipulate this", - key_type=schema.TextLine(title=u"User id"), + title="Drafts", + description="Use the methods below to inspect and manipulate this", + key_type=schema.TextLine(title="User id"), value_type=schema.Dict( - key_type=schema.TextLine(title=u"Draft target key"), + key_type=schema.TextLine(title="Draft target key"), value_type=schema.Dict( - key_type=schema.TextLine(title=u"Draft name"), + key_type=schema.TextLine(title="Draft name"), value_type=schema.Object(schema=IDraft), ), ), @@ -70,7 +69,7 @@ def discardDraft(draft): """Discard a particular draft.""" def getDrafts(userId, targetKey): - """Get a list mappping of all drafts under the given userId and + """Get a list mapping of all drafts under the given userId and target key. The returned mapping should not be modified directly. """ @@ -128,11 +127,11 @@ class ICurrentDraftManagement(Interface): The current draft information may be persisted across requests by calling ``save()``. Once saved, it can be later discard by calling ``save()``. - The deafult implementation stores information in cookies that are set + The default implementation stores information in cookies that are set when the form is entered and cleared when it is saved or cancelled. The - cookes are set for a path corresponding to the content object. This allows + cookies are set for a path corresponding to the content object. This allows things like AJAX requests in the visual editor to find the same draft - information, and minimises the risk of a draft for one object being used + information, and minimizes the risk of a draft for one object being used for another. The default path may be obtained via the ``defaultPath`` property, but @@ -145,18 +144,18 @@ class ICurrentDraftManagement(Interface): been set. """ - userId = schema.TextLine(title=u"Current user id") - targetKey = schema.TextLine(title=u"Current target key") - draftName = schema.TextLine(title=u"Current draft name") - path = schema.TextLine(title=u"Path prefix in which the data should be retained") + userId = schema.TextLine(title="Current user id") + targetKey = schema.TextLine(title="Current target key") + draftName = schema.TextLine(title="Current draft name") + path = schema.TextLine(title="Path prefix in which the data should be retained") defaultPath = schema.TextLine( - title=u"Default path prefix for this request", readonly=True + title="Default path prefix for this request", readonly=True ) draft = schema.Object( - title=u"Current draft", - description=u"If userId, targetKey and draftName are set, the " - u"draft will be lazily fetched from the storage", + title="Current draft", + description="If userId, targetKey and draftName are set, the " + "draft will be lazily fetched from the storage", schema=IDraft, ) diff --git a/plone/app/drafts/lifecycle.py b/src/plone/app/drafts/lifecycle.py similarity index 99% rename from plone/app/drafts/lifecycle.py rename to src/plone/app/drafts/lifecycle.py index 230c1fb..038e771 100644 --- a/plone/app/drafts/lifecycle.py +++ b/src/plone/app/drafts/lifecycle.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.app.drafts.interfaces import ICurrentDraftManagement from plone.app.drafts.interfaces import IDraftStorage from plone.app.drafts.utils import getCurrentDraft diff --git a/src/plone/app/drafts/profiles/default/componentregistry.xml b/src/plone/app/drafts/profiles/default/componentregistry.xml new file mode 100644 index 0000000..956962e --- /dev/null +++ b/src/plone/app/drafts/profiles/default/componentregistry.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/src/plone/app/drafts/profiles/default/metadata.xml b/src/plone/app/drafts/profiles/default/metadata.xml new file mode 100644 index 0000000..5380f6f --- /dev/null +++ b/src/plone/app/drafts/profiles/default/metadata.xml @@ -0,0 +1,6 @@ + + + 1 + + + diff --git a/plone/app/drafts/profiles/default/plone.app.drafts.txt b/src/plone/app/drafts/profiles/default/plone.app.drafts.txt similarity index 100% rename from plone/app/drafts/profiles/default/plone.app.drafts.txt rename to src/plone/app/drafts/profiles/default/plone.app.drafts.txt diff --git a/src/plone/app/drafts/profiles/default/toolset.xml b/src/plone/app/drafts/profiles/default/toolset.xml new file mode 100644 index 0000000..ab6e123 --- /dev/null +++ b/src/plone/app/drafts/profiles/default/toolset.xml @@ -0,0 +1,6 @@ + + + + diff --git a/plone/app/drafts/proxy.py b/src/plone/app/drafts/proxy.py similarity index 98% rename from plone/app/drafts/proxy.py rename to src/plone/app/drafts/proxy.py index 81cc43d..acaae14 100644 --- a/plone/app/drafts/proxy.py +++ b/src/plone/app/drafts/proxy.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from Acquisition import aq_base from collections.abc import MutableMapping from plone.app.drafts.interfaces import IDraftProxy @@ -56,7 +55,7 @@ def __get__(self, inst, cls=None): @implementer(IDraftProxy) -class DraftProxy(object): +class DraftProxy: """A simple proxy object that is initialised with a draft object and the underlying target. All attribute and annotation writes are performed against the draft; all reads are performed against the draft unless the @@ -145,8 +144,7 @@ def __getitem__(self, key): def __iter__(self): # adhere to MutableMapping interface - for val in self.draftAnnotations.values(): - yield val + yield from self.draftAnnotations.values() def __len__(self): # adhere to MutableMapping interface diff --git a/plone/app/drafts/storage.py b/src/plone/app/drafts/storage.py similarity index 94% rename from plone/app/drafts/storage.py rename to src/plone/app/drafts/storage.py index 935f04f..537c7b3 100644 --- a/plone/app/drafts/storage.py +++ b/src/plone/app/drafts/storage.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from BTrees.OOBTree import OOBTree from OFS.SimpleItem import SimpleItem from plone.app.drafts.draft import Draft @@ -41,19 +40,19 @@ def createDraft(self, userId, targetKey, factory=None): draft = factory(userId, targetKey) if not draft.__name__: - draft.__name__ = u"draft" + draft.__name__ = "draft" if draft.__name__ in container: idx = len(container) while ( - u"{0}-{1}".format( + "{}-{}".format( draft.__name__, idx, ) in container ): idx += 1 - draft.__name__ = u"{0}-{1}".format( + draft.__name__ = "{}-{}".format( draft.__name__, idx, ) diff --git a/plone/app/drafts/testing.py b/src/plone/app/drafts/testing.py similarity index 99% rename from plone/app/drafts/testing.py rename to src/plone/app/drafts/testing.py index c45a335..1d3d873 100644 --- a/plone/app/drafts/testing.py +++ b/src/plone/app/drafts/testing.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from plone.app.testing import FunctionalTesting from plone.app.testing import IntegrationTesting from plone.app.testing import PLONE_FIXTURE diff --git a/plone/app/drafts/tests.py b/src/plone/app/drafts/tests.py similarity index 82% rename from plone/app/drafts/tests.py rename to src/plone/app/drafts/tests.py index 6d745dd..601a04d 100644 --- a/plone/app/drafts/tests.py +++ b/src/plone/app/drafts/tests.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from pkg_resources import parse_version from plone.app.drafts.draft import Draft from plone.app.drafts.interfaces import DRAFT_NAME_KEY @@ -78,14 +77,14 @@ def test_createDraft_existing_user_only(self): def test_createDraft_factory(self): def factory(userId, targetKey): - return Draft(name=u"foo") + return Draft(name="foo") draft1 = self.storage.createDraft("user1", "123", factory=factory) - self.assertEqual(u"foo", draft1.__name__) + self.assertEqual("foo", draft1.__name__) self.assertTrue(draft1.__name__ in self.storage.drafts["user1"]["123"]) draft2 = self.storage.createDraft("user1", "123", factory=factory) - self.assertEqual(u"foo-1", draft2.__name__) + self.assertEqual("foo-1", draft2.__name__) self.assertTrue(draft2.__name__ in self.storage.drafts["user1"]["123"]) def test_discardDrafts(self): @@ -145,17 +144,17 @@ def test_discardDraft_keep_user(self): def test_discardDraft_not_found(self): self.storage.createDraft("user1", "123") - draft = Draft("user1", "123", u"bogus") + draft = Draft("user1", "123", "bogus") self.storage.discardDraft(draft) def test_discardDraft_no_key(self): self.storage.createDraft("user1", "123") - draft = Draft("user1", "234", u"draft") + draft = Draft("user1", "234", "draft") self.storage.discardDraft(draft) def test_discardDraft_no_user(self): self.storage.createDraft("user1", "123") - draft = Draft("user2", "123", u"draft") + draft = Draft("user2", "123", "draft") self.storage.discardDraft(draft) def test_getDrafts(self): @@ -182,7 +181,7 @@ def test_getDraft_found(self): def test_getDraft_not_found(self): self.storage.createDraft("user1", "123") - self.assertEqual(None, self.storage.getDraft("user1", "123", u"bogus")) + self.assertEqual(None, self.storage.getDraft("user1", "123", "bogus")) def test_getDraft_no_key(self): draft = self.storage.createDraft("user1", "123") @@ -211,32 +210,32 @@ def test_attributes(self): self.folder.invokeFactory("Document", "d1") target = self.folder["d1"] - target.title = u"Old title" + target.title = "Old title" draft = Draft() draft.someAttribute = 1 proxy = DraftProxy(draft, target) - self.assertEqual(u"Old title", proxy.title) + self.assertEqual("Old title", proxy.title) self.assertEqual(1, proxy.someAttribute) - proxy.title = u"New title" + proxy.title = "New title" - self.assertEqual(u"New title", proxy.title) + self.assertEqual("New title", proxy.title) def test_attribute_deletion(self): self.folder.invokeFactory("Document", "d1") target = self.folder["d1"] - target.title = u"Old title" - target.description = u"Old description" + target.title = "Old title" + target.description = "Old description" draft = Draft() draft.someAttribute = 1 - draft.description = u"New description" + draft.description = "New description" proxy = DraftProxy(draft, target) @@ -245,7 +244,7 @@ def test_attribute_deletion(self): del proxy.description self.assertEqual( - set(["someAttribute", "title", "description"]), + {"someAttribute", "title", "description"}, draft._proxyDeleted, ) @@ -257,8 +256,8 @@ def test_attribute_deletion(self): self.assertFalse(hasattr(proxy, "title")) self.assertFalse(hasattr(proxy, "description")) - self.assertEqual(u"Old title", target.title) - self.assertEqual(u"Old description", target.description) + self.assertEqual("Old title", target.title) + self.assertEqual("Old description", target.description) def test_interfaces(self): @@ -281,58 +280,58 @@ def test_annotations(self): target = self.folder["d1"] targetAnnotations = IAnnotations(target) - targetAnnotations[u"test.key"] = 123 - targetAnnotations[u"other.key"] = 456 + targetAnnotations["test.key"] = 123 + targetAnnotations["other.key"] = 456 draft = Draft() draftAnnotations = IAnnotations(draft) - draftAnnotations[u"some.key"] = 234 + draftAnnotations["some.key"] = 234 proxy = DraftProxy(draft, target) proxyAnnotations = IAnnotations(proxy) - self.assertEqual(123, proxyAnnotations[u"test.key"]) - self.assertEqual(234, proxyAnnotations[u"some.key"]) + self.assertEqual(123, proxyAnnotations["test.key"]) + self.assertEqual(234, proxyAnnotations["some.key"]) - proxyAnnotations[u"test.key"] = 789 + proxyAnnotations["test.key"] = 789 - self.assertEqual(789, proxyAnnotations[u"test.key"]) - self.assertEqual(123, targetAnnotations[u"test.key"]) + self.assertEqual(789, proxyAnnotations["test.key"]) + self.assertEqual(123, targetAnnotations["test.key"]) # Annotations API - self.assertEqual(789, proxyAnnotations.get(u"test.key")) + self.assertEqual(789, proxyAnnotations.get("test.key")) keys = proxyAnnotations.keys() - self.assertTrue(u"test.key" in keys) - self.assertTrue(u"some.key" in keys) - self.assertTrue(u"other.key" in keys) - - self.assertEqual(789, proxyAnnotations.setdefault(u"test.key", -1)) - self.assertEqual(234, proxyAnnotations.setdefault(u"some.key", -1)) - self.assertEqual(456, proxyAnnotations.setdefault(u"other.key", -1)) - self.assertEqual(-1, proxyAnnotations.setdefault(u"new.key", -1)) - - del proxyAnnotations[u"test.key"] - self.assertFalse(u"test.key" in proxyAnnotations) - self.assertFalse(u"test.key" in draftAnnotations) - self.assertTrue(u"test.key" in targetAnnotations) - self.assertTrue(u"test.key" in draft._proxyAnnotationsDeleted) - - del proxyAnnotations[u"some.key"] - self.assertFalse(u"some.key" in proxyAnnotations) - self.assertFalse(u"some.key" in draftAnnotations) - self.assertFalse(u"some.key" in targetAnnotations) - self.assertTrue(u"some.key" in draft._proxyAnnotationsDeleted) + self.assertTrue("test.key" in keys) + self.assertTrue("some.key" in keys) + self.assertTrue("other.key" in keys) + + self.assertEqual(789, proxyAnnotations.setdefault("test.key", -1)) + self.assertEqual(234, proxyAnnotations.setdefault("some.key", -1)) + self.assertEqual(456, proxyAnnotations.setdefault("other.key", -1)) + self.assertEqual(-1, proxyAnnotations.setdefault("new.key", -1)) + + del proxyAnnotations["test.key"] + self.assertFalse("test.key" in proxyAnnotations) + self.assertFalse("test.key" in draftAnnotations) + self.assertTrue("test.key" in targetAnnotations) + self.assertTrue("test.key" in draft._proxyAnnotationsDeleted) + + del proxyAnnotations["some.key"] + self.assertFalse("some.key" in proxyAnnotations) + self.assertFalse("some.key" in draftAnnotations) + self.assertFalse("some.key" in targetAnnotations) + self.assertTrue("some.key" in draft._proxyAnnotationsDeleted) # this key was never in the proxy/draft - del proxyAnnotations[u"other.key"] - self.assertFalse(u"other.key" in proxyAnnotations) - self.assertFalse(u"other.key" in draftAnnotations) - self.assertTrue(u"other.key" in targetAnnotations) - self.assertTrue(u"other.key" in draft._proxyAnnotationsDeleted) + del proxyAnnotations["other.key"] + self.assertFalse("other.key" in proxyAnnotations) + self.assertFalse("other.key" in draftAnnotations) + self.assertTrue("other.key" in targetAnnotations) + self.assertTrue("other.key" in draft._proxyAnnotationsDeleted) class TestDraftSyncer(unittest.TestCase): @@ -340,7 +339,7 @@ class TestDraftSyncer(unittest.TestCase): layer = DRAFTS_INTEGRATION_TESTING def test_syncDraft(self): - class Target(object): + class Target: pass draft = Draft() @@ -351,7 +350,7 @@ class Target(object): @adapter(Draft, Target) @implementer(IDraftSyncer) - class Syncer1(object): + class Syncer1: def __init__(self, draft, target): self.draft = draft self.target = target @@ -359,11 +358,11 @@ def __init__(self, draft, target): def __call__(self): self.target.a1 = self.draft.a1 - provideAdapter(Syncer1, name=u"s1") + provideAdapter(Syncer1, name="s1") @adapter(Draft, Target) @implementer(IDraftSyncer) - class Syncer2(object): + class Syncer2: def __init__(self, draft, target): self.draft = draft self.target = target @@ -371,7 +370,7 @@ def __init__(self, draft, target): def __call__(self): self.target.a2 = self.draft.a2 - provideAdapter(Syncer2, name=u"s2") + provideAdapter(Syncer2, name="s2") syncDraft(draft, target) @@ -392,8 +391,8 @@ def test_userId(self): current = ICurrentDraftManagement(request) self.assertEqual(TEST_USER_ID, current.userId) - current.userId = u"third-user" - self.assertEqual(u"third-user", current.userId) + current.userId = "third-user" + self.assertEqual("third-user", current.userId) def test_targetKey(self): request = self.request @@ -401,13 +400,13 @@ def test_targetKey(self): current = ICurrentDraftManagement(request) self.assertEqual(None, current.targetKey) - request.set("plone.app.drafts.targetKey", u"123") - self.assertEqual(u"123", current.targetKey) + request.set("plone.app.drafts.targetKey", "123") + self.assertEqual("123", current.targetKey) - current.targetKey = u"234" - self.assertEqual(u"234", current.targetKey) + current.targetKey = "234" + self.assertEqual("234", current.targetKey) - self.assertEqual(u"123", request.get("plone.app.drafts.targetKey")) + self.assertEqual("123", request.get("plone.app.drafts.targetKey")) def test_draftName(self): request = self.request @@ -415,13 +414,13 @@ def test_draftName(self): current = ICurrentDraftManagement(request) self.assertEqual(None, current.draftName) - request.set("plone.app.drafts.draftName", u"draft-1") - self.assertEqual(u"draft-1", current.draftName) + request.set("plone.app.drafts.draftName", "draft-1") + self.assertEqual("draft-1", current.draftName) - current.draftName = u"draft-2" - self.assertEqual(u"draft-2", current.draftName) + current.draftName = "draft-2" + self.assertEqual("draft-2", current.draftName) - self.assertEqual(u"draft-1", request.get("plone.app.drafts.draftName")) + self.assertEqual("draft-1", request.get("plone.app.drafts.draftName")) def test_path(self): request = self.request @@ -429,13 +428,13 @@ def test_path(self): current = ICurrentDraftManagement(request) self.assertEqual(None, current.path) - request.set("plone.app.drafts.path", u"/test") - self.assertEqual(u"/test", current.path) + request.set("plone.app.drafts.path", "/test") + self.assertEqual("/test", current.path) - current.path = u"/test/test-1" - self.assertEqual(u"/test/test-1", current.path) + current.path = "/test/test-1" + self.assertEqual("/test/test-1", current.path) - self.assertEqual(u"/test", request.get("plone.app.drafts.path")) + self.assertEqual("/test", request.get("plone.app.drafts.path")) def test_draft(self): request = self.request @@ -443,19 +442,19 @@ def test_draft(self): current = ICurrentDraftManagement(request) self.assertEqual(None, current.draft) - current.userId = u"user1" - current.targetKey = u"123" - current.draftName = u"draft" + current.userId = "user1" + current.targetKey = "123" + current.draftName = "draft" self.assertEqual(None, current.draft) storage = getUtility(IDraftStorage) - created = storage.createDraft(u"user1", u"123") + created = storage.createDraft("user1", "123") current.draftName = created.__name__ self.assertEqual(created, current.draft) - newDraft = storage.createDraft(u"user1", u"123") + newDraft = storage.createDraft("user1", "123") current.draft = newDraft self.assertEqual(newDraft, current.draft) @@ -484,7 +483,7 @@ def test_mark(self): current.mark() self.assertFalse(IDrafting.providedBy(request)) - current.targetKey = u"123" + current.targetKey = "123" current.mark() self.assertTrue(IDrafting.providedBy(request)) @@ -500,32 +499,32 @@ def test_save(self): self.assertFalse("plone.app.drafts.userId" in response.cookies) self.assertFalse("plone.app.drafts.path" in response.cookies) - current.targetKey = u"123" + current.targetKey = "123" self.assertEqual(True, current.save()) self.assertEqual( - {"value": "123", "quoted": True, "path": "/"}, + {"value": "123", "Path": "/"}, response.cookies["plone.app.drafts.targetKey"], ) self.assertFalse("plone.app.drafts.draftName" in response.cookies) self.assertFalse("plone.app.drafts.path" in response.cookies) - current.targetKey = u"123" - current.draftName = u"draft-1" + current.targetKey = "123" + current.draftName = "draft-1" self.assertEqual(True, current.save()) self.assertEqual( - {"value": "123", "quoted": True, "path": "/"}, + {"value": "123", "Path": "/"}, response.cookies["plone.app.drafts.targetKey"], ) self.assertEqual( - {"value": "draft-1", "quoted": True, "path": "/"}, + {"value": "draft-1", "Path": "/"}, response.cookies["plone.app.drafts.draftName"], ) self.assertFalse("plone.app.drafts.path" in response.cookies) - current.targetKey = u"123" - current.draftName = u"draft-1" + current.targetKey = "123" + current.draftName = "draft-1" current.path = "/test" # clear data @@ -535,15 +534,15 @@ def test_save(self): self.assertEqual(True, current.save()) self.assertEqual( - {"value": "123", "quoted": True, "path": "/test"}, + {"value": "123", "Path": "/test"}, response.cookies["plone.app.drafts.targetKey"], ) self.assertEqual( - {"value": "draft-1", "quoted": True, "path": "/test"}, + {"value": "draft-1", "Path": "/test"}, response.cookies["plone.app.drafts.draftName"], ) self.assertEqual( - {"value": "/test", "quoted": True, "path": "/test"}, + {"value": "/test", "Path": "/test"}, response.cookies["plone.app.drafts.path"], ) @@ -566,10 +565,9 @@ def test_discard(self): pass deletedToken = { - "expires": expires, - "max_age": 0, - "path": "/", - "quoted": True, + "Expires": expires, + "Max-Age": "0", + "Path": "/", "value": "deleted", } @@ -589,7 +587,7 @@ def test_discard(self): current.path = "/test" current.discard() - deletedToken["path"] = "/test" + deletedToken["Path"] = "/test" self.assertEqual( deletedToken, @@ -678,9 +676,9 @@ def test_getCurrentDraft_draft_details_set_not_in_storage(self): request = self.request management = ICurrentDraftManagement(request) - management.userId = u"user1" - management.targetKey = u"123" - management.draftName = u"bogus" + management.userId = "user1" + management.targetKey = "123" + management.draftName = "bogus" draft = getCurrentDraft(request) self.assertEqual(None, draft) @@ -693,12 +691,12 @@ def test_getCurrentDraft_draft_details_set_not_in_storage_create(self): request = self.request management = ICurrentDraftManagement(request) - management.userId = u"user1" - management.targetKey = u"123" - management.draftName = u"bogus" + management.userId = "user1" + management.targetKey = "123" + management.draftName = "bogus" draft = getCurrentDraft(request, create=True) - inStorage = getUtility(IDraftStorage).getDraft(u"user1", u"123", draft.__name__) + inStorage = getUtility(IDraftStorage).getDraft("user1", "123", draft.__name__) self.assertEqual(inStorage, draft) @@ -718,11 +716,11 @@ def test_getCurrentDraft_draft_details_set_not_in_storage_create(self): def test_getCurrentDraft_draft_details_set_in_storage(self): request = self.request - inStorage = getUtility(IDraftStorage).createDraft(u"user1", u"123") + inStorage = getUtility(IDraftStorage).createDraft("user1", "123") management = ICurrentDraftManagement(request) - management.userId = u"user1" - management.targetKey = u"123" + management.userId = "user1" + management.targetKey = "123" management.draftName = inStorage.__name__ draft = getCurrentDraft(request) @@ -735,11 +733,11 @@ def test_getCurrentDraft_draft_details_set_in_storage(self): def test_getCurrentDraft_draft_details_set_in_storage_create(self): request = self.request - inStorage = getUtility(IDraftStorage).createDraft(u"user1", u"123") + inStorage = getUtility(IDraftStorage).createDraft("user1", "123") management = ICurrentDraftManagement(request) - management.userId = u"user1" - management.targetKey = u"123" + management.userId = "user1" + management.targetKey = "123" management.draftName = inStorage.__name__ draft = getCurrentDraft(request, create=True) @@ -788,9 +786,9 @@ def test_add_to_portal_root_cancel(self): # We should now have cookies with the drafts information cookies = browser.cookies.forURL(browser.url) - self.assertEqual('"/plone"', cookies["plone.app.drafts.path"]) + self.assertEqual("/plone", cookies["plone.app.drafts.path"]) self.assertEqual( - '"{0}"'.format(self.get_portal_target_key()), + f"{self.get_portal_target_key()}", cookies["plone.app.drafts.targetKey"], ) self.assertNotIn( @@ -828,9 +826,9 @@ def test_add_to_portal_root_save(self): # We should now have cookies with the drafts information cookies = browser.cookies.forURL(browser.url) - self.assertEqual('"/plone"', cookies["plone.app.drafts.path"]) + self.assertEqual("/plone", cookies["plone.app.drafts.path"]) self.assertEqual( - '"{0}"'.format(self.get_portal_target_key()), + f"{self.get_portal_target_key()}", cookies["plone.app.drafts.targetKey"], ) self.assertNotIn( @@ -847,16 +845,14 @@ def test_add_to_portal_root_save(self): browser.cookies.create( DRAFT_NAME_KEY, - u"draft", + "draft", path="/plone", ) # We can now fill in the required fields and save. The cookies should # expire. - browser.getControl( - name="form.widgets.IDublinCore.title" - ).value = u"New Document" + browser.getControl(name="form.widgets.IDublinCore.title").value = "New Document" browser.getControl(name="form.buttons.save").click() self.assertNotIn( "plone.app.drafts.targetKey", @@ -887,11 +883,11 @@ def test_add_to_folder(self): # We should now have cookies with the drafts information cookies = browser.cookies.forURL(browser.url) self.assertEqual( - '"{0}"'.format(self.folder.absolute_url_path()), + f"{self.folder.absolute_url_path()}", cookies["plone.app.drafts.path"], ) self.assertEqual( - '"{0}"'.format(IUUID(self.folder)), + f"{IUUID(self.folder)}", cookies["plone.app.drafts.targetKey"], ) self.assertNotIn( @@ -915,7 +911,7 @@ def test_edit(self): browser.handleErrors = False self.folder.invokeFactory("MyDocument", "d1") - self.folder["d1"].title = u"New title" + self.folder["d1"].title = "New title" transaction.commit() @@ -933,11 +929,11 @@ def test_edit(self): # We should now have cookies with the drafts information cookies = browser.cookies.forURL(browser.url) self.assertEqual( - '"{0}"'.format(self.folder["d1"].absolute_url_path()), + "{}".format(self.folder["d1"].absolute_url_path()), cookies["plone.app.drafts.path"], ) self.assertEqual( - '"{0}"'.format(uuid), + f"{uuid}", cookies["plone.app.drafts.targetKey"], ) self.assertNotIn( @@ -965,7 +961,7 @@ def test_edit_existing_draft(self): browser.handleErrors = False self.folder.invokeFactory("MyDocument", "d1") - self.folder["d1"].title = u"New title" + self.folder["d1"].title = "New title" uuid = IUUID(self.folder["d1"]) @@ -987,19 +983,19 @@ def test_edit_existing_draft(self): # We should now have cookies with the drafts information cookies = browser.cookies.forURL(browser.url) self.assertEqual( - '"{0}"'.format(self.folder["d1"].absolute_url_path()), + "{}".format(self.folder["d1"].absolute_url_path()), cookies["plone.app.drafts.path"], ) self.assertEqual( - '"{0}"'.format(uuid), + f"{uuid}", cookies["plone.app.drafts.targetKey"], ) self.assertEqual( - '"{0}"'.format(TEST_USER_ID), + f"{TEST_USER_ID}", cookies["plone.app.drafts.userId"], ) self.assertEqual( - '"{0}"'.format(draft.__name__), + f"{draft.__name__}", cookies["plone.app.drafts.draftName"], ) @@ -1027,7 +1023,7 @@ def test_edit_multiple_existing_drafts(self): browser.handleErrors = False self.folder.invokeFactory("MyDocument", "d1") - self.folder["d1"].title = u"New title" + self.folder["d1"].title = "New title" transaction.commit() @@ -1050,11 +1046,11 @@ def test_edit_multiple_existing_drafts(self): # We should now have cookies with the drafts information cookies = browser.cookies.forURL(browser.url) self.assertEqual( - '"{0}"'.format(self.folder["d1"].absolute_url_path()), + "{}".format(self.folder["d1"].absolute_url_path()), cookies["plone.app.drafts.path"], ) self.assertEqual( - '"{0}"'.format(uuid), + f"{uuid}", cookies["plone.app.drafts.targetKey"], ) self.assertNotIn( diff --git a/plone/app/drafts/utils.py b/src/plone/app/drafts/utils.py similarity index 98% rename from plone/app/drafts/utils.py rename to src/plone/app/drafts/utils.py index db7d4d9..74ba3fc 100644 --- a/plone/app/drafts/utils.py +++ b/src/plone/app/drafts/utils.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from AccessControl import getSecurityManager from plone.app.drafts.interfaces import ICurrentDraftManagement from plone.app.drafts.interfaces import IDraftStorage diff --git a/test-5.2.cfg b/test-5.2.cfg deleted file mode 100644 index d1e31d8..0000000 --- a/test-5.2.cfg +++ /dev/null @@ -1,26 +0,0 @@ -[buildout] -extends = - https://raw.githubusercontent.com/collective/buildout.plonetest/master/test-5.2.x.cfg - https://raw.githubusercontent.com/collective/buildout.plonetest/master/qa.cfg - -package-name = plone.app.drafts -package-extras = [test] -package-min-coverage = 80 -parts+= - createcoverage - coverage-sh - code-analysis - -[code-analysis] -directory = plone -# E203 Whitespace before ':' (false positives when using black) -# E231 missing whitespace after ',' (conflicts with black) -# E501 line too long -# W503 Line break occurred before a binary operator [outdated] -flake8-ignore = E203,E231,E501,W503 - -[versions] -# plone.app.drafts is pinned in core, so we must unpin it here. -plone.app.drafts = -setuptools = 41.2.0 -zc.buildout = 2.13.3 diff --git a/test-6.0.cfg b/test-6.0.cfg deleted file mode 100644 index 0a924a5..0000000 --- a/test-6.0.cfg +++ /dev/null @@ -1,54 +0,0 @@ -[buildout] -extends = - https://raw.githubusercontent.com/plone/buildout.coredev/6.0/sources.cfg - https://raw.githubusercontent.com/plone/buildout.coredev/6.0/checkouts.cfg - https://raw.githubusercontent.com/plone/buildout.coredev/6.0/versions.cfg - https://raw.githubusercontent.com/collective/buildout.plonetest/master/qa.cfg - -parts = - instance - test - code-analysis - createcoverage - -extensions = mr.developer -versions = versions -package-name = plone.app.drafts -package-extras = [test] -test-eggs = -develop = . - -[instance] -recipe = plone.recipe.zope2instance -user = ${buildout:plone-user} -wsgi = on -eggs = - Plone - plone.app.upgrade - ${buildout:package-name} - ${buildout:eggs} -deprecation-warnings = on -environment-vars = - zope_i18n_compile_mo_files true -zcml = - ${buildout:package-name} - -[test] -recipe = zc.recipe.testrunner -defaults = ['-s', '${buildout:package-name}', '--auto-color', '--auto-progress'] -eggs = - Plone - plone.app.upgrade - ${buildout:package-name} ${buildout:package-extras} - ${buildout:test-eggs} - -[code-analysis] -directory= ${buildout:directory}/plone/app/tiles -flake8-ignore = E203,E231,E501,W503 - -[versions] -plone.app.drafts = -setuptools = -zc.buildout = -coverage = >=3.7 -plone.app.robotframework = 1.5.0 diff --git a/tox.ini b/tox.ini index b33a469..ef633eb 100644 --- a/tox.ini +++ b/tox.ini @@ -1,18 +1,238 @@ +# Generated from: +# https://github.com/plone/meta/tree/main/src/plone/meta/default +# See the inline comments on how to expand/tweak this configuration file [tox] -minversion = 3.18 +# We need 4.4.0 for constrain_package_deps. +min_version = 4.4.0 envlist = - plone52-py{37,38,39} - plone60-py{37,38,39} + lint + test + py313-plone62 + py312-plone62 + py311-plone62 + py310-plone62 + dependencies + + +## +# Add extra configuration options in .meta.toml: +# - to specify a custom testing combination of Plone and python versions, use `test_matrix` +# Use ["*"] to use all supported Python versions for this Plone version. +# - to specify extra custom environments, use `envlist_lines` +# - to specify extra `tox` top-level options, use `config_lines` +# [tox] +# test_matrix = {"6.2" = ["3.13", "3.12"], "6.1" = ["*"]} +# envlist_lines = """ +# my_other_environment +# """ +# config_lines = """ +# my_extra_top_level_tox_configuration_lines +# """ +## + +[testenv:init] +description = Prepare environment +skip_install = true +allowlist_externals = + echo +commands = + echo "Initial setup complete" + +[testenv:format] +description = automatically reformat code +skip_install = true +deps = + pre-commit +commands = + pre-commit run -a pyupgrade + pre-commit run -a isort + pre-commit run -a black + pre-commit run -a zpretty + +[testenv:lint] +description = run linters that will help improve the code style +skip_install = true +deps = + pre-commit +commands = + pre-commit run -a + +[testenv:dependencies] +description = check if the package defines all its dependencies +skip_install = true +deps = + build + z3c.dependencychecker==2.14.3 +commands = + 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 = + pipdeptree==2.5.1 + graphviz # optional dependency of pipdeptree +commands = + sh -c 'pipdeptree --exclude setuptools,wheel,pipdeptree,zope.interface,zope.component --graph-output svg > dependencies.svg' + + +[test_runner] +deps = zope.testrunner +test = + zope-testrunner --all --test-path={toxinidir}/src -s plone.app.drafts {posargs} +coverage = + coverage run --branch --source plone.app.drafts {envbindir}/zope-testrunner --quiet --all --test-path={toxinidir}/src -s plone.app.drafts {posargs} + coverage report -m --format markdown + coverage xml + coverage html + +[base] +description = shared configuration for tests and coverage +use_develop = true +skip_install = false +constrain_package_deps = true +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 = + {[test_runner]deps} + plone62: -c https://dist.plone.org/release/6.2-dev/constraints.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" +## +extras = + test + + +## +# Add extra configuration options in .meta.toml: +# [tox] +# test_extras = """ +# tests +# widgets +# """ +# +# Add extra configuration options in .meta.toml: +# [tox] +# testenv_options = """ +# basepython = /usr/bin/python3.8 +# """ +## + +[testenv:test] +description = run the distribution tests +use_develop = {[base]use_develop} +skip_install = {[base]skip_install} +constrain_package_deps = {[base]constrain_package_deps} +set_env = {[base]set_env} +deps = + {[test_runner]deps} + -c https://dist.plone.org/release/6.2-dev/constraints.txt + +commands = {[test_runner]test} +extras = {[base]extras} + [testenv] -# We do not install with pip, but with buildout: -usedevelop = false +description = run the distribution tests (generative environments) +use_develop = {[base]use_develop} +skip_install = {[base]skip_install} +constrain_package_deps = {[base]constrain_package_deps} +set_env = {[base]set_env} +deps = {[base]deps} +commands = {[test_runner]test} +extras = {[base]extras} + + +[testenv:coverage] +description = get a test coverage report +use_develop = {[base]use_develop} +skip_install = {[base]skip_install} +constrain_package_deps = {[base]constrain_package_deps} +set_env = {[base]set_env} +deps = + {[test_runner]deps} + coverage + -c https://dist.plone.org/release/6.2-dev/constraints.txt + +commands = {[test_runner]coverage} +extras = {[base]extras} + + +[testenv:release-check] +description = ensure that the distribution is ready to release skip_install = true deps = - zc.buildout -commands_pre = - plone52: {envbindir}/buildout -Nc {toxinidir}/test-5.2.cfg buildout:directory={envdir} buildout:develop={toxinidir} install test code-analysis - plone60: {envbindir}/buildout -Nc {toxinidir}/test-6.0.cfg buildout:directory={envdir} buildout:develop={toxinidir} install test code-analysis + twine + build + towncrier + -c https://dist.plone.org/release/6.2-dev/constraints.txt commands = - {envbindir}/code-analysis {toxinidir}/plone/app/drafts - {envbindir}/test + # fake version to not have to install the package + # we build the change log as news entries might break + # the README that is displayed on PyPI + towncrier build --version=100.0.0 --yes + 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 https://dist.plone.org/release/6.2-dev/constraints.txt +commands = + # 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_ +# """ +##