[PonyORM-list] Pony ORM Release 0.6.2

Alexey Malashkevich alexeymalashkevich at gmail.com
Mon Jan 11 13:28:26 UTC 2016

Hi all,

Below is the list of new features and bugfixes.

Python 3.5 support

Pony now supports Python 3.5

Better raw SQL support

Before this release Pony provided an ability to write raw SQL queries using
the Entity.select_by_sql() method. But in this case you had to write the
whole SQL query by itself.

Starting with this release Pony allows embedding raw SQL fragments into a
lambda or generator query using the raw_sql() function.

Here is an example of using raw_sql() function:

    s = 'J%'
    select(p for p in Person if p.age > 20 and raw_sql('"p"."name" LIKE

The string '"p"."name" LIKE ' will be embedded into generated SQL query.
The value of the parameter will be taken from the s variable. p is an alias
of SQL table used in this query, not Python generator variable. Pony uses
the variable from the generator as an alias for SQL table.

You also can embed more complex Python expressions into raw SQL fragment:

    import datetime
    Task.select(lambda t: raw_sql("t.due_date <
date($datetime.date.today(), '+1 day')"))

Here datetime.date.today() is a Python expression which will be evaluated
and replaced with a single parameter.

You can find more examples of using raw_sql() function in Pony docs at

Using @db_session with generator functions

Previously the @db_session decorator was used for decorating functions that
work with the database. But it didn't work correctly when was applied to
generators (functions that return value using the yield expression).
Starting with this release you can use the @db_session decorator for
generators too.

With regular functions, the @db_session decorator works as a scope. When
your program leaves the db_session scope, Pony finishes the transaction by
performing commit (or rollback) and clears the db_session cache.

In case of a generator, the program can reenter the generator code for
several times. In this case, when your program leaves the generator code,
the db_session is not over, but suspended and Pony doesn't clear the cache.
In the same time, we don't know if the program will come back to this
generator code again. That is why you have to explicitly commit or rollback
current transaction before the program leaves the generator on yield. On
regular functions Pony calls commit() or rollback() automatically on
leaving the @db_session scope.

In essence, here is the difference with using @db_session with generator

1. You have to call commit() or rollback() before the yield expression
2. Pony doesn't clear the transaction cache, so you can continue using
loaded objects when coming back to the same generator.
3. With a generator function, the @db_session can be used only as a
decorator, not a context manager. This is because in Python the context
manager cannot understand that it was left on yield.
4. The @db_session parameters, such as retry, serializable cannot be used
with generator functions. The only parameter that can be used in this case
is immediate.

This fixes the issue #126.

Getting SQL statement as a string

Now you can use Query.get_sql() method in order to get SQL statement that
will be sent to the database:

    sql = select(c for c in Category if c.name.startswith('a')).get_sql()
    print sql

    SELECT "c"."id", "c"."name"
    FROM "category" "c"
    WHERE "c"."name" LIKE 'a%%'

Deleting objects

Before Pony release 0.6.2 you could delete objects only by calling the
delete() method on an entity instance. Now you can use the delete() query:

    delete(p for p in Product if p.picture is None)

Another option is calling the delete() method on a query:

    select(p for p in Product if p.picture is None).delete()

The Query.delete() method has the bulk parameter, which is False by
default. When bulk=False Pony loads each instance into memory and calls the
delete() method on each instance (calling before_delete and after_delete
hooks if they were defined). If bulk=True Pony doesn't load instances, it
just generates the SQL DELETE statement which deletes objects in the

Ability to override entity constructor and add methods to an entity

Now you can override the __init__() method of an entity, and also
monkeypatch your own methods in an entity.

Backward incompatibilities

Normalizing table names for symmetric relationships

Pony can automatically generate database table names when it creates tables
for entities and many-to-many relationships. Depending on the database, it
normalizes the table name using either upper or lower case letters. In
previous releases this normalization was not applied to symmetric
relationships (where both ends of a relationships are specified using the
same attribute). Here is an example of a symmetric relationship:

    class Person(db.Entity):
        friends = Set("Person", reverse="friends")

Now, when this bug is fixed, Pony applies the same normalization rules to
all table names. So, you might need to change the database table name or
use the table option of a symmetric attribute for specifying your current
table name:

class Person(db.Entity):
    friends = Set("Person", reverse="friends", table="current_table_name")


Now Pony automatically removes leading and trailing whitespace characters
in a string attribute. You can control it by using the autostrip option. By
default autostrip=True. The behavior is similar to Python string.strip()
function. If you want to keep leading and trailing characters, you have to
set autostrip parameter to False:

    class Person(db.Entity):
        name = Required(str, autostrip=False)


We have moved Pony ORM documentation to a separate repo at
https://github.com/ponyorm/pony-doc. Also we have changed the license of
documentation to Apache 2.0. This way it will be easier to receive pull
request for docs and it makes collaboration easier. Please create new
documentation related issues here.
The compiled version of docs still can be found at https://docs.ponyorm.com

Other changes and bug fixes

Fixed #87: Pony fails with pymysql installed as MySQLdb
Fixed #116: Add support to select by UUID
Fixed #118: Pony should reconnect if previous connection was created before
process was forked
Fixed #121: Unable to update value of unique attribute
Fixed #122: AssertionError when changing part of a composite key
Fixed #127: a workaround for incorrect pysqlite locking behavior
Fixed #136: Cascade delete does not work correctly for one-to-one
Fixed #141, #143: remove restriction on adding new methods to entities
Fixed #142: Entity.select_random() AssertionError
Fixed #147: Add 'atom_expr' symbol handling for Python 3.5 grammar

-------------- next part --------------
An HTML attachment was scrubbed...
URL: </ponyorm-list/attachments/20160111/de07433c/attachment.html>

More information about the ponyorm-list mailing list