DS2 Interface to Python

DS2 modules, running in SAS Micro Analytic Service, can publish and execute Python modules.
Note that Python 2.7 or Python 3.4 must be available for SAS Micro Analytic Service to load. If both are available, SAS Micro Analytic Service loads Python 3.4. See Python Support in SAS Micro Analytic Service, for information about installing Python and configuring the environment variables necessary to allow Python to run embedded in SAS Micro Analytic Service. As is the case when calling any package from DS2, it is recommended that you always check return codes where available, and return any error codes using an output argument from your DS2 method.
Each package instance represents exactly one module revision. You can create as many instances as desired, allowing multiple modules to be used. The module name (or the Python script name) is given as a package constructor argument. The constructor automatically sets up user and module contexts to house the instance.
Here are some operations that a DS2 module would typically perform.
Instantiate the following DS2 package:
py = _new_ maspy(“myPythonScript”);
Calling publish() compiles your Python script and creates the revision. The Python code is passed as a string in the first argument. A list of argument names is required by Python and is passed as an array of strings in the second argument. As is the case with any method signature in SAS Micro Analytic Service, all of the input arguments must precede the output arguments in the list.
rc = py.publish(python_script, arguments, numinputs);
Call setType methods to set input values before executing the script. Because these setters store arguments by name, they can be called in any order and will insert the values in the correct positions:
py.setDouble(“airflow”, sensor_maf);
Since the DS2 package instance represents a single revision, the execute() method needs no arguments.
rc = py.execute();
After execution, call getters to retrieve the results.
score = py.getDouble(“credit_score”);
Scalar argument setters are of the form:
return_code = set<type>(name, value)
Scalar argument getters are of the form:
value = get<type>(name)
Array argument setters are of the form:
rc = set<type>Array(name, array-value)
Array argument getters are of the following form.
Note: DS2 passes arrays and output values by reference.
get<type>Array(name, array-value, rc)
The following setOut methods reserve space in the argument list for output arguments.
rc = setOut<type>(name)
rc = setOut<type>Array(name)
Note: If an array is not originally allocated, or if it is allocated with insufficient size, it will be allocated or reallocated with sufficient size to accommodate DS2.
The example below assumes that you have declared your package as py:
dcl package pymas py;
dcl int rc;
dcl bigint result;

rc = py.publish(python_script, symbols, number_of_inputs);
py.setString(“inString”, “A string”);
rc = py.setOutLong(“outLong”);

py.execute()

result = py.getLong(“outLong”);
The requestInterrupt(userContext, moduleContext, revision, entryPoint) method can be used to halt the execution of a runaway module or method, such as a method containing an infinite loop. It can be used to halt the execution of DS2 modules, Python modules, or DS2 modules that call Python. When interrupting a Python module, the entryPoint parameter is ignored, since a Python module represents one entire Python script.
The complete set of DS2 package methods follows, where rc is the integer return code, and py is the package instance.
Methods for Python module management and execution:
rc = py.publish(python_script, arguments, numinputs);
rc = py.remove();
rc = py.isLoaded(); // returns true is Python is available and false otherwise
rc = py.getModuleContextID();
rc = py.getRevisionNumber();
rc = py.setTimeZone(time_zone_identifier);
rc = py.execute();
Scalar argument setters:
 rc = py.setString(argument_name, value);
rc = py.setBool(argument_name, value);
rc = py.setLong(argument_name, value);
rc = py.setInt(argument_name, value);
rc = py.setDouble(argument_name, value);
rc = py.setDateTime(argument_name, value);
rc = py.setDate(argument_name, value);
rc = py.setTime(argument_name, value);
Scalar argument getters:
string_value   = py.getString(argument_name);
int_value              = py.getBool(argument_name);
long_value             = py.getLong(argument_name);
int_value              = py.getInt(argument_name);
double_value           = py.getDouble(argument_name);
date_time_value        = py.getDateTime(argument_name);
date_value             = py.getDate(argument_name);
time_value             = py.getTime(argument_name);
Scalar output argument setters:
rc = py.setOutString(argument_name);
rc = py.setOutBool(argument_name);
rc = py.setOutLong(argument_name);
rc = py.setOutInt(argument_name);
rc = py.setOutDouble(argument_name);
rc = py.setOutDateTime(argument_name);
rc = py.setOutDate(argument_name);
rc = py.setOutTime(argument_name);
Array argument setters:
rc = py.setStringArray(argument_name, string_array);
rc = py.setBoolArray(argument_name, integer_array);
rc = py.setLongArray(argument_name, bigint_array);
rc = py.setIntArray(argument_name, integer_array);
rc = py.setDoubleArray(argument_name, double_array);
rc = py.setDateTimeArray(argument_name, date_time_array);
rc = py.setDateArray(argument_name, date_array);
rc = py.setTimeArray(argument_name, time_array);
Array argument getters:
py.getStringArray(argument_name, string_array, rc);
py.getBoolArray(argument_name, integer_array, rc);
py.getLongArray(argument_name, bigint_array, rc);
py.getIntArray(argument_name, integer_array, rc);
py.getDoubleArray(argument_name, double_array, rc);
py.getDateTimeArray(argument_name, date_time_array, rc);
py.getDateArray(argument_name, date_array, rc);
py.getTimeArray(argument_name, time_array, rc);
Array output argument setters:
rc = py.setOutStringArray(argument_name);
rc = py.setOutBoolArray(argument_name);
rc = py.setOutLongArray(argument_name);
rc = py.setOutIntArray(argument_name);
rc = py.setOutDoubleArray(argument_name);
rc = py.setOutDateTimeArray(argument_name);
rc = py.setOutDateArray(argument_name);
rc = py.setOutTimeArray(argument_name);
Python 2.x uses ASCII as the default encoding. Therefore, you must specify another encoding at the top of the file to use non-ASCII Unicode characters in literals. As a best practice, when using Python 2.x, always use the following as the first line of your Python script:
# -*- coding: utf-8 -*-
Also, in Python 2.x, the Unicode literal must be preceded by the letter u. Therefore, literal strings should be written using the following form:
u”xxxxx”
Note: Python 3.x uses UTF-8 as the default encoding, so these issues affect Python 2.x only. When using Python 3.x, the default encoding can be used, and literals can simply be enclosed in quotation marks.