python jedi: how to retrieve methods of instances?
Asked Answered
K

1

10

I built simple text editor with some accessibility feature for screen reading software. I'm using Python for .NET (pythonnet) to show a form containing a rich text box. When user press tab after a period it pop-ups a context menu with completions for selected element. Ok, it works fine with Python objects, but it doesn't work with .net live objects, there is no solution to this problem. Now, I want build a TreeView object with all names and definitions of module I'm editing.

So, for example I type:

import sys
import os
lst = list()

etc... If I use jedi.names of my source, I can retrieve os, sys and lst. For each name, I want retrieve sub definitions, such as functions for sys and os module, and methods for lst. I can't find a way to do this with jedi:

names = jedi.names(MySource)
names[0].defined_names() # works for sys
names[1].defined_names() # works for os
names[2].defined_names() # doesn't work for lst instance of list().

Any suggestions? I tried to use more and more editors, but accessibility support is very very bad...

Kincaid answered 7/6, 2016 at 18:4 Comment(4)
What is MySource object?Edla
You wouldn't expect to see any auto completes for import sys, It's a complete statement. However if it was from sys import then you would expect some auto complete options.Presidium
@denfromufa, I think MySource is just a string holding the source code shown in the first code block.Figment
Can you describe your use case a bit better? I'd be happy to add this functionality (I'm the creator of Jedi). Do you want to list all attributes of an instance (including super classes) or do you want a list of all the attributes of an instance that are defined in just that class?Seventeenth
F
7

This looks like a bug, where jedi.evaluate.representation.Instance.__getattr__() mistakenly blocks evaluation of .names_dict. I added a pull request to the jedi repository to fix this. In the mean time, you can either add 'names_dict' to the whitelist in Instance.__getattr__() in your copy of jedi/evaluate/representation.py, or use the code below to patch this method automatically for the current session.

import jedi

def patch_jedi():

    __old__getattr__ = jedi.evaluate.representation.Instance.__getattr__

    def __patched__getattr__(self, name):
        if name == 'names_dict':
            # do a simplified version of __old__getattr__, bypassing the name check
            return getattr(self.base, name)
        else:
            # use standard behavior
            return __old__getattr__(self, name)

    # test whether jedi has been updated to avoid the Instance.defined_names() bug
    try:
        jedi.names("lst = list()")[0].defined_names()
    except AttributeError as e:
        if e.args[0].startswith("Instance ") and e.args[0].endswith("Don't touch this (names_dict)!"):
            # patch jedi to avoid this error
            print "patching jedi"
            jedi.evaluate.representation.Instance.__getattr__ = __patched__getattr__
        else:
            # something else strange is going on
            raise

patch_jedi()
print jedi.names("lst = list()")[0].defined_names()
# or: print jedi.Script("lst = list()").goto_definitions()[0].defined_names()

I should note that I'm not familiar with jedi, so I don't know whether defined_names() is supposed to work for definitions that create instances. The code above won't fix references like jedi.names("lst = []")[0].defined_names(), and there's no obvious patch to do that. So there may be something deeper going on that I don't know about. Hopefully the developer will help set this straight in response to that pull request.

Figment answered 18/8, 2016 at 8:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.