Cannot "import pcbnew" when running KiCad/bin/python.exe on the command-line

I want to do batch work on multiple board files using python. This is easiest if I can run python from the command-line and import pcbnew and then manipulate board files without actually starting the PCBNEW application. For example, here is a simple python test script:

(test.py)

import pcbnew
board = pcbnew.LoadBoard("test.kicad_pcb")
print board.GetFileName()

which I then try to run from the command-line using the (supposedly) correct python environment like this:

C:/Program Files/KiCad/bin/python.exe test.py

I get the following ImportError:

Traceback (most recent call last):
  File ".\test.py", line 1, in <module>
    import pcbnew
  File "C:\Program Files\KiCad\lib\python2.7\site-packages/pcbnew.py", line 38, in <module>
    import _pcbnew
ImportError: DLL load failed: The specified procedure could not be found.

I’ve tried with both KiCad v5.0.2 and v6.0.0-rc1-dev1455. I’m on Windows 7 Ultimate (Service Pack 1). This use to work in the older versions of KiCad. What has changed?

The system installed python is not setup for the kicad environment (it is possible to do but unnecessary)

Use python that ships with kicad instead.

That is exactly what I did! See my post where I specifically state that I execute my script using the KiCad/bin/python.exe executable.

What does the version info string say? (Kicad->help->about->copy version information)

Here it is:

Version: (6.0.0-rc1-dev-1455-g4b7ef22ec), release build
Libraries:
    wxWidgets 3.0.4
    libcurl/7.61.1 OpenSSL/1.1.1 (WinSSL) zlib/1.2.11 brotli/1.0.6 libidn2/2.0.5 libpsl/0.20.2 (+libidn2/2.0.5) nghttp2/1.34.0
Platform: Windows 7 (build 7601, Service Pack 1), 64-bit edition, 64 bit, Little endian, wxMSW
Build Info:
    wxWidgets: 3.0.4 (wchar_t,wx containers,compatible with 2.8)
    Boost: 1.68.0
    OpenCASCADE Community Edition: 6.9.1
    Curl: 7.61.1
    Compiler: GCC 8.2.0 with C++ ABI 1013

Build settings:
    USE_WX_GRAPHICS_CONTEXT=OFF
    USE_WX_OVERLAY=OFF
    KICAD_SCRIPTING=ON
    KICAD_SCRIPTING_MODULES=ON
    KICAD_SCRIPTING_PYTHON3=OFF
    KICAD_SCRIPTING_WXPYTHON=ON
    KICAD_SCRIPTING_WXPYTHON_PHOENIX=OFF
    KICAD_SCRIPTING_ACTION_MENU=ON
    BUILD_GITHUB_PLUGIN=ON
    KICAD_USE_OCE=ON
    KICAD_USE_OCC=OFF
    KICAD_SPICE=ON

Here is an even simpler example of the error where I just cd into the KiCad bin directory, execute the python.exe contained there and try to import pcbnew:

PS C:\> cd 'C:\Program Files\KiCad\bin'
PS C:\Program Files\KiCad\bin> .\python.exe
Python 2.7.15 (default, Oct 11 2018, 12:09:51)  [GCC 8.2.0 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import pcbnew
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Program Files\KiCad\lib\python2.7\site-packages/pcbnew.py", line 38, in <module>
    import _pcbnew
ImportError: DLL load failed: The specified procedure could not be found.
>>>

I can sadly not test this for myself as i do not have access to a windows machine. Your later example runs normally with current nightly unter ubuntu 16.04.

So this might be a bug in the windows installer. (maybe the dll referenced in the error message really is missing.)

I can confirm that _pcbnew.pyd exists in C:\Program Files\KiCad\lib\python2.7\site-packages. However, there is still the possibility that another DLL referenced by _pcbnew.pyd is not being found.

One weird thing is that I can successfully execute import pcbnew when using the scripting console inside the PCBNEW application. I wonder what is the difference?

Maybe printing pythonpath from the scripting console and from within the commandline python might give a clue (or any other environment variable for that matter)

Paths seem ok.

In the KiCad/bin/python.exe:

print sys.path
['', 'C:\\Program Files\\KiCad\\lib\\python27.zip', 'C:\\Program Files\\KiCad\\lib\\python2.7', 'C:\\Program Files\\KiCad\\lib\\python2.7\\plat-win32', 'C:\\Program Files\\KiCad\\lib\\python2.7\\lib-tk', 'C:\\Program Files\\KiCad\\lib\\python2.7\\lib-old', 'C:\\Program Files\\KiCad\\lib\\python2.7\\lib-dynload', 'C:\\building\\msys64\\mingw64', 'C:\\Program Files\\KiCad\\lib\\python2.7\\site-packages', 'C:\\Program Files\\KiCad\\lib\\python2.7\\site-packages\\wx-3.0-msw']

In the scripting console:

print sys.path
['', 'C:\\Program Files\\KiCad\\lib\\python27.zip', 'C:\\Program Files\\KiCad\\lib\\python2.7', 'C:\\Program Files\\KiCad\\lib\\python2.7\\plat-win32', 'C:\\Program Files\\KiCad\\lib\\python2.7\\lib-tk', 'C:\\Program Files\\KiCad\\lib\\python2.7\\lib-old', 'C:\\Program Files\\KiCad\\lib\\python2.7\\lib-dynload', 'C:\\building\\msys64\\mingw64', 'C:\\Program Files\\KiCad\\lib\\python2.7\\site-packages', 'C:\\Program Files\\KiCad\\lib\\python2.7\\site-packages\\wx-3.0-msw', '.', 'C:\\Program Files\\KiCad\\share\\kicad\\scripting', 'C:\\Program Files\\KiCad\\share\\kicad\\scripting\\plugins']

The scripting console has these additional paths appended to sys.path:
'.', 'C:\\Program Files\\KiCad\\share\\kicad\\scripting', 'C:\\Program Files\\KiCad\\share\\kicad\\scripting\\plugins'

but adding those manually before import pcbnew does not make a difference.

Also for the PATH environment variable:

In the KiCad/bin/python.exe:

print os.environ['PATH']
C:\Program Files\KiCad\bin;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\ProgramData\Oracle\Java\javapath;C:\Program Files (x86)\Common Files\Intel\Shared Files\cpp\bin\Intel64;C:\Program Files (x86)\Intel\iCLS Client;C:\Program Files\Intel\iCLS Client;C:\Program Files\Common Files\Microsoft Shared\Windows Live;C:\Program Files (x86)\Common Files\Microsoft Shared\Windows Live;C:\Python27\Lib\site-packages\PyQt4;C:\Program Files (x86)\AMD APP\bin\x86_64; (snip)

In the scripting console:

print os.environ['PATH']
C:\Program Files\KiCad\bin;C:\Program Files\KiCad\bin;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\ProgramData\Oracle\Java\javapath;C:\Program Files (x86)\Common Files\Intel\Shared Files\cpp\bin\Intel64;C:\Program Files (x86)\Intel\iCLS Client;C:\Program Files\Intel\iCLS Client;C:\Program Files\Common Files\Microsoft Shared\Windows Live;C:\Program Files (x86)\Common Files\Microsoft Shared\Windows Live;C:\Python27\Lib\site-packages\PyQt4;C:\Program Files (x86)\AMD APP\bin\x86_64; (snip)

All the other environment variables seem OK too.

I checked by dumping all of the environment variables to a python dictionary in the scripting console and then setting all of those environment variables from the dictionary in the command-line session. Still no change.

I am out of ideas now.

You could head over to the bugtracker and report this. Or maybe wait till somebody more knowledgeable comes along here.

Thanks Rene! I appreciate your suggestions so far.

BTW, I wonder if you can call pcbnew.exe with command-line options to have it execute a python script and exit?

No, KiCad uses command line options for very few purposes.

I found that I can get this working if I do the following 2 things:

  1. Copy _pcbnew.pyd from the sites-packages folder to the KiCad/bin folder.
  2. In my python session, changing the working directory to KiCad/bin before trying to import pcbnew, like this:
os.chdir("C:\\Program Files\\KiCad\\bin")
import pcbnew

I don’t understand why this works because I would think that having C:\Program Files\KiCad\bin on the PATH would achieve the same thing but it does not. My partial theory is that there are DLLs in the KiCad\bin folder that the import process is not finding.

Program Files in latest windows can do some smoke and mirrors tricks. I would bet if you install KiCad to another folder those problems would go away.

I bet the code near following line was hard coded the path of loading _pcbnew.pyd DLL to current dir.
“C:\Program Files\KiCad\lib\python2.7\site-packages/pcbnew.py”, line 38

I checked but there is no hard-coded path information in pcbnew.py. That file is auto-generated by SWIG.

Line 38 of pcbnew.py looks like this:

import _pcbnew

That mean the error seem to be deeper inside the _pcbnew.pyd. I think is it a bug may need to be reported.
What if you don’t copy _pcbnew.pyd file into Kicad\bin, but do a chdir to it only?..

I did try that first but no, you definitely need to copy it.