Home
Categories
Dictionary
Glossary
Download
Project Details
Changes Log
What Links Here
FAQ
License

Python http modules



Python http modules are Python modules where the associated Python script communicate with the framework using http requests.

Overview

These modules allow to execute Python code in a Python 3 environment:
  • A Python module creates a Python process using the Python executable path defined in the framework properties. By default the framework will look for a Python 2.x executable among the applications installed on the System. As you need to use a Python 3 runtime, you should set the pythonDefaultRuntime property to python3 if you don't set the Python runtime explicitly[1]
    See python configuration properties for more information
  • services reception from the Python module will be deferred to the associated Python script by sending a GET request
  • services invocation from the Python script will be deferred as a Python module Service invocation by sending a POST request

pythonarchihttp
Two generic additional Python scripts are necessary to handle the communication between the Python module and the Python script:
  • The pythonHttpModule.py script is responsible for the Services subscription in the Python environment
  • The pythonHttpUtils.py script is an utility script usable by the user Python script


Note that these two modules are only valid for a Python 3 environment.

Initialization and runtime sequence


The initialization and runtime sequence of Python scripts using http communication follows two general phases: Note that if the initialization phase does not end correctly[2]
It can be the case if the Python script takes too much time to start-up, or if there is an exception during the initialization of the script
, then the Python module initialization will be aborted. Else the runtime phase will be started.

sequencepython

Using lengthy methods for the Python scripts


Python framework

Main Article: Python executable path

The Python script is not executed in the JVM, but the framework will look for a Python executable on the Platform, or the user can specify the path of the Python executable.

Deployment

These modules do not need a deployment in their parent application because they are scripted.

Declaration

These modules are declared by the top-level pythonHttpModule element. For example:
      <pythonHttpModule name="FlightManagementSystem">
The optional pythonModuleType attribute specifies the type of http communication. It can be:
  • "http" (the default)
  • or "webSocket"
Note that for the moment only the "http" value is supported.

Types limitations

There are no types limitations for Python http modules. There is a JSON library included in the Python implementation, so the exchange of Data is performed using the JSON format. With this format, there are no limitations on the types which can be exchanged with Python modules, including types complex types[3]
For example, it is possible to exchange arrays of structures, or maps whose values are structures
.

Python http module implementation

The pythonImplementation element declares the Python script file which implements the script, and specified associated properties:
  • path: refer to the name of the file (without the ".py" extension) which implements the Python script. The path of this file is by default relative to the application.xml file which declares the module
  • port: define the port which will be used to communicate between the Java application and the Python Script
  • waitAtStart: the maximum duration to wait for after the start of the Python script[4]
    This is necessary to allow the Python executable to start-up, see also Python initialization and runtime sequence
    . By default the duration will be specified as 200 ms if not defined. See also Waiting for Python runtime initialization
  • pythonEnumAsString: an optional boolean to specify that enumeration values should be sent as names to the Python module rather than their index. See Enumerations as String for more information
  • className: the optional name of the Python class to call. By default the name is derived from the name of the Python module. See Python class name for more information
  • compatibility: Allows to set a compatibility for an older version of the Python modules. See Python compatibility for more information

Example

For example:
      <pythonHttpModule name="FlightManagementSystem" >
         <pythonImplementation path="pythonAppli" port="8080"/>
      </pythonHttpModule>

Python class name

By default the module must contain at least one class which must have the same name as the module file itself[5]
Minus the first character which must be upper case
. For example, if the file name is myPythonAppli.py, then the path parameter must be myPythonAppli, and the class defined in the module must be named MyPythonAppli.

The module is free to contain other classes as well.

For example:
      <pythonHttpModule name="FlightManagementSystem" id="1" >
         <pythonImplementation path="pythonAppli" port="8080"/>
      </pythonHttpModule>
and:
      from pythonHttpUtils import PythonHttpUtils

      class PythonAppli:
However, it is possible to specify the name of the class to call in the module by using the className parameter.

For example:
      <pythonHttpModule name="FlightManagementSystem" >
         <pythonImplementation path="pythonAppli" className="FMS" port="8080" />
      </pythonHttpModule>
and:
      from pythonHttpUtils import PythonHttpUtils

      class FMS:

Python module implementation constraint

For the moment, there are two limitations on the way the module should be implemented:
  • The module must import the PythonHttpUtils class in the pythonHttpUtils module
  • If the module has a start(self) method, it will be called at start
For example:
      from pythonHttpUtils import PythonHttpUtils

      class PythonAppli:

         def start(self):
           self.pythonHttpUtils.startTimer('timer', 1, self.tick)

Enumerations as String

By default, enumeration values for the JSON content sent to the Python module are sent wityh the state value (an int).

The pythonEnumAsString property specifies that the state names should be sent instead. Note that this can also be configured with the framework property of the same name.

Services interface declaration


Python http modules have specific options for the service interfaces declaration, allowing to block the Python script on specific services receptions.

Python http modules notifications do not work as for regular Python UDP modules because these modules use http requests, which means that they need to send a GET request to receive a notification from a service.


By default the framework sends the response as soon as the call has been performed by the Python script, and is not blocking after the call, but there are specific options to configure how to block the Python script after the call for:
  • The eventReceived, requestSend and subscribe notifications
  • The eventSend, requestReceived and push invocations

Python compatibility

Main Article: Python modules version

The pythonHttpModule.py and pythonHttpUtils.py scripts must be updated when the communication between Java and Python is upgraded.

The Python modules version is provided by the Framework as a launch argument when starting the Python process. The pythonHttpModule.py script check if its own version is compatible with the version proviced by Java. This means that you normally should replace the pythonHttpModule.py and pythonHttpUtils.py scripts if the Python modules version changes.

Python library


In order for the Python script to work properly, you must copy two additional Python scripts which will be used as a library in the same directory as the script itself:
  • The pythonHttpModule.py script
  • The pythonHttpUtils.py script
These two supporting scripts do not depend on the content of the Python script and can be retrieved in the Browser by performing the command Tools => Generate Python Library.

Note that you must use the correct version of the Python scripts depending on the version of Python you intend to use. See generating a Python library more information.

The version of the two supporting scripts must be identical to the version expected by the Java module, else the Python script will exit with an error message

pythonHttpUtils.py script

The pythonHttpUtils.py script utility has the following utility methods:



class PythonHttpUtils


var CHANGED
Value indicating that a service has changed since the last notify call


var INVALID
Value indicating that a service declaration is invalid


var NOT_CHANGED
Value indicating that a service has not changed since the last notify call


var VALID
Value indicating that a service declaration is valid


def echo(self, content, wait=True)
print the content on the system.out Stream. Note that due to the rate of exchange between Java and Python, this method force a flush. Using only print(content) would not print the content in many cases.


def err(self, content, wait=True)
print the content on the system.err Stream. Note that due to the rate of exchange between Java and Python, this method force a flush. Using only print(content) would not print the content in many cases.


def getService(self, name)
get a Service with its name


def invoke(self, name)
Invoke a service


def notify(self, name, instanceId=0)
Get the content of one service for one instance


def setValue(self, service, name, value)
set a Data value for a Service


def startTimer(self, name, seconds, theMethod)
Start a timer loop. The method has the following arguments:
  • name: the name of the timer
  • seconds: the number of seconds for each iteration of the loop (can be a decimal)
  • theMethod: the method to call for each iteration of the loop

Note that to get a Data value for a Service, you just have to use:
      value = service[data_name]

Http requests and routes

The Framework acts as a http server which accepts requests from several routes.

There are several http requests and routes that can be used by the Python script:
  • A GET request named /proto/api/notify/<serviceName> for each service for which the module is subscribed to[6]
    It can also be used for each service for which the module is a provider
    . This request allow to get the content of the service in the server response
  • A POST request named /proto/api/invoke/<serviceName> for each service for which the module is a provider. This request allow to invoke the service
  • A POST request named /proto/api/stdout/ for sending a message to the framework
  • A POST request named /proto/api/stderr/ for sending an exception message to the framework
There are several methods in the pythonHttpUtils script which take care of the sending of these requests automatically.

Notification

As an http dialog is always initialized by the Client, it is not possible with this protocol for the server to post content without a request from the client. Therefore the notification of the content of a service must be performed by the server after a request from the Python script.

The notify(self, name, instanceId=0) method allow to get the content of a service. The method will return:
  • PythonHttpUtils.INVALID if the service does not exist
  • PythonHttpUtils.CHANGED if the service has been updated since the last time its request has been sent
  • PythonHttpUtils.UNCHANGED if the service has not been updated since the last time its request has been sent
  • PythonHttpUtils.ERROR if a JSON decoding error has been encountered
After this call returned, the service content has been updated and therefore its datas have their latest values and can be used.

The optional instanceId argument allows to make the call for several instances of the python class. In that case, the returned value will depend on which instance made the call.

Invocation

The invoke(self, name) method allow to invoke a service. The method will return:
  • PythonHttpUtils.VALID if the service does exist
  • PythonHttpUtils.INVALID if the service does not exist

Example

Suppose the following module declaration, with the same services definition as for the first tutorial:
      <pythonHttpModule name="PublishModule" pythonModuleType="http">
         <pythonImplementation path="pythonAppli" port="8080"/>
         <interfaces>
            <eventReceived service="event"/>
            <push service="published"/>
         </interfaces>
      </pythonHttpModule>
The following code updates the value of the published service, depending on the event value:
      def tick(self):   
         self.pythonHttpUtils.notify("event")
         eventService = self.pythonHttpUtils.getService(serviceName);
         eventValue = eventService["event"]
         if eventValue:
           step = -1
         else:
           step = 1

         publishService = self.pythonHttpUtils.getService("published");
         self.pythonHttpUtils.setValue(publishService, "value", self.count)
         r1 = self.pythonHttpUtils.invoke("published")
         self.count = self.count + step      

Spawning subprocesses in Python http modules


Notes

  1. ^ See python configuration properties for more information
  2. ^ It can be the case if the Python script takes too much time to start-up, or if there is an exception during the initialization of the script
  3. ^ For example, it is possible to exchange arrays of structures, or maps whose values are structures
  4. ^ This is necessary to allow the Python executable to start-up, see also Python initialization and runtime sequence
  5. ^ Minus the first character which must be upper case
  6. ^ It can also be used for each service for which the module is a provider

See also


Categories: concepts | python

Copyright 2017-2020 Dassault Aviation. All Rights Reserved. Documentation and source under the LGPL v3 licence