diff --git a/.meta.toml b/.meta.toml
index 46eeeeff..e6f53a10 100644
--- a/.meta.toml
+++ b/.meta.toml
@@ -7,7 +7,7 @@ commit-id = "55bda5c9"
[pyproject]
codespell_ignores = "hove"
-dependencies_ignores = "['plone.app.relationfield', 'plone.directives.form', 'plone.directives.dexterity', 'five.grok', 'plone.app.intid', 'plone.contentrules', 'plone.schema', 'z3c.relationfield']"
+dependencies_ignores = "['plone.app.content', 'plone.app.relationfield', 'plone.directives.form', 'plone.directives.dexterity', 'five.grok', 'plone.app.intid', 'plone.contentrules', 'plone.schema', 'z3c.relationfield']"
[flake8]
extra_lines = """
diff --git a/news/3858.internal b/news/3858.internal
new file mode 100644
index 00000000..3fde256c
--- /dev/null
+++ b/news/3858.internal
@@ -0,0 +1,3 @@
+Make the dependency on ``plone.app.content`` conditional.
+This is for ``INameFromTitle``, which we want to move to ``plone.base``.
+[maurits]
diff --git a/plone/app/dexterity/behaviors/configure.zcml b/plone/app/dexterity/behaviors/configure.zcml
index c28738fe..aee0d089 100644
--- a/plone/app/dexterity/behaviors/configure.zcml
+++ b/plone/app/dexterity/behaviors/configure.zcml
@@ -59,23 +59,31 @@
for="plone.dexterity.interfaces.IDexterityContent"
/>
-
-
+
+
+
+
-
-
+
+
-
+
+
>> portal = layer['portal']
- >>> from plone.dexterity.fti import DexterityFTI
- >>> fti = DexterityFTI('dinosaur')
- >>> portal.portal_types._setObject('dinosaur', fti)
- 'dinosaur'
- >>> fti.klass = 'plone.dexterity.content.Container'
- >>> fti.filter_content_types = False
-
-We can declare that it supports the "name from title" behavior defined in
-plone.app.content (normally this would be done via Generic Setup)::
-
- >>> fti.behaviors = ('plone.app.content.interfaces.INameFromTitle',
- ... 'plone.app.dexterity.behaviors.metadata.IBasic')
-
-Now let's fire up the browser and confirm that new content gets renamed
-appropriately::
-
- >>> from plone.app.testing import TEST_USER_ID, TEST_USER_NAME, TEST_USER_PASSWORD, setRoles
- >>> setRoles(portal, TEST_USER_ID, ['Manager'])
- >>> import transaction; transaction.commit()
- >>> from plone.testing.z2 import Browser
- >>> browser = Browser(layer['app'])
- >>> browser.addHeader('Authorization', 'Basic %s:%s' % (TEST_USER_NAME, TEST_USER_PASSWORD,))
-
- >>> browser.open('http://nohost/plone/++add++dinosaur')
- >>> browser.getControl('Title').value = 'Brachiosaurus'
- >>> browser.getControl('Save').click()
- >>> browser.url
- 'http://nohost/plone/brachiosaurus/view'
-
-
-Title-to-id within a Dexterity container
-----------------------------------------
-
-Does it still work if we're adding content within a Dexterity container? Let's
-check::
-
- >>> browser.open('http://nohost/plone/brachiosaurus/++add++dinosaur')
- >>> browser.getControl('Title').value = 'Baby Brachiosaurus'
- >>> browser.getControl('Save').click()
- >>> browser.url
- 'http://nohost/plone/brachiosaurus/baby-brachiosaurus/view'
diff --git a/plone/app/dexterity/tests/test_doctests.py b/plone/app/dexterity/tests/test_doctests.py
index ecdfce99..6b361554 100644
--- a/plone/app/dexterity/tests/test_doctests.py
+++ b/plone/app/dexterity/tests/test_doctests.py
@@ -8,7 +8,6 @@
tests = (
"discussion.txt",
"editing.rst",
- "namefromtitle.txt",
"metadata.txt",
"nextprevious.txt",
"filename.txt",
diff --git a/plone/app/dexterity/tests/test_namefromtitle.py b/plone/app/dexterity/tests/test_namefromtitle.py
new file mode 100644
index 00000000..94d137b7
--- /dev/null
+++ b/plone/app/dexterity/tests/test_namefromtitle.py
@@ -0,0 +1,84 @@
+from plone.app.dexterity.testing import DEXTERITY_FUNCTIONAL_TESTING
+from plone.app.testing import setRoles
+from plone.app.testing import TEST_USER_ID
+from plone.app.testing import TEST_USER_NAME
+from plone.app.testing import TEST_USER_PASSWORD
+from plone.dexterity.fti import DexterityFTI
+from plone.testing.zope import Browser
+
+import transaction
+import unittest
+
+
+def add_dinosaur_type(portal, behavior_name):
+ fti = DexterityFTI("dinosaur")
+ portal.portal_types._setObject("dinosaur", fti)
+ fti.klass = "plone.dexterity.content.Container"
+ fti.filter_content_types = False
+ fti.behaviors = (
+ behavior_name,
+ "plone.basic",
+ )
+ return fti
+
+
+class NameFromTitleFunctionalTest(unittest.TestCase):
+ """Test name-from-title using named behavior."""
+
+ layer = DEXTERITY_FUNCTIONAL_TESTING
+ behavior_name = "plone.namefromtitle"
+
+ def setUp(self):
+ app = self.layer["app"]
+ self.portal = self.layer["portal"]
+ self.request = self.layer["request"]
+ setRoles(self.portal, TEST_USER_ID, ["Manager"])
+ self.portal_url = self.portal.absolute_url()
+
+ # Say we have a 'Dinosaur' content type:
+ self.fti = add_dinosaur_type(self.portal, self.behavior_name)
+
+ transaction.commit()
+ self.browser = Browser(app)
+ self.browser.handleErrors = False
+ self.browser.addHeader(
+ "Authorization",
+ "Basic {}:{}".format(
+ TEST_USER_NAME,
+ TEST_USER_PASSWORD,
+ ),
+ )
+
+ def test_create(self):
+ self.browser.open(f"{self.portal_url}/++add++dinosaur")
+ self.browser.getControl("Title").value = "Brachiosaurus"
+ self.browser.getControl("Save").click()
+ self.assertEqual(self.browser.url, f"{self.portal_url}/brachiosaurus/view")
+
+ # Does it still work if we are adding content within a container?
+ self.browser.open(f"{self.portal_url}/brachiosaurus/++add++dinosaur")
+ self.browser.getControl("Title").value = "Baby Brachiosaurus"
+ self.browser.getControl("Save").click()
+ self.assertEqual(
+ self.browser.url,
+ f"{self.portal_url}/brachiosaurus/baby-brachiosaurus/view",
+ )
+
+
+class PloneAppContentNameFromTitleFunctionalTest(NameFromTitleFunctionalTest):
+ """Test name-from-title using old plone.app.content behavior interface."""
+
+ behavior_name = "plone.app.content.interfaces.INameFromTitle"
+
+
+# We could test that you can use the new interface location as behavior name,
+# but this fails, and this is fine: it was never supported.
+# In all cases the named behavior is recommended.
+#
+# class PloneBaseNameFromTitleFunctionalTest(NameFromTitleFunctionalTest):
+# """Test name-from-title using new plone.base behavior interface."""
+# behavior_name = "plone.base.interfaces.INameFromTitle"
+
+
+def test_suite():
+ return unittest.defaultTestLoader.loadTestsFromName(__name__)
diff --git a/pyproject.toml b/pyproject.toml
index 6e0a8720..3aac14c1 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -92,7 +92,7 @@ Zope = [
'Products.CMFCore', 'Products.CMFDynamicViewFTI',
]
python-dateutil = ['dateutil']
-ignore-packages = ['plone.app.relationfield', 'plone.directives.form', 'plone.directives.dexterity', 'five.grok', 'plone.app.intid', 'plone.contentrules', 'plone.schema', 'z3c.relationfield']
+ignore-packages = ['plone.app.content', 'plone.app.relationfield', 'plone.directives.form', 'plone.directives.dexterity', 'five.grok', 'plone.app.intid', 'plone.contentrules', 'plone.schema', 'z3c.relationfield']
##
# Add extra configuration options in .meta.toml:
diff --git a/setup.py b/setup.py
index 43b15267..84f69e45 100644
--- a/setup.py
+++ b/setup.py
@@ -62,7 +62,6 @@
# Plone/Zope core
"lxml",
"plone.base",
- "plone.app.content",
"plone.app.uuid",
"plone.app.z3cform>=1.1.0",
"plone.autoform>=1.1",