Sunday, 29 August 2021

Different Python packages use different versions of the same DLL

For my project I use pyenchant library for spell checking and win32com.client.dispatch to call SAPI.SpVoice for automatic voiceovers. I have some Speech2Go packages installed and all worked fine until I decided it's time to move my project to Python 3.9. The only thing preventing me to do it is the new version of pyenchant, which uses the same DLL as Speech2Go, but the different version. By trial and error I deduced that the DLL in question is libstdc++-6.dll and I cannot force one of these 2 programs to use the same version neither I can rename the DLL obviously. But it turned out that this code does not work in Python 3.9:

import win32com.client
speaker = win32com.client.Dispatch("SAPI.SpVoice")

def speaktest(text):
    voices = speaker.GetVoices("Language = 409", 'Gender = Male')
    for voice in voices:
        desc = voice.GetDescription()
        if "Eric" in desc:
            speaker.Voice = voice
            speaker.Speak(text)
            break

if __name__ == '__main__':
    speaktest("Hello")
    import enchant
    from enchant.checker import SpellChecker

After speaker.Speak(text) is called, provided a Speech2Go voice is selected (named "Eric" in my case, because that's what I have installed), I cannot load pyenchant because of this error:

Traceback (most recent call last):
  File "C:\Users\User\AppData\Roaming\JetBrains\PyCharm2021.2\scratches\scratch_9.py", line 21, in <module>
    import enchant
  File "C:\Plan Z Editor XXL\venv\lib\site-packages\enchant\__init__.py", line 81, in <module>
    from enchant import _enchant as _e
  File "C:\Plan Z Editor XXL\venv\lib\site-packages\enchant\_enchant.py", line 162, in <module>
    e = ctypes.cdll.LoadLibrary(enchant_lib_path)
  File "C:\python39\lib\ctypes\__init__.py", line 452, in LoadLibrary
    return self._dlltype(name)
  File "C:\python39\lib\ctypes\__init__.py", line 374, in __init__
    self._handle = _dlopen(self._name, mode)
OSError: [WinError 127] The specified procedure could not be found

Process finished with exit code 1

If I call speaktest after importing pyenchant, this happens:

Traceback (most recent call last):
  File "C:\Users\User\AppData\Roaming\JetBrains\PyCharm2021.2\scratches\scratch_9.py", line 22, in <module>
    speaktest("Hello")
  File "C:\Users\User\AppData\Roaming\JetBrains\PyCharm2021.2\scratches\scratch_9.py", line 16, in speaktest
    speaker.Speak(text)
  File "C:\Users\USER\AppData\Local\Temp\gen_py\3.9\C866CA3A-32F7-11D2-9602-00C04F8EE628x0x5x4\ISpeechVoice.py", line 70, in Speak
    return self._oleobj_.InvokeTypes(12, LCID, 1, (3, 0), ((8, 1), (3, 49)),Text
pywintypes.com_error: (-2147352567, 'Exception occurred.', (0, None, None, None, 0, -2147221164), None)

Process finished with exit code 1

What CAN be a working solution is to use multiprocessing to handle the speaking and making sure multiprocessing.freeze_support() is called before importing pyenchant, thus making different Python instances load different versions of libstdc++-6.dll, but since I already have a code base around both pyEnchant and SAPI.SpVoice and it works the way it is, it's not a good idea to rewrite all the code just because these 2 libraries conflict with each other.

That's why I'm here asking whether there is a much simpler method of resolving this conflict without rewriting a large chunk of code?



from Different Python packages use different versions of the same DLL

No comments:

Post a Comment