Migrate a Zope ZODB Data.fs to Python 3

TL;DR Use zodbupdate.

Problem

A ZODB Data.fs which was created under Python 2 cannot be opened under Python 3. This is prevented by using a different magic code in the first bytes of the file. This is done on purpose because str has a different meaning for the two Python versions: Under Python 2 a str is a container for characters with an arbitrary encoding (aka bytes​). Python 3 knows str as a text datatype which was called unicode in Python 2. Trying to load a str object in Python 3 which actually contains binary data will fail. It has to be bytes, but bytes is an alias for str  in Python 2 which means Python 2 replaces bytes  with str making is impossible to give Python 3 the class it expects for binary data. A Python 2 str  with an arbitrary encoding will break, too.

Solution

The Data.fs has to be migrated: each str  which actually contains bytes has to be converted into a zodbpickle.binary object which deserialises as bytes under Python 3. The str objects actually containing text have to be decoded to unicode. There are currently two tools which claim that they are able to do such a migration:

  • zodb.py3migrate was already written at Berlin Strategic sprint in 2016, but it was never able to prove that it can do what it claims: At the time when it was written there was no Zope which could run on Python 3. Now as we have Zope 4 running on Python 3 it does not seem to do its conversion job quite well: I was able to migrate a toy database but had to catch an unpickling error.
  • zodbupdate was enriched by a Python 3 migration. A big thank you to Sylvain Viollon and the developers at Minddistrict! It has proven its claims! At the Zope 4 welcome sprint I was able to migrate a Data.fs created on Zope 2.13 running on Python 2 to Zope 4 running on Python 3.

Steps

  1. Migrate your Zope application to Zope 4. (zodbupdate  requires at least ZODB 4 which is not the default ZODB version of Zope 2.13) — For my toy database containing only a file object and an image this was no problem. Zope 4  is starting with such a database. It might show some broken objects because Zope no longer depends on some previous core packages like Products.Sessions. If your application needs those packages you should add them to your Zope environment.
  2. ​zodbupdate has to be installed into the Zope 4 environment so it can access the Python classes. (It has to read the pickles in the ZODB.)
  3. There needs to be an entry_point in setup.py for each package which contains persistent Python classes. The entry point has to be named "zodbupdate.decode" and needs to point to a dictionary mapping paths to  str attributes to a conversion (bytes resp. a specific encoding). For Details see the migration documentation of zodbupdate. I prepared a branch of Zope 4 which contains this configuration dictionary for OFS.Image and OFS.File, see zopefoundation/Zope#285.
  4. Run zodbupdate --pack --convert-py3 on the Data.fs using Python 2.
  5. Copy the Data.fs over to the Zope 4 instance running on Python 3. Data.fs.index will be discarded at the first start. (There is an error message telling that it cannot be read.)
  6. Enjoy the contents of the Data.fs running on Python 3.

Conclusion

It is possible (proven for a toy database) to migrate a Data.fs from Zope 2.13  (Python 2) to Zope 4 (Python 3).

zodbupdate is the way to go. Although it cannot do the migration completely autonomously the developers of Python packages can provide migration configuration in their packages which can be used in the migration step so the configuration has only to be written once.

zodb.py3migrate has an analysis step which shows the attribute names where the str objects are stored. (This could be added to zodbupdate, so do not expect that there will be two tools trying to achieve the same goal.)

mdtools.relstorage contains a relstorage variant of zodbupdate which claims to be much faster on relstorage as it can leverage parallelism.

Open issues

The pull request containing the migration strategy (zopefoundation/Zope#285) has to be extended for the other persistent classes in Zope. There have to be alike changes in all packages providing persistent classes.

Catching and rendering exceptions

Error handling in Zope 4

TL;DR: You have to write an exception view in file system code which is rendered when an exception occurs.

History

If an exception occurred in Zope 2 the standard_error_message (an object in the ZODB) was rendered. This way the error page could be customised through the web.

When using a WSGI server on Zope 2 the standard_error_message is no longer used. The exceptions have to be handled in a WSGI middleware. (This is a sub-optimal solution as the middleware is not run in the same execution context where the exception occurred.)

Thats why error handling changed again in Zope 4:  Like Zope 3 (aka BlueBream) Zope 4 tries to lookup an exception view if an exception occurs. If the lookup succeeds (aka there is an exception view registered for the current exception) this view is rendered as response. This approach allows different views for different exceptions. The standard_error_message is even gone when installing Zope 4 from scratch.

Continue reading “Catching and rendering exceptions”

Earl Zope II is dead, long live Earl Zope

Zope 4.0b1 released

 

Narrative version

Once upon the time there was Earl Zope II. His lands where threatened by a huge disaster called “Python 2 sunset”. His only chance was to emigrate to the Python 3 wonderland. After a long preparation phase for himself and his courtiers he was able to move to the new land. But the Python 3 wonderland has strict immigration authorities: They only allow “compatible” fellows to get a residency permit. The permission itself has three levels:

  • alpha – To get this level the candidate has to prove that he can breath the Python 3 air and drink the water in this land without getting falling over. Earl Zope II needed a while to acclimate in the Python 3 wonderland as its climate is a bit different from what he was used to.
  • beta – This level requires the the acclimation phase was successful and people could start to rely that the candidate will stay in the new land. Earl Zope II reached this level by proving that all his courtiers – he relies on – are ready for this level.
  • final – To reach this level the candidate needs to prove that he is living in successful relations in Python 3 wonderland. Other inhabitants must be able to trust him and the services he offers. After Earl Zope II now has reached the beta phase he is now able to offer his services and hope that he gets the final level about fall 2018.

Back in his own country Earl Zope II had the official name “Zope2 2.13”. Before the beta phase of his immigration he thought that he would have to change the name to something like “Zope2 4.0b1”. This is looks ugly and some people protested against this name. With the kind and quick help of Baiju Muthukadan Earl Zope II was able to change his official name to “Zope 4.0b1”. Thank you very much Baiju Muthukadan! Earl Zope is very proud of this new shorter name and is heartily thankful for this opportunity.

Technical version

The release of the first Beta version means, that no currently existing features will be removed until the final version. But There will be some new features and many bugfixes.

New Features of Zope version 4.0

  • Support for Python 3.4 up to 3.6: Currently Python 3 can only be used for new projects. There is only an experimental way to convert an existing ZODB from Python 2 to 3 as it is not possible to run the same Data.fs under both versions, see zodb.py3migrate.
  • Zope now by default runs as a WSGI application. The previously used ZServer is still supported but only runs under Python 2.
  • Chameleon based templates are now the default.

Changes

  • The name of the distribution changed from Zope2 to Zope. The previous Zope2 package will remain as a meta package which depends on Zope. This allows packages which require Zope 4.x to depend on Zope instead of Zope2.
  • Removed deprecated code and BBB imports like the Globals package or the internal help system.
  • Some smaller features, bug fixes and security fixes, see the Change log.

Thanks

A big “Thank you!” to all who made this release possible:

  • dedicated people investing time, thoughts and money
  • nice companies allowing their people to participate on Zope sprints
  • the Plone Foundation sponsoring Zope sprints

We had a great Zope 4 Phoenix Sprint helping to raise Zope from the ashes! Thank you to everybody who participated in Halle or from remote.

Roadmap

Beta one of Zope is out:

We need the feedback to adapt Zope to the needs in the wild. The current plan is to create new beta releases once a while after implementing features resp. bug fixes or on demand. The current plan is to release a final 4.0 version in fall of 2018. This should allow software projects built upon Zope to migrate there code before the Python 2 sunset in 2020.

Zope 2 Resurrection Sprint – Goal accomplished

The sprint days were really busy for Earl Zope II and the people helping him with the Python 3 wonderland immigration authorities.

  • Zope
    • can be installed using Python 3
    • can be started and renders some views
    • has more than 1.700 of more than 2.300 tests running
    • has some optional dependencies left to be ported.
  • To accomplished this by:
    • Complete porting of RestrictedPython, so a first alpha release with the new implementation was released. (This includes about 260 commits, nearly 100 files changed, 9.000 lines of newly written code and 1.000 lines of code deleted.)
    • Port AccessControl to Python 3. This port covers the Python code of the package.
    • Make an alpha release of DocumentTemplate which supports Python 3. It is purely based on Python code. (Thanks Hanno for the porting work from C to Python!)
    • Note: There were problems porting AccessControl and DocumentTemplate to PyPy so we left this out for now. (Volunteers welcome!)

Besides working on Zope there was other ongoing work:

His majesty Earl Zope II says a warm “Thank you!” to all who helped him to start his new live in Python 3 wonderland. There is still enough work to be done so he can live there and having all the comfort and stability of Python 3. See you on the next sprint!

Zope Resurrection Part 1 – Reanimation

Now we are helping Zope in the Python 3 wonderland: Almost 20 people started with the reanimation of Zope. We are working mostly on porting important dependencies of Zope to Python 3:

Zope 4 is now per default based on WSGI. Thanks to Hanno who invested much time to make the WSGI story of Zope much more streamlined.

We found out that the ZTK (Zope Toolkit) is no longer used in any of the projects using packages of it (Zope, Grok, Bluebream – as it is dead). It should be kept to test compatibility between the packages inside the ZTK.

Running tests using gocept.selenium on Travis-CI

Travis-CI is a free hosted continuous integration platform for the open source community. It has a good integration with Github, so each push to a project runs the tests  of the project.

gocept.selenium is a python package our company has developed as a test-friendly Python API for Selenium which allows to run tests in a browser.

Travis-CI uses YML-Files to configure the test run. I found only little documentation how to run Selenium tests on Travis-CI. But it is straight forward. The following YML file I took from a personal project of mine. (I simplified it a bit for this blog post.):

[code]
language: python
python:
– 2.6
before_install:
– "export DISPLAY=:99.0"
– "sh -e /etc/init.d/xvfb start"
– "wget http://selenium.googlecode.com/files/selenium-server-standalone-2.31.0.jar"
– "java -jar selenium-server-standalone-2.31.0.jar &"
– "export GOCEPT_SELENIUM_BROWSER=’*firefox’"
install:
– python bootstrap.py
– bin/buildout
script:
– bin/test
[/code]

Explanation:

  • Lines 1 – 4: My project is a Python project which currently only runs on Python 2.6. But other Python versions will work as well.
  • Lines 5, 6: Firefox needs a running XServer, so we start it first as it takes some seconds to launch. See Travis-CI documentation, too.
  • Lines  7, 8: The Selenium server seems not to be installed by default, so get it and launch it.
  • Line 9: Tell gocept.selenium to use Firefox to run the tests. (Note: To use the new Webdriver-API in the upcoming version 2 of gocept.selenium you have to set other environment variables.)
  • Lines 10 – 14: Install the project and run the tests as usual. (The example uses zc.buildout to do this.)

Note: Although I use the Firefox which is installed by default on the Travis-CI machine, I did not yet find out which version it is.