From 51a41665cf0214f64869654afe1fe31385c20e3f Mon Sep 17 00:00:00 2001 From: Claudiu Popa Date: Wed, 24 Jun 2015 15:08:56 +0300 Subject: Add astroid.helpers, a module of various useful utilities which don't belong yet into other components. Added *object_type*, a function which can be used to obtain the type of almost any astroid object, similar to how the builtin *type* works. --- astroid/helpers.py | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 astroid/helpers.py (limited to 'astroid/helpers.py') diff --git a/astroid/helpers.py b/astroid/helpers.py new file mode 100644 index 00000000..5996c7c7 --- /dev/null +++ b/astroid/helpers.py @@ -0,0 +1,95 @@ +# copyright 2003-2015 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# This file is part of astroid. +# +# astroid is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 2.1 of the License, or (at your +# option) any later version. +# +# astroid is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with astroid. If not, see . + +""" +Various helper utilities. +""" + +import six + +from astroid import bases +from astroid import exceptions +from astroid import manager +from astroid import raw_building +from astroid import scoped_nodes + + +BUILTINS = six.moves.builtins.__name__ + + +def _build_proxy_class(cls_name, builtins): + proxy = raw_building.build_class(cls_name) + proxy.parent = builtins + return proxy + + +def _function_type(function, builtins): + if isinstance(function, scoped_nodes.Lambda): + if function.root().name == BUILTINS: + cls_name = 'builtin_function_or_method' + else: + cls_name = 'function' + elif isinstance(function, bases.BoundMethod): + if six.PY2: + cls_name = 'instancemethod' + else: + cls_name = 'method' + elif isinstance(function, bases.UnboundMethod): + if six.PY2: + cls_name = 'instancemethod' + else: + cls_name = 'function' + return _build_proxy_class(cls_name, builtins) + + +def _object_type(node, context=None): + astroid_manager = manager.AstroidManager() + builtins = astroid_manager.astroid_cache[BUILTINS] + context = context or bases.InferenceContext() + + for inferred in node.infer(context=context): + if isinstance(inferred, scoped_nodes.Class): + if inferred.newstyle: + metaclass = inferred.metaclass() + if metaclass: + yield metaclass + continue + yield builtins.getattr('type')[0] + elif isinstance(inferred, (scoped_nodes.Lambda, bases.UnboundMethod)): + yield _function_type(inferred, builtins) + elif isinstance(inferred, scoped_nodes.Module): + yield _build_proxy_class('module', builtins) + else: + yield inferred._proxied + + +def object_type(node, context=None): + """Obtain the type of the given node + + The node will be inferred first, so this function can support all + sorts of objects, as long as they support inference. It will try to + retrieve the Python type, as returned by the builtin `type`. + """ + + try: + types = set(_object_type(node, context)) + except exceptions.InferenceError: + return bases.YES + if len(types) > 1: + return bases.YES + return list(types)[0] -- cgit v1.2.1