def find_syntax_node_name(evaluator, python_object):
try:
python_object = _get_object_to_check(python_object)
path = inspect.getsourcefile(python_object)
except TypeError:
# The type might not be known (e.g. class_with_dict.__weakref__)
return None, None
if path is None or not os.path.exists(path):
# The path might not exist or be e.g. <stdin>.
return None, None
module = _load_module(evaluator, path, python_object)
if inspect.ismodule(python_object):
# We don't need to check names for modules, because there's not really
# a way to write a module in a module in Python (and also __name__ can
# be something like ``email.utils``).
return module, path
try:
name_str = python_object.__name__
except AttributeError:
# Stuff like python_function.__code__.
return None, None
if name_str == '<lambda>':
return None, None # It's too hard to find lambdas.
# Doesn't always work (e.g. os.stat_result)
try:
names = module.get_used_names()[name_str]
except KeyError:
return None, None
names = [n for n in names if n.is_definition()]
try:
code = python_object.__code__
# By using the line number of a code object we make the lookup in a
# file pretty easy. There's still a possibility of people defining
# stuff like ``a = 3; foo(a); a = 4`` on the same line, but if people
# do so we just don't care.
line_nr = code.co_firstlineno
except AttributeError:
pass
else:
line_names = [name for name in names if name.start_pos[0] == line_nr]
# There's a chance that the object is not available anymore, because
# the code has changed in the background.
if line_names:
return line_names[-1].parent, path
# It's really hard to actually get the right definition, here as a last
# resort we just return the last one. This chance might lead to odd
# completions at some points but will lead to mostly correct type
# inference, because people tend to define a public name in a module only
# once.
return names[-1].parent, path
评论列表
文章目录