Skip to content

Commit 0163429

Browse files
committed
fixed del for nonlocal scopes; added test cases
1 parent dfd7977 commit 0163429

File tree

2 files changed

+84
-12
lines changed

2 files changed

+84
-12
lines changed

custom_components/pyscript/eval.py

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -154,14 +154,14 @@ class EvalLocalVar:
154154
def __init__(self, name, **kwargs):
155155
"""Initialize value of local symbol."""
156156
self.name = name
157-
self.valid = False
157+
self.defined = False
158158
if "value" in kwargs:
159159
self.value = kwargs["value"]
160-
self.valid = True
160+
self.defined = True
161161

162162
def get(self):
163163
"""Get value of local symbol."""
164-
if not self.valid:
164+
if not self.defined:
165165
raise NameError(f"name '{self.name}' is not defined")
166166
return self.value
167167

@@ -172,15 +172,19 @@ def get_name(self):
172172
def set(self, value):
173173
"""Set value of local symbol."""
174174
self.value = value
175-
self.valid = True
175+
self.defined = True
176176

177-
def defined(self):
178-
"""Return whether value is valid."""
179-
return self.valid
177+
def is_defined(self):
178+
"""Return whether value is defined."""
179+
return self.defined
180+
181+
def set_undefined(self):
182+
"""Set local symbol to undefined."""
183+
self.defined = False
180184

181185
def __getattr__(self, attr):
182186
"""Get attribute of local variable."""
183-
if not self.valid:
187+
if not self.defined:
184188
raise NameError(f"name '{self.name}' is not defined")
185189
return getattr(self.value, attr)
186190

@@ -614,7 +618,7 @@ async def call(self, ast_ctx, args=None, kwargs=None):
614618
for name, value in self.local_sym_table.items():
615619
if name in sym_table:
616620
sym_table[name] = EvalLocalVar(name, value=sym_table[name])
617-
elif value.defined():
621+
elif value.is_defined():
618622
sym_table[name] = value
619623
else:
620624
sym_table[name] = EvalLocalVar(name)
@@ -1145,9 +1149,15 @@ async def ast_delete(self, arg):
11451149
if arg1.id in self.global_sym_table:
11461150
del self.global_sym_table[arg1.id]
11471151
elif arg1.id in self.sym_table:
1148-
del self.sym_table[arg1.id]
1152+
if isinstance(self.sym_table[arg1.id], EvalLocalVar):
1153+
if self.sym_table[arg1.id].is_defined():
1154+
self.sym_table[arg1.id].set_undefined()
1155+
else:
1156+
raise NameError(f"name '{arg1.id}' is not defined")
1157+
else:
1158+
del self.sym_table[arg1.id]
11491159
else:
1150-
raise NameError(f"name '{arg1.id}' is not defined in del")
1160+
raise NameError(f"name '{arg1.id}' is not defined")
11511161
else:
11521162
raise NotImplementedError(f"unknown target type {arg1} in del")
11531163

@@ -1662,6 +1672,10 @@ async def get_names_set(self, arg, names, nonlocal_names=None, global_names=None
16621672
local_names.add(arg.name)
16631673
names.add(arg.name)
16641674
return
1675+
elif cls_name == "Delete":
1676+
for arg1 in arg.targets:
1677+
if isinstance(arg1, ast.Name):
1678+
local_names.add(arg1.id)
16651679
for child in ast.iter_child_nodes(arg):
16661680
await self.get_names_set(
16671681
child,

tests/test_unit_eval.py

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,38 @@ def f1(x):
784784
""",
785785
[3, 12, 16, 42],
786786
],
787+
[
788+
"""
789+
def func():
790+
def f1():
791+
nonlocal i
792+
del i
793+
i = 20
794+
return i + 1
795+
796+
def f2():
797+
return 2 * i
798+
799+
i = 10
800+
return f1, f2
801+
802+
f1, f2 = func()
803+
[f2(), f1(), f2()]
804+
""",
805+
[20, 21, 40],
806+
],
807+
[
808+
"""
809+
def func():
810+
def func2():
811+
z = x + 2
812+
return z
813+
x = 1
814+
return func2()
815+
func()
816+
""",
817+
3,
818+
],
787819
]
788820

789821

@@ -836,7 +868,7 @@ async def test_eval(hass):
836868
"import math; math.sinXYZ",
837869
"Exception in test line 1 column 13: module 'math' has no attribute 'sinXYZ'",
838870
],
839-
["del xx", "Exception in test line 1 column 0: name 'xx' is not defined in del"],
871+
["del xx", "Exception in test line 1 column 0: name 'xx' is not defined"],
840872
["return", "Exception in test line 1 column 0: return statement outside function"],
841873
["break", "Exception in test line 1 column 0: break statement outside loop"],
842874
["continue", "Exception in test line 1 column 0: continue statement outside loop"],
@@ -912,6 +944,32 @@ def func():
912944
""",
913945
"Exception in test line 4 column 10: 'bad_key'",
914946
],
947+
[
948+
"""
949+
def func():
950+
def func2():
951+
nonlocal x
952+
del x
953+
del x
954+
x = 1
955+
func2()
956+
func()
957+
""",
958+
"Exception in func2(), test line 6 column 8: name 'x' is not defined",
959+
],
960+
[
961+
"""
962+
def func():
963+
def func2():
964+
z = x + 2
965+
return z
966+
del x
967+
x = 1
968+
return func2()
969+
func()
970+
""",
971+
"Exception in func2(), test line 4 column 12: name 'x' is not defined",
972+
],
915973
]
916974

917975

0 commit comments

Comments
 (0)