This is on a Mac (macOS Sequoia 15.5), with Plone 6.1.2.
I first invoked uvx cookieplone to create a “Backend Add-on for Plone”.
Then, inside the generated directory tree’s src subdirectory, I invoked make add content_type
which gave the error:
AttributeError: module 'case_conversion' has no attribute 'pascalcase'
(see the full error stack at the end of this post)
How can I check which release of case_conversion I have in here? The paths are confusing because uv has its cache, and
% pip show case-conversion
WARNING: Package(s) not found: case-conversion
% make add content_type
==> Generate constraints file
###############################################################################
# Load configuration
Can not parse override:
###############################################################################
# Read infiles
Read [r]: requirements.txt
Read [c]: https://dist.plone.org/release/6.1.2/constraints.txt
###############################################################################
# No sources configured!
###############################################################################
# Write outfiles
Write [c]: constraints-mxdev.txt
Write [r]: requirements-mxdev.txt
🎂 You are now ready for: pip install -r requirements-mxdev.txt
(path to pip may vary dependent on your installation method)
==> Install environment
Using CPython 3.10.15 interpreter at: /opt/homebrew/opt/python@3.10/bin/python3.10
Creating virtual environment at: .venv
Activate with: source .venv/bin/activate
Resolved 291 packages in 3.33s
Built triangle-notes @ file:///Users/bubba/src/triangle.notes
Prepared 31 packages in 718ms
Installed 291 packages in 1.77s
+ accesscontrol==7.2
+ acquisition==6.1
+ attrs==25.3.0
+ authencoding==6.0
+ babel==2.16.0
+ beautifulsoup4==4.12.3
+ borg-localrole==3.1.11
+ btrees==6.1
+ certifi==2024.12.14
+ cffi==1.17.1
+ chameleon==4.4.4
+ charset-normalizer==3.4.1
+ click==8.2.1
+ collective-mockmailhost==3.0.0
+ collective-monkeypatcher==2.0.0
+ coverage==7.8.2
+ cssselect==1.3.0
+ datetime==5.5
+ decorator==5.2.1
+ diazo==2.0.3
+ documenttemplate==4.6
+ docutils==0.21.2
+ exceptiongroup==1.3.0
+ extensionclass==6.0
+ feedparser==6.0.11
+ five-customerize==4.0
+ five-intid==3.0.1
+ five-localsitemanager==5.0
+ furl==2.1.4
+ grpcio==1.70.0
+ grpcio-tools==1.70.0
+ gunicorn==23.0.0
+ h11==0.16.0
+ horse-with-no-namespace==20250705.0
+ icalendar==6.3.1
+ idna==3.10
+ iniconfig==2.1.0
+ jsonschema==4.24.0
+ jsonschema-specifications==2025.4.1
+ lxml==5.4.0
+ lxml-html-clean==0.4.2
+ markdown==3.8
+ missing==5.0
+ multimapping==5.0
+ multipart==1.2.1
+ natsort==8.4.0
+ orderedmultidict==1.0.1
+ outcome==1.3.0.post0
+ overrides==7.7.0
+ packaging==24.2
+ paste==3.10.1
+ pastedeploy==3.1.0
+ persistence==5.1
+ persistent==6.1
+ piexif==1.1.3
+ pillow==11.2.1
+ plone-alterego==2.0.1
+ plone-api==2.5.2
+ plone-app-caching==4.1.0
+ plone-app-content==4.1.10
+ plone-app-contentlisting==3.0.5
+ plone-app-contentmenu==3.0.7
+ plone-app-contentrules==5.0.7
+ plone-app-contenttypes==4.0.5
+ plone-app-customerize==2.0.2
+ plone-app-dexterity==4.1.0
+ plone-app-discussion==5.2.0
+ plone-app-event==5.2.2
+ plone-app-i18n==4.0.1
+ plone-app-intid==2.0.0
+ plone-app-iterate==6.2.0
+ plone-app-layout==5.0.2
+ plone-app-linkintegrity==4.0.6
+ plone-app-locales==6.0.31
+ plone-app-lockingbehavior==2.0.2
+ plone-app-multilingual==8.3.0
+ plone-app-portlets==6.0.2
+ plone-app-querystring==2.1.3
+ plone-app-redirector==3.0.4
+ plone-app-registry==2.0.6
+ plone-app-relationfield==4.0.2
+ plone-app-robotframework==2.1.5
+ plone-app-testing==7.1.1
+ plone-app-textfield==3.0.0
+ plone-app-theming==5.0.13
+ plone-app-upgrade==3.2.2
+ plone-app-users==3.1.3
+ plone-app-uuid==2.2.3
+ plone-app-versioningbehavior==2.0.4
+ plone-app-viewletmanager==4.0.4
+ plone-app-vocabularies==6.0.2
+ plone-app-workflow==5.0.4
+ plone-app-z3cform==4.7.8
+ plone-autoform==2.0.3
+ plone-autoinclude==2.0.3
+ plone-base==3.1.0
+ plone-batching==2.0.6
+ plone-behavior==2.0.2
+ plone-browserlayer==3.0.2
+ plone-cachepurging==3.0.2
+ plone-caching==2.0.1
+ plone-classicui==1.0.1
+ plone-contentrules==3.0.1
+ plone-dexterity==3.0.7
+ plone-distribution==3.2.0
+ plone-event==2.0.2
+ plone-exportimport==1.1.0
+ plone-folder==4.0.1
+ plone-formwidget-namedfile==3.1.1
+ plone-formwidget-recurrence==3.0.5
+ plone-i18n==5.1.0
+ plone-indexer==2.0.1
+ plone-intelligenttext==4.0.1
+ plone-keyring==4.0.2
+ plone-locking==3.0.2
+ plone-memoize==3.0.3
+ plone-namedfile==7.2.0
+ plone-outputfilters==5.0.4
+ plone-portlet-collection==4.0.4
+ plone-portlet-static==4.0.4
+ plone-portlets==3.0.2
+ plone-protect==5.0.5
+ plone-registry==2.0.1
+ plone-resource==3.0.2
+ plone-resourceeditor==4.0.1
+ plone-rest==5.0.0
+ plone-restapi==9.15.1
+ plone-rfc822==3.0.1
+ plone-scale==4.2.0
+ plone-schema==2.0.2
+ plone-schemaeditor==4.0.11
+ plone-session==4.0.5
+ plone-staticresources==2.3.0
+ plone-stringinterp==2.0.2
+ plone-subrequest==2.0.5
+ plone-supermodel==2.0.4
+ plone-testing==9.0.6
+ plone-theme==4.0.3
+ plone-transformchain==3.0.1
+ plone-uuid==2.0.1
+ plone-z3cform==2.0.5
+ plonetheme-barceloneta==3.3.0
+ pluggy==1.6.0
+ products-btreefolder2==5.1
+ products-cmfcore==3.7
+ products-cmfdifftool==4.0.4
+ products-cmfdynamicviewfti==7.0.2
+ products-cmfeditions==4.0.5
+ products-cmfplacefulworkflow==3.0.5
+ products-cmfplone==6.1.2
+ products-cmfuid==4.2
+ products-daterecurringindex==3.0.1
+ products-dcworkflow==3.0
+ products-extendedpathindex==4.0.1
+ products-externalmethod==6.0
+ products-genericsetup==5.0.0
+ products-isurlinportal==3.0.0
+ products-mailhost==6.0
+ products-mimetypesregistry==3.0.1
+ products-plonepas==8.0.5
+ products-pluggableauthservice==3.0
+ products-pluginregistry==2.0
+ products-portaltransforms==4.1.1
+ products-pythonscripts==5.1
+ products-sessions==6.0
+ products-siteerrorlog==6.0
+ products-standardcachemanagers==5.0
+ products-statusmessages==5.0.6
+ products-zcatalog==7.1
+ products-zopeversioncontrol==4.1
+ prompt-toolkit==3.0.51
+ protobuf==5.29.3
+ pycparser==2.22
+ pygments==2.19.1
+ pyjwt==2.10.1
+ pysocks==1.7.1
+ pytest==8.4.0
+ pytest-cov==6.2.1
+ pytest-plone==1.0.0a2
+ python-dateutil==2.9.0.post0
+ python-gettext==5.0
+ pytz==2024.2
+ record==4.1
+ referencing==0.36.2
+ repoze-xmliter==1.0b1
+ requests==2.32.3
+ restrictedpython==8.0
+ robotframework==6.0.2
+ robotframework-assertion-engine==3.0.3
+ robotframework-browser==19.3.1
+ robotframework-debuglibrary==2.5.0
+ robotframework-pythonlibcore==4.4.1
+ robotframework-selenium2library==3.0.0
+ robotframework-seleniumlibrary==6.1.3
+ robotframework-seleniumtestability==2.1.0
+ robotsuite==2.3.2
+ roman==5.0
+ rpds-py==0.22.3
+ seedir==0.5.0
+ selenium==4.9.1
+ setuptools==80.9.0
+ sgmllib3k==1.0.0
+ simplejson==3.20.1
+ six==1.17.0
+ sniffio==1.3.1
+ sortedcontainers==2.4.0
+ soupsieve==2.6
+ tomli==2.2.1
+ transaction==5.0
+ triangle-notes==1.0.0a0 (from file:///Users/bubba/src/triangle.notes)
+ trio==0.30.0
+ trio-websocket==0.12.2
+ typing-extensions==4.14.0
+ tzdata==2025.2
+ unidecode==1.4.0
+ urllib3==2.3.0
+ waitress==3.0.2
+ wcwidth==0.2.13
+ webob==1.8.9
+ webresource==1.2
+ webtest==3.0.3
+ wrapt==1.17.2
+ wsgiproxy2==0.5.1
+ wsproto==1.2.0
+ z3c-caching==4.0
+ z3c-form==6.0
+ z3c-formwidget-query==3.0
+ z3c-jbot==3.0
+ z3c-objpath==3.0
+ z3c-pt==5.0
+ z3c-relationfield==3.0
+ z3c-unconfigure==3.0
+ z3c-zcmlhook==3.0
+ zc-lockfile==3.0.post1
+ zc-relation==2.1
+ zconfig==4.2
+ zexceptions==5.0
+ zodb==6.0.1
+ zodbpickle==4.1.1
+ zope==5.13
+ zope-annotation==5.0
+ zope-app-locales==5.0
+ zope-browser==3.0
+ zope-browsermenu==5.0
+ zope-browserpage==5.0
+ zope-browserresource==5.1
+ zope-cachedescriptors==5.0
+ zope-component==6.0
+ zope-componentvocabulary==3.0
+ zope-configuration==6.0
+ zope-container==6.1
+ zope-contentprovider==6.0
+ zope-contenttype==5.1
+ zope-copy==5.0
+ zope-datetime==5.0.0
+ zope-deferredimport==5.0
+ zope-deprecation==5.1
+ zope-dottedname==6.0
+ zope-event==5.0
+ zope-exceptions==5.2
+ zope-filerepresentation==6.0
+ zope-globalrequest==2.0
+ zope-hookable==7.0
+ zope-i18n==5.2
+ zope-i18nmessageid==7.0
+ zope-interface==7.2
+ zope-intid==5.1
+ zope-keyreference==6.1
+ zope-lifecycleevent==5.0
+ zope-location==5.0
+ zope-pagetemplate==5.1
+ zope-processlifetime==3.0
+ zope-proxy==6.1
+ zope-ptresource==5.0
+ zope-publisher==7.3
+ zope-pytestlayer==8.3
+ zope-ramcache==3.1
+ zope-schema==7.0.1
+ zope-security==7.3
+ zope-sendmail==6.2
+ zope-sequencesort==5.0
+ zope-site==5.0
+ zope-size==5.0
+ zope-structuredtext==5.0
+ zope-tal==5.0.1
+ zope-tales==6.0
+ zope-testbrowser==7.0
+ zope-testing==5.0.1
+ zope-testrunner==7.2
+ zope-traversing==5.0
+ zope-viewlet==5.0
Built plonecli==2.5
Installed 26 packages in 84ms
RUN: mrbob bobtemplates.plone:content_type -c .mrbob.ini
Welcome to mr.bob interactive mode. Before we generate directory structure, some questions need to be answered.
Answer with a question mark to display help.
Values in square brackets at the end of the questions show the default value if there is no answer.
RUN: git status --porcelain --ignore-submodules
git status result:
----------------------------
b'A .editorconfig\nA .flake8\nA .github/workflows/ci.yml\nA .gitignore\nA .mrbob.ini\nA CHANGELOG.md\nA CONTRIBUTORS.md\nA LICENSE.GPL\nA LICENSE.md\nA Makefile\nA README.md\nA bobtemplate.cfg\nA instance.yaml\nA mx.ini\nA news/.changelog_template.jinja\nA news/.gitkeep\nA pyproject.toml\nA scripts/create_site.py\nA src/triangle/__init__.py\nA src/triangle/notes/__init__.py\nA src/triangle/notes/browser/__init__.py\nA src/triangle/notes/browser/configure.zcml\nA src/triangle/notes/browser/overrides/.gitkeep\nA src/triangle/notes/browser/static/.gitkeep\nA src/triangle/notes/configure.zcml\nA src/triangle/notes/content/__init__.py\nA src/triangle/notes/controlpanels/__init__.py\nA src/triangle/notes/controlpanels/configure.zcml\nA src/triangle/notes/dependencies.zcml\nA src/triangle/notes/indexers/__init__.py\nA src/triangle/notes/indexers/configure.zcml\nA src/triangle/notes/interfaces.py\nA src/triangle/notes/locales/__init__.py\nA src/triangle/notes/locales/__main__.py\nA src/triangle/notes/locales/en/LC_MESSAGES/triangle.notes.po\nA src/triangle/notes/locales/triangle.notes.pot\nA src/triangle/notes/permissions.zcml\nA src/triangle/notes/profiles.zcml\nA src/triangle/notes/profiles/default/browserlayer.xml\nA src/triangle/notes/profiles/default/catalog.xml\nA src/triangle/notes/profiles/default/controlpanel.xml\nA src/triangle/notes/profiles/default/diff_tool.xml\nA src/triangle/notes/profiles/default/metadata.xml\nA src/triangle/notes/profiles/default/registry/main.xml\nA src/triangle/notes/profiles/default/repositorytool.xml\nA src/triangle/notes/profiles/default/rolemap.xml\nA src/triangle/notes/profiles/default/types.xml\nA src/triangle/notes/profiles/default/types/.gitkeep\nA src/triangle/notes/profiles/uninstall/browserlayer.xml\nA src/triangle/notes/setuphandlers/__init__.py\nA src/triangle/notes/testing.py\nA src/triangle/notes/upgrades/__init__.py\nA src/triangle/notes/upgrades/configure.zcml\nA src/triangle/notes/vocabularies/__init__.py\nA src/triangle/notes/vocabularies/configure.zcml\nA tests/conftest.py\nA tests/setup/test_setup_install.py\nA tests/setup/test_setup_uninstall.py\n?? docs/\n'
--> Please commit your changes, before using a sub-template! Continue anyway? [n/y] [n]: y
--> Content type name (Allowed: _ a-z A-Z and whitespace) [Todo Task]: triangle_note
--> Content type description: Notes for Triangle Manufacturing
--> Content type icon (See https://icons.getbootstrap.com/) [puzzle]:
--> Use XML Model [n]:
--> Dexterity base class (Container/Item) [Container]:
--> Should the content type globally addable? [y]:
--> Should we filter content types to be added to this container? [n]:
--> Create a content type class [y]:
--> Activate default behaviors? [y]:
>>> reading Plone version from bobtemplate.cfg
Traceback (most recent call last):
File "/Users/bubba/.cache/uv/archive-v0/SkwULtgn14jxMfrLQGHH1/bin/plonecli", line 12, in <module>
sys.exit(cli())
^^^^^
File "/Users/bubba/.cache/uv/archive-v0/SkwULtgn14jxMfrLQGHH1/lib/python3.11/site-packages/click/core.py", line 1442, in __call__
return self.main(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/bubba/.cache/uv/archive-v0/SkwULtgn14jxMfrLQGHH1/lib/python3.11/site-packages/click/core.py", line 1363, in main
rv = self.invoke(ctx)
^^^^^^^^^^^^^^^^
File "/Users/bubba/.cache/uv/archive-v0/SkwULtgn14jxMfrLQGHH1/lib/python3.11/site-packages/click/core.py", line 1861, in invoke
rv.append(sub_ctx.command.invoke(sub_ctx))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/bubba/.cache/uv/archive-v0/SkwULtgn14jxMfrLQGHH1/lib/python3.11/site-packages/click/core.py", line 1226, in invoke
return ctx.invoke(self.callback, **ctx.params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/bubba/.cache/uv/archive-v0/SkwULtgn14jxMfrLQGHH1/lib/python3.11/site-packages/click/core.py", line 794, in invoke
return callback(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/bubba/.cache/uv/archive-v0/SkwULtgn14jxMfrLQGHH1/lib/python3.11/site-packages/click/decorators.py", line 34, in new_func
return f(get_current_context(), *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/bubba/.cache/uv/archive-v0/SkwULtgn14jxMfrLQGHH1/lib/python3.11/site-packages/plonecli/cli.py", line 128, in add
mrbobmain(mrbob_args)
File "/Users/bubba/.cache/uv/archive-v0/SkwULtgn14jxMfrLQGHH1/lib/python3.11/site-packages/mrbob/cli.py", line 175, in main
c.render()
File "/Users/bubba/.cache/uv/archive-v0/SkwULtgn14jxMfrLQGHH1/lib/python3.11/site-packages/mrbob/configurator.py", line 185, in render
f(self)
File "/Users/bubba/.cache/uv/archive-v0/SkwULtgn14jxMfrLQGHH1/lib/python3.11/site-packages/bobtemplates/plone/content_type.py", line 270, in prepare_renderer
dx_type_name_klass = get_normalized_classname(type_name)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/bubba/.cache/uv/archive-v0/SkwULtgn14jxMfrLQGHH1/lib/python3.11/site-packages/bobtemplates/plone/base.py", line 541, in get_normalized_classname
normalized_name = cc.pascalcase(name)
^^^^^^^^^^^^^
AttributeError: module 'case_conversion' has no attribute 'pascalcase'
make: *** [add] Error 1