[GIS] Importing fmeobjects into PyQGIS

fmefmeobjectspyqgis

I use FME a lot for manipulation of spatial data, and would like to leverage it's Python library, fmeobjects in PyQgis.

If I run the following in my standard Python IDE it works fine:

import sys 
sys.path.append("C:\\Program Files (x86)\\fme\\fmeobjects\\python27") 
import fmeobjects

But the exact same code, when run in PyQgis, throws
ImportError: DLL load failed: The specified module could not be found.

In actual fact, fmeobjects is a .pyd file. I don't know if that's the problem, as my understanding is that pyd and dll are analogous to each other.

How can I get fmeobjects to import into PyQgis?

Best Answer

2016 update! Been trying to get this to work myself and thought I'd put what I've researched so far. This is done on Windows 10. For Linux users - try this if you're encountering problems.

Warning: For those wanting to integrate FME 2016 into python qgis, know that it isn't as easy as 'pip install fmeobjects' :)


Step 1

Locate your fmeobjects.pyd file. This I think is the hardest part really! See here for an intro to .pyd files. It's basically a Python Windows DLL file.

For Python 2.7 the file should be at:

C:\apps\FME2016\fmeobjects\python27\fmeobjects.pyd

QGIS doesn't use Python3 yet as of now, but if it does in upcoming QGIS 3 version, you should use:

C:\apps\FME2016\fmeobjects\python34\fmeobjects.pyd

For me, the file was located at D:\apps\FME2016\fmeobjects\python27\fmeobjects.pyd. So search around until you find that file.


Step 2

Next, let's import the fmeobjects module! The most official documentation I can find is here, note that it refers to FME 2015, but it should work on 2016. In 'theory', the following code should work:

import sys
sys.path.append("C:\\apps\\FME2016\\fmeobjects\\python27")
import fmeobjects

Advanced

If you are getting the error "ImportError: DLL load failed: The specified module could not be found", see here.

Now, if you're keen, you can go to http://www.dependencywalker.com/, download the application (it's portable) and search for your fmeobjects.pyd file, and run it

fmeobjects.pyd in dependencywalker fmeobjects.pyd in dependencywalker

See how fme.dll, fmepython27.dll, fmeutil.dll and rwtool_fme.dll are yellow in the second image? Those are missing dependencies not in our sys.path.

Those four files appear to located in a higher level directory (D:\apps\FME2016\ in my case). So we add that top-level directory to our sys.path, and also cd (change directory) to where fme is located so that fmeobjects will load properly. The python script thus becomes:

import os
import sys
sys.path.append("C:\\apps\\FME2016\\fmeobjects\\python27")
sys.path.append("C:\\apps\\FME2016\\")                     #add this
os.chdir("C:\\apps\\FME2016\\")        #do this too (somehow needed)
import fmeobjects

Step 3

Verify that things work.

licMan = fmeobjects.FMELicenseManager()               # Print FME license type.
print 'FME License Type :', licMan.getLicenseType()   # FME license property names.

Note: if you get the error "FMEException: FMEException: -1:" here, I think that means your python script is not running on the same machine as FME Desktop. E.g. your code is on your local drive but FME is installed on a server.


Step 4

Run a workbench!

worker = fmeobjects.FMEWorkspaceRunner()
worker.run('D:/fme/Workspaces/test.fmw') 

Step 5

Immerse yourself in the API.


Personally, I run my script over and over again alot, so I have some if-then statements and try-except stuff:

import sys
fmePydPath = "C:\\apps\\FME2016\\fmeobjects\\python27"      #fme file path
fmePath = "C:\\apps\\FME2016\\"
if fmePydPath not in sys.path: sys.path.append(fmePydPath)  #prevents too much appending
if fmePath not in sys.path: sys.path.append(fmePath)

os.chdir(fmePath)
import fmeobjects

#Verifies that things work
licMan = fmeobjects.FMELicenseManager()               # Print FME license type.
print 'FME License Type :', licMan.getLicenseType()   # FME license property names.

#Runs a workspace (.fmw) file
try:
    worker = fmeobjects.FMEWorkspaceRunner()
    worker.run('D:/fme/Workspaces/test.fmw')
except fmeobjects.FMEException, err:
    print "FMEException: %s" % err
Related Question