Skip to content

Commit

Permalink
Merge pull request beeware#267 from freakboy3742/master
Browse files Browse the repository at this point in the history
Added support for closures and properties.
  • Loading branch information
freakboy3742 authored Oct 3, 2016
2 parents 6bf447e + ba3eb97 commit 2cd6758
Show file tree
Hide file tree
Showing 11 changed files with 212 additions and 119 deletions.
1 change: 0 additions & 1 deletion python/common/org/Python.java
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,6 @@ public static java.util.Map<java.lang.String, org.python.Object> addToKwargs(jav
return kwargs;
}


@org.python.Method(
__doc__ = "__import__(name, globals=None, locals=None, fromlist=(), level=0) -> module" +
"\n" +
Expand Down
52 changes: 35 additions & 17 deletions python/common/org/python/types/Property.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
package org.python.types;

public class Property extends org.python.types.Object {
org.python.Object getter;
org.python.Object setter;
org.python.Object deleter;
org.python.Object docstring;
org.python.Object fget;
org.python.Object fset;
org.python.Object fdel;
org.python.Object doc;

public Property(org.python.Object fget, org.python.Object fset, org.python.Object fdel, org.python.Object doc) {
this.getter = fget;
this.setter = fset;
this.deleter = fdel;
this.docstring = doc;
this.fget = fget;
this.fset = fset;
this.fdel = fdel;
this.doc = doc;
}

@org.python.Method(
Expand All @@ -27,11 +27,11 @@ public org.python.Object __repr__() {
)
public org.python.Object __get__(org.python.Object instance, org.python.Object klass) {
// System.out.println("Property __get__ on " + instance);
if (this.getter != null) {
if (this.fget != null) {
try {
return ((org.python.types.Function) this.getter).invoke(instance, null, null);
return ((org.python.types.Function) this.fget).invoke(instance, null, null);
} catch (java.lang.ClassCastException e) {
throw new org.python.exceptions.TypeError("'" + this.getter.typeName() + "' object is not callable");
throw new org.python.exceptions.TypeError("'" + this.fget.typeName() + "' object is not callable");
}
} else {
throw new org.python.exceptions.AttributeError("can't get attribute");
Expand All @@ -44,11 +44,11 @@ public org.python.Object __get__(org.python.Object instance, org.python.Object k
)
public void __set__(org.python.Object instance, org.python.Object value) {
// System.out.println("Property __set__ on " + instance);
if (this.setter != null) {
if (this.fset != null) {
try {
((org.python.types.Function) this.setter).invoke(instance, new org.python.Object [] { value }, null);
((org.python.types.Function) this.fset).invoke(instance, new org.python.Object [] { value }, null);
} catch (java.lang.ClassCastException e) {
throw new org.python.exceptions.TypeError("'" + this.setter.typeName() + "' object is not callable");
throw new org.python.exceptions.TypeError("'" + this.fset.typeName() + "' object is not callable");
}
} else {
throw new org.python.exceptions.AttributeError("can't set attribute");
Expand All @@ -61,14 +61,32 @@ public void __set__(org.python.Object instance, org.python.Object value) {
)
public void __delete__(org.python.Object instance) {
// System.out.println("Property __delete__ on " + instance);
if (this.deleter != null) {
if (this.fdel != null) {
try {
((org.python.types.Function) this.deleter).invoke(instance, null, null);
((org.python.types.Function) this.fdel).invoke(instance, null, null);
} catch (java.lang.ClassCastException e) {
throw new org.python.exceptions.TypeError("'" + this.deleter.typeName() + "' object is not callable");
throw new org.python.exceptions.TypeError("'" + this.fdel.typeName() + "' object is not callable");
}
} else {
throw new org.python.exceptions.AttributeError("can't delete attribute");
}
}

@org.python.Method(
__doc__ = "",
args = {"fn"}
)
public org.python.Object setter(org.python.Object fn) {
// Duplicate the property, substituting the new setter.
return new org.python.types.Property(this.fget, fn, this.fdel, this.doc);
}

@org.python.Method(
__doc__ = "",
args = {"fn"}
)
public org.python.Object deleter(org.python.Object fn) {
// Duplicate the property, substituting the new deleter.
return new org.python.types.Property(this.fget, this.fset, fn, this.doc);
}
}
11 changes: 10 additions & 1 deletion tests/builtins/test_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,22 @@ class ListTests(TranspileTestCase):
class BuiltinListFunctionTests(BuiltinFunctionTestCase, TranspileTestCase):
functions = ["list"]

substitutions = {
"[1, 2.3456, 'another']": [
"[1, 'another', 2.3456]",
"[2.3456, 1, 'another']",
"[2.3456, 'another', 1]",
"['another', 1, 2.3456]",
"['another', 2.3456, 1]",
]
}

not_implemented = [
'test_bytearray',
'test_bytes',
'test_class',
'test_complex',
'test_dict',
'test_frozenset',
'test_set',
'test_str',
]
21 changes: 21 additions & 0 deletions tests/structures/test_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,24 @@ def second(self):
print(obj.second())
print('Done.')
""")

def test_redefine(self):
self.assertCodeExecution("""
class MyClass:
def __init__(self, val):
print("VAL: ", val)
self.value = val
def stuff(self, delta):
print("DELTA: ", delta)
return self.value + delta
def stuff(self, delta):
print("Redefined DELTA: ", delta)
return self.value + delta * 2
obj = MyClass(4)
obj.stuff(5)
print('Done.')
""", run_in_function=False)
1 change: 0 additions & 1 deletion tests/structures/test_decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ def calculate(value):
print("Done.")
""")

@expectedFailure
def test_decorator_with_argument(self):
self.assertCodeExecution("""
def thing(multiplier):
Expand Down
81 changes: 78 additions & 3 deletions tests/structures/test_descriptor.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,44 @@ def setter(self, value):
self._attr = value * 2
print("Attribute set")
def deleter(self, value):
def deleter(self):
print("Deleting attribute")
self._attr = 42
print("Attribute deleted")
attr = property(getter, setter, deleter)
obj = MyObject()
print("obj.attr =", obj.attr)
obj.attr = 2345
print("obj.attr =", obj.attr)
del obj.attr
print("obj.attr =", obj.attr)
print("Done.")
""")

def test_with_decorators(self):
self.assertCodeExecution("""
class MyObject:
def __init__(self):
self._attr = None
@property
def attr(self):
print("Got attribute")
return self._attr
@attr.setter
def attr(self, value):
print("Setting attribute")
self._attr = value * 2
print("Attribute set")
attr = property(getter)
@attr.deleter
def attr(self):
print("Deleting attribute")
self._attr = 42
print("Attribute deleted")
obj = MyObject()
print("obj.attr =", obj.attr)
Expand All @@ -89,4 +121,47 @@ def deleter(self, value):
del obj.attr
print("obj.attr =", obj.attr)
print("Done.")
""")
""")

def test_with_decorators_misnamed_methods(self):
self.assertCodeExecution("""
class MyObject:
def __init__(self):
self._attr = None
@property
def attr(self):
print("Got attribute")
return self._attr
@attr.setter
def attr1(self, value):
print("Setting attribute")
self._attr = value * 2
print("Attribute set")
@attr.deleter
def attr2(self):
print("Deleting attribute")
self._attr = 42
print("Attribute deleted")
obj = MyObject()
print("obj.attr =", obj.attr)
print("obj.attr1 =", obj.attr1)
print("obj.attr2 =", obj.attr2)
obj.attr1 = 2345
print("obj.attr =", obj.attr)
print("obj.attr1 =", obj.attr1)
print("obj.attr2 =", obj.attr2)
try:
obj.attr2 = 3456
print("Shouldn't be able to set value of attr2")
except AttributeError:
print("Can't set value of attr2")
del obj.attr2
print("obj.attr =", obj.attr)
print("obj.attr1 =", obj.attr1)
print("obj.attr2 =", obj.attr2)
print("Done.")
""")
14 changes: 14 additions & 0 deletions tests/structures/test_function.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,3 +207,17 @@ def myfunc(*args):
print("values count =", myfunc(*values_tuple))
print('Done.')
""", run_in_function=False)

def test_redefine(self):
self.assertCodeExecution("""
def myfunc(value):
print(value * 3)
return value + 5
def myfunc(value):
print(value * 4)
return value + 6
print("value =", myfunc(5))
print('Done.')
""")
10 changes: 5 additions & 5 deletions tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -680,7 +680,7 @@ def func(self):
x_values=SAMPLE_DATA[self.data_type],
operation=operation,
format=self.format,
substitutions=SAMPLE_SUBSTITUTIONS
substitutions=getattr(self, 'substitutions', SAMPLE_SUBSTITUTIONS)
)
return func

Expand Down Expand Up @@ -725,7 +725,7 @@ def func(self):
y_values=examples,
operation=operation,
format=self.format,
substitutions=SAMPLE_SUBSTITUTIONS
substitutions=getattr(self, 'substitutions', SAMPLE_SUBSTITUTIONS)
)
return func

Expand Down Expand Up @@ -796,7 +796,7 @@ def func(self):
y_values=examples,
operation=operation,
format=self.format,
substitutions=SAMPLE_SUBSTITUTIONS,
substitutions=getattr(self, 'substitutions', SAMPLE_SUBSTITUTIONS)
)
return func

Expand Down Expand Up @@ -861,7 +861,7 @@ def func(self):
f_values=self.functions,
operation=operation,
format=self.format,
substitutions=SAMPLE_SUBSTITUTIONS
substitutions=getattr(self, 'substitutions', SAMPLE_SUBSTITUTIONS)
)
return func

Expand Down Expand Up @@ -913,7 +913,7 @@ def func(self):
y_values=examples2,
operation=operation,
format=self.format,
substitutions=SAMPLE_SUBSTITUTIONS
substitutions=getattr(self, 'substitutions', SAMPLE_SUBSTITUTIONS)
)
return func

Expand Down
Loading

0 comments on commit 2cd6758

Please sign in to comment.