pywin32 icon indicating copy to clipboard operation
pywin32 copied to clipboard

Feature request: Add IPython code completion

Open fuglede opened this issue 7 years ago • 3 comments

Currently, win32com code completion on COM objects only works for methods, and not properties, and the present feature requests concerns ensuring that properties are supported as well.

Given that the PythonWin shell already supports code completion, I can see how this could be considered outside the scope of the project, but given the popularity of Jupyter/IPython notebooks as a means of writing exploratory Python code, and given that IPython comes with an API for adding third-party code completion logic, I figured it would be worth checking whether or not this would be of interest. Certainly it would be very helpful for myself and those of my colleagues that deal with Microsoft automation on a daily basis.

The code completion in IPython 6.2.1 is handled by core.completer.IPCompleter, and the API for adding custom code completers is provided by IPython.utils.generics.complete_object. One gotcha is that with complete_object being based on simplegeneric, only one completer may be provided for any given type. Luckily, most of the relevant types generated by makepy will inherit from win32com.client.DispatchBaseClass, and adding code completion boils down to running

from IPython.utils.generics import complete_object
import win32com.client

@complete_object.when_type(win32com.client.DispatchBaseClass)
def complete_dispatch_base_class(obj, prev_completions):
    try:
        ole_props = set(obj._prop_map_get_).union(set(obj._prop_map_put_))
        return list(ole_props) + prev_completions
    except AttributeError:
        pass

This works, cf. the screenshots below, and at some point was the approach taken by e.g. pandas (after a simple check that 'IPython' in sys.modules); in the case of pandas, they switched to the more elegant approach of simply defining __dir__, which is also what IPython suggests. This approach is also nice in that it makes no assumption on the interactive prompt in which win32com is used, and as such would be useful in contexts other than IPython as well.

I can't claim to fully understand how gencache code generation works, but in this world, it looks like this would boil down to adding a

def __dir__(self):
    return list(set(self._prop_map_get_).union(set(self._prop_map_put_)))

to a generated DispatchBaseClass while a CoClassBaseClass needs more work.

image image

fuglede avatar Feb 05 '18 19:02 fuglede

I can't claim to fully understand how gencache code generation works, but in this world, it looks like this would boil down to adding a

def dir(self): return list(set(self.prop_map_get).union(set(self.prop_map_put)))

A PR which added that dir to classes sounds reasonable and safe.

mhammond avatar Feb 06 '18 11:02 mhammond

On Tue, Feb 06, 2018 at 11:31:31AM +0000, Mark Hammond wrote:

A PR which added that dir to classes sounds reasonable and safe.

Happy to hear that. I wouldn't mind adding such a PR myself, but the build/test process does seem a bit overwhelming compared to the relative simplicity of the change.

fuglede avatar Jul 09 '18 21:07 fuglede

but the build/test process does seem a bit overwhelming compared to the relative simplicity of the change.

If you're having too many issues building, you could always submit a PR, and use the build artefact from said PR to confirm that the changes work as expected.

Avasam avatar Jun 05 '24 02:06 Avasam