{"id":3229,"date":"2018-06-07T10:19:52","date_gmt":"2018-06-07T08:19:52","guid":{"rendered":"http:\/\/blog.gocept.com\/?p=3229"},"modified":"2018-06-07T10:19:52","modified_gmt":"2018-06-07T08:19:52","slug":"migrate-a-zope-zodb-data-fs-to-python-3","status":"publish","type":"post","link":"https:\/\/blog.gocept.com\/2018\/06\/07\/migrate-a-zope-zodb-data-fs-to-python-3\/","title":{"rendered":"Migrate a Zope ZODB Data.fs to Python 3"},"content":{"rendered":"

TL;DR <\/strong>Use\u00a0zodbupdate<\/a>.<\/p>\n

Problem<\/h3>\n

A ZODB\u00a0Data.fs<\/code>\u00a0which 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<\/code>\u00a0has a different meaning for the two Python versions: Under Python 2 a str<\/code>\u00a0is a container for characters with an arbitrary encoding (aka bytes<\/code>\u200b). Python 3 knows str<\/code>\u00a0as a text\u00a0datatype which was called unicode<\/code>\u00a0in Python 2. Trying to load a str<\/code> object in Python 3 which actually contains binary data will fail. It has to be bytes<\/code>, but bytes<\/code>\u00a0is an alias for str<\/code>\u00a0 in Python 2 which means Python 2 replaces bytes<\/code>\u00a0 with str<\/code>\u00a0making is impossible to give Python 3 the class it expects for binary data. A Python 2 str<\/code>\u00a0 with an arbitrary encoding will break, too.<\/p>\n

Solution<\/h3>\n

The Data.fs<\/code>\u00a0has to be migrated: each str<\/code>\u00a0 which actually contains bytes<\/code>\u00a0has to be converted into a zodbpickle.binary<\/code>\u00a0object which deserialises as bytes<\/code>\u00a0under Python 3. The str<\/code>\u00a0objects actually containing text have to be decoded to unicode<\/code>. There are currently two tools which claim that they are able to do such a migration:<\/p>\n