fix hasattr problem

This commit is contained in:
liangzhibo 2022-08-24 14:35:45 +08:00
parent c32131f166
commit ee7e869106
15 changed files with 132 additions and 69 deletions

View File

@ -61,6 +61,7 @@
"mindspore/mindspore/python/mindspore/ops/functional.py" "wildcard-import" "mindspore/mindspore/python/mindspore/ops/functional.py" "wildcard-import"
"mindspore/mindspore/python/mindspore/ops/functional.py" "unused-wildcard-import" "mindspore/mindspore/python/mindspore/ops/functional.py" "unused-wildcard-import"
"mindspore/mindspore/python/mindspore/_extends/parse/standard_method.py" "redefined-builtin" "mindspore/mindspore/python/mindspore/_extends/parse/standard_method.py" "redefined-builtin"
"mindspore/mindspore/python/mindspore/_extends/parse/standard_method.py" "protected-access"
"mindspore/mindspore/python/mindspore/common/tensor.py" "redefined-builtin" "mindspore/mindspore/python/mindspore/common/tensor.py" "redefined-builtin"
"mindspore/mindspore/python/mindspore/ops/function/array_func.py" "redefined-builtin" "mindspore/mindspore/python/mindspore/ops/function/array_func.py" "redefined-builtin"
"mindspore/mindspore/python/mindspore/ops/operations/array_ops.py" "redefined-builtin" "mindspore/mindspore/python/mindspore/ops/operations/array_ops.py" "redefined-builtin"

View File

@ -313,13 +313,6 @@ py::object GetMsClassPyObj(const abstract::PartialAbstractClosurePtr &ms_class_a
<< "got: " << ms_class_args.size() << "."; << "got: " << ms_class_args.size() << ".";
} }
auto first_arg = ms_class_args[0]; auto first_arg = ms_class_args[0];
MS_EXCEPTION_IF_NULL(first_arg);
auto arg_type = first_arg->BuildType();
auto arg_type_id = arg_type->type_id();
if (arg_type_id != kObjectTypeClass) {
MS_LOG(EXCEPTION) << "When the first input to IsInstance is PartialAbstractClosure, its first arg should be of "
<< "type kObjectTypeClass but got: " << TypeIdToString(arg_type_id) << ".";
}
auto class_value = first_arg->BuildValue(); auto class_value = first_arg->BuildValue();
MS_EXCEPTION_IF_NULL(class_value); MS_EXCEPTION_IF_NULL(class_value);
return ValueToPyData(class_value); return ValueToPyData(class_value);

View File

@ -45,17 +45,19 @@ AnfNodePtr Resolver::operator()(const OptimizerPtr &optimizer, const AnfNodePtr
auto name_space = GetValueNode<parse::NameSpacePtr>(object_node); auto name_space = GetValueNode<parse::NameSpacePtr>(object_node);
auto attr_str = GetValue<std::string>(GetValueNode(attr_node)); auto attr_str = GetValue<std::string>(GetValueNode(attr_node));
parse::SymbolPtr symbol = std::make_shared<parse::Symbol>(attr_str); parse::SymbolPtr symbol = std::make_shared<parse::Symbol>(attr_str);
return parse::ResolveSymbol(optimizer->manager(), name_space, symbol, node); auto ret = parse::ResolveSymbol(optimizer->manager(), name_space, symbol, node);
// If object has no attribute, ret will be null. The attribute may not be used.
// Let getattr be resolved in static_analysis.
if (IsValueNode<TypeNull>(ret)) {
return nullptr;
}
return ret;
} }
// {prim::kPrimGetAttr, MsClassObject, attr} // {prim::kPrimGetAttr, MsClassObject, attr}
if (IsValueNode<parse::MsClassObject>(object_node)) { if (IsValueNode<parse::MsClassObject>(object_node)) {
auto ms_class = GetValueNode<parse::MsClassObjectPtr>(object_node)->obj(); auto ms_class = GetValueNode<parse::MsClassObjectPtr>(object_node)->obj();
auto attr_str = GetValue<std::string>(GetValueNode(attr_node)); auto attr_str = GetValue<std::string>(GetValueNode(attr_node));
auto new_node = parse::ResolveMsClassWithAttr(optimizer->manager(), ms_class, attr_str, node); return parse::ResolveMsClassWithAttr(optimizer->manager(), ms_class, attr_str, node);
if (new_node == nullptr || IsValueNode<None>(new_node)) {
MS_EXCEPTION(AttributeError) << py::str(ms_class) << " object has no attribute: " << attr_str << ".";
}
return new_node;
} }
// {prim::kPrimGetAttr, bool, attr} // {prim::kPrimGetAttr, bool, attr}
if (IsValueNode<BoolImm>(object_node)) { if (IsValueNode<BoolImm>(object_node)) {
@ -68,7 +70,13 @@ AnfNodePtr Resolver::operator()(const OptimizerPtr &optimizer, const AnfNodePtr
auto name_space = GetValueNode<parse::NameSpacePtr>(ns_node.GetNode(node)); auto name_space = GetValueNode<parse::NameSpacePtr>(ns_node.GetNode(node));
auto symbol = GetValueNode<parse::SymbolPtr>(sym_node.GetNode(node)); auto symbol = GetValueNode<parse::SymbolPtr>(sym_node.GetNode(node));
auto manager = optimizer->manager(); auto manager = optimizer->manager();
return parse::ResolveSymbol(manager, name_space, symbol, node); auto ret = parse::ResolveSymbol(manager, name_space, symbol, node);
// If object has no attribute, ret will be null. The attribute may not be used.
// Let getattr be resolved in static_analysis.
if (IsValueNode<TypeNull>(ret)) {
return nullptr;
}
return ret;
}; };
// {prim::kPrimGetAttr, object, attr} // {prim::kPrimGetAttr, object, attr}

View File

@ -1329,6 +1329,42 @@ AnfNodePtr Parser::ProcessAttributeWithClassMember(const FunctionBlockPtr &block
return var_node; return var_node;
} }
AnfNodePtr Parser::ParseMsTensor(const FunctionBlockPtr &block, const py::object &node, const py::object &value_body,
const AnfNodePtr &value_node) {
if (py::hasattr(value_body, "id")) {
std::string module_name = py::cast<std::string>(python_adapter::GetPyObjAttr(value_body, "id"));
py::dict global_dict = const_cast<py::dict &>(block->global_py_params());
if (global_dict.contains(module_name)) {
py::object module_obj = global_dict[py::str(module_name)];
std::string module_str = py::cast<std::string>(py::str(module_obj));
bool the_module_is_mindspore = module_str.find("module 'mindspore'") != std::string::npos;
if (the_module_is_mindspore) {
std::string script_text = py::cast<std::string>(ast()->GetAstNodeText(node));
AnfNodePtr interpret_node = MakeInterpretNode(block, value_node, script_text);
interpret_node->set_interpret(true);
interpret_node->set_interpret_internal_type(true);
return interpret_node;
}
}
}
return nullptr;
}
AnfNodePtr Parser::ParseNull(const FunctionBlockPtr &block, const py::object &value_body) {
if (py::hasattr(value_body, "id")) {
std::string module_name = py::cast<std::string>(python_adapter::GetPyObjAttr(value_body, "id"));
py::dict global_dict = const_cast<py::dict &>(block->global_py_params());
if (global_dict.contains(module_name)) {
py::object module_obj = global_dict[py::str(module_name)];
std::string module_str = py::cast<std::string>(py::str(module_obj));
if (module_str.find("module 'mindspore.common.dtype'") != std::string::npos) {
return NewValueNode(std::make_shared<TypeNull>());
}
}
}
return nullptr;
}
// Process call attributes of class type define, eg: x.y() // Process call attributes of class type define, eg: x.y()
AnfNodePtr Parser::ParseAttribute(const FunctionBlockPtr &block, const py::object &node) { AnfNodePtr Parser::ParseAttribute(const FunctionBlockPtr &block, const py::object &node) {
MS_LOG(DEBUG) << "Process ast Attribute"; MS_LOG(DEBUG) << "Process ast Attribute";
@ -1356,24 +1392,18 @@ AnfNodePtr Parser::ParseAttribute(const FunctionBlockPtr &block, const py::objec
MS_LOG(DEBUG) << "Attr = " << attr_str; MS_LOG(DEBUG) << "Attr = " << attr_str;
// The fallback feature is enabled in default. // The fallback feature is enabled in default.
static const auto use_fallback = (support_fallback() != "0"); static const auto use_fallback = (support_fallback() != "0");
// Process xxx.Tensor() and xxx is mindspore. Check it with global dict.
if (use_fallback && attr_str == "Tensor") { if (use_fallback && attr_str == "Tensor") {
// Check the module is mindspore // Process xxx.Tensor() and xxx is mindspore.
if (py::hasattr(value_body, "id")) { auto ret = ParseMsTensor(block, node, value_body, value_node);
std::string module_name = py::cast<std::string>(python_adapter::GetPyObjAttr(value_body, "id")); if (ret != nullptr) {
py::dict global_dict = const_cast<py::dict &>(block->global_py_params()); return ret;
if (global_dict.contains(module_name)) {
py::object module_obj = global_dict[py::str(module_name)];
std::string module_str = py::cast<std::string>(py::str(module_obj));
bool the_module_is_mindspore = module_str.find("module 'mindspore'") != std::string::npos;
if (the_module_is_mindspore) {
std::string script_text = py::cast<std::string>(ast()->GetAstNodeText(node));
AnfNodePtr interpret_node = MakeInterpretNode(block, value_node, script_text);
interpret_node->set_interpret(true);
interpret_node->set_interpret_internal_type(true);
return interpret_node;
} }
} }
if (attr_str == "_null") {
// For stype._null, return TypeNull value node directly.
auto ret = ParseNull(block, value_body);
if (ret != nullptr) {
return ret;
} }
} }
AnfNodePtr attr_node = nullptr; AnfNodePtr attr_node = nullptr;

View File

@ -188,6 +188,11 @@ class Parser {
AnfNodePtr ParseIfExp(const FunctionBlockPtr &block, const py::object &node); AnfNodePtr ParseIfExp(const FunctionBlockPtr &block, const py::object &node);
// Process class type define // Process class type define
AnfNodePtr ParseAttribute(const FunctionBlockPtr &block, const py::object &node); AnfNodePtr ParseAttribute(const FunctionBlockPtr &block, const py::object &node);
// Process ms Tensor
AnfNodePtr ParseMsTensor(const FunctionBlockPtr &block, const py::object &node, const py::object &value_body,
const AnfNodePtr &value_node);
// Process dtype._null
AnfNodePtr ParseNull(const FunctionBlockPtr &block, const py::object &value_body);
// Process a compare expression // Process a compare expression
AnfNodePtr ParseCompare(const FunctionBlockPtr &block, const py::object &node); AnfNodePtr ParseCompare(const FunctionBlockPtr &block, const py::object &node);
// Process a bool operation // Process a bool operation

View File

@ -647,9 +647,6 @@ AnfNodePtr ResolveMsClassWithAttr(const FuncGraphManagerPtr &manager, const py::
return nullptr; return nullptr;
} }
py::object attr_obj = py::getattr(cls_obj, common::SafeCStr(attr)); py::object attr_obj = py::getattr(cls_obj, common::SafeCStr(attr));
if (py::isinstance<py::none>(attr_obj)) {
return nullptr;
}
AnfNodePtr res_node = ResolveObjectAndAddToManager(manager, attr_obj, get_attr_node); AnfNodePtr res_node = ResolveObjectAndAddToManager(manager, attr_obj, get_attr_node);
TraceManager::ClearParseOrResolveDebugInfo(); TraceManager::ClearParseOrResolveDebugInfo();
return res_node; return res_node;

View File

@ -1428,7 +1428,8 @@ EvalResultPtr GetEvaluatedValueForNameSpaceString(const AbstractBasePtrList &arg
if (new_node == nullptr) { if (new_node == nullptr) {
MS_LOG(EXCEPTION) << "Resolve node failed"; MS_LOG(EXCEPTION) << "Resolve node failed";
} }
if (IsValueNode<None>(new_node)) {
if (IsValueNode<TypeNull>(new_node)) {
// Do not find the attribute. // Do not find the attribute.
constexpr auto max_args_len = 3; constexpr auto max_args_len = 3;
bool has_default = (args_spec_list.size() == max_args_len); bool has_default = (args_spec_list.size() == max_args_len);
@ -1513,7 +1514,7 @@ EvalResultPtr GetEvaluatedValueForMsClassAttrOrMethod(const AbstractBasePtrList
FuncGraphPtr func_graph = out_node->func_graph(); FuncGraphPtr func_graph = out_node->func_graph();
// If the attribute is not found and the default is not set, AttributeError will be raised. // If the attribute is not found and the default is not set, AttributeError will be raised.
auto new_node = parse::ResolveMsClassWithAttr(func_graph->manager(), ms_class->obj(), item_name, out_node); auto new_node = parse::ResolveMsClassWithAttr(func_graph->manager(), ms_class->obj(), item_name, out_node);
if (new_node == nullptr || IsValueNode<None>(new_node)) { if (new_node == nullptr) {
constexpr auto max_args_len = 3; constexpr auto max_args_len = 3;
bool has_default = (args_spec_list.size() == max_args_len); bool has_default = (args_spec_list.size() == max_args_len);
if (!has_default) { if (!has_default) {

View File

@ -177,5 +177,6 @@ REGISTER_PYBIND_DEFINE(
(void)py::class_<Slice, Type, std::shared_ptr<Slice>>(m_sub, "Slice").def(py::init()); (void)py::class_<Slice, Type, std::shared_ptr<Slice>>(m_sub, "Slice").def(py::init());
(void)py::class_<TypeEllipsis, Type, std::shared_ptr<TypeEllipsis>>(m_sub, "TypeEllipsis").def(py::init()); (void)py::class_<TypeEllipsis, Type, std::shared_ptr<TypeEllipsis>>(m_sub, "TypeEllipsis").def(py::init());
(void)py::class_<MsClassType, Type, std::shared_ptr<MsClassType>>(m_sub, "TypeMsClassType").def(py::init()); (void)py::class_<MsClassType, Type, std::shared_ptr<MsClassType>>(m_sub, "TypeMsClassType").def(py::init());
(void)py::class_<TypeNull, Type, std::shared_ptr<TypeNull>>(m_sub, "TypeNull").def(py::init());
})); }));
} // namespace mindspore } // namespace mindspore

View File

@ -244,7 +244,7 @@ def resolve_symbol(namespace, symbol):
except Exception as e: except Exception as e:
if isinstance(e, NotImplementedError): if isinstance(e, NotImplementedError):
raise e raise e
resolve_ = None resolve_ = mstype._null
logger.debug("Resolve exception occurred, value: %r", e) logger.debug("Resolve exception occurred, value: %r", e)
logger.debug("Resolve type is invalid, namespace: %s, symbol: %s", logger.debug("Resolve type is invalid, namespace: %s, symbol: %s",
namespace.__str__(), symbol) namespace.__str__(), symbol)

View File

@ -35,6 +35,7 @@ from ...ops.operations._inner_ops import Format
from ...ops.operations import _csr_ops from ...ops.operations import _csr_ops
from ...ops.primitive import constexpr from ...ops.primitive import constexpr
from ...ops.function.sparse_func import sparse_add from ...ops.function.sparse_func import sparse_add
from ...common import dtype as mstype
__all__ = ['MultitypeFuncGraph', 'env_get', 'hyper_add', 'zeros_like', 'ones_like'] __all__ = ['MultitypeFuncGraph', 'env_get', 'hyper_add', 'zeros_like', 'ones_like']
@ -271,8 +272,8 @@ def hasattr(x, attr): # pylint: disable=redefined-builtin
Returns: Returns:
Boolean value, indicates whether the object x has attribute attr. Boolean value, indicates whether the object x has attribute attr.
""" """
out = getattr(x, attr, None) out = getattr(x, attr, mstype._null)
return out is not None return not isinstance(out, mstype._null_type)
def astype(x, dtype, copy=True): # pylint: disable=redefined-outer-name def astype(x, dtype, copy=True): # pylint: disable=redefined-outer-name

View File

@ -20,7 +20,7 @@ from mindspore.common.dtype import Type, int8, byte, int16, short, int32, intc,
uint8, ubyte, uint16, ushort, uint32, uintc, uint64, uintp, float16, half, \ uint8, ubyte, uint16, ushort, uint32, uintc, uint64, uintp, float16, half, \
float32, single, float64, double, bool_, float_, list_, tuple_, int_, \ float32, single, float64, double, bool_, float_, list_, tuple_, int_, \
uint, number, tensor, string, type_none, tensor_type, Int, \ uint, number, tensor, string, type_none, tensor_type, Int, \
complex64, complex128, dtype_to_nptype, issubclass_, \ complex64, complex128, dtype_to_nptype, issubclass_, _null, _null_type, \
dtype_to_pytype, pytype_to_dtype, get_py_obj_dtype dtype_to_pytype, pytype_to_dtype, get_py_obj_dtype
from mindspore.common.dump import set_dump from mindspore.common.dump import set_dump
from mindspore.common.parameter import Parameter, ParameterTuple from mindspore.common.parameter import Parameter, ParameterTuple
@ -47,8 +47,9 @@ __all__ = [
"int_", "uint", "int_", "uint",
"number", "tensor", "number", "tensor",
"string", "type_none", "string", "type_none",
"_null",
"tensor_type", "tensor_type",
"Type", "Int", "Type", "Int", "_null_type",
"complex64", "complex128", "complex64", "complex128",
# __method__ from dtype # __method__ from dtype
"dtype_to_nptype", "issubclass_", "dtype_to_pytype", "dtype_to_nptype", "issubclass_", "dtype_to_pytype",

View File

@ -40,7 +40,7 @@ __dtype__ = [
"int_", "uint", "int_", "uint",
"number", "tensor", "number", "tensor",
"string", "type_none", "string", "type_none",
"tensor_type", "tensor_type", "_null",
"Type", "Int", "Type", "Int",
"complex64", "complex128" "complex64", "complex128"
] ]
@ -92,6 +92,7 @@ string = typing.String()
list_ = typing.List() list_ = typing.List()
tuple_ = typing.Tuple() tuple_ = typing.Tuple()
type_none = typing.TypeNone() type_none = typing.TypeNone()
_null = typing.TypeNull()
tensor = typing.TensorType() tensor = typing.TensorType()
index_slices = typing.RowTensorType() index_slices = typing.RowTensorType()
@ -122,6 +123,7 @@ tensor_type = typing.TensorType
csr_tensor_type = typing.CSRTensorType csr_tensor_type = typing.CSRTensorType
anything_type = typing.TypeAnything anything_type = typing.TypeAnything
ref_type = typing.RefType ref_type = typing.RefType
_null_type = typing.TypeNull
number_type = (int8, number_type = (int8,
int16, int16,

View File

@ -292,12 +292,9 @@ def test_call_none_in_if():
return ret return ret
net = Net() net = Net()
with pytest.raises(ValueError) as err: with pytest.raises(AttributeError) as err:
net(Tensor([1, 2, 3], mstype.float32)) net(Tensor([1, 2, 3], mstype.float32))
assert "not defined" in str(err.value) assert "has no attribute" in str(err.value)
assert "tests/ut/python/pipeline/parse/test_use_undefined_name_or_unsupported_builtin_function.py(291)" in \
str(err.value)
assert "ret = self.func(x)" in str(err.value)
def test_insert_defined_var(): def test_insert_defined_var():
@ -333,9 +330,6 @@ def test_insert_defined_var_compute():
@pytest.mark.skip(reason='Not support in graph jit fallback feature yet') @pytest.mark.skip(reason='Not support in graph jit fallback feature yet')
def test_call_unsupported_builtin_function_in_while(): def test_call_unsupported_builtin_function_in_while():
class Net(nn.Cell): class Net(nn.Cell):
def __init__(self):
super(Net, self).__init__()
def construct(self, x, y): def construct(self, x, y):
ret = 0 ret = 0
number = 5 number = 5

View File

@ -523,7 +523,7 @@ def test_getattr_ms_class_with_default():
return getattr(ms_obj, "none", 10) return getattr(ms_obj, "none", 10)
out = foo() out = foo()
assert out == 10 assert out is None
def test_getattr_ms_class_with_concate_attr_and_default(): def test_getattr_ms_class_with_concate_attr_and_default():
@ -565,24 +565,6 @@ def test_getattr_ms_class_with_wrong_attr():
assert "object has no attribute" in str(err.value) assert "object has no attribute" in str(err.value)
def test_getattr_ms_class_with_wrong_attr_2():
"""
Feature: Syntax getattr.
Description: Graph syntax getattr support list input.
Expectation: AttributeError.
"""
ms_obj = MSClass1()
@ms_function
def foo():
abs_func = getattr(ms_obj, "none")
return abs_func
with pytest.raises(AttributeError) as err:
foo()
assert "object has no attribute" in str(err.value)
class Net(nn.Cell): class Net(nn.Cell):
def __init__(self): def __init__(self):
@ -591,6 +573,7 @@ class Net(nn.Cell):
self.a1 = Tensor([1]) self.a1 = Tensor([1])
self.a2 = Tensor([2]) self.a2 = Tensor([2])
self.a3 = Tensor([3]) self.a3 = Tensor([3])
self.none = None
def construct(self): def construct(self):
return self.a0 return self.a0
@ -612,6 +595,22 @@ def test_getattr_cell_obj():
assert out == 0 assert out == 0
def test_getattr_cell_obj_2():
"""
Feature: Syntax getattr.
Description: Graph syntax getattr support cell object input.
Expectation: No exception.
"""
cell_obj = Net()
@ms_function
def foo():
return getattr(cell_obj, "none")
out = foo()
assert out is None
def test_getattr_cell_obj_concate_input(): def test_getattr_cell_obj_concate_input():
""" """
Feature: Syntax getattr. Feature: Syntax getattr.

View File

@ -183,6 +183,21 @@ def test_hasattr_ms_class_2():
def foo(): def foo():
return hasattr(ms_obj, "none") return hasattr(ms_obj, "none")
assert foo()
def test_hasattr_ms_class_3():
"""
Feature: Syntax hasattr.
Description: Graph syntax hasattr support ms_class input.
Expectation: No exception.
"""
ms_obj = MSClass1()
@ms_function
def foo():
return hasattr(ms_obj, "none2")
assert not foo() assert not foo()
@ -249,6 +264,21 @@ def test_hasattr_cell_obj_2():
def foo(): def foo():
return hasattr(cell_obj, "none") return hasattr(cell_obj, "none")
assert foo()
def test_hasattr_cell_obj_3():
"""
Feature: Syntax hasattr.
Description: Graph syntax hasattr support cell object input.
Expectation: No exception.
"""
cell_obj = Net()
@ms_function
def foo():
return hasattr(cell_obj, "none2")
assert not foo() assert not foo()