Skip to content

Request: Definition.fullname #61

Closed
tkf opened this Issue Nov 13, 2012 · 9 comments

2 participants

@tkf
Collaborator
tkf commented Nov 13, 2012

It would be nice if I can get "full name" or "absolute path" of the function or class. For example, if I have

import json
l = json.load
l# <- cursor

then corresponding Definition.fullname should return "json.load". This is mainly for document lookup. For example, you can directly search this "full name" using online Sphinx document. In Emacs, you can directly go to the document using pydoc-info [1] or pylookup [2] if you have the "full name". Also, I think you can use objects.inv (intersphinx) [3] to get the direct link to online documents generated by sphinx (not only stdlib!). I guess even having objects.inv handing as a jedi feature makes sense.

The problem is that many functions and classes have real location different from what is written in the document. For example, os.path.join in Linux is actually posixpath.join and io.Bytes is _io.Bytes. Can jedi workaround this problem?

[1] https://bitbucket.org/jonwaltman/pydoc-info
[2] https://github.com/tsgates/pylookup
[3] http://sphinx-doc.org/ext/intersphinx.html

@davidhalter
Owner

os.path.join in Linux is actually posixpath.join

which one do you want? That's not clear for me.

@tkf
Collaborator
tkf commented Nov 13, 2012

I want os.path.join instead of posixpath.join, as posixpath functions are not in the document.

@davidhalter
Owner

All right, I think we have to do that with a mapping for builtin modules. Everything else would be too complicated to implement.

@davidhalter davidhalter added a commit that referenced this issue Nov 18, 2012
@davidhalter added fullname for #61 5430d15
@davidhalter
Owner

What do you think? I just added your example, please add other files as well!

@tkf
Collaborator
tkf commented Nov 18, 2012

Hi, thanks for the enhancement! When I try full_name on os.path, I got this:

In [2]:
source = """\
import os
os.path"""
lines = source.splitlines()
script = jedi.Script(source, len(lines), len(lines[-1]), None)
definition = script.get_definition()
definition
Out [2]:
[<Definition module genericpath>,
 <Definition module ntpath>,
 <Definition module posixpath>,
 <Definition module genericpath>,
 <Definition module os2emxpath>]

In [3]:
[(d, d.full_name) for d in definition]
Out [3]:
[(<Definition module genericpath>, 'genericpath'),
 (<Definition module ntpath>, 'os.path'),
 (<Definition module posixpath>, 'os.path'),
 (<Definition module genericpath>, 'genericpath'),
 (<Definition module os2emxpath>, 'os.path')]

For my purpose, I want d.full_name to be "os.path", because then I can simply do definition[0].full_name to get full name. Or maybe it is better to have Script.get_full_name(), which returns a string, rather than having Definition.full_name? Having same "full name" for different definitions feels a bit strange (or not?). Sorry, I was not aware of that Script.get_definition might return multiple definitions when I wrote the request, although I already knew that from the other question I asked before.

@davidhalter
Owner

There won't be another version of this, because there is always a possibility to return two different versions of a path (here it would be genericpath and os.path, I fixed this in the above commit). A script like

if a:
    import foo as path
else:
    from os import path

is always possible. Therefore multiple elements can and should be returned. So I suggest you use this code:

set(d.full_name for d in definition)

if you just want soome element (this would work in the above example). Normally there is only one fullname. If there are multiple fullnames, you have to handle that. I would suggest to let the user choose. If that's not what you want, just take one definition by chance.

@tkf
Collaborator
tkf commented Nov 18, 2012

I see. It makes sense that library user must decide how to pickup the full name.

I tried another example:

In [4]:
source = """\
import argparse
parser = argparse.ArgumentParser()
parser.add_argument"""
lines = source.splitlines()
script = jedi.Script(source, len(lines), len(lines[-1]), None)
definition = script.get_definition()
definition
Out [4]:
[<Definition def add_argument>]

In [5]:
definition[0].full_name
Out [5]:
'argparse._ActionsContainer.add_argument'

I think definition[0].full_name should return argparse.ArgumentParser.add_argument. But I think current implementation of full_name cannot fix this name, right? Perhaps BaseOutput._mapping should be a map from tuple-of-str to str, instead of a map from str to str, so that you can do something like this (untested)?

head = paths[:-1]
tail = [paths[-1]]
# Try to find the longest match in self._mapping:
while head:
    try:
        tail.append(self._mapping[tuple(head)])
        break
    except KeyError:
        pass
    tail.append(head.pop())
return '.'.join(reversed(tail))
@davidhalter davidhalter added a commit that referenced this issue Nov 18, 2012
@davidhalter extension for #61 381b999
@davidhalter
Owner

I added some code... I didn't do any testing, so please be sure to test it. Also if it fails, just fix it. :-)

@tkf
Collaborator
tkf commented Nov 18, 2012

Thanks! I will add mappings when I find some. Hope that there are not too many.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.