mhammond / pywin32

Python for Windows (pywin32) Extensions
5.08k stars 801 forks source link

Generate a wrapper for members of the VBA object library accessed by pywin32 #1351

Open eliyahuA opened 5 years ago

eliyahuA commented 5 years ago

Some users of pywin32 use it for sending VBA commands to Word and Excel. The problem is that pywin32 does not have permanent wrappers around VBA objects, instead makepy is used to generate the necessary modules. That causes some inconvenience.

For example a workbook object type would be: <class 'win32com.gen_py.00020813-0000-0000-C000-000000000046x0x1x9.Workbook.Workbook'>

So to use the Workbook type in annotations, type checks, parameter hints etc.. A manual definition is required, such as:

Workbook = win32com.gen_py.00020813-0000-0000-C000-000000000046x0x1x9.Workbook.Workbook

However consider:

Is it possible to alter type library construction by makepy so VBA types are easily accessible for the api users?

Several use case examples:

import win32com.client as win32client
from gen_py.ms_word_object_library_16 import Documents, Document, Range
from gen_py.ms_excel_object_library_16 import Application, Workbooks, Workbook, WorkSheets, WorkSheet, Range
excel = win32client.gencache.EnsureDispatch('Excel.Application')
workbook: Workbook = excel.Workbooks.Add()

def foo (doc: Document) -> Range

etc...

Greedquest commented 3 years ago

@eliyahuA It's worse than that; because the gen_py outputs contain hyphens (win32com.gen_py.00020813-0000-0000-C000-000000000046x0x1x9) you actually can't import them at design & compile time and mypy doesn't follow __import__() statements. On top of that, depending on your environment setup, make_py may use a temp directory so you can't really know where to locate these.

Current workaround:


To solve this problem I think a good method might be:

  1. Change the module names to use underscores instead of hyphens or to be a sanitised lib name like ms_word_object_library_16 if there is a way to get tlib name from tlib id and vice-versa.
  2. For static analysis like mypy to work it needs files with known paths at design time. Since it looks like we don't want to get makepy to add files to the install directory, their location will always be unknown until runtime when they are looked up. Therefore I think makepy should generate stub .pyi files from the typelibs and allow the user to look after these - e.g. in a per project directory or a known place.
    • stub files can be generated from the proxy files with stubgen, or as a step in the creation of the proxy files.

So if I call makepy and pass a stubs directory C:/code/mpyproj/stubs, I should get:

__gen_path__/00020813_0000_0000_C000_000000000046x0x1x9/Application.py
__gen_path__/00020813_0000_0000_C000_000000000046x0x1x9/AppEvents.py

etc., as well as:

C:/code/mpyproj/stubs/win32com/gen_py/00020813_0000_0000_C000_000000000046x0x1x9/Application.pyi
C:/code/mpyproj/stubs/win32com/gen_py/00020813_0000_0000_C000_000000000046x0x1x9/AppEvents.pyi

(if the module names are human readable then 00020813_0000_0000_C000_000000000046x0x1x9 becomes Excel in all cases in these examples, so in user code I write from win32com.gen_py.Excel.Application import Application and I would get all the type info even though the .py files are dynamically located).

  1. There could definitely be type info for all the win32comext modules which can also be distributed as stub files to retro-add types without having to change the dynamic locations of the actual source code.
KingKnecht commented 8 months ago

Any news on this? It's really a pity that we can't use the generated stubs and have intellisense working.