Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

Latest Version Supported - Python Versions Number of PyPI downloads License Tests Coverage

Introduction

The problem with “acquisition” and publishTraverse is that the current method returns too many different URLs for the same content. For instance here is some potential url for the “kb” page of the plone.org website

and here is a generic “Plone” site with two content items “a” and “b” (folderish or not)

All the urls above returns 200 with the same content, while I would like the “canonical url” to return 200 and the other to return 404.

The behaviour described above constitute a problem because:

  • multiple url for the same content is a problem for SEO and is confusing to people. For SEO, in the latest versions Plone introduced the canonical META, but IMHO it’s just a workaround. People are confused. For example: sometimes some of my editors ask me: “I can’t remove the http://example.com/Plone/a/b/a/page. Can you do it for me?”

  • the page doesn’t seem really the same on all urls: if you open https://plone.org/documentation/kb and https://plone.org/documentation/manual/kb the second has a portlet that the first is missing

  • removing page from external cache (varnish or squid), for example after a content modification, will be a pain. This is because for the same content there could be multiple urls without any control or rules (collective.purgebyid solves this)

  • when using subsite (or multiple plone site on the same zope app) the problem is even more annoying: suppose that “a” is a subsite (marked with INavigationRoot) for http://a.example.org and “b” for http://b.example.org. Opening the url http://a.example.org/b will probably show the homepage of site “a” inside the “b” site. collective.siteisolation and probably collective.lineage do something to isolate subsite, but IMHO again are only workarounds.

Versions

Series

Plone

Implementation

2.x

6.0, 6.1, 6.2

Products.CMFCore.explicitacquisition

1.x

5.2, 6.0, 6.1, 6.2

monkey patch (this branch)

This is the 1.x series, maintained for Plone 5.2, 6.0, 6.1 and 6.2 (Zope < 6.2). Since Products.CMFCore 3.1 (i.e. Plone 6) Plone also ships a native implementation of this same idea, based on the IPubAfterTraversal event instead of a monkey patch, and the 2.x series of this package builds on that instead. That implementation only inspects the last traversed object, so it misses acquired content reached through a view that consumes further path segments – for instance:

/folder/acquired_image/@@images/image          served by 2.x, 404 with 1.x
/folder/acquired_doc/@types/Document           served by 2.x, 404 with 1.x

The monkey patch used here does not have that gap, because it checks at every traversal step. So 1.x gives more complete coverage than 2.x on every Plone version both support.

Usage

This is a monkey patch for publishTraverse method of Zope2’s ZPublisher.BaseRequest.DefaultPublishTraverse and a monkey patch for Products.Archetypes.BaseObject.BaseObject.__bobo_traverse__

By default invalid traverse is only logged as warning.

For enable raising exceptions, you need to manually modify config.py changing DRYRUN to False.

Or using plone.recipe.zope2instance >= 4.2.14, e.g.:

[instance]
recipe = plone.recipe.zope2instance
eggs =
    experimental.noacquisition
...
initialization =
   from experimental.noacquisition import config
   config.DRYRUN = False

Warning

USE AT YOUR OWN RISK

Don’t use it, if you don’t know exactly what are you doing… at least use leaving DRYRUN = True.

Other solutions

The Products.CMFPlone branch that used to be linked here, based on the IPubAfterTraversal event instead of a monkey patch, was merged into Products.CMFCore itself (3.1+) as Products.CMFCore.explicitacquisition, and is what the 2.x series of this package builds on. It still doesn’t work for all cases, at least when there is a custom traversal at the end of the request (take a look at the tests inside this package) – see Versions above.

There is also other packages with the same event based approach: collective.explicitacquisition and collective.redirectacquired

Changelog

1.1.0b1 (2026-08-27)

  • Support Zope 6.2 (Plone 6.2’s current pin): raise the paranoid version check from Zope < 6.2 to Zope < 6.3 (verified that DefaultPublishTraverse.publishTraverse is unchanged between the Zope 6.1 and 6.2 tags). dist.plone.org’s 6.2-dev/6.2-latest constraints moved from Zope 6.1.x to Zope==6.2 after 1.1.0b0 was released, which re-tripped the check. [mamico]

1.1.0b0 (2026-08-12)

  • Support Plone 6.2 (Zope 6.1): raise the paranoid version check from Zope < 6 to Zope < 6.2 (verified that DefaultPublishTraverse.publishTraverse is unchanged between Zope 5.13 and 6.1), and delegate the final publishability check to request.ensure_publishable() when available (Zope >= 5.10), falling back to the old docstring/typeCheck logic on older Zope (e.g. Plone 5.2’s Zope 4.x). ensure_publishable also understands the newer @zpublish marker, which the previous docstring-only check did not. [mamico]

  • CI: pin zc.buildout = 3.1.0 for Plone 5.2 (test-5.2.x.cfg). Plone 5.2’s own pin, 3.0.1, has a race-condition bug in _move_to_eggs_dir_and_compile() that raises a bare AssertionError instead of the real error (fixed in 3.1.0, see buildout/buildout#307). Stayed below 4.0, which requires Python >= 3.9 and would break py27/py36/py37/py38. [mamico]

  • CI: add Plone 6.1 and 6.2 to the test matrix (py310-py313), bootstrapping each from its own official https://dist.plone.org/release/<x>/requirements.txt. Comment out py27-plone52, py37-plone52 and py38-plone60 (all still work with tox locally): actions/setup-python can no longer install Python 2.7/3.7 on the ubuntu-24.04 runner image, and Plone 6.0’s current constraints pin plone.recipe.zope2instance >= 8.0.0, which requires Python >= 3.9. Also set fail-fast: false so one broken leg stops hiding the others. [mamico]

  • Replace the Bandit security check (broken: its Docker image is based on an archived Debian Buster) with ruff --select S, the equivalent ruleset. Renamed bandit.yml to sast.yaml. [mamico]

1.0.0b10 (2023-02-09)

  • Zope < 6 (no changes) [daniele-andreotti]

1.0.0b9 (2020-07-02)

  • Zope < 5 (no changes) [mamico]

1.0.0b7 (2019-12-10)

  • Zope < 4.2 (no changes) [mamico]

1.0.0b6 (2019-11-07)

  • Python3 Plone 5.2 [mamico]

1.0.0b5 (2019-06-05)

  • Zope2 2.13.28 (no changes) [mamico]

1.0.0b4 (2018-05-14)

  • Zope2 2.13.27 (no changes) [mamico]

1.0.0b3 (2017-05-09)

  • Zope2 2.13.26 (no changes) [mamico]

1.0.0b2 (2016-06-10)

  • Zope2 2.13.24 [mamico]

1.0.0b1 (2015-10-23)

  • Zope2 2.13.23 (Plone 4.3.7/5.0) [mamico]

1.0.0a5 (2014-10-31)

  • Nothing changed yet.

1.0.0a4 (2014-10-31)

  • Initial release

Release files for experimental.noacquisition 1.1.0b1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for experimental.noacquisition 1.1.0b1
File Size Uploaded
experimental_noacquisition-1.1.0b1.tar.gz 18.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for experimental.noacquisition 1.1.0b1
File Interpreter ABI Platform
experimental_noacquisition-1.1.0b1-py3-none-any.whl Python 3 none any Details

Total release size: 32.6 kB

Release files / experimental_noacquisition-1.1.0b1.tar.gz

Download URL experimental_noacquisition-1.1.0b1.tar.gz
Size 18.1 kB
Tags Source
SHA-256 checksum
How to use checksums
2a85b70de6e37cc7fb12f679e5224748d731c8c3f446cbe0db2c129bc10e1c35
BLAKE2b-256 checksum
How to use checksums
da8d16e9dff75189012515a2823288d7509311c3bdab24458deebbe958d0b2c9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.12

Release files / experimental_noacquisition-1.1.0b1-py3-none-any.whl

Download URL experimental_noacquisition-1.1.0b1-py3-none-any.whl
Size 14.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
55a715d5bd8ac3398ecb68b4e48556389635d027e85bf0cf06f4dfc493aee325
BLAKE2b-256 checksum
How to use checksums
2d22a0b0cc414f2a19a540544d758459ff5ec54de969d368abe438d24869e91e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.12
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page