Skip to content

Commit 27d3bc1

Browse files
author
hartsantler
committed
added __setattr__ operator overloading, and tests to make sure its compatible with instance vs class-level attributes.
1 parent 9096e40 commit 27d3bc1

3 files changed

Lines changed: 202 additions & 6 deletions

File tree

pythonscript/python_to_pythonjs.py

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -501,14 +501,46 @@ def visit_Assign(self, node):
501501
elif hasattr(target.value, 'returns_type'):
502502
typedef = self.get_typedef( class_name=target.value.returns_type )
503503

504-
fallback = True
505-
if typedef and target.attr in typedef.properties:
506-
setter = typedef.properties[ target.attr ].get('set',None)
507-
if setter:
504+
505+
if typedef and target.attr in typedef.properties and 'set' in typedef.properties[ target.attr ]:
506+
setter = typedef.properties[ target.attr ]['set']
507+
writer.write( '%s( [%s, %s] )' %(setter, target_value, self.visit(node.value)) )
508+
elif typedef and target.attr in typedef.class_attributes:
509+
writer.write( '''%s['__class__']['__dict__']['%s'] = %s''' %(target_value, target.attr, self.visit(node.value)))
510+
elif typedef and target.attr in typedef.attributes:
511+
writer.write( '''%s['__dict__']['%s'] = %s''' %(target_value, target.attr, self.visit(node.value)))
512+
513+
elif typedef and typedef.parents:
514+
parent_prop = typedef.check_for_parent_with( property=target.attr )
515+
parent_classattr = typedef.check_for_parent_with( class_attribute=target.attr )
516+
parent_setattr = typedef.check_for_parent_with( method='__setattr__' )
517+
if parent_prop and 'set' in parent_prop.properties[target.attr]:
518+
setter = parent_prop.properties[target.attr]['set']
508519
writer.write( '%s( [%s, %s] )' %(setter, target_value, self.visit(node.value)) )
509-
fallback = False
520+
elif parent_classattr:
521+
writer.write( "window['__%s_attrs']['%s'] = %s" %(parent_classattr.name, target.attr, self.visit(node.value)) )
522+
elif parent_setattr:
523+
func = parent_setattr.get_pythonjs_function_name( '__setattr__' )
524+
writer.write( '%s([%s, "%s", %s])' %(func, target_value, target.attr, self.visit(node.value)) )
525+
526+
elif '__setattr__' in typedef.methods:
527+
func = typedef.get_pythonjs_function_name( '__setattr__' )
528+
writer.write( '%s([%s, "%s", %s])' %(func, target_value, target.attr, self.visit(node.value)) )
529+
530+
else:
531+
code = 'set_attribute(%s, "%s", %s)' % (
532+
target_value,
533+
target.attr,
534+
self.visit(node.value)
535+
)
536+
writer.write(code)
537+
538+
elif typedef and '__setattr__' in typedef.methods:
539+
func = typedef.get_pythonjs_function_name( '__setattr__' )
540+
writer.write( '%s([%s, "%s", %s])' %(func, target_value, target.attr, self.visit(node.value)) )
510541

511-
if fallback:
542+
543+
else:
512544
code = 'set_attribute(%s, "%s", %s)' % (
513545
target_value,
514546
target.attr,

tests/test__setattr__.html

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<html>
2+
<head>
3+
<script src="pythonscript.js"></script>
4+
5+
<script type="text/python" closure="false">
6+
7+
8+
class B:
9+
Y = 'parent class attribute'
10+
11+
@property
12+
def y(self):
13+
return self._y
14+
@y.setter
15+
def y(self, value):
16+
print 'using @y.setter:', value
17+
self._y = value
18+
19+
class C( B ):
20+
Z = 'my class attribute'
21+
22+
def __init__(self, x,y,z):
23+
self.x = x
24+
self._y = y
25+
self._z = z
26+
27+
@property
28+
def z(self):
29+
return self._z
30+
@z.setter
31+
def z(self, value):
32+
print 'using @z.setter:', value
33+
self._z = value
34+
35+
def __setattr__(self, name, value):
36+
print 'using __setattr__:', name, value
37+
setattr(self, name, value)
38+
39+
40+
41+
def test():
42+
a = C(1,2,3)
43+
44+
print('--testing parent class level attribute')
45+
print( a.Y )
46+
a.Y = 'changed grandparent class level attribute'
47+
print( a.Y )
48+
print('--testing class level attribute')
49+
print( a.Z )
50+
a.Z = 'changed parent class level attribute'
51+
print( a.Z )
52+
53+
print('--testing normal attributes and @property')
54+
print( a.x )
55+
print( a.y )
56+
print( a.z )
57+
a.x = 100
58+
a.y = 200
59+
a.z = 300
60+
print( a.x )
61+
print( a.y )
62+
print( a.z )
63+
64+
print('--testing __setattr__')
65+
a.hello = 'HELLO'
66+
a.world = 'WORLD'
67+
a.XXX = 999
68+
69+
print( a.hello )
70+
print( a.world )
71+
print( a.XXX )
72+
73+
74+
</script>
75+
</head>
76+
77+
<body>
78+
<button onclick="test()">click me</button>
79+
</body>
80+
</html>
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<html>
2+
<head>
3+
<script src="pythonscript.js"></script>
4+
5+
<script type="text/python" closure="false">
6+
7+
class A:
8+
X = 'root parent class attribute'
9+
10+
def __setattr__(self, name, value):
11+
print 'using __setattr__:', name, value
12+
setattr(self, name, value)
13+
14+
class B( A ):
15+
Y = 'parent class attribute'
16+
17+
@property
18+
def y(self):
19+
return self._y
20+
@y.setter
21+
def y(self, value):
22+
print 'using @y.setter:', value
23+
self._y = value
24+
25+
class C( B ):
26+
Z = 'my class attribute'
27+
28+
def __init__(self, x,y,z):
29+
self.x = x
30+
self._y = y
31+
self._z = z
32+
33+
@property
34+
def z(self):
35+
return self._z
36+
@z.setter
37+
def z(self, value):
38+
print 'using @z.setter:', value
39+
self._z = value
40+
41+
42+
def test():
43+
a = C(1,2,3)
44+
print('--testing root class level attribute')
45+
print( a.X )
46+
a.X = 'changed root level attribute'
47+
print( a.X )
48+
print('--testing parent class level attribute')
49+
print( a.Y )
50+
a.Y = 'changed grandparent class level attribute'
51+
print( a.Y )
52+
print('--testing class level attribute')
53+
print( a.Z )
54+
a.Z = 'changed parent class level attribute'
55+
print( a.Z )
56+
57+
print('--testing normal attributes and @property')
58+
print( a.x )
59+
print( a.y )
60+
print( a.z )
61+
a.x = 100
62+
a.y = 200
63+
a.z = 300
64+
print( a.x )
65+
print( a.y )
66+
print( a.z )
67+
68+
print('--testing __setattr__')
69+
a.hello = 'HELLO'
70+
a.world = 'WORLD'
71+
a.XXX = 999
72+
73+
print( a.hello )
74+
print( a.world )
75+
print( a.XXX )
76+
77+
78+
</script>
79+
</head>
80+
81+
<body>
82+
<button onclick="test()">click me</button>
83+
</body>
84+
</html>

0 commit comments

Comments
 (0)