Pony ORM 0.6 Release Candidate 1

One of the most often requests that we are getting from Pony users is adding support for Python 3. And today we are happy to announce that we’ve just finished development and have prepared Pony 0.6 Release Candidate with Python 3 support!

In order to install this release candidate version you need to execute the following command:

    pip install pony==0.6rc1

If you don’t specify the version explicitly, pip will install the latest stable release 0.5.4

The same Pony code runs both on Python 2 (≥ 2.6) and Python 3 (≥ 3.3). If you clone Pony git repository from GitHub you can use it on Python 2 and Python 3 without any modifications.

Now let’s see what changes we had to make along the way.

Unicode strings

As you know, Python 3 has some differences from Python 2 when it comes to strings. Python 2 provides two string types – str (byte string) and unicode (unicode string), whereas in Python 3 the str type represents unicode strings and the unicode type has gone.

When we were working on adding Python 3 support to Pony, one of our goals was to have the same Pony entity declarations working on both Python 2 and 3 in the same manner. In order to achieve this we had to make one non-backward compatible change – treat both str and unicode types as they are unicode strings in both Python 2 and 3. Pony just adds unicode as an alias to str in Python 3. When you importing * from pony.orm you will get this alias along with other stuff.

    attr1 = Required(str)
    #   is now the same as
    attr2 = Required(unicode)
    attr3 = Required(LongStr)
    #   is now the same as
    attr4 = Required(LongUnicode)

Before this release, Pony stored values of str and unicode attributes as unicode in the database, but for str attributes it had to convert unicode to byte string on reading from the database. Starting with the Pony Release 0.6 the attributes of str type in Python 2 behave as if they were declared as unicode attributes. There is no difference now if you specify str or unicode as the attribute type – you will have unicode string in Python and in the database.

The same thing is with the LongUnicode and LongStr. LongStr now is an alias to LongUnicode. This type uses unicode in Python and in the database.

Byte sequences

If you need to represent a byte sequence in Python 2, you can use the buffer type. In Python 3 the buffer type has gone, and Pony uses the bytes type which was added in Python 3 to represent binary data. But for the sake of backward compatibility we still keep buffer as an alias to the bytes type in Python 3. If you’re importing * from pony.orm you will get this alias too.

If you want to write code which can run both on Python 2 and Python 3, you should use the buffer type for binary attributes. If your code is for Python 3 only, you can use bytes instead:

    attr1 = Required(buffer) # Python 2 and 3

    attr2 = Required(bytes) # Python 3 only

It would be cool if we could use the bytes type as an alias to buffer in Python 2, but unfortunately it is impossible, because Python 2.6 adds bytes as a synonym for the str type (Btw, there is a good read regarding this decision)

Porting from previous Pony releases to 0.6

In most cases, you don’t need to do anything in order to port your code to Pony ORM 0.6. Pony entity declarations and queries should work correctly by default both in Python 2 and Python 3.

If you declare string attribute as unicode, it will work correctly in Python 2 and Python 3, because Pony adds unicode as an alias to str in Python 3.

If you declare string attribute as str and keep only ASCII data there, it will not require any change and will work both on Python 2 and Python 3. But now that attribute will accept and return unicode values. In Python 2, if you assign an ASCII byte string to such attribute, the value will be automatically converted to unicode.

If you use str attribute type for storing byte strings, you should use buffer or bytes attribute type instead. The bytes type can be used in Python 3 only, it cannot be used correctly in Python 2. The buffer type can be used both in Python 2 and Python 3 with the same meaning. In Python 3 Pony just adds buffer as an alias to bytes.

Declaring Pony entities which work in both Python 2 and 3

It does not matter if you use type str or unicode in you string attributes – both will do the same, because Pony adds unicode as an alias to str in Python 3. But for aesthetical reasons we recommend to keep consistency and assign the same type for all of you string attributes. Starting with this release we prefer to use the str as a string type, because it looks more naturally in Python 3.

For BLOB attributes the preferred type is buffer. In Python 3 Pony adds buffer as an alias to bytes. Don’t use bytes if you want to run your code both in Python 2 and Python 3, because in Python 2 bytes is an alias to str, and has different meaning.

pymysql adapter for MySQL database added

Now Pony can use pymysql adapter in Python 2 and 3. By default, in Python 2, Pony uses MySQLdb for accessing MySQL databases. Now it falls back to pymysql if MySQLdb is not available.

Since MySQLdb doesn’t work in Python 3, here you can use only pymysql adapter.

Other changes

In this release we’ve fixed the following bugs:
Fixes #74: Wrong FK column type when using sql_type on foreign ID column
Fixes #75: MappingError for self-referenced entities in a many-to-many relationship
Fixes #80: “Entity NoneType does not belong to database” when using to_dict

As always, we appreciate your feedback. Try to use Pony in Python 3 and share your experience with us in our email list or by email at team [at] ponyorm.com