Should we be using setuphandlers.post_install instead of setup_various in the future?

I noted that in setuphandlers.py the post_install method is now called by convention.

One thing that doesn't seem to work in the context of a post_install is checking for a marker file.

As I understand it, the marker file was a mechanism to prevent "leaking" of install instructions, effectively ensuring that the code only runs when the specific package installer is invoked.

Does the post_install way avoid the "leakage" issue? By extension, does this mean that we don't need to use mechanisms like marker files when using the the new post_install way?

Background
Thanks to settings in configure.zcml, post_install is the default facility provided by bobtemplates.plone

For reference, this is what I've been looking at:
https://github.com/plone/bobtemplates.plone/blob/master/bobtemplates/plone_addon/src/%2Bpackage.namespace%2B/%2Bpackage.name%2B/configure.zcml.bob

More background:
The code below fails because there is no readDataFile in the context.

def post_install(context):
    """Post install script"""
    # Do something at the end of the installation of this package.

    if context.readDataFile('acme.marker.txt') is None:
        return

    api.content.delete(api.content.get('/news'))

When I install my add-on I get the following output

Module acme.site.setuphandlers, line 13, in post_install
AttributeError: readDataFile

It seems that post_install is run in a slightly different context from the traditional setup_various. I added an importstep with setup_various to my configure.zcml and including the code above in setup_various instead of post_install, this worked flawlessly.

Upon reflection, I'm starting to wonder whether what I should have done is just forget about using readDataFile to look for a marker text file and just put everything in a post_install method instead, hence the question.

"GenericSetup" used to have two important concepts: "step" and "profile". Associated with a "GenericSetup" configuration is a set of "step"s where each step has as executable component an associate handler. When a "profile" is imported, the import context is set to the profile and then all steps are executed in this context (i.e. their handlers are executed). Most handlers have a configuration in a file; if the file is missing in the profile, such a handler does nothing in this context. However, other handlers are too specific for a general external configuration (all its configuration is directly expressed in Python code without external configuration). If executing (all) its code is potentially dangerous, an artificial (empty) configuration file is used to prevent the execution of part of its code in inappropriate contexts.

Apparently, "maurits" has introduced (in "GenericSetup 1.8.2") as new concept "pre_" and "post_handler" -- apparently documented only in "docs/CHANGES.rst". Those are not associated with a step but with a profile. Apparently, he did not anticipate a need to have external configuration, indicated by its "context" lacking a "readDataFile" method (used to read the external configuration maintained in a file). As those handlers are explicitely associated with the profile (and not a step), there is no need for an artificial configuration file to prevent the execution of part of its code during the import of "foreign" profiles.

Your reflection (at the end of your post) is (likely) the right one.

Note, however, that "pre_/post_handler"s are executed at the beginning or end, respectively, of a profile import - and, thus, never between two steps. In contrast, with appropriate "depends" declarations, a step handler can be forced to be executed between other steps. This is one aspect where the step handlers might be considered more flexible.

There is a bit of info here: http://docs.plone.org/develop/addons/components/genericsetup.html?highlight=genericsetup#custominstall
This also mentions a way to get back the old context in case you really need to:

profile_id = 'profile-your.addonpackage:default'
good_old_context = context._getImportContext(profile_id)

The need to create a marker file when using the old way, has been a source of confusion for some developers, myself included. Ten years ago it took me a while to discover the reason why installing a package in a particular site took so long: an already installed other package had an import step (created by me) that did a clear and rebuild of the catalog. This was meant for a single package, but did not have the marker file check, so it got executed each time any package got installed...

So recently I created this new way. The post_install fits what I think is the most common use case: after applying the configuration from xml files, do a few more things. And only do that after installing a specific profile.

The old way is still possible and will always be possible, because that is simply how most import steps in GenericSetup work. And they can indeed be ordered a bit. But note that Plone had a plone-final import step which was meant to be the last one, but in practice it never was: it would have needed to add forty or more others steps as dependencies.

"Products.GenericSetup" has quite a good documentation incorporated in its source distribution (in the "docs" subfolder). It is there, I always look first for details about "GenericSetup". Would you mind to document your extension there?

Thanks @dieter and @mauritsvanrees very useful. I think I'll mostly be using post_install for my projects however I see the value of the step approach.

@pigeonflight we had some discussion about the "removal" of the txt hack in https://github.com/plone/Products.CMFPlone/issues/1070, which motivated the changes that @mauritsvanrees did. Nice read as well.

1 Like