The SAS DS2 pymas package
provides interfaces that enable users to publish and execute Python
code using the SAS Micro Analytic Service. This section describes
how SAS Micro Analytic Service can be configured in a SAS Application
Server, enabling you to test DS2 pymas package usage using PROC DS2
running in a SAS session. Examples of a SAS session are a workspace
server that has been launched by SAS Studio or SAS Decision Manager.
Two user modifications
are needed when configuring a SAS Application Server to support the
use of the SAS DS2 pymas package in a SAS server, such as the workspace
server. Here is a brief example:
-
Copy the SAS Micro Analytic
Service shared libraries from SASHome/SASFoundation
on
the middle tier to the appropriate directory under SAS Foundation,
on the server tier.
-
Add environment settings
to the server's corresponding _usermods.sh(.bat) file provided in
the server's configuration directory.
Because the _usermods
files are sourced within each of the server wrapper scripts, the server
inherits any logic or environment. SAS preserves _usermods files during
software updates, unlike the server wrapper scripts, which SAS overwrites.
For this reason, editing the wrapper scripts is discouraged.
One place that SAS Micro
Analytic Service is installed in the middle tier is a platform-specific
location within
SASHome/SASFoundation
.
Here is an example on UNIX platforms:
-
SASHome/SASFoundation/<release>/sasexe
A specific instance
on a UNIX platform can look like this:
-
/install/SASServer/SASHome/SASFoundation/9.4/sasexe
Here is a list of the
shared libraries that must be copied from that directory on a UNIX
platform:
The library name t1j8en.so
is the English translation of the SAS Micro Analytic Service message
file. Copy any other SAS Micro Analytic Service language files matching
t1j8??.so as well.
On Windows, the list
is almost the same as UNIX except that the file extensions are .dll
instead of .so, and libtksf.so is tksf.dll:
On Windows, those libraries
are located at
core\sasext
, instead
of sasexe. Here is an example:
-
C:\Program Files\SASHome\SASFoundation\9.4\core\sasext
With respect to environment
setting changes needed in the _usermodes.sh(.bat) file, the environment
must be updated to enable the server to find Python and any Python
modules needed by your Python code. When configuring the workspace
server on UNIX, you are updating the following environment sas-configuration-directory/<LevN>/SASApp/WorkspaceServer/WorkspaceServer_usermods.sh
:
First make a backup
copy. Here is an example:
cp --preserve=timestamps WorkspaceServer_usermods.sh \
WorkspaceServer_usermods.orig.sh
Then, make the following
changes to WorkspaceServer_usermods.sh. This example assumes that
Anaconda Python is installed and configured on the server machine,
and that at least one Python environment has been created.
-
Update the name of the
shell in the first line from sh to bash. Here is an example:
Note: The remainder of the updates
are the same commands that you use to activate and configure your
Anaconda Python environment normally.
-
Source the Anaconda
activate script to activate the desired environment. Here is an example:
source /anaconda3/bin/activate python27
Note: A dot (.) is an alias for
the source command.
-
Add ${CONDA_PREFIX}/lib
to the LD_LIBRARY_PATH environment variable. Here is an example:
LD_LIBRARY_PATH=${CONDA_PREFIX}/lib:${LD_LIBRARY_PATH}
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH%:}
-
If the server has multiple
Python installations that are conflicting, you could possibly encounter
an error, such as Python DateTime API failed to load.
If so, set the PYTHONHOME to your Python home directory. Here is
an example:
PYTHONHOME=/anaconda3
export PYTHONHOME
On Windows, when configuring
the workspace server, you are updating WorkspaceServer_usermods.bat.
Add the command that you used to activate the Anaconda Python environment
that you created previously. Here is an example:
c:\Anaconda3\Scripts\activate python27
If you have other environment
settings needed for your Anaconda Python environment, add those commands
as well.
You can test your configuration
by submitting a PROC DS2 program to make sure it can successfully
use the DS2 pymas package. Here is an example:
%macro chkrc; if rc then put rc=; %mend;
%macro addln( line ); rc = py.appendSrcLine( &line ); %chkrc; %mend;
/* Input data for the test.*/
data tstinput; a = 8; b = 4; output; a = 10; b = 2; output;
run;
proc ds2;
ds2_options sas;
package testpkg /overwrite=yes;
dcl package pymas py();
dcl package logger logr('App.tk.MAS');
dcl varchar(67108864) character set utf8 pycode;
dcl int rc revision;
method testpkg( varchar(256) modulename,
varchar(256) pyfuncname );
%addln( '# The first Python function:' )
%addln( 'def domath1(a, b):' )
%addln( ' "Output: c, d"' )
%addln( ' c = a * b' )
%addln( ' d = a / b' )
%addln( ' return c, d' )
%addln( '' )
%addln( '# Here is the second function:' )
%addln( 'def domath2(a, b):' )
%addln( ' "Output: c, d"' )
%addln( ' c,d = domath1( a, b )' )
if rc then logr.log( 'E', 'py.appendSrcLine() failed.');
rc = py.appendSrcLine(' return c, d' );
pycode = py.getSource();
revision = py.publish( pycode, modulename );
if revision lt 1 then
logr.log( 'E', 'py.publish() failed.');
rc = py.useMethod( pyfuncname );
if rc then logr.log( 'E', 'py.useMethod() failed.');
end;
method usefunc( varchar(256) pyfuncname );
rc = py.useMethod( pyfuncname );
if rc then logr.log( 'E', 'py.useMethod() failed.');
end;
method exec( double a, double b, in_out int rc,
in_out double c, in_out double d );
rc = py.setDouble( 'a', a ); if rc then return;
rc = py.setDouble( 'b', b ); if rc then return;
rc = py.execute(); if rc then return;
c = py.getDouble( 'c' );
d = py.getDouble( 'd' );
end;
endpackage;
data _null_;
dcl package logger logr( 'App.tk.MAS' );
dcl package testpkg t( 'my Py Module Ctxt name', 'domath1' );
dcl int rc;
dcl double a b c d;
method run();
a = b = c = d = 0.0;
set tstinput;
t.exec( a, b, rc, c, d );
logr.log( 'I', '##### Results: a=$s b=$s c=$s d=$s',
a, b, c, d );
end;
method term();
t.usefunc( 'domath2' );
a = 6; b = 3;
t.exec( a, b, rc, c, d );
logr.log( 'I', '##### Results: a=$s b=$s c=$s d=$s',
a, b, c, d );
end;
enddata;
run;
quit;