Fail closed on class namespace alias mutations
This commit is contained in:
@@ -1659,6 +1659,107 @@ NODE_CLASS_MAPPINGS = {
|
|||||||
self.assertEqual({}, result["nodes"])
|
self.assertEqual({}, result["nodes"])
|
||||||
self.assertEqual("no_static_nodes", result["pack"]["status"])
|
self.assertEqual("no_static_nodes", result["pack"]["status"])
|
||||||
|
|
||||||
|
def test_class_body_locals_alias_return_types_setitem_skips_node(self):
|
||||||
|
source = '''
|
||||||
|
class LocalsAliasReturnTypesNode:
|
||||||
|
RETURN_TYPES = ("IMAGE",)
|
||||||
|
ns = locals()
|
||||||
|
ns["RETURN_TYPES"] = ("MASK",)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(cls):
|
||||||
|
return {
|
||||||
|
"required": {
|
||||||
|
"image": ("IMAGE",),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NODE_CLASS_MAPPINGS = {
|
||||||
|
"LocalsAliasReturnTypesNode": LocalsAliasReturnTypesNode,
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
result = self._extract_source(source, "locals-alias-return-types-pack")
|
||||||
|
|
||||||
|
self.assertEqual({}, result["nodes"])
|
||||||
|
self.assertEqual("no_static_nodes", result["pack"]["status"])
|
||||||
|
|
||||||
|
def test_class_body_vars_alias_return_types_update_skips_node(self):
|
||||||
|
source = '''
|
||||||
|
class VarsAliasReturnTypesNode:
|
||||||
|
RETURN_TYPES = ("IMAGE",)
|
||||||
|
ns = vars()
|
||||||
|
ns.update(RETURN_TYPES=("MASK",))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(cls):
|
||||||
|
return {
|
||||||
|
"required": {
|
||||||
|
"image": ("IMAGE",),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NODE_CLASS_MAPPINGS = {
|
||||||
|
"VarsAliasReturnTypesNode": VarsAliasReturnTypesNode,
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
result = self._extract_source(source, "vars-alias-return-types-pack")
|
||||||
|
|
||||||
|
self.assertEqual({}, result["nodes"])
|
||||||
|
self.assertEqual("no_static_nodes", result["pack"]["status"])
|
||||||
|
|
||||||
|
def test_class_body_chained_namespace_alias_return_types_setitem_skips_node(self):
|
||||||
|
source = '''
|
||||||
|
class ChainedNamespaceAliasReturnTypesNode:
|
||||||
|
RETURN_TYPES = ("IMAGE",)
|
||||||
|
ns = other = locals()
|
||||||
|
other["RETURN_TYPES"] = ("MASK",)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(cls):
|
||||||
|
return {
|
||||||
|
"required": {
|
||||||
|
"image": ("IMAGE",),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NODE_CLASS_MAPPINGS = {
|
||||||
|
"ChainedNamespaceAliasReturnTypesNode": ChainedNamespaceAliasReturnTypesNode,
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
result = self._extract_source(source, "chained-namespace-alias-return-types-pack")
|
||||||
|
|
||||||
|
self.assertEqual({}, result["nodes"])
|
||||||
|
self.assertEqual("no_static_nodes", result["pack"]["status"])
|
||||||
|
|
||||||
|
def test_class_body_namespace_alias_return_names_update_skips_node(self):
|
||||||
|
source = '''
|
||||||
|
class NamespaceAliasReturnNamesNode:
|
||||||
|
RETURN_TYPES = ("IMAGE",)
|
||||||
|
RETURN_NAMES = ["image"]
|
||||||
|
ns = locals()
|
||||||
|
ns.update(RETURN_NAMES=["mask"])
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(cls):
|
||||||
|
return {
|
||||||
|
"required": {
|
||||||
|
"image": ("IMAGE",),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NODE_CLASS_MAPPINGS = {
|
||||||
|
"NamespaceAliasReturnNamesNode": NamespaceAliasReturnNamesNode,
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
result = self._extract_source(source, "namespace-alias-return-names-pack")
|
||||||
|
|
||||||
|
self.assertEqual({}, result["nodes"])
|
||||||
|
self.assertEqual("no_static_nodes", result["pack"]["status"])
|
||||||
|
|
||||||
def test_except_handler_binding_to_return_types_skips_node(self):
|
def test_except_handler_binding_to_return_types_skips_node(self):
|
||||||
source = '''
|
source = '''
|
||||||
class ExceptHandlerBoundReturnTypesNode:
|
class ExceptHandlerBoundReturnTypesNode:
|
||||||
@@ -4234,6 +4335,40 @@ NODE_CLASS_MAPPINGS = {
|
|||||||
self.assertEqual({}, result["nodes"])
|
self.assertEqual({}, result["nodes"])
|
||||||
self.assertEqual("no_static_nodes", result["pack"]["status"])
|
self.assertEqual("no_static_nodes", result["pack"]["status"])
|
||||||
|
|
||||||
|
def test_class_body_namespace_alias_input_types_patch_skips_node(self):
|
||||||
|
source = '''
|
||||||
|
def build_inputs(cls):
|
||||||
|
return {
|
||||||
|
"required": {
|
||||||
|
"mask": ("MASK",),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class NamespaceAliasInputTypesPatchNode:
|
||||||
|
RETURN_TYPES = ("IMAGE",)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(cls):
|
||||||
|
return {
|
||||||
|
"required": {
|
||||||
|
"image": ("IMAGE",),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
ns = locals()
|
||||||
|
ns["INPUT_TYPES"] = build_inputs
|
||||||
|
|
||||||
|
|
||||||
|
NODE_CLASS_MAPPINGS = {
|
||||||
|
"NamespaceAliasInputTypesPatchNode": NamespaceAliasInputTypesPatchNode,
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
result = self._extract_source(source, "namespace-alias-input-types-patch-pack")
|
||||||
|
|
||||||
|
self.assertEqual({}, result["nodes"])
|
||||||
|
self.assertEqual("no_static_nodes", result["pack"]["status"])
|
||||||
|
|
||||||
def test_input_types_alias_observed_by_arbitrary_call_skips_node(self):
|
def test_input_types_alias_observed_by_arbitrary_call_skips_node(self):
|
||||||
source = '''
|
source = '''
|
||||||
class AliasObservedInputTypesNode:
|
class AliasObservedInputTypesNode:
|
||||||
|
|||||||
@@ -933,6 +933,15 @@ def _class_body_module_mutation_names(cls):
|
|||||||
return names
|
return names
|
||||||
|
|
||||||
|
|
||||||
|
def _class_body_namespace_mutation_names(cls):
|
||||||
|
names = set()
|
||||||
|
namespace_aliases = set()
|
||||||
|
for stmt in cls.body:
|
||||||
|
names.update(_namespace_alias_mutation_target_names(stmt, namespace_aliases))
|
||||||
|
_update_namespace_aliases(stmt, namespace_aliases)
|
||||||
|
return names
|
||||||
|
|
||||||
|
|
||||||
def _apply_module_stmt_to_env(stmt, env, class_bindings=None):
|
def _apply_module_stmt_to_env(stmt, env, class_bindings=None):
|
||||||
names = _mutating_call_target_names(stmt)
|
names = _mutating_call_target_names(stmt)
|
||||||
if isinstance(stmt, ast.ClassDef):
|
if isinstance(stmt, ast.ClassDef):
|
||||||
@@ -1165,6 +1174,9 @@ def _update_input_types_aliases_from_unpack(target, value, aliases):
|
|||||||
def _class_attr(cls, name, env):
|
def _class_attr(cls, name, env):
|
||||||
value = _MISSING
|
value = _MISSING
|
||||||
aliases = set()
|
aliases = set()
|
||||||
|
namespace_mutations = _class_body_namespace_mutation_names(cls)
|
||||||
|
if _name_invalidated_by(name, namespace_mutations):
|
||||||
|
return _INVALID
|
||||||
for stmt in cls.body:
|
for stmt in cls.body:
|
||||||
mutating_targets = _mutating_call_target_names(stmt)
|
mutating_targets = _mutating_call_target_names(stmt)
|
||||||
observed_targets = _arbitrary_call_observed_names(stmt)
|
observed_targets = _arbitrary_call_observed_names(stmt)
|
||||||
@@ -1295,6 +1307,9 @@ def _input_types(cls, env, decorator_env):
|
|||||||
value = _MISSING
|
value = _MISSING
|
||||||
aliases = set()
|
aliases = set()
|
||||||
classmethod_shadowed = "classmethod" in decorator_env
|
classmethod_shadowed = "classmethod" in decorator_env
|
||||||
|
namespace_mutations = _class_body_namespace_mutation_names(cls)
|
||||||
|
if _name_invalidated_by("INPUT_TYPES", namespace_mutations):
|
||||||
|
return None
|
||||||
for stmt in cls.body:
|
for stmt in cls.body:
|
||||||
mutating_targets = _mutating_call_target_names(stmt)
|
mutating_targets = _mutating_call_target_names(stmt)
|
||||||
observed_targets = _arbitrary_call_observed_names(stmt)
|
observed_targets = _arbitrary_call_observed_names(stmt)
|
||||||
|
|||||||
Reference in New Issue
Block a user