TypeError: NoneType when creating a Site with `_create_site` in a python console

A Plone site can be created either with addPloneSite or with _create_site.

Both methods (_create_site and addPloneSite) are working fine in the zconsole.

But _create_site seems to work only in the zconsole and raises an error in a normal python console (see below).

addPloneSite on the other side works fine both in the zconsole and the normal python console.

What do I miss here?

Traceback (most recent call last):
  File "/home/map/myplone/zope_app.py", line 41, in <module>
    site = site_api._create_site(
        context=app,
    ...<8 lines>...
        },
    )
  File "/home/map/myplone/.venv/lib/python3.13/site-packages/plone/distribution/api/site.py", line 104, in _create_site
    site = handler(distribution, site, answers)
  File "/home/map/myplone/.venv/lib/python3.13/site-packages/plone/distribution/handler.py", line 44, in default_handler
    importer.import_site(content_json_path)
    ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^
  File "/home/map/myplone/.venv/lib/python3.13/site-packages/plone/exportimport/importers/__init__.py", line 58, in import_site
    report.append(importer.import_data(path))
                  ~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/home/map/myplone/.venv/lib/python3.13/site-packages/plone/exportimport/importers/content.py", line 168, in import_data
    self.request[settings.IMPORT_PATH_KEY] = base_path
    ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: 'NoneType' object does not support item assignment

To reproduce it run the following script:

In zconsole:

  • .venv/bin/zconsole run parts/client2/etc/zope.conf create_site.py

In python console:

  • .venv/bin/python create_site.py
# create_site.py
import Zope2
import transaction
from AccessControl.SecurityManagement import newSecurityManager
from OFS.Application import Application
from Products.CMFPlone.factory import addPloneSite
from Testing.makerequest import makerequest
from Zope2.Startup.run import make_wsgi_app
from plone.distribution.api import site as site_api

global_config = {
        'debug_mode': 'true',
        'debug_exceptions': 'false'
    }
zope_conf = "parts/client2/etc/zope.conf"
_ = make_wsgi_app(global_config, zope_conf)

app: Application = Zope2.app()
app = makerequest(app)
request = app.REQUEST

admin = app.acl_users.getUserById("admin")
admin = admin.__of__(app.acl_users)
newSecurityManager(None, admin)

site_id = "Plone"

if site_id in app.objectIds():
    app.manage_delObjects([site_id])
    transaction.commit()
    app._p_jar.sync()

# following works only in zconsole
# but not in normal python console
site = site_api._create_site(
    context=app,
    distribution_name='classic',
    answers={
        'site_id': 'Plone',
        'title': 'My Title',
        'description': 'My Description',
        'default_language': 'en',
        'portal_timezone': 'Europe/Berlin',
        'setup_content': True,
    },
)

# following works in zconsole and normal python console
# plone_site = addPloneSite(
#     app,
#     'Plone',
#     title='My Title',
#     description='My Description',
#     default_language='de',
#     portal_timezone='Europe/Berlin',
#     setup_content=True,
# )

transaction.commit()
app._p_jar.sync()

First. Please use addPloneSite method anyway, since the _ in _create_site indicates a internal method not meant to be used directly.

I just looked breefly into it.

It seems like addPloneSite only uses _create_site internally if you pas a distribution_name as an argument. Products.CMFPlone/Products/CMFPlone/factory.py at 6.1.1 · plone/Products.CMFPlone · GitHub

You do not, so it runs an entirely different code than _create_site does.

If you run zconsole there is some setting up happening in the background, like setting up component registry, etc. I assume the plone.distrubution create script depends on that, while the fallback in addPloneSite does not.

Edit: Your error indicates that it is missing a base_path, seems to me a missing setup part on which the _create_site method depends on.

Edit 2: Sorry I checked with plone 6 not plone 5 :slight_smile:

@maethu Thank you very much for the hint.

Indeed there is different code in zconsole.runscript(). Instead of simply

app = makerequest(app)
request = app.REQUEST

It sets:

After changing that in my code it works fine.

1 Like

Related issue in plone.exportimport: Import breaks if there isn't a global request · Issue #63 · plone/plone.exportimport · GitHub

Quite 29 years of Zope and still fighting on how to get the request :stuck_out_tongue:

The question is why there's self.request at all. If the request can be retrieved by from zope.globalrequest import getRequest, what is the idea supporting saving it at a random time in self.request? There's nothing to cache, the request is the same per... request. Or it was a way to manage subrequests?

But getRequest() requires a previous setRequest().

In some cases there is not yet a request. A request must first be made, e.g. via makerequest(), eventually be modified, and then be set via setRequest().

1 Like