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