Procedure for installing python libraries from source

While I understand that 3rd party scripts can be dropped into the user-lib/pylib folder, what is the proper way to import a more complex library that requires running ‘python setup.py install’, or is normally installed with a package manager? Do I first need to build it using a separate python installation and move the resulting files into pylib? Do I use the Distutils packaged with Ignition to build it using the python packaged with Ignition?

Specifically, I’m trying to get the install twilio (not the module, just the regular twilio python package) to support some legacy scripts. After downloading the source, I tried simply moving the twilio folder containing the scripts to user-lib/pylib on the gateway to no avail:

Capture

Thanks for your time.

There’s actually a procedure you can use to use pip from within Jython to install packages, then link Ignition’s Jython lib to an-off-the-shelf Jython lib and use that…however, the article specifically calls out the twilio module as not working, because one of its dependencies, cffi, has C dependencies (IE, won’t work in Jython).

For posterity, here’s the procedure, copied verbatim from an internal document:
0) On the server, install Java 8 if you haven’t already.

  1. Download the full Jython 2.7.1 installer, and install. I installed to c:\jython2.7.1 for simplicity. Keep all other options default. Link: http://search.maven.org/remotecontent?filepath=org/python/jython-installer/2.7.1/jython-installer-2.7.1.jar
  2. Make sure JAVA_HOME points to the jre directory (tested with 8u191). If it’s not there, add the environment variable.
  3. Open a CMD prompt in admin mode. (Not PowerShell) “cd” to the /bin
  4. run “jython -m ensurepip” to install pip and setuptools
  5. Shut down Ignition if it’s already running
  6. In the CMD prompt, “cd” to the Ignition/user-lib/pylib folder
  7. Delete the “site-packages” folder
  8. Create a Junction link to the Jython site-packages directory: “mklink /J site-packages c:\jython2.7.1\Lib\site-packages”
5 Likes

Thank you very much for the response. Exactly what I needed. Bummer about the twilio C dependencies. Would the java twilio API suffer from the same issues? I’m hoping I can maybe import a precompiled .JAR instead.

Cheers

No, the Java package should be fine, although if you’re already loading a JAR it’s not that much more work to just write a module that exposes some scripting functions.

Hi,
I tried to follow these instructions and I got the following error when I ran “jython -m ensurepip” to install pip and setuptools:

Exception in thread “main” java.lang.UnsatisfiedLinkError: Could not load library. Reasons: [no jansi in java.library.path, The system cannot find the path specified]
at org.fusesource.hawtjni.runtime.Library.doLoad(Library.java:182)
at org.fusesource.hawtjni.runtime.Library.load(Library.java:140)
at org.fusesource.jansi.internal.CLibrary.(CLibrary.java:42)
at org.fusesource.jansi.AnsiConsole.wrapOutputStream(AnsiConsole.java:48)
at org.fusesource.jansi.AnsiConsole.(AnsiConsole.java:38)
at org.python.jline.AnsiWindowsTerminal.detectAnsiSupport(AnsiWindowsTerminal.java:57)
at org.python.jline.AnsiWindowsTerminal.(AnsiWindowsTerminal.java:27)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at java.lang.Class.newInstance(Unknown Source)
at org.python.jline.TerminalFactory.getFlavor(TerminalFactory.java:211)
at org.python.jline.TerminalFactory.create(TerminalFactory.java:102)
at org.python.jline.TerminalFactory.get(TerminalFactory.java:186)
at org.python.jline.TerminalFactory.get(TerminalFactory.java:192)
at org.python.jline.console.ConsoleReader.(ConsoleReader.java:243)
at org.python.util.JLineConsole.install(JLineConsole.java:107)
at org.python.core.Py.installConsole(Py.java:1744)
at org.python.core.PySystemState.initConsole(PySystemState.java:1269)
at org.python.core.PySystemState.doInitialize(PySystemState.java:1119)
at org.python.core.PySystemState.initialize(PySystemState.java:1033)
at org.python.core.PySystemState.initialize(PySystemState.java:989)
at org.python.core.PySystemState.initialize(PySystemState.java:984)
at org.python.util.jython.run(jython.java:263)
at org.python.util.jython.main(jython.java:142)

Any help would be appreciated.

Well, that’s a Jython problem, not an Ignition problem, but, it seems like the error is trying to tell you as much as it can. It looks like there’s some general bugs with jansi in Jython on Windows; there may not be much to do here other than investigate with Jython’s folks:
https://bugs.jython.org/issue2427

Is this the same procedure when attempting the same from a Ignition 8.1.X system?(Currently looking at a 8.1.4, but you guys upgraded to java 11 for a bunch of stuff and I figured I would check)

These instructions were written against 8.0, which also runs Java 11, and work fine. The Java installation is just for Jython’s pip, nothing to do with your actual Ignition system. You could also run Java 11 and I doubt it would cause any problems.

1 Like

I tried all these steps and I was able to successfully install the desired package to jython. One issue I am having is that when I try importing from the package I installed (literally 1st line of my .py script) I get the following error:

File “C:\jython2.7.1\Lib\site-packages\serial_ init _.py”, line 33, in
from serial.serialjava import Serial
File “C:\jython2.7.1\Lib\site-packages\serial\serialjava.py”, line 38, in
comm = detect_java_comm([
File “C:\jython2.7.1\Lib\site-packages\serial\serialjava.py”, line 32, in detect_java_comm
raise ImportError(“No Java Communications API implementation found”)
ImportError: No Java Communications API implementation found

Does this mean that Java does not have serial communications abilities? The package I want to use uses python’s pyserial package which I also installed.

I don’t think Java had ever included an implementation of the comm API. It’s very old and has always been BYO implementation because it’s just an API to program against.

Something called rxtx used to be a popular implementation but I don’t know if it works any more.

So you don't think there's a way to use this package with Ignition/Jython?

pySerial uses DLLs which you can't use in Jython.

That’s unfortunate… My python script simply queries a serial device and outputs a result. Is there any way I can display this result in Ignition?

The simplest option would probably be to use system.util.execute to launch your Python script directly and examine the result.
Alternately, you could (purchase and) install the serial module for the appropriate scope (Vision client or gateway) and then adapt your script to use system.serial scripting functions - then everything is kept within Ignition and is somewhat more ‘portable’.

4 Likes

I am trying to use that function in the script console, but I am seeing no output. Here’s how I’m executing the function:

system.util.execute(["C:\\Python27\\python.exe","C:\\Users\\mdia\\Desktop\\test.py"])

Pretty sure I’m doing it wrong… How can I execute the python script using this function?

Oh, right - system.util.execute is a 'fire-and-forget', it doesn't give you access to standard output. Try adapting this:

from java.lang import ProcessBuilder, String

pb = ProcessBuilder([r"C:\Users\pgriffith\AppData\Local\Microsoft\WindowsApps\python3.exe", r"C:\Users\pgriffith\Downloads\test.py"])
process = pb.start()
output = String(process.getInputStream().readAllBytes())

print output

(Note: This blocks until the process completes waiting on the input stream. It may or may not ever complete, depending on what you're running, which could block a thread forever. Be careful).

2 Likes

I tried the following and it’s still not printing out an output.

from java.lang import ProcessBuilder, String

pb = ProcessBuilder([r"C:\Users\mdia\AppData\Local\Microsoft\WindowsApps\python.exe", r"C:\Users\mdia\Desktop\test.py"])

process = pb.start()

output = String(process.getInputStream().readAllBytes())

print output

Not working with python3 either. The script that I am testing with simply prints out a string.

Where are you running this, and is the Python binary and test script located on the same machine?

That code worked fine for me in the Designer script console with some changes for my environment:

from java.lang import ProcessBuilder, String

pb = ProcessBuilder([r"python", r"/Users/kevin/Desktop/test.py"])

process = pb.start()

output = String(process.getInputStream().readAllBytes())

print output

1 Like

Running in the script console, and yes.

It finally worked for some reason after replacing the full python directory

“C:\Users\mdia\AppData\Local\Microsoft\WindowsApps\python.exe” with just “python”.

Hello all,
it works in the script console but not in an script event, any idea ?