This only explains how to use ZODB Components from a developer point of view and
what has changed since the presentation at Europython 2012.
The general technical implementation of ZODB Components for ERP5 is documented
in the slides written for Europython 2012. You can find the slides and notes
there and the video there. Even though there has been some changes since then,
the general idea still stands so this document is still worth reading.
Note that TYPE, used in this document, refers to ZODB Component type and may
be currently equal to document, extension or test.
Here is what you should know when using ZODB Components:
Unless a ZODB Component is in validated or modified validation_state,
it will never be used (on filesystem, it would mean that the file does not
exist at all).
A Component is in modified state if it has been previously validated, but
some errors were found after it has been saved. Until these errors have been
fixed, reference, version and source code set when the Component was
validated will be used.
Also, as ZODB Component are lazily loaded, no error may be displayed nor reported
until you actually access the object.
Only the reference and version matters to lookup for a Component to
be loaded. Even though ID could be set to anything, it should only follow
naming convention defined in the section below.
Generally speaking, any ZODB Component can be imported like any Python
module (but for most of them you should not do that except in tests, see the
per-Components sections below for further information), for example:
Import Component of the version with the highest priority:
import erp5.component.TYPE.Foo
Import specifically Component of version PROJECT:
import erp5.component.TYPE.PROJECT_version.Foo
For security reasons, a Developer Role has been introduced which is not
available through the UI. Only users with Developer Role can modify ZODB
Components. Similarly to Class Tool which requires creating a file in
ERP5Type Product, you must edit zope.conf on the filesystem to add users to
Developer Role. For instance, to add zope users to Developer
Role:
%import Products.ERP5Type
<ERP5Type erp5>
developers zope
</ERP5Type>
Upon export on the filesystem, a Component is split up into 2 files:
metadata (.xml) and source code (.py).
Likewise ZODB Property Sheets and Portal Type as Classes, when a ZODB
Component is modified, this reset Components and Portal Type as Classes as
well as inheritance may have changed or Property Sheets.
By default, textarea is used to edit source code through the web browser, but
Ace Editor (provided in erp5_ace_editor) provides a much better UI along with
maximize and fullscreen modes, jumping to line and column where an error or
warning has been found... After installing erp5_ace_editor bt5, you can enable
it as Source Code Editor in User Interface tab in Site/User
Preference. Later on, Ace Editor will also be useable from ZMI (Jérôme).
You can also edit ZODB Components through WebDAV or FTP (actually supported by
Zope directly with a few code to make it work for ZODB Components). You must modify
zope.conf and add the following section:
<webdav-source-server>
address IP:PORT
force-connection-close off
</webdav-source-server>
For example to mount your ERP5 instance and edit ZODB Components with davfs2 (on
Debian, the package is davfs2, read mount.davfs(8), umount.davfs(8) and
davfs2.conf(5)):
mount -t davfs -o uid=UID,gid=GID,username=USERNAME http://IP:PORT/erp5/portal_components /MOUNT/DIRECTORY
Even though ID could be anything, it should be in the following format:
TYPE.VERSION.REFERENCE
Migrating bt5 Documents, Extensions and Tests from filesystem actually follows
this naming convention.
For projects, you should add at least one specific version, which can be
achieved by the following steps:
- Add a version and its priority in Portal Properties, for example: project | 60.0
- Add this version to Registered Version Priority Selection field in
Business Template view.
For ERP5 Components, there is already erp5 version defined in erp5_core, so
you don``t need to add anything.
Except for ERP5-specific version, you should create a new version, see previous
section for that.
You can migrate Business Template thanks to Migrate Components from Filesystem
action in Business Template view. In the next screen, you can specify versions
of Components to be migrated.
Note that the migration is all or nothing and ZODB Components will not be
automatically validated.
Also, Products in bt5 are deprecated, instead you must either migrate your
Products to Documents or move them to normal Products, through your SlapOS
Software Release recipe.
When adding an External Method, you can specify Module Name exactly as you
used to do.
For example, a ZODB Extension Component whose version is project, reference is
Bar and ID is extension.project.Bar, you must only specify Bar. Unless you
have an Extension Component with the same reference and whose version has an
higher priority, then it will be used automatically. From an implementation
point of view, this will actually import erp5.component.extension.Bar,
equivalent to erp5.component.extension.HIGHEST_PRIORITY_VERSION_version.Bar.
By default, when specifying Bar as Module Name, ZODB Components will be
lookup and if there is no such Components, then it will fallback on the
filesystem.
Likewise filesystem bt5 Document, ZODB Document Components in bt5 must only
be used as Portal Types Type Class. But if you use these documents in tests for
example, you must use erp5.component.document instead of erp5.document.
Basically, a Test Component behaves like a Document Component. However, as a
Test Component is within a bt5, there is a chicken & egg issue with
runUnitTest command for installation of bt5 dependencies because in current
Unit Test, the list of required bt5s is defined in
getBusinessTemplateList() class method which requires to load the
Component. However, it cannot be loaded until the bt5 (and its dependencies)
have been installed as it may depend on Document or other Test Components.
One solution would have been to fiddle with sys.path and implement workaround
to load the Component without installing any bt5, but that would be hackish
and would not work when trying to import Document Components.
Therefore, the solution implemented is to specify through runUnitTest command
line the bt5 where the test can be found. This bt5 will be installed as well
as its dependencies using bt5list file (so you must make sure that this
file is up-to-date before doing running any test).
Migration steps:
This should already be the case but all the bt5 dependencies must be
properly defined (dependency_list Business Template property or
Dependencies field on Business Template view).
For bt5s required specifically to run tests, there is a new property,
test_dependency_list (Test Dependencies on Business Template view)
where they can be added. Please note that in contrary to filesystem test,
the bt5 are not forced installed so you must define all dependencies,
including solving virtual dependencies (for example, for
erp5_full_text_catalog, you can add erp5_full_text_myisam_catalog
to Test Dependencies).
For customer project, make sure that your SlapOS recipe generates bt5list
for your customer bt5s. Also, to your customer tests/__init__.py, add
the following path to your tests path:
%s/bt5/*/TestTemplateItem/portal_components/test.*.test*.py
Finally, to execute a Test Component as a Live Tests, you can do through Run
Live Tests Component Tool Action. As of runUnitTest command considering that
testFoo is in bt5 called hogehoge:
runUnitTest hogehoge:testFoo
- With erp5.git before merge request 1032 (2b8c630500f8a65566cf5ccf76b5215add840e54):
- Replace deprecated newTempXXX calls as done in 26e3c68b10be9165318dec9c02184dca0398d3e4.
- Migrate all customer Products to ZODB Components to their appropriate bt5s using Migrate Components from Filesystem Business Template Action. This will automatically select classes used in the current Business Template Portal Types and will not delete anything from the filesystem once done. Also, this will fix imports only for the migrated files..
- Commit.
- With current erp5.git:
- Delete .pyc files to make sure now deleted Documents are not loaded: git clean -xdf product/
- Fix imports (name of the module before migration from the FS is in source_reference property, you can use https://lab.nexedi.com/nexedi/erp5/uploads/cef2ce5429e7abb9c9d0ab53b75b6593/fix_imports script for now: ./fix_imports /path/to/erp5/repository/ /path/to/customer/repository/
- Commit.
- Regenerate bt5list: ./product/ERP5/bin/genbt5list bt5 product/ERP5/bootstrap
- Update all bt5s.
- Filesystem Products can now be deleted from FS. Also make sure to remove .pyc files: git clean -xdf -e bt5list product/.
- Commit.
This section lists major changes, excluding bootstrap issue, minor bug fixes and
UI improvements here and there.
Access to Component Tool has been further restricted (anyone was able to view
Components) and is now set through Component Tool class rather than instance, so
it can be easily changed anytime, rather than only being set at creation or
through an upgrade script.
Before, in order to check that the source code was somewhat valid, the code was
actually executing, but this approach has the following drawbacks:
- Executing the source code may have side-effect, such as importing module or
for monkey-patches.
- Does not detect error in code executed later (function...).
- Only the first error was reported.
The source code is now checked statically through Pylint if it can be
imported, otherwise it fallbacks on executing the source code as before (please
note that Pylint has been added to SlapOS recipe specifically for ZODB
Components so you may need to update your environment).
Pylint has been chosen in favor of (faster) other implementation such as
pyflakes because it can also check coding style and naming conventions, which
will be used in the future. Moreover, it seems to report errors that pyflakes
could not find.
As a side note, edition of ZODB Components through Ace Editor has been greatly
improved so you can click directly on the errors or warning and it will go the
corresponding line and column.
Upon any import in Python < 3.3, the Python global import lock is acquired (to
avoid race conditions while checking sys.path, avoid incomplete modules from
being seen by other threads or processes and also to avoid a module from being
executed twice). Therefore, ZODB Component import hooks (following PEP302) are
protected by import lock.
However, there was a deadlock when trying to import Components, as these import
hooks tries to fetch properties from ZODB, which may unpickle objects in another
thread (for an Exception class with ZEO for example) and thus trying to acquire
import lock when importing classes.
From now on, the import lock is released in import hooks until sys.path is
actually modified and there is another lock (aq_method_lock, common to Portal
Type as Classes and ZODB Property Sheets) to prevent entering import hooks in
parallel.
A solution would be to introduce a per Component package lock (still coarse
grain) or a per Component lock (finest grain we could do) if the performances
end up being too bad but it seems to be working well enough as it is.
The best solution would be to use Python 3.3, as there is no more global lock
but a lock per module. However, the import machinery has completely changed
(implemented in Python and not C anymore), so it would be probably quite
difficult to backport...
A Component was automatically validated on Business Template installation, but
this meant, among other things, that exchanging bt5 containing Components with
errors was not possible.
The last Workflow History of Component Validation Workflow is now exported
without adding anything, thanks to a new Property introduced in Business
Template (before, you could only export the full Workflow History).
As requested by a customer, this could be fairly useful to be able to change
ZODB Components on one specific node before the changes are actually propagated
on other nodes (for example, when fixing a bug on production to allow testing on
only one node).
Being able to know where a given ZODB Component comes from and where it is
currently used (which Portal Type classes, which Property Sheets and so
on). This should be common to ZODB Property Sheets and Portal Type as Classes.
Once bugs found with bt5 ZODB Components and other bugs requiring restart of
ERP5 have been fixed, the next milestone is to migrate filesystem Products to
ZODB.
For now and likewise ZODB Property Sheets and Portal Type as Classes, everytime
a ZODB Component is modified, a reset of all ZODB Components is done, but
after implementing nicely introspection, it should be possible to only reset the
modified Components and its dependencies.