Can't get FontForge to import as a module in a custom Python script
Asked Answered
S

1

1

I have the following script:

import fontforge
import os.path
import sys

if len(sys.argv) < 3:
    print("Usage: [FONT] [OUTPUTDIR]")
    exit(1)

fontpath = sys.argv[1]
font     = fontforge.open(fontpath)
outdir   = sys.argv[2]

if os.path.exists(outdir):
    pass
elif os.access(os.path.dirname(outdir), os.W_OK):
    os.makedirs(outdir)
else:
    exit(1)

for name in font:
    filename = name + ".svg"
    outfull = os.path.join(outdir,filename)
    font[name].export(outfull)

The script dumps all glyphs to individual SVG files in a folder.

Anyway, I've installed the latest windows version of FontForge.

From what I understand, FontForge embeds python, and the binary is ffpython.exe. So you should be able to call ffpython myscript.py {arg1 arg2 arg3}

The problem is that this doesn't work.

When I do ffpython myscript.py arg1 arg2, I get an error:

ImportError: DLL load failed while importing fontforge: The specified procedure could not be found.

You can also result with the same error by simply invoking ffpython and then typing import fontforge directly into the interpreter.

There is a batch file that comes with FontForge located at C:\Program Files (x86)\FontForgeBuilds\fontforge-console.bat.

If I run this batch file, it sets some variables and then opens a console window. If I then call ffpython in that console window and enter import fontforge, everything magically works as expected.

But this is a really limited and improper solution. I don't want to have to open this magical batch file every time I want to run a Python script that interfaces with FontForge.

So here's my question:

How can I get FontForge properly installed as a module in Python? How can I get a python script to import the fontforge module when being run via ffpython?

I would greatly appreciate any help at all.

Edit:

Running the test script by @CristiFati from an Admin PowerShell prompt where the PWD is not the same as ffpython (Failure):

03-14 20:06:09 D:\> & 'C:\Program Files (x86)\FontForgeBuilds\bin\ffpython.exe' .\code00.py
Executable: C:\Program Files (x86)\FontForgeBuilds\bin\ffpython.exe
Version: 3.10.9 (main, Dec 10 2022, 09:16:22)  [GCC 12.2.0 32 bit]
CWD: D:\
UName: None
PATH: C:\Program Files\PowerShell\7;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.0\bin;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.0\libnvvp;C:\Program Files (x86)\Common Files\Intel\Shared Libraries\redist\intel64_win\compiler;C:\Program Files (x86)\Common Files\Intel\Shared Files\cpp\bin\Intel64;C:\Program Files (x86)\Common Files\Intel\Shared Libraries\redist\intel64_win\compiler;C:\Program Files (x86)\Common Files\Intel\Shared Libraries\redist\ia32_win\compiler;C:\Python\Python310\Scripts\;C:\Python\Python310\;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\BIN;C:\Program Files\Git\cmd;C:\Program Files\GitHub CLI\;C:\Program Files\7-Zip;C:\Program Files\NVIDIA Corporation\Nsight Compute 2020.1.1;C:\Program Files\dotnet\;C:\Program Files\CMake\bin;C:\Program Files\Microsoft SQL Server\150\Tools\Binn\;C:\Program Files\PowerShell\7\;C:\Program Files (x86)\FontForgeBuilds\bin;C:\Users\myusername\AppData\Local\Microsoft\WindowsApps;C:\Users\myusername\AppData\Local\Programs\Microsoft VS Code\bin;C:\Users\myusername\.dotnet\tools;C:\Program Files (x86)\FontForgeBuilds\bin\
PYTHONHOME: None
PYTHONPATH: None
sys.path: ['D:\\', 'C:\\Program Files (x86)\\FontForgeBuilds\\lib\\python310.zip', 'C:\\Program Files (x86)\\FontForgeBuilds\\lib\\python3.10', 'C:\\Program Files (x86)\\FontForgeBuilds\\lib\\python3.10\\lib-dynload', 'D:\\', 'C:\\Program Files (x86)\\FontForgeBuilds\\lib\\python3.10\\site-packages']
Traceback (most recent call last):
  File "D:\code00.py", line 12, in <module>
    import fontforge as ff
ImportError: DLL load failed while importing fontforge: The specified procedure could not be found.
03-14 20:06:24 D:\>

Same results occur if I use CMD.

Running the test script by @CristiFati from an Admin PowerShell prompt where the PWD is C:\Program Files (x86)\FontForgeBuilds\bin (Success):

03-14 20:16:08 C:\Program Files (x86)\FontForgeBuilds\bin> ffpython D:\code00.py
Executable: C:\Program Files (x86)\FontForgeBuilds\bin\ffpython.exe
Version: 3.10.9 (main, Dec 10 2022, 09:16:22)  [GCC 12.2.0 32 bit]
CWD: C:\Program Files (x86)\FontForgeBuilds\bin
UName: None
PATH: C:\Program Files\PowerShell\7;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.0\bin;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.0\libnvvp;C:\Program Files (x86)\Common Files\Intel\Shared Libraries\redist\intel64_win\compiler;C:\Program Files (x86)\Common Files\Intel\Shared Files\cpp\bin\Intel64;C:\Program Files (x86)\Common Files\Intel\Shared Libraries\redist\intel64_win\compiler;C:\Program Files (x86)\Common Files\Intel\Shared Libraries\redist\ia32_win\compiler;C:\Python\Python310\Scripts\;C:\Python\Python310\;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\BIN;C:\Program Files\Git\cmd;C:\Program Files\GitHub CLI\;C:\Program Files\7-Zip;C:\Program Files\NVIDIA Corporation\Nsight Compute 2020.1.1;C:\Program Files\dotnet\;C:\Program Files\CMake\bin;C:\Program Files\Microsoft SQL Server\150\Tools\Binn\;C:\Program Files\PowerShell\7\;C:\Program Files (x86)\FontForgeBuilds\bin;C:\Users\myusername\AppData\Local\Microsoft\WindowsApps;C:\Users\myusername\AppData\Local\Programs\Microsoft VS Code\bin;C:\Users\myusername\.dotnet\tools;C:\Program Files (x86)\FontForgeBuilds\bin\
PYTHONHOME: None
PYTHONPATH: None
sys.path: ['D:\\', 'C:\\Program Files (x86)\\FontForgeBuilds\\lib\\python310.zip', 'C:\\Program Files (x86)\\FontForgeBuilds\\lib\\python3.10', 'C:\\Program Files (x86)\\FontForgeBuilds\\lib\\python3.10\\lib-dynload', 'C:\\Program Files (x86)\\FontForgeBuilds\\bin', 'C:\\Program Files (x86)\\FontForgeBuilds\\lib\\python3.10\\site-packages']
Python 3.10.9 (main, Dec 10 2022, 09:16:22)  [GCC 12.2.0 32 bit] 032bit on win32

<module 'fontforge' from 'C:\\Program Files (x86)\\FontForgeBuilds\\lib\\python3.10\\site-packages\\fontforge.pyd'>
['SpiroVersion', 'UnicodeAnnotationFromLib', 'UnicodeBlockCountFromLib', 'UnicodeBlockEndFromLib', 'UnicodeBlockNameFromLib', 'UnicodeBlockStartFromLib', 'UnicodeNameFromLib', 'UnicodeNames2FromLib', 'UnicodeNamesListVersion', '__date__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '__version__', 'activeFont', 'activeFontInUI', 'activeGlyph', 'activeLayer', 'ask', 'askChoices', 'askMulti', 'askString', 'awcontext', 'awglyph', 'configurePlugins', 'contour', 'cvt', 'defaultOtherSubrs', 'font', 'fonts', 'fontsInFile', 'getConvexNib', 'getPluginInfo', 'getPrefs', 'glyph', 'glyphPen', 'hasSpiro', 'hasUserInterface', 'hooks', 'layer', 'layer_array', 'layerinfo', 'layerinfo_array', 'loadEncodingFile', 'loadNamelist', 'loadNamelistDir', 'loadPlugins', 'loadPrefs', 'logWarning', 'math', 'mathKern', 'nameFromUnicode', 'onAppClosing', 'open', 'openFilename', 'parseTTInstrs', 'point', 'postError', 'postNotice', 'preloadCidmap', 'printSetup', 'private', 'readOtherSubrsFile', 'references', 'registerGlyphSeparationHook', 'registerImportExport', 'registerMenuItem', 'runInitScripts', 'saveFilename', 'savePrefs', 'scriptFromUnicode', 'scriptPath', 'selection', 'setConvexNib', 'setPrefs', 'spiroCorner', 'spiroG2', 'spiroG4', 'spiroLeft', 'spiroOpen', 'spiroRight', 'splineCorner', 'splineCurve', 'splineHVCurve', 'splineTangent', 'unParseTTInstrs', 'unicodeFromName', 'unitShape', 'unspecifiedMathValue', 'userConfigPath', 'version']

Done.

So I need to figure out why things are only working when my PWD is C:\Program Files (x86)\FontForgeBuilds\bin. I don't understand why it won't work otherwise.

Strongroom answered 26/8, 2022 at 21:21 Comment(0)
P
2

Just installed FontForge 20230101. Using the following test script.

code00.py:

#!/usr/bin/env python

import os
import sys

print("Executable:", sys.executable)
print("Version:", sys.version)
print("CWD:", os.getcwd())
print("UName:", getattr(os, "uname", lambda: None)())
for evn in ("PATH", "PYTHONHOME", "PYTHONPATH"):
    print("{:s}: {:}".format(evn, os.environ.get(evn)))
print("sys.path:", sys.path)

import fontforge as ff


def main(*argv):
    print(ff)
    print(dir(ff))


if __name__ == "__main__":
    print("Python {:s} {:03d}bit on {:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")),
                                                   64 if sys.maxsize > 0x100000000 else 32, sys.platform))
    rc = main(*sys.argv[1:])
    print("\nDone.\n")
    sys.exit(rc)

Output:

[cfati@CFATI-W10PC064:e:\Work\Dev\StackExchange\StackOverflow\q073506592]> sopr.bat
### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ###

[prompt]> :: Run FFPython (full path)
[prompt]> "c:\Install\pc032\FontForge\FontForgeBuilds\Version\bin\ffpython.exe" ./code00.py
Python 3.10.9 (main, Dec 10 2022, 09:16:22)  [GCC 12.2.0 32 bit] 032bit on win32

Executable: c:\Install\pc032\FontForge\FontForgeBuilds\Version\bin\ffpython.exe
Version: 3.10.9 (main, Dec 10 2022, 09:16:22)  [GCC 12.2.0 32 bit]
CWD: E:\Work\Dev\StackExchange\StackOverflow\q073506592
UName: None
PATH: C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\OpenSSH\;C:\Users\cfati\AppData\Local\Programs\Python\Launcher\;e:\Work\Dev\Utils\current;e:\Work\Dev\Utils\current\Win;e:\Work\Dev\VEnvs\py_pc064_03.08.07_test0\Scripts;C:\Users\cfati\AppData\Local\Microsoft\WindowsApps;;C:\Install\pc032\FontForge\FontForgeBuilds\Version\bin\
PYTHONHOME: None
PYTHONPATH: None
sys.path: ['e:\\Work\\Dev\\StackExchange\\StackOverflow\\q073506592', 'C:\\Install\\pc032\\FontForge\\FontForgeBuilds\\Version\\lib\\python310.zip', 'C:\\Install\\pc032\\FontForge\\FontForgeBuilds\\Version\\lib\\python3.10', 'C:\\Install\\pc032\\FontForge\\FontForgeBuilds\\Version\\lib\\python3.10\\lib-dynload', 'E:\\Work\\Dev\\StackExchange\\StackOverflow\\q073506592', 'C:\\Install\\pc032\\FontForge\\FontForgeBuilds\\Version\\lib\\python3.10\\site-packages']
<module 'fontforge' from 'C:\\Install\\pc032\\FontForge\\FontForgeBuilds\\Version\\lib\\python3.10\\site-packages\\fontforge.pyd'>
['SpiroVersion', 'UnicodeAnnotationFromLib', 'UnicodeBlockCountFromLib', 'UnicodeBlockEndFromLib', 'UnicodeBlockNameFromLib', 'UnicodeBlockStartFromLib', 'UnicodeNameFromLib', 'UnicodeNames2FromLib', 'UnicodeNamesListVersion', '__date__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '__version__', 'activeFont', 'activeFontInUI', 'activeGlyph', 'activeLayer', 'ask', 'askChoices', 'askMulti', 'askString', 'awcontext', 'awglyph', 'configurePlugins', 'contour', 'cvt', 'defaultOtherSubrs', 'font', 'fonts', 'fontsInFile', 'getConvexNib', 'getPluginInfo', 'getPrefs', 'glyph', 'glyphPen', 'hasSpiro', 'hasUserInterface', 'hooks', 'layer', 'layer_array', 'layerinfo', 'layerinfo_array', 'loadEncodingFile', 'loadNamelist', 'loadNamelistDir', 'loadPlugins', 'loadPrefs', 'logWarning', 'math', 'mathKern', 'nameFromUnicode', 'onAppClosing', 'open', 'openFilename', 'parseTTInstrs', 'point', 'postError', 'postNotice', 'preloadCidmap', 'printSetup', 'private', 'readOtherSubrsFile', 'references', '
registerGlyphSeparationHook', 'registerImportExport', 'registerMenuItem', 'runInitScripts', 'saveFilename', 'savePrefs', 'scriptFromUnicode', 'scriptPath', 'selection', 'setConvexNib', 'setPrefs', 'spiroCorner', 'spiroG2', 'spiroG4', 'spiroLeft', 'spiroOpen', 'spiroRight', 'splineCorner', 'splineCurve', 'splineHVCurve', 'splineTangent', 'unParseTTInstrs', 'unicodeFromName', 'unitShape', 'unspecifiedMathValue', 'userConfigPath', 'version']

Done.


[prompt]>
[prompt]> :: More tests (paths related)
[prompt]> set _PATH=%PATH%

[prompt]> set PATH=%_PATH%;c:\Install\pc032\FontForge\FontForgeBuilds\Version\bin

[prompt]> :: Run FFPython (from PATH). Suppress stdout
[prompt]> ffpython.exe ./code00.py > nul

[prompt]>
[prompt]> :: Check module
[prompt]> "c:\Install\pc064\LucasG\DependenciesWalkerPolitistTexan\Version\DependenciesGui.exe" "c:\Install\pc032\FontForge\FontForgeBuilds\Version\lib\python3.10\site-packages\fontforge.pyd"

[prompt]> :: Dependencies window pops up

And the (extension) module Dependencies ([GitHub]: lucasg/Dependencies) window:

Img0

Apparently, everything works, and the only logical conclusion one could draw, is that your environment is messed up.
Then I noticed a "small" detail: you're using a virtual environment.

Output (another (Cmd) terminal):

[cfati@CFATI-W10PC064:e:\Work\Dev\StackExchange\StackOverflow\q073506592]> sopr.bat
### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ###

[prompt]> :: Create VEnv (from FFPython)
[prompt]> "c:\Install\pc064\Python\Python\03.10\python.exe" -m virtualenv -p "c:\Install\pc032\FontForge\FontForgeBuilds\Version\bin\ffpython.exe" "c:\Work\Dev\VEnvs\py_pc032_03.10_test1ff0"
created virtual environment CPython3.10.9.final.0-32 in 843ms
  creator CPython3Windows(dest=C:\Work\Dev\VEnvs\py_pc032_03.10_test1ff0, clear=False, no_vcs_ignore=False, global=False)
  seeder FromAppData(download=False, pip=bundle, setuptools=bundle, wheel=bundle, via=copy, app_data_dir=C:\Users\cfati\AppData\Local\pypa\virtualenv)
    added seed packages: pip==23.0.1, setuptools==67.4.0, wheel==0.38.4
  activators BashActivator,BatchActivator,FishActivator,NushellActivator,PowerShellActivator,PythonActivator

[prompt]> "c:\Work\Dev\VEnvs\py_pc032_03.10_test1ff0\bin\activate.bat"

(py_pc032_03.10_test1ff0) [prompt]>
(py_pc032_03.10_test1ff0) [prompt]> :: Various tests
(py_pc032_03.10_test1ff0) [prompt]> "c:\Install\pc032\FontForge\FontForgeBuilds\Version\bin\ffpython.exe" ./code00.py > nul

(py_pc032_03.10_test1ff0) [prompt]> set _PATH=%PATH%

(py_pc032_03.10_test1ff0) [prompt]> set PATH=%_PATH%;c:\Install\pc032\FontForge\FontForgeBuilds\Version\bin

(py_pc032_03.10_test1ff0) [prompt]>
(py_pc032_03.10_test1ff0) [prompt]> ffpython ./code00.py > nul

(py_pc032_03.10_test1ff0) [prompt]> python ./code00.py > nul
Traceback (most recent call last):
  File "e:\Work\Dev\StackExchange\StackOverflow\q073506592\code00.py", line 14, in <module>
    import fontforge as ff
ModuleNotFoundError: No module named 'fontforge'

(py_pc032_03.10_test1ff0) [prompt]>
(py_pc032_03.10_test1ff0) [prompt]> :: View differences
(py_pc032_03.10_test1ff0) [prompt]> ffpython ./code00.py
Executable: C:\Install\pc032\FontForge\FontForgeBuilds\Version\bin\ffpython.exe
Version: 3.10.9 (main, Dec 10 2022, 09:16:22)  [GCC 12.2.0 32 bit]
CWD: E:\Work\Dev\StackExchange\StackOverflow\q073506592
UName: None
PATH: C:\Work\Dev\VEnvs\py_pc032_03.10_test1ff0\bin;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\OpenSSH\;C:\Users\cfati\AppData\Local\Programs\Python\Launcher\;e:\Work\Dev\Utils\current;e:\Work\Dev\Utils\current\Win;e:\Work\Dev\VEnvs\py_pc064_03.08.07_test0\Scripts;C:\Users\cfati\AppData\Local\Microsoft\WindowsApps;;c:\Install\pc032\FontForge\FontForgeBuilds\Version\bin;C:\Install\pc032\FontForge\FontForgeBuilds\Version\bin\
PYTHONHOME: None
PYTHONPATH: None
sys.path: ['e:\\Work\\Dev\\StackExchange\\StackOverflow\\q073506592', 'C:\\Install\\pc032\\FontForge\\FontForgeBuilds\\Version\\lib\\python310.zip', 'C:\\Install\\pc032\\FontForge\\FontForgeBuilds\\Version\\lib\\python3.10', 'C:\\Install\\pc032\\FontForge\\FontForgeBuilds\\Version\\lib\\python3.10\\lib-dynload', 'E:\\Work\\Dev\\StackExchange\\StackOverflow\\q073506592', 'C:\\Install\\pc032\\FontForge\\FontForgeBuilds\\Version\\lib\\python3.10\\site-packages']
Python 3.10.9 (main, Dec 10 2022, 09:16:22)  [GCC 12.2.0 32 bit] 032bit on win32

<module 'fontforge' from 'C:\\Install\\pc032\\FontForge\\FontForgeBuilds\\Version\\lib\\python3.10\\site-packages\\fontforge.pyd'>
['SpiroVersion', 'UnicodeAnnotationFromLib', 'UnicodeBlockCountFromLib', 'UnicodeBlockEndFromLib', 'UnicodeBlockNameFromLib', 'UnicodeBlockStartFromLib', 'UnicodeNameFromLib', 'UnicodeNames2FromLib', 'UnicodeNamesListVersion', '__date__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '__version__', 'activeFont', 'activeFontInUI', 'activeGlyph', 'activeLayer', 'ask', 'askChoices', 'askMulti', 'askString', 'awcontext', 'awglyph', 'configurePlugins', 'contour', 'cvt', 'defaultOtherSubrs', 'font', 'fonts', 'fontsInFile', 'getConvexNib', 'getPluginInfo', 'getPrefs', 'glyph', 'glyphPen', 'hasSpiro', 'hasUserInterface', 'hooks', 'layer', 'layer_array', 'layerinfo', 'layerinfo_array', 'loadEncodingFile', 'loadNamelist', 'loadNamelistDir', 'loadPlugins', 'loadPrefs', 'logWarning', 'math', 'mathKern', 'nameFromUnicode', 'onAppClosing', 'open', 'openFilename', 'parseTTInstrs', 'point', 'postError', 'postNotice', 'preloadCidmap', 'printSetup', 'private', 'readOtherSubrsFile', 'references', '
registerGlyphSeparationHook', 'registerImportExport', 'registerMenuItem', 'runInitScripts', 'saveFilename', 'savePrefs', 'scriptFromUnicode', 'scriptPath', 'selection', 'setConvexNib', 'setPrefs', 'spiroCorner', 'spiroG2', 'spiroG4', 'spiroLeft', 'spiroOpen', 'spiroRight', 'splineCorner', 'splineCurve', 'splineHVCurve', 'splineTangent', 'unParseTTInstrs', 'unicodeFromName', 'unitShape', 'unspecifiedMathValue', 'userConfigPath', 'version']

Done.


(py_pc032_03.10_test1ff0) [prompt]>
(py_pc032_03.10_test1ff0) [prompt]> python ./code00.py
Executable: C:\Work\Dev\VEnvs\py_pc032_03.10_test1ff0\bin\python.exe
Version: 3.10.9 (main, Dec 10 2022, 09:16:22)  [GCC 12.2.0 32 bit]
CWD: E:\Work\Dev\StackExchange\StackOverflow\q073506592
UName: None
PATH: C:\Work\Dev\VEnvs\py_pc032_03.10_test1ff0\bin;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\OpenSSH\;C:\Users\cfati\AppData\Local\Programs\Python\Launcher\;e:\Work\Dev\Utils\current;e:\Work\Dev\Utils\current\Win;e:\Work\Dev\VEnvs\py_pc064_03.08.07_test0\Scripts;C:\Users\cfati\AppData\Local\Microsoft\WindowsApps;;c:\Install\pc032\FontForge\FontForgeBuilds\Version\bin;C:\Install\pc032\FontForge\FontForgeBuilds\Version\bin\
PYTHONHOME: None
PYTHONPATH: None
sys.path: ['e:\\Work\\Dev\\StackExchange\\StackOverflow\\q073506592', 'C:\\Install\\pc032\\FontForge\\FontForgeBuilds\\Version\\lib\\python310.zip', 'C:\\Install\\pc032\\FontForge\\FontForgeBuilds\\Version\\lib\\python3.10', 'C:\\Install\\pc032\\FontForge\\FontForgeBuilds\\Version\\lib\\python3.10\\lib-dynload', 'E:\\Work\\Dev\\StackExchange\\StackOverflow\\q073506592', 'C:\\Work\\Dev\\VEnvs\\py_pc032_03.10_test1ff0\\lib\\python3.10\\site-packages']
Traceback (most recent call last):
  File "e:\Work\Dev\StackExchange\StackOverflow\q073506592\code00.py", line 14, in <module>
    import fontforge as ff
ModuleNotFoundError: No module named 'fontforge'

Looking at the sys.path's last entry (in both cases), it becomes obvious why this happens.

So, this is a virtual environment related issue. To be more precise, it's a matter of virtual environment accessing the site-packages directory of the Python instance (system) it was created from.
In order to get past this, when creating the virtual environment, pass the --system-site-packages flag, mentioned in:

Output (continued):

(py_pc032_03.10_test1ff0) [prompt]> deactivate
[prompt]>
[prompt]> :: Create VEnv (from FFPython) - WITH --system-site-packages
[prompt]> "c:\Install\pc064\Python\Python\03.10\python.exe" -m virtualenv -p "c:\Install\pc032\FontForge\FontForgeBuilds\Version\bin\ffpython.exe" --system-site-packages "c:\Work\Dev\VEnvs\py_pc032_03.10_test1ff1"
created virtual environment CPython3.10.9.final.0-32 in 859ms
  creator CPython3Windows(dest=C:\Work\Dev\VEnvs\py_pc032_03.10_test1ff1, clear=False, no_vcs_ignore=False, global=True)
  seeder FromAppData(download=False, pip=bundle, setuptools=bundle, wheel=bundle, via=copy, app_data_dir=C:\Users\cfati\AppData\Local\pypa\virtualenv)
    added seed packages: pip==23.0.1, setuptools==67.4.0, wheel==0.38.4
  activators BashActivator,BatchActivator,FishActivator,NushellActivator,PowerShellActivator,PythonActivator

[prompt]>
[prompt]> "c:\Work\Dev\VEnvs\py_pc032_03.10_test1ff1\bin\activate.bat"

(py_pc032_03.10_test1ff1) [prompt]>  python ./code00.py > nul

(py_pc032_03.10_test1ff1) [prompt]>

Important note:

  • Python bundled by FontForge doesn't seem to be compatible with other "regular" Python instances, as it's:

    • Built with GCC (as opposed to VStudio). I think a consequence of that is its folder structure resembling to a Nix one

    • Crippled: lacks some standard modules (SSL, HashLib, ..)

    so attempting to load the .pyd by one of those (or virtual environments based on them) might yield Undefined Behavior

More debug info

  • Cmd:

    [cfati@CFATI-W10PC064:e:\Work\Dev\Utils\current\Win]> sopr.bat
    ### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ###
    
    [prompt]> echo %PATH%
    C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\OpenSSH\;C:\Users\cfati\AppData\Local\Programs\Python\Launcher\;e:\Work\Dev\Utils\current;e:\Work\Dev\Utils\current\Win;C:\Users\cfati\AppData\Local\Microsoft\WindowsApps;
    
    [prompt]>
    [prompt]> "c:\Install\pc032\FontForge\FontForgeBuilds\Version\bin\ffpython.exe" -c "import os;print(os.environ[\"PATH\"]);import fontforge;print(\"\nDone.\")"
    C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\OpenSSH\;C:\Users\cfati\AppData\Local\Programs\Python\Launcher\;e:\Work\Dev\Utils\current;e:\Work\Dev\Utils\current\Win;C:\Users\cfati\AppData\Local\Microsoft\WindowsApps;;C:\Install\pc032\FontForge\FontForgeBuilds\Version\bin\
    
    Done.
    
    [prompt]>
    [prompt]> where ffpython
    INFO: Could not find files for the given pattern(s).
    
    [prompt]> set _PATH=%PATH%
    
    [prompt]> set PATH=%_PATH%;c:\Install\pc032\FontForge\FontForgeBuilds\Version\bin
    
    [prompt]> where ffpython
    c:\Install\pc032\FontForge\FontForgeBuilds\Version\bin\ffpython.exe
    
    [prompt]>
    [prompt]> ffpython -c "import os;print(os.environ[\"PATH\"]);import fontforge;print(\"\nDone.\")"
    C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\OpenSSH\;C:\Users\cfati\AppData\Local\Programs\Python\Launcher\;e:\Work\Dev\Utils\current;e:\Work\Dev\Utils\current\Win;C:\Users\cfati\AppData\Local\Microsoft\WindowsApps;;c:\Install\pc032\FontForge\FontForgeBuilds\Version\bin;C:\Install\pc032\FontForge\FontForgeBuilds\Version\bin\
    
    Done.
    
  • PowerShell (PS):

    [cfati@CFATI-W10PC064:E:\Work\Dev\StackExchange\StackOverflow\q073506592]> function prompt { "[PS prompt]> "; }
    [PS prompt]>
    [PS prompt]> ${Env:PATH}
    C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\OpenSSH\;C:\Users\cfati\AppData\Local\Programs\Python\Launcher\;e:\Work\Dev\Utils\current;e:\Work\Dev\Utils\current\Win;C:\Users\cfati\AppData\Local\Microsoft\WindowsApps;
    [PS prompt]>
    [PS prompt]> & "c:\Install\pc032\FontForge\FontForgeBuilds\Version\bin\ffpython.exe" -c "import os;print(os.environ[\`"PATH\`"]);import fontforge;print(\`"\nDone.\`")"
    C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\OpenSSH\;C:\Users\cfati\AppData\Local\Programs\Python\Launcher\;e:\Work\Dev\Utils\current;e:\Work\Dev\Utils\current\Win;C:\Users\cfati\AppData\Local\Microsoft\WindowsApps;;C:\Install\pc032\FontForge\FontForgeBuilds\Version\bin\
    
    Done.
    [PS prompt]>
    [PS prompt]> where.exe ffpython
    INFO: Could not find files for the given pattern(s).
    [PS prompt]>
    [PS prompt]> ${Env:_PATH} = ${Env:PATH}
    [PS prompt]> ${Env:PATH} = ${Env:_PATH} + "c:\Install\pc032\FontForge\FontForgeBuilds\Version\bin"
    [PS prompt]> where.exe ffpython
    c:\Install\pc032\FontForge\FontForgeBuilds\Version\bin\ffpython.exe
    [PS prompt]>
    [PS prompt]> ffpython -c "import os;print(os.environ[\`"PATH\`"]);import fontforge;print(\`"\nDone.\`")"
    C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\OpenSSH\;C:\Users\cfati\AppData\Local\Programs\Python\Launcher\;e:\Work\Dev\Utils\current;e:\Work\Dev\Utils\current\Win;C:\Users\cfati\AppData\Local\Microsoft\WindowsApps;c:\Install\pc032\FontForge\FontForgeBuilds\Version\bin;C:\Install\pc032\FontForge\FontForgeBuilds\Version\bin\
    
    Done.
    

As seen, it works from PS as well, with no (or very few) manual interventions. If things don't work on your side, try running:

  1. The above steps

  2. FFPython, but from its directory

  3. ffpython -c "import os, sys;os.add_dll_directory(os.path.dirname(sys.executable));import fontforge"

Useful when debugging these kind of errors:



Update #0

After last findings, most likely some (older / newer version of) dependent .dlls of fontforge.pyd are located in some directories listed in %PATH%, and they are loaded before the correct versions (from FontForge's bin directory). That's a bit trickier to solve:

  1. Read the 1st URL from the list above and install Dependencies.

  2. Then you'll have to do a comparison of fontforge.pyd's dependent .dlls when (Dependencies tool is) launched from:

    1. FontForge's bin directory

    2. A different one

    Any .dlls that are in the former location should not be present (or if they are, they should have the same version) in any others (that come before it in %PATH%). You can either use the GUI version or the CmdLine one (like in the image below - FontForge's bin directory on the right side):

    Img1

    The command that I used to list dependent .dlls (obviously, you'll have to adjust the paths):

    "c:\Install\pc064\LucasG\DependenciesWalkerPolitistTexan\Version\Dependencies.exe" -modules "c:\Install\pc032\FontForge\FontForgeBuilds\Version\lib\python3.10\site-packages\fontforge.pyd" | findstr /R "\[Environment\] \[WindowsFolder\]"
    

    Another method is using ProcMon ([MS.Learn]: Process Monitor) when launching the script via FFPython, as shown in [SO]: C DLL loads in C++ program, not in python Ctypes (@MarkTolonen's answer)

  3. Once you've found the "faulty" .dlls, either:

    1. Remove their directories from %PATH%. Actually, removing might be enough in this particular case, but in order to be certain that it will work in any circumstance (other directories containing "duplicates" might be present on some machines at some point) you should set it to some minimum that (is required for running any Win application and) works for you. You can do that either (again, I'm exemplifying on my FontForge installation directory - adapt it to yours and things should be fine):

      • By creating a .bat wrapper file:

        set PATH=C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;c:\Install\pc032\FontForge\FontForgeBuilds\Version\bin
        
        ffpython script.py arg0, arg1 :: ...
        
      • From script.py:

        import os
        os.environ["PATH"] = r"C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;c:\Install\pc032\FontForge\FontForgeBuilds\Version\bin"
        
        import fontforge as ff
        

      This way, loading the .dll(s) happens in a sandboxed environment (in regard to %PATH%), immune to any directories capable of messing things up.

    2. Of course, there's the (currently working, but a bit inconvenient) option of launching the script from FontForge's bin directory (cd ${FONTFORGE_BIN_DIR} before launching the script)

    3. If any of the previous is not possible (for whatever reason - although I can't think of one at this point), remove (or better: rename) them (proceed with caution as applications that placed them there will (most likely) cease to work), but only use this as a last resort

Photoelectron answered 14/3, 2023 at 2:42 Comment(13)
I am extremely appreciative of your thorough reply and earnest help trying to get this solved. However, I don't think it's a VENV thing. I did a quick test and still run into the problem: i.imgur.com/PyQI5S4.png The image above shows me using a vanilla powershell prompt to call ffpython and then attempting to import fontforge. Still get the error. Any other ideas? Am I missing something?Strongroom
I edited the answer. Run the steps I indicated and also post the output, as the error alone doesn't help. What's the Win version? Any particularity that one should be aware of?Photoelectron
Ok! I'm getting somewhere now, but still confused. I have C:\Program Files (x86)\FontForgeBuilds\bin added to my system-wide PATH environment variable. When I feed PowerShell ${Env:PATH} it returns all of my entries as expected, with the FontForge path at the end. To make sure, I checked where.exe ffpython and it returned the correct path to the executable. However when I then successively ran ffpython -c "import os;print(os.environ["PATH"]);import fontforge;print("\nDone.")" I yet again got the error (ImportError: DLL load failed).Strongroom
However, when I simply navigated to the directory containing ffpython (C:\Program Files (x86)\FontForgeBuilds\bin\) ... and then ran the command again (ffpython -c "import os;print(os.environ["PATH"]);import fontforge;print("\nDone.")") it worked properly and I finally got no error. So I'm happy I have a semi-working state but confused as to why things break when I call ffpython from another working directory. I'd like to be able to just call ffpython from any working directory I'm in.Strongroom
FontForge version: FontForge Windows build (32-bit) Sun, Jan 1, 2023 5:36:43 AM +0000 a1dad3e81da03d5d5f3c4c1c1b9b5ca5ebcfcecf [master] Based on master: a1dad3e81da03d5d5f3c4c1c1b9b5ca5ebcfcecf https://github.com/fontforge/fontforge/releases/download/20230101/FontForge-2023-01-01-Windows.exe I'm on Windows 10 Pro 22H2.Strongroom
Lastly, ffpython -c "import os, sys;os.add_dll_directory(os.path.dirname(sys.executable));import fontforge" still returns ImportError: DLL load failed if I run the command outside of where ffpython is located. The only way I've been able to get things to work is by invoking ffpython from within its parent directory. Any more ideas?Strongroom
Sorry, one last comment - I updated the post with the results of running your test script. Maybe that will help narrow things down.Strongroom
Added a new update.Photoelectron
Using Dependencies I figured it out. Thank you so much. libfontforge.dll was referencing the wrong version of zlib1.dll from another directory I had in %PATH%. This is going to be problematic because I have quite a few applications with their own version of zlib1.dll that are added to PATH. Not sure how to handle that going forward but I suppose that is outside the scope of this problem. Thank you for your help, I would have never figured this out alone.Strongroom
I wanted to say it might be zlib1.dll (as it's the most common). I edited the answer (adding more details that will hopefully get this issue solved).Photoelectron
You're a lifesaver. I actually had no idea that DLL files were leveraged from directories in %PATH%, I thought that only executable (exe's/bat/com/etc) files were rendered universally public. I think I just need to slim down my %PATH% variable and leverage full paths to utilities in my scrpits that I use commonly use. It's nice to add all of my common applications to PATH so I can simply invoke them by name only, but I can see now it's creating more problems than solutions. Time to downsize. :)Strongroom
I have a total of 9 instances of zlib1.dll in my %PATH%: i.imgur.com/iyGUsdJ.png This is bound to create conflicts. Renaming zlib1.dll to zlib1.dll.old fixed the problem, now I'm concerned other applications might not work though, Time to remove the the rogue zlib1.dll files from PATH.Strongroom
instead of renaming, I'd suggest to manually set PATH (as I shown)because it's scalable, and it will work on any machine, and also on yours (if at a later time you'll install a new app that will add its dir containing a .dll in PATH).Photoelectron

© 2022 - 2024 — McMap. All rights reserved.