17

Over the last few days, I have been working on automating the generation of some pivot tables for a number of reports.

Boiled down to the minimum, the following code was working without issue:

import win32com.client    
objExcelApp = win32com.client.gencache.EnsureDispatch('Excel.Application')
objExcelApp.Visible = 1

This would pop-up an instance of excel and I could continue working in Python. But suddenly, today my scripts are failing with the following:

>>>import win32com.client
>>> objExcelApp = win32com.client.gencache.EnsureDispatch('Excel.Application')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Program Files (x86)\Python37-32\lib\site-packages\win32com\client\gencache.py", line 534, in EnsureDispatch
    mod = EnsureModule(tla[0], tla[1], tla[3], tla[4], bForDemand=bForDemand)
  File "C:\Program Files (x86)\Python37-32\lib\site-packages\win32com\client\gencache.py", line 391, in EnsureModule
    module = GetModuleForTypelib(typelibCLSID, lcid, major, minor)
  File "C:\Program Files (x86)\Python37-32\lib\site-packages\win32com\client\gencache.py", line 266, in GetModuleForTypelib
    AddModuleToCache(typelibCLSID, lcid, major, minor)
  File "C:\Program Files (x86)\Python37-32\lib\site-packages\win32com\client\gencache.py", line 552, in AddModuleToCache
    dict = mod.CLSIDToClassMap
AttributeError: module 'win32com.gen_py.00020813-0000-0000-C000-000000000046x0x1x9' has no attribute 'CLSIDToClassMap'

The code has not changed from yesterday to today. I have no idea what is happening!!!.

Another interesting kicker. if I do the same code in the same session again I get a different error:

>>> objExcelApp = win32com.client.gencache.EnsureDispatch('Excel.Application')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Program Files (x86)\Python37-32\lib\site-packages\win32com\client\gencache.py", line 534, in EnsureDispatch
    mod = EnsureModule(tla[0], tla[1], tla[3], tla[4], bForDemand=bForDemand)
  File "C:\Program Files (x86)\Python37-32\lib\site-packages\win32com\client\gencache.py", line 447, in EnsureModule
    if module.MinorVersion != tlbAttributes[4] or genpy.makepy_version != module.makepy_version:
AttributeError: module 'win32com.gen_py.00020813-0000-0000-C000-000000000046x0x1x9' has no attribute 'MinorVersion'
>>>

So I jump over to a windows machine with a fresh windows install, install python37 and pip install pypiwin32. Run the very same lines and excel opens just like it did yesterday on my original machine.

I tried un-installing and re-installing with no luck. Any idea what is going on here?

NOTE: Dynamic dispatch still works:

import win32com.client
objExcelApp = win32com.client.Dispatch("Excel.Application")
objExcelApp.Visible = 1

But I specifically need static dispatch as Pivot Tables won't work with a dynamically dispatched object (much later in my code):

objExcelPivotCache = objExcelWorkbook.PivotCaches().Create(SourceType=win32c.xlDatabase, SourceData=objExcelPivotSourceRange)
Chris
  • 370
  • 1
  • 3
  • 11

5 Answers5

34

I had the same issue and I resolved it by following the instructions here: https://mail.python.org/pipermail/python-win32/2007-August/006147.html

Deleting the gen_py output directory and re-running makepy SUCCEEDS and subsequently the test application runs OK again.

So the symptom is resolved, but any clues as to how this could have happened. This is a VERY long running application (think 24x7 for years) and I'm concerned that whatever caused this might occur again.

To find the output directory, run this in your python console / python session:

import win32com
print(win32com.__gen_path__)

Based on the exception message in your post, the directory you need to remove will be titled '00020813-0000-0000-C000-000000000046x0x1x9'. So delete this directory and re-run the code. And if you're nervous about deleting it (like I was) just cut the directory and paste it somewhere else.

I have no idea why this happens nor do I know how to prevent it from happening again, but the directions in the link I provided seemed to work for me.

Ian
  • 731
  • 9
  • 16
  • 3
    fwiw, the path for me was "C:\Users\\AppData\Local\Temp\gen_py" – Rafael Zayas Feb 05 '19 at 18:09
  • 1
    @RafaelZayas, yes so navigate to "C:\Users\\AppData\Local\Temp\gen_py" and somewhere within that directory you will find a folder with the same name as displayed in the AttributeError message (and based on the original post, the op should delete the folder titled '00020813-0000-0000-C000-000000000046x0x1x9'). So find that weirdly named directory, delete it, and re-run your code. – Ian Feb 06 '19 at 19:26
  • 5
    And for those that are wondering how to run makepy after deleting the gen_py directory navigate to C:\\Lib\site-packages\win32com\client and then run makepy.py. – Jason Apr 28 '19 at 20:22
10

A more straightforward solution was posted in a related question Issue in using win32com to access Excel file.

Basically, you just need to delete the folder C:\Users\<your username>\AppData\Local\Temp\gen_py and rerun your code.

Qin Heyang
  • 1,059
  • 10
  • 14
  • It works for me! I had got `module 'win32com.gen_py.00020813-0000-0000-C000-000000000046x0x1x9' has no attribute 'CLSIDToClassMap'` error. After deleting the `gen_py` folder, problem solved. – etoricky Feb 17 '21 at 17:27
  • Mine has no folders inside gen_py, and just delete as your advice. Thanks! – Quy Nguyen Mar 23 '21 at 02:44
7

Execute this command line in a powershell or cmd (NOT in Administrator mode => wouldn't work for me)

   python -m win32com.client.makepy "Excel.Application"

It fixes all errors and you don't have to change your python code. And keep using

win32com.client.gencache.EnsureDispatch("Excel.Application")

With gencache.EnsureDispatch you have access to the constants of the application loaded dynamically by makepy which must have the registered application (in our case Excel.Application). If you have the same problem with Outlook, use "Outlook.Application" in above.

If still not working, reinstall pywin32 of your python distribution

<path to python root or venv>\pip.exe uninstall pywin32
<path to python root or venv>\pip.exe install pywin32
Julienm
  • 108
  • 1
  • 7
3

What has worked for me is:

excel = win32.gencache.EnsureDispatch('Excel.Application')
#change to =>
excel = win32.Dispatch('Excel.Application')
  • 1
    You meant win32com.client.Dispatch. That works only if you do NOT use the win32com.client.constants which is the problem that Chris described... – Julienm Oct 01 '21 at 10:51
  • I came to this post googling for a similiar problem, but at my case I don't care about optional parameters - pywin32 doesn't accept them. Sure I could have known this simplier form before, but it is always time to learn. (I also guess that at the tile example, Dipatch could also be used for PivotTables, just change the use of optional parameters for the default order). – ChrCury78 Dec 02 '21 at 02:38
  • This worked for you, but for everybody it didn't: please look [here](http://www.icodeguru.com/WebServer/Python-Programming-on-Win32/ch12.htm) . Specifically at the paragraph `Forcing Early or Late Binding`. tl;dr: what Nikita proposed is not deterministic. You're letting Python chose automatically the binding (the source of the error) and who knows if it chooses right :) – z33k Jan 31 '22 at 11:13
0

For me, it seems, the issue was that I have multiple processes that interact with Windows apps through win32com.

Since win32com creates the "gen_py" directory in win32api.GetTempPath() this can cause conflicts and the cache getting corrupted.

My solution is to set a custom location for "gen_py" for each process. A simple example:

from pathlib import Path
import win32com

gen_py_path = '/some/custom/location/gen_py'

Path(gen_py_path).mkdir(parents=True, exist_ok=True)
win32com.__gen_path__ = gen_py_path

# Any other imports/code that uses win32com

This way you don't have to delete the default "gen_py" folder and wonder what issues might arise. But if you still find you need to delete, you can just delete the custom folder and know you're deleting the cache just for that process.

Griffin
  • 11,022
  • 4
  • 29
  • 41