Бывают случаи, когда при работе sas-кода необходимо выполнение действия, которое сам sas делает неэффективно (медленно, требует слишком много кода), например, сложные запросы в БД или работу с файловой системой.

Сложные запросы в БД можно оптимизировать с использованием SAS SQL Pass-Through, для работы с файловой системой можно использовать системные команды ОС или вызвать исполнение скрипта на другом языке программирования.

В данной статье будет рассмотрен пример исполнения py-кода внутри SAS–скрипта для Windows.

Вызов py-кода возможен с использованием команд SYSTASK и X, которые исполняют системные команды ОС.

1. Конструкция X

Синтаксис: X <'command'>;

Позволяет исполнять команды командной строки (CMD) или запускать Windows-приложения. Дополнительных опций данная конструкция не предусматривает.

Пример вызова:

options noxwait;

%let py_script_path = C:\python_scripts\; /*папка со скриптами*/

%let py_path = C:\Python34\python.exe; /*исполняемый файл Python*/

    x "&py_path &py_script_path\py_example.py";

В данном случае откроется сессия командной строки, в которой будет выполняться вызов py-скрипта.

Для удобства путь к исполняемому файлу Python и к папке со скриптами вынесены в макро-переменные.

! Все пути к файлам и папкам в SAS-коде должен указываться для той машины, на которой установлен SAS-сервер (или в расшаренной папке, к которой есть доступ с сервера), не для клиента.

Если путь к Python добавлен в переменную среды PATH, то команду можно сократить до:

x "python &py_script_path\py_example.py";

Глобальная опция NOXWAIT позволяет при завершении работы команд конструкции X выходить из командной строки автоматически. По умолчанию используется опция XWAIT, в этом случае после исполнения команд командную строку нужно явно закрывать, используя EXIT.

Важным ограничением конструкции X является невозможность редиректа stdout и, следовательно, логирования исполнения команд командной строки.

То есть, в примере ниже:

x "&py_path &py_script_path\py_example.py > &log_path";

скрипт будет исполнен, но редиректа лога не произойдет.

Поэтому если нужен лог файла, то стоит указать редирект внутри py-кода.

Например,

import sys
log_path =
r'C:\logs\py_result.log'
with open(log_path, 'w+') as f:
sys.stdout = f

Еще одним ограничением команды является отсутствие какого-либо статуса выполнения (или кода ошибки), который бы передавался из командной строки обратно в текущую SAS-сессию.

Таким образом, отсутствует обратная связь между результатом работы команд командной строки и SAS-сессией, в которой эта строка была вызвана.

Вместо конструкции X можно использовать так же макро команду %SYSEXEC в открытом коде или CALL SYSTEM в шаге Data . Они работают схожим образом, и так же закрывают командную строку или нет в зависимости от опции NOXWAIT / XWAIT соответственно.


 2. Конструкция SYSTASK COMMAND

Данная конструкция, так же как X, выполняет команды операционной среды, но делает это в фоне в виде асинхронных задач, поэтому нет необходимости закрывать окно командной строки используя EXIT.

Так же как и в конструкции X, SYSTASK COMMAND не показывает стандартный вывод и не может сделать его редирект. Если нужно сохранить лог выполнения py -скрипта, то нужно сделать перенаправление stdout внутри py -кода.

Синтаксис SYSTASK COMMAND, в отличие от X, включает набор опций, которые позволяют управлять исполняемыми в фоне задачами, в частности, именовать их, отображать их список, принудительно закрывать и  отображать статус выполнения задачи. Именно статус выполнения задачи позволяет управлять исключениями, которые могли возникнуть при выполнении команды командной строки.

Например,

%let py_script_path = C:\python_scripts\; /*папка со скриптами*/

%let py_path = C:\Python34\python.exe; /*исполняемый файл Python*/

systask command "&py_path &py_script_path\py_example.py" status=py_status wait;

%put status = &py_status;

В данном случае статус выполнения py-скрипта будет сохраняться в макро-переменную &py_status, которая равна 0, если скрипт выполнен без ошибок, и отлична от 0, если скрипт отработал некорректно.

Опция WAIT указывает, что команда выполняется синхронно, то есть SAS-сессия ждет завершение исполнения кода и только после этого продолжает работу.

По умолчанию используется опция NOWAIT, то есть все команды работают в асинхронном режиме в фоне текущей SAS-сессии.

При помощи опций LIST и KILL конструкции SYSTASK COMMAND можно вывести список всех действующих задач и принудительно остановить их выполнение.

Если последующий этап SAS -сессии нужно начинать только после завершения этих зада, то можно воспользоваться конструкцией WAITFOR

Пример :

systask command "&py_path &py_script_path\py_example1.py" taskname=py1;

systask command "&py_path &py_script_path\py_example2.py" taskname=py2;

systask command "&py_path &py_script_path\py_example3.py" taskname=py3;

waitfor _all_ py1 py2 py3;

В данном случае параллельно (точнее асинхронно, так как по умолчанию работает опция NOWAIT) запускается 3 py-скрипта, и затем SAS-сессия ждет, когда все эти скрипты отработают. Для конструкции WAITFOR нужно указывать названия задач, которые ждет сессия, поэтому в SYSTASK COMMAND с помощью опции TASKNAME указаны названия для этих задач.

Результат работы WAITFOR сохраняется в системную макро-переменную &SYSRC.

В обоих случаях вызов Python осуществляется через командную строку Windows, но SYASTASK COMMAND обладает большими возможностями для управления данной задачей.

Так же вариантом использования Python может являться создание веб-сервиса на Python и обращение к нему в SAS-сессии со стороны клиента, но это тема для отдельной статьи :)