"""
self._check_in_scopes(code, raises=NameError)
+ def test_references___class___nested(self):
+ code = """
+ res = [(lambda: __class__)() for _ in [1]]
+ """
+ self._check_in_scopes(code, raises=NameError)
+
+ def test_references___class___nested_used(self):
+ class _C:
+ res = [lambda: __class__ for _ in [1]]
+ self.assertIs(_C.res[0](), _C)
+
def test_references___class___defined(self):
code = """
__class__ = 2
code, outputs={"res": [2]}, scopes=["module", "function"])
self._check_in_scopes(code, raises=NameError, scopes=["class"])
+ def test_references___class___defined_nested(self):
+ code = """
+ __class__ = 2
+ res = [(lambda: __class__)() for x in [1]]
+ """
+ self._check_in_scopes(
+ code, outputs={"res": [2]}, scopes=["module", "function"])
+ self._check_in_scopes(code, raises=NameError, scopes=["class"])
+
def test_references___classdict__(self):
code = """
class i: [__classdict__ for x in y]
"""
self._check_in_scopes(code, raises=NameError)
+ def test_references___classdict___nested(self):
+ class _C:
+ res = [(lambda: __classdict__)() for _ in [1]]
+ self.assertIn("res", _C.res[0])
+
def test_references___conditional_annotations__(self):
code = """
class i: [__conditional_annotations__ for x in y]
"""
self._check_in_scopes(code, raises=NameError)
+ def test_references___conditional_annotations___nested(self):
+ code = """
+ class i: [lambda: __conditional_annotations__ for x in y]
+ """
+ self._check_in_scopes(code, raises=NameError)
+
def test_references___class___enclosing(self):
code = """
__class__ = 2
return 0;
}
// __class__, __classdict__ and __conditional_annotations__ are
- // never allowed to be free through a class scope (see
- // drop_class_free)
+ // not allowed to be free through a class scope (see
+ // drop_class_free) unless children scopes need it
if (scope == FREE && ste->ste_type == ClassBlock &&
(_PyUnicode_EqualToASCIIString(k, "__class__") ||
_PyUnicode_EqualToASCIIString(k, "__classdict__") ||
_PyUnicode_EqualToASCIIString(k, "__conditional_annotations__"))) {
scope = GLOBAL_IMPLICIT;
- if (PySet_Discard(comp_free, k) < 0) {
+ int child_needs_free = is_free_in_any_child(comp, k);
+ if (child_needs_free < 0) {
return 0;
}
-
+ if (!child_needs_free) {
+ if (PySet_Discard(comp_free, k) < 0) {
+ return 0;
+ }
+ }
if (_PyUnicode_EqualToASCIIString(k, "__class__")) {
remove_dunder_class = 1;
}