Most Powerful Open Source ERP

Guideline Prevent Acquisition From Acquiring Restricted Properties In Python

To prevent acquisition errors.
  • Last Update:2019-07-15
  • Version:001
  • Language:en

Prevent Acquisition From Acquiring Restricted Properties In Python

The design of ERP5 is based on implicit acquisition just as most of Zope 2. However, ERP5 has its own way of considering acquisition. In ERP5, acquisition of methods is considered as a good thing while acquisition of document properties is considered as risky . This is why all properties defined in property sheets are set to 'None' at the level of the class or at the level of the PropertyHolder instance created by _aq_dynamic in Base class.

This way, acquisition is blocked on all properties defined by property sheets on portal types. If one wants to acquire a given property from a parent object or through a relation, this should be explicitly defined in property sheets. For an example, see Amount.py.

A good example would be acquiring methods through context or through containment, which is perfectly acceptable. It is used for example to access the current WebSection with the method getWebSectionValue in WebSection.py. It may be used also to display on a child object some properties which are defined on its parent. This is considered as normal in ERP5. The required use of accessors in ERP5 for getting and setting properties removes most risks related to implicit acquisition in Zope.

The use of acquisition for properties should therefore be considered only for implementation purpose and with great care. This following bad example (broken link) bug fix gives a very good example of what can happen if one does not care enough about property acquisition. Before this bug fix, 'getToolByName' was called on 'business_template' and therefore included 'business_template' in its acquisition chain.

The new business template which was created shortly after by 'newContent' would then also acquire 'business_template' properties. As a result, calling 'install' and 'uninstall' would install not only those items which were defined on the new business template but also all items for which nothing was defined on the new business template. This is because the way business template documents look up for business template items consists in accessing private properties such as '_message_translation_item' through 'getattr' rather than with an accessor.

This is perfectly acceptable in the context of ERP5 since such properties are considered as private or implementation related and we do not want to force implementors to use accessors at this level. However, it has risks. The risk in this case was to massively destroy installed scripts and forms in an ERP5 site in case of revert operation (and retrieve them later thanks to the portal_trash). The bug fix consisted in removing the acquisition context of 'business_template' by invoking 'getPortalObject()'.

To prevent further risk, we have set all private properties to None on the BusinessTemplate.py class with the following. This is a kind of application of the another principle, to write code that works even if all else fails.