Skip to content

Commit

Permalink
Merge branch 'master' to 'orm': bugfixes
Browse files Browse the repository at this point in the history
  • Loading branch information
kozlovsky committed Jan 10, 2017
2 parents ac5da5e + 5ab01cb commit f77bf11
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 21 deletions.
69 changes: 57 additions & 12 deletions pony/orm/decompiling.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,23 +77,32 @@ def __init__(decompiler, code, start=0, end=None):
decompiler.external_names = decompiler.names - decompiler.assnames
assert not decompiler.stack, decompiler.stack
def decompile(decompiler):
PY36 = sys.version_info >= (3, 6)
code = decompiler.code
co_code = code.co_code
free = code.co_cellvars + code.co_freevars
try:
extended_arg = 0
while decompiler.pos < decompiler.end:
i = decompiler.pos
if i in decompiler.targets: decompiler.process_target(i)
op = ord(code.co_code[i])
i += 1
if op >= HAVE_ARGUMENT:
oparg = ord(co_code[i]) + ord(co_code[i+1])*256
if PY36:
if op >= HAVE_ARGUMENT:
oparg = ord(co_code[i + 1]) | extended_arg
extended_arg = (arg << 8) if op == EXTENDED_ARG else 0
i += 2
if op == EXTENDED_ARG:
op = ord(code.co_code[i])
i += 1
oparg = ord(co_code[i]) + ord(co_code[i+1])*256 + oparg*65536
else:
i += 1
if op >= HAVE_ARGUMENT:
oparg = ord(co_code[i]) + ord(co_code[i + 1]) * 256
i += 2
if op == EXTENDED_ARG:
op = ord(code.co_code[i])
i += 1
oparg = ord(co_code[i]) + ord(co_code[i + 1]) * 256 + oparg * 65536
i += 2
if op >= HAVE_ARGUMENT:
if op in hasconst: arg = [code.co_consts[oparg]]
elif op in hasname: arg = [code.co_names[oparg]]
elif op in hasjrel: arg = [i + oparg]
Expand Down Expand Up @@ -147,6 +156,14 @@ def BINARY_SUBSCR(decompiler):
if isinstance(oper2, ast.Tuple): return ast.Subscript(oper1, 'OP_APPLY', list(oper2.nodes))
else: return ast.Subscript(oper1, 'OP_APPLY', [ oper2 ])

def BUILD_CONST_KEY_MAP(decompiler, length):
keys = decompiler.stack.pop()
assert isinstance(keys, ast.Const)
keys = [ ast.Const(key) for key in keys.value ]
values = decompiler.pop_items(length)
pairs = list(izip(keys, values))
return ast.Dict(pairs)

def BUILD_LIST(decompiler, size):
return ast.List(decompiler.pop_items(size))

Expand Down Expand Up @@ -177,7 +194,10 @@ def CALL_FUNCTION(decompiler, argc, star=None, star2=None):
args.append(ast.Keyword(key, arg))
for i in xrange(posarg): args.append(pop())
args.reverse()
tos = pop()
return decompiler._call_function(args, star, star2)

def _call_function(decompiler, args, star=None, star2=None):
tos = decompiler.stack.pop()
if isinstance(tos, ast.GenExpr):
assert len(args) == 1 and star is None and star2 is None
genexpr = tos
Expand All @@ -192,13 +212,31 @@ def CALL_FUNCTION_VAR(decompiler, argc):
return decompiler.CALL_FUNCTION(argc, decompiler.stack.pop())

def CALL_FUNCTION_KW(decompiler, argc):
return decompiler.CALL_FUNCTION(argc, None, decompiler.stack.pop())
if sys.version_info < (3, 6):
return decompiler.CALL_FUNCTION(argc, star2=decompiler.stack.pop())
keys = decompiler.stack.pop()
assert isinstance(keys, ast.Const)
keys = keys.value
values = decompiler.pop_items(argc)
assert len(keys) <= len(values)
args = values[:-len(keys)]
for key, value in izip(keys, values[-len(keys):]):
args.append(ast.Keyword(key, value))
return decompiler._call_function(args)

def CALL_FUNCTION_VAR_KW(decompiler, argc):
star2 = decompiler.stack.pop()
star = decompiler.stack.pop()
return decompiler.CALL_FUNCTION(argc, star, star2)

def CALL_FUNCTION_EX(decompiler, argc):
star2 = None
if argc:
if argc != 1: throw(NotImplementedError)
star2 = decompiler.stack.pop()
star = decompiler.stack.pop()
return decompiler._call_function([], star, star2)

def COMPARE_OP(decompiler, op):
oper2 = decompiler.stack.pop()
oper1 = decompiler.stack.pop()
Expand Down Expand Up @@ -310,9 +348,16 @@ def MAKE_CLOSURE(decompiler, argc):
return decompiler.MAKE_FUNCTION(argc)

def MAKE_FUNCTION(decompiler, argc):
if argc: throw(NotImplementedError)
tos = decompiler.stack.pop()
if not PY2: tos = decompiler.stack.pop()
if sys.version_info >= (3, 6):
if argc:
if argc != 0x08: throw(NotImplementedError, argc)
qualname = decompiler.stack.pop()
tos = decompiler.stack.pop()
if (argc & 0x08): func_closure = decompiler.stack.pop()
else:
if argc: throw(NotImplementedError)
tos = decompiler.stack.pop()
if not PY2: tos = decompiler.stack.pop()
codeobject = tos.value
func_decompiler = Decompiler(codeobject)
# decompiler.names.update(decompiler.names) ???
Expand Down
2 changes: 1 addition & 1 deletion pony/orm/sqltranslation.py
Original file line number Diff line number Diff line change
Expand Up @@ -843,7 +843,7 @@ def __init__(subquery, parent_subquery=None, left_join=False):
subquery.alias_counters = {}
subquery.expr_counter = itertools.count(1)
else:
subquery.alias_counters = parent_subquery.alias_counters
subquery.alias_counters = parent_subquery.alias_counters.copy()
subquery.expr_counter = parent_subquery.expr_counter
subquery.used_from_subquery = False
def get_tableref(subquery, name_path, from_subquery=False):
Expand Down
5 changes: 3 additions & 2 deletions pony/orm/tests/test_declarative_func_monad.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import absolute_import, print_function, division
from pony.py23compat import PY2

import unittest
import sys, unittest
from datetime import date, datetime
from decimal import Decimal

Expand Down Expand Up @@ -115,7 +115,8 @@ def test_datetime_now1(self):
self.assertEqual(result, {Student[1], Student[2], Student[3], Student[4], Student[5]})
@raises_exception(ExprEvalError, "1 < datetime.now() raises TypeError: " +
("can't compare datetime.datetime to int" if PY2 else
"unorderable types: int() < datetime.datetime()"))
"unorderable types: int() < datetime.datetime()" if sys.version_info < (3, 6) else
"'<' not supported between instances of 'int' and 'datetime.datetime'"))
def test_datetime_now2(self):
select(s for s in Student if 1 < datetime.now())
def test_datetime_now3(self):
Expand Down
15 changes: 11 additions & 4 deletions pony/orm/tests/test_declarative_sqltranslator.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ class Room(db.Entity):
g1.rooms = [ r1, r2 ]
g2.rooms = [ r2, r3 ]
c1.students.add(s1)
c1.students.add(s2)
c2.students.add(s2)

db2 = Database('sqlite', ':memory:')
Expand Down Expand Up @@ -283,13 +284,13 @@ def test_composite_key1(self):
self.assertEqual(result, {Teacher.get(name='T1')})
def test_composite_key2(self):
result = set(select(s for s in Student if Course['Math', 1] in s.courses))
self.assertEqual(result, {Student[1]})
self.assertEqual(result, {Student[1], Student[2]})
def test_composite_key3(self):
result = set(select(s for s in Student if Course['Math', 1] not in s.courses))
self.assertEqual(result, {Student[2], Student[3]})
self.assertEqual(result, {Student[3]})
def test_composite_key4(self):
result = set(select(s for s in Student if len(c for c in Course if c not in s.courses) == 2))
self.assertEqual(result, {Student[1], Student[2]})
self.assertEqual(result, {Student[1]})
def test_composite_key5(self):
result = set(select(s for s in Student if not (c for c in Course if c not in s.courses)))
self.assertEqual(result, set())
Expand Down Expand Up @@ -332,7 +333,7 @@ def test_hint_join1(self):
self.assertEqual(result, {Student[2]})
def test_hint_join2(self):
result = set(select(c for c in Course if JOIN(len(c.students) == 1)))
self.assertEqual(result, {Course['Math', 1], Course['Economics', 1]})
self.assertEqual(result, {Course['Economics', 1]})
def test_tuple_param(self):
x = Student[1], Student[2]
result = set(select(s for s in Student if s not in x))
Expand Down Expand Up @@ -365,6 +366,12 @@ def test_lambda_4(self):
q = select(s for s in Student)
q = q.filter(lambda stud: exists(s for s in Student if stud.name < s.name))
self.assertEqual(set(q), {Student[1], Student[2]})
def test_optimized_1(self):
q = select((g, count(g.students)) for g in Group if count(g.students) > 1)
self.assertEqual(set(q), {(Group[1], 2)})
def test_optimized_2(self):
q = select((s, count(s.courses)) for s in Student if count(s.courses) > 1)
self.assertEqual(set(q), {(Student[2], 2)})


if __name__ == "__main__":
Expand Down
1 change: 1 addition & 0 deletions pony/orm/tests/test_validate.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def setUp(self):
db.execute('delete from Person')
registry = getattr(core, '__warningregistry__', {})
for key in list(registry):
if type(key) is not tuple: continue
text, category, lineno = key
if category is DatabaseContainsIncorrectEmptyValue:
del registry[key]
Expand Down
5 changes: 3 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Topic :: Software Development :: Libraries',
'Topic :: Database'
]
Expand All @@ -88,8 +89,8 @@

if __name__ == "__main__":
pv = sys.version_info[:2]
if pv not in ((2, 7), (3, 3), (3, 4), (3, 5)):
s = "Sorry, but %s %s requires Python of one of the following versions: 2.7, 3.3, 3.4 and 3.5." \
if pv not in ((2, 7), (3, 3), (3, 4), (3, 5), (3, 6)):
s = "Sorry, but %s %s requires Python of one of the following versions: 2.7, 3.3-3.6." \
" You have version %s"
print(s % (name, version, sys.version.split(' ', 1)[0]))
sys.exit(1)
Expand Down

0 comments on commit f77bf11

Please sign in to comment.