Skip to content

Commit

Permalink
Pony ORM release 0.5.1
Browse files Browse the repository at this point in the history
# Changes/features:

Before this release, if a text attribute was defined without the max length specified (e.g. `name = Required(unicode)`), Pony set the maximum length equal to 200 and used SQL type `VARCHAR(200)`. Actually, PostgreSQL and SQLite do not require specifying the maximum length for strings. Starting with this release such text attributes are declared as `TEXT` in SQLite and PostgreSQL. In these DBMSes, the `TEXT` datatype has the same performance as `VARCHAR(N)` and doesn't have arbitrary length restrictions.

For other DBMSes default varchar limit was increased up to 255 in MySQL and to 1000 in Oracle.

# Bugfixes:

* Correct parsing of datetime values with T separator between date and time
* Entity.delete() bug fixed
* Lazy attribute loading bug fixed
  • Loading branch information
kozlovsky committed Jul 11, 2014
2 parents d42f4b4 + d6b54bf commit a29f0ef
Show file tree
Hide file tree
Showing 9 changed files with 68 additions and 21 deletions.
19 changes: 16 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
# Pony ORM Release 0.5 (2014-05-31)
# Pony ORM Release 0.5.1 (2014-07-11)

## Changes/features:

Before this release, if a text attribute was defined without the max length specified (e.g. `name = Required(unicode)`), Pony set the maximum length equal to 200 and used SQL type `VARCHAR(200)`. Actually, PostgreSQL and SQLite do not require specifying the maximum length for strings. Starting with this release such text attributes are declared as `TEXT` in SQLite and PostgreSQL. In these DBMSes, the `TEXT` datatype has the same performance as `VARCHAR(N)` and doesn't have arbitrary length restrictions.

For other DBMSes default varchar limit was increased up to 255 in MySQL and to 1000 in Oracle.

## Changes since 0.4.9
## Bugfixes:

* Correct parsing of datetime values with T separator between date and time
* Entity.delete() bug fixed
* Lazy attribute loading bug fixed


# Pony ORM Release 0.5 (2014-05-31)

* New transaction model ([link](http://blog.ponyorm.com/?p=125))
* New method `Query.filter()` allows step-by-step query construction ([link](http://doc.ponyorm.com/queries.html?highlight=filter#Query.filter))
Expand All @@ -13,7 +26,7 @@
* Ability to specify `sequence_name='seq_name'` for PrimaryKey attributes for Oracle database
* Ability to create new entity instances specifying the value of the primary key instead of the object
* Ability to read entity object attributes outside of the db_session
* Ability to use lambdas as a reference to an entity in relationship attribute declarations ([link](http://doc.ponyorm.com/entities.html?highlight=lambda#relationships))
* Ability to use lambdas as a reference to an entitys in relationship attribute declarations ([link](http://doc.ponyorm.com/entities.html?highlight=lambda#relationships))
* The names of tables, indexes and constraints in the database creation script now are sorted in the alphabetical order
* In MySQL and PostgreSQL Pony converts the table names to the lower case. In Oracle – to the upper case. In SQLite leaves as is.
* The option `options.MAX_FETCH_COUNT` is set to `None` by default now
Expand Down
2 changes: 1 addition & 1 deletion pony/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from os.path import dirname
from itertools import count

__version__ = '0.5.post1'
__version__ = '0.5.1'

uid = str(random.randint(1, 1000000))

Expand Down
2 changes: 1 addition & 1 deletion pony/orm/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -4144,7 +4144,7 @@ def _fetch(query, range=None, distinct=None):
if isinstance(translator.expr_type, EntityMeta):
entity = translator.expr_type
result = entity._fetch_objects(cursor, attr_offsets, for_update=query._for_update,
used_attrs=translator.tableref.used_attrs)
used_attrs=translator.get_used_attrs())
elif len(translator.row_layout) == 1:
func, slice_or_offset, src = translator.row_layout[0]
result = list(starmap(func, cursor.fetchall()))
Expand Down
32 changes: 18 additions & 14 deletions pony/orm/dbapiprovider.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ class DBAPIProvider(object):
max_time_precision = default_time_precision = 6
select_for_update_nowait_syntax = True

# SQLite and PostgreSQL does not limit varchar max length.
varchar_default_max_len = None

dialect = None
dbapi_module = None
dbschema_cls = None
Expand Down Expand Up @@ -234,12 +237,12 @@ def _get_converter_type_by_py_type(provider, py_type):

def get_converter_by_py_type(provider, py_type):
converter_cls = provider._get_converter_type_by_py_type(py_type)
return converter_cls(py_type)
return converter_cls(provider, py_type)

def get_converter_by_attr(provider, attr):
py_type = attr.py_type
converter_cls = provider._get_converter_type_by_py_type(py_type)
return converter_cls(py_type, attr)
return converter_cls(provider, py_type, attr)

def get_pool(provider, *args, **kwargs):
return Pool(provider.dbapi_module, *args, **kwargs)
Expand Down Expand Up @@ -302,7 +305,8 @@ def disconnect(pool):
class Converter(object):
def __deepcopy__(converter, memo):
return converter # Converter instances are "immutable"
def __init__(converter, py_type, attr=None):
def __init__(converter, provider, py_type, attr=None):
converter.provider = provider
converter.py_type = py_type
converter.attr = attr
if attr is None: return
Expand All @@ -328,18 +332,18 @@ def sql_type(converter):
return "BOOLEAN"

class BasestringConverter(Converter):
def __init__(converter, py_type, attr=None):
def __init__(converter, provider, py_type, attr=None):
converter.max_len = None
converter.db_encoding = None
Converter.__init__(converter, py_type, attr)
Converter.__init__(converter, provider, py_type, attr)
def init(converter, kwargs):
attr = converter.attr
if not attr.args: max_len = None
elif len(attr.args) > 1: unexpected_args(attr, attr.args[1:])
else: max_len = attr.args[0]
if issubclass(attr.py_type, (LongStr, LongUnicode)):
if max_len is not None: throw(TypeError, 'Max length is not supported for CLOBs')
elif max_len is None: max_len = 200
elif max_len is None: max_len = converter.provider.varchar_default_max_len
elif not isinstance(max_len, (int, long)):
throw(TypeError, 'Max length argument must be int. Got: %r' % max_len)
converter.max_len = max_len
Expand All @@ -365,9 +369,9 @@ def validate(converter, val):
return BasestringConverter.validate(converter, val)

class StrConverter(BasestringConverter):
def __init__(converter, py_type, attr=None):
def __init__(converter, provider, py_type, attr=None):
converter.encoding = 'ascii' # for the case when attr is None
BasestringConverter.__init__(converter, py_type, attr)
BasestringConverter.__init__(converter, provider, py_type, attr)
converter.utf8 = is_utf8(converter.encoding)
def init(converter, kwargs):
BasestringConverter.init(converter, kwargs)
Expand Down Expand Up @@ -456,9 +460,9 @@ def sql_type(converter):
return 'REAL'

class DecimalConverter(Converter):
def __init__(converter, py_type, attr=None):
def __init__(converter, provider, py_type, attr=None):
converter.exp = None # for the case when attr is None
Converter.__init__(converter, py_type, attr)
Converter.__init__(converter, provider, py_type, attr)
def init(converter, kwargs):
attr = converter.attr
args = attr.args
Expand Down Expand Up @@ -543,9 +547,9 @@ def sql_type(converter):

class DatetimeConverter(Converter):
sql_type_name = 'DATETIME'
def __init__(converter, py_type, attr=None):
def __init__(converter, provider, py_type, attr=None):
converter.precision = None # for the case when attr is None
Converter.__init__(converter, py_type, attr)
Converter.__init__(converter, provider, py_type, attr)
def init(converter, kwargs):
attr = converter.attr
args = attr.args
Expand Down Expand Up @@ -587,11 +591,11 @@ def sql_type(converter):
return converter.sql_type_name + '(%d)' % precision

class UuidConverter(Converter):
def __init__(converter, py_type, attr=None):
def __init__(converter, provider, py_type, attr=None):
if attr is not None and attr.auto:
attr.auto = False
if not attr.default: attr.default = uuid4
Converter.__init__(converter, py_type, attr)
Converter.__init__(converter, provider, py_type, attr)
def validate(converter, val):
if isinstance(val, UUID): return val
if isinstance(val, buffer): return UUID(bytes=val)
Expand Down
1 change: 1 addition & 0 deletions pony/orm/dbproviders/mysql.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ class MySQLProvider(DBAPIProvider):
index_if_not_exists_syntax = False
select_for_update_nowait_syntax = False
max_time_precision = default_time_precision = 0
varchar_default_max_len = 255

dbapi_module = MySQLdb
dbschema_cls = MySQLSchema
Expand Down
1 change: 1 addition & 0 deletions pony/orm/dbproviders/oracle.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ class OraProvider(DBAPIProvider):
max_name_len = 30
table_if_not_exists_syntax = False
index_if_not_exists_syntax = False
varchar_default_max_len = 1000

dbapi_module = cx_Oracle
dbschema_cls = OraSchema
Expand Down
7 changes: 6 additions & 1 deletion pony/orm/sqltranslation.py
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,8 @@ def ast_transformer(ast):
if aggr_ast: select_ast = [ 'AGGREGATES', aggr_ast ]
elif isinstance(translator.expr_type, EntityMeta) and not translator.parent \
and not translator.aggregated and not translator.optimize:
select_ast, attr_offsets = translator.expr_type._construct_select_clause_(translator.alias, distinct)
select_ast, attr_offsets = translator.expr_type._construct_select_clause_(
translator.alias, distinct, translator.tableref.used_attrs)
else: select_ast = [ distinct and 'DISTINCT' or 'ALL' ] + translator.expr_columns
sql_ast.append(select_ast)
sql_ast.append(translator.subquery.from_ast)
Expand Down Expand Up @@ -448,6 +449,10 @@ def ast_transformer(ast):

sql_ast = ast_transformer(sql_ast)
return sql_ast, attr_offsets
def get_used_attrs(translator):
if isinstance(translator.expr_type, EntityMeta) and not translator.aggregated and not translator.optimize:
return translator.tableref.used_attrs
return ()
def without_order(translator):
translator = deepcopy(translator)
translator.order = []
Expand Down
23 changes: 23 additions & 0 deletions pony/orm/tests/test_lazy.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,26 @@ def test_lazy_2(self):
self.assertIn(X.b, x1._vals_)
self.assertNotIn(X.b, x2._vals_)
self.assertNotIn(X.b, x3._vals_)

@db_session
def test_lazy_3(self): # coverage of https://github.com/ponyorm/pony/issues/49
X = self.X
x1 = X.get(b='first')
self.assertTrue(X._bits_[X.b] & x1._rbits_)
self.assertIn(X.b, x1._vals_)

@db_session
def test_lazy_4(self): # coverage of https://github.com/ponyorm/pony/issues/49
X = self.X
result = select(x for x in X if x.b == 'first')[:]
for x in result:
self.assertTrue(X._bits_[X.b] & x._rbits_)
self.assertIn(X.b, x._vals_)

@db_session
def test_lazy_5(self): # coverage of https://github.com/ponyorm/pony/issues/49
X = self.X
result = select(x for x in X if x.b == 'first' if count() > 0)[:]
for x in result:
self.assertFalse(X._bits_[X.b] & x._rbits_)
self.assertNotIn(X.b, x._vals_)
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import sys

name = "pony"
version = "0.5.post1"
version = "0.5.1"
description = "Pony Object-Relational Mapper"
long_description = """Pony is an object-relational mapper. The most interesting feature of Pony is its ability to write queries to the database using generator expressions. Pony works with entities which are mapped to a SQL database. Using generator syntax for writing queries allows the user to formulate very eloquent queries. It increases the level of abstraction and allows a programmer to concentrate on the business logic of the application. For this purpose Pony analyzes the abstract syntax tree of a generator and translates it to its SQL equivalent.
Expand Down

0 comments on commit a29f0ef

Please sign in to comment.