Skip to main content

So today we did an upgrade from FMECloud 2020 to FMECloud 2022, I was a bit nervous because I was afraid some of the apps would break. Of course there was a reason for my concern,  because I had modified FME 2020 to fit our needs. We like to make nice reports with a structured layout, thats why we use 3rd party libraries. These does not come with an FMECloud instance, so you need to do some tricks to install libraries on it. But how do you install libraries on an instance which is made up from containers, wouldn't they dissapear suddenly? 

Well, there are some persistent storage on FMECloud which you actually use quite frequently.  I'm talking about the FME_SHARED_RESOURCE  storage. Yup, you can install libraries on this storage. There are 2 ways to achive this, fire up a linux machine with the same os as FME Cloud install a library to a folder, then upload that data to FME SHARED RESOURCES or use the underlying machine to do the task. I choose option 2, I want packages I can use with the FME Python engine, to do so I need to run commands on the instance. This can be achieved with a SystemCaller or a PythonCaller or maybe som other non-python transformer too. To be able to install packages I would like to use the following syntax:

fme python -m pip install {pkg} -t {destination}

 This wont work, since the path to fme is not in the global PATH, so you need to locate where it is. One way is to look for it with find. I did the following:

find / -name 'fme'

This revield serveral results so I went for the one inside the bin folder: /opt/fme-engine-2022/bin/fme

Now you can build you full command with the help of FME Parameters:

/opt/fme-engine-2022/bin/fme python -m pip install pkg  -t ${FME_SHAREDRESOURCE_DATA}/pkg-site-packages

I use this kind of command inside the python transformer:

import fmeobjects
import os
import subprocess as sp
import shlex
 
logger = fmeobjects.FMELogFile()
 
class PipInstaller(object):
 
    def __init__(self):
        self.requirements= '''
pkg1==1.0.0
pkg2==1.2.3
'''
        
    def input(self, feature):
        command = "/opt/fme-engine-2022/bin/fme python -m pip install {pkg} -t {dest}"
        #command = "find / -name 'fme'"
        dest = os.path.join(FME_MacroValuesÂ'FME_SHAREDRESOURCE_DATA'], 'site-packages')
        for pkg in self.requirements.splitlines():
            pkg = pkg.strip()
            if not pkg:
                continue
            cmd = shlex.split(command.format(pkg=pkg, dest=dest))
            logger.logMessageString(f'Running command {cmd}', 1)
            session = sp.Popen(cmd, stdin=-1, stdout=-1, stderr=-1)
            result, *_ = session.communicate()
            logger.logMessageString(result.decode(), 1)
        newFeature = fmeobjects.FMEFeature()
        self.pyoutput(newFeature)
        
    def close(self):
        pass

 

Next you only need to add this folder to your sys.path before importing the package.

import os
import sys
path = os.path.join(FME_MacroValuesÂ'FME_SHAREDRESOURCE_DATA'], 'site-packages')
sys.path =  path] + sys.path
import pkg1
import pkg2

 pkg1 and pkg2 is just dummy names.

 

Maybe I can revisit this on our next upgrade in 2024.

 

Be the first to reply!

Reply