Publié le :
Administration CREATION_INTERNE

Exécution de code Python via SAS

Ce code est également disponible en : Français
En attente de validation
Attention : Ce code nécessite des droits administrateur.
Cette macro est conçue pour faciliter l'intégration de scripts Python dans un environnement SAS©, notamment SAS© Viya 4 et SAS© Studio. Elle prend une chaîne de commandes Python (`pgm`), les écrit dans un fichier temporaire (.py) situé dans le répertoire de travail SAS©, puis exécute ce script Python en appelant l'interpréteur Python via une commande système (`filename pipe`). Les sorties standard (`stdout`) et d'erreur (`stderr`) du script Python sont redirigées vers des fichiers temporaires dédiés, qui sont ensuite affichés dans le log SAS© pour permettre un suivi et un débogage. De plus, si un nom de variable macro est fourni au paramètre `return`, la macro tente de lire la dernière ligne du presse-papiers (où le script Python est supposé avoir placé sa sortie) et d'affecter cette valeur à la variable macro SAS© spécifiée avec une portée globale.
Analyse des données

Type : CREATION_INTERNE


La macro crée des fichiers temporaires (`py_pgm.py`, `stderr.txt`, `stdout.txt`) dans le répertoire de travail SAS (`WORK`) pour stocker le code Python à exécuter, ainsi que les sorties standard et d'erreur de son exécution. Elle utilise également le presse-papiers (`CLIPBRD`) comme mécanisme de communication pour récupérer une valeur de retour du script Python. La macro elle-même ne lit pas de données SASHELP ni de données externes pour son propre fonctionnement, mais elle agit comme un pont pour le code Python qui, lui, pourrait potentiellement interagir avec des données SAS ou externes. Le chemin de l'exécutable Python ('d:\Python310\python.exe') est codé en dur.

1 Bloc de code
MACRO CALL
Explication :
Ce bloc utilise la macro `%utlfkil` pour supprimer les fichiers temporaires (`py_pgm.py`, `stderr.txt`, `stdout.txt`) générés lors des exécutions antérieures. Cela garantit un état propre pour chaque nouvelle exécution du script Python, évitant ainsi l'utilisation de résultats ou de fichiers obsolètes.
Copié !
1* delete temporary files;
2%utlfkil(%sysfunc(pathname(work))/py_pgm.py);
3%utlfkil(%sysfunc(pathname(work))/stderr.txt);
4%utlfkil(%sysfunc(pathname(work))/stdout.txt);
2 Bloc de code
DATA STEP
Explication :
Ce bloc initialise le presse-papiers (clipboard) en y écrivant un caractère espace. Ceci est une étape préparatoire pour la récupération optionnelle d'une valeur de retour du script Python via le presse-papiers, s'assurant que le presse-papiers est 'vide' avant que le script Python n'y écrive sa propre sortie.
Copié !
1 /* clear clipboard */
2 filename _clp clipbrd;
3 DATA _null_;
4 file _clp;
5 put " ";
6 RUN;QUIT;
3 Bloc de code
DATA STEP Data
Explication :
Ce bloc crée le fichier Python temporaire nommé `py_pgm.py` dans le répertoire de travail SAS. Il prend la chaîne de commandes Python passée au paramètre `pgm` de la macro, la résout, puis la divise en commandes individuelles en se basant sur le point-virgule comme délimiteur. Chaque commande est ensuite écrite ligne par ligne dans le fichier `py_pgm.py`. Une logique est incluse pour nettoyer les commandes qui commencent par ". " (point-espace).
Copié !
1 filename py_pgm "%sysfunc(pathname(work))/py_pgm.py" lrecl=32766 recfm=v;
2 DATA _null_;
3 LENGTH pgm $32755 cmd $1024;
4 file py_pgm ;
5 pgm=resolve(&pgm);
6 semi=countc(pgm,";");
7 DO idx=1 to semi;
8 cmd=cats(scan(pgm,idx,";"));
9 IF cmd=:". " THEN
10 cmd=trim(substr(cmd,2));
11 put cmd $char384.;
12 putlog cmd ;
13 END;
14 RUN;QUIT;
4 Bloc de code
FILENAME PIPE / DATA STEP
Explication :
Ce bloc est responsable de l'exécution du script Python. Il définit des variables macro pour le chemin complet du script Python généré (`_loc`), et les chemins des fichiers pour la sortie d'erreur (`_stderr`) et la sortie standard (`_stdout`) du script Python. La déclaration `filename rut pipe` est utilisée pour exécuter l'interpréteur Python (`d:\Python310\python.exe`) avec le script temporaire (`&_loc`). La sortie standard du processus Python est lue via le fileref `rut` et affichée dans le log SAS, tandis que la sortie d'erreur est redirigée vers le fichier `_stderr`. Après l'exécution, les filerefs `rut` et `py_pgm` sont libérés.
Copié !
1 %let _loc=%sysfunc(pathname(py_pgm));
2 %let _stderr=%sysfunc(pathname(work))/stderr.txt;
3 %let _stdout=%sysfunc(pathname(work))/stdout.txt;
4 filename rut pipe "d:\Python310\python.exe &_loc 2> &_stderr";
5 DATA _null_;
6 file PRINT;
7 INFILE rut;
8 INPUT;
9 put _infile_;
10 RUN;
11 filename rut clear;
12 filename py_pgm clear;
5 Bloc de code
DATA STEP
Explication :
Ce bloc lit le contenu du fichier `stderr.txt`, qui contient toutes les erreurs générées par l'exécution du script Python. Le contenu est ensuite affiché dans le log SAS, permettant à l'utilisateur de diagnostiquer les problèmes du script Python.
Copié !
1 DATA _null_;
2 file PRINT;
3 INFILE "%sysfunc(pathname(work))/stderr.txt";
4 INPUT;
5 put _infile_;
6 RUN;
6 Bloc de code
FILENAME CLEAR
Explication :
Ce bloc efface explicitement les filerefs `rut` et `py_pgm`. Bien qu'ils aient été libérés plus tôt, cette répétition assure qu'ils sont bien fermés et libérés, même en cas d'erreurs ou de flux d'exécution anormaux dans les étapes précédentes.
Copié !
1 filename rut clear;
2 filename py_pgm clear;
7 Bloc de code
DATA STEP / MACRO CALL
Explication :
Ce bloc conditionnel s'exécute uniquement si le paramètre `return` de la macro a été fourni. Il définit un fileref `clp` pour interagir avec le presse-papiers du système. Il lit la dernière ligne du presse-papiers (assumant que le script Python y a écrit la valeur de retour souhaitée) et utilise `call symputx` pour assigner cette valeur à la variable macro spécifiée par l'utilisateur (`&return`) avec une portée globale ('G'). La valeur lue est également affichée dans le log SAS à des fins de débogage.
Copié !
1 * use the clipboard to create macro variable;
2 %IF "&return" ^= "" %THEN %DO;
3 filename clp clipbrd ;
4 DATA _null_;
5 INFILE clp;
6 INPUT;
7 putlog "******* " _infile_;
8 call symputx("&return",_infile_,"G");
9 RUN;QUIT;
10 %END;
Ce matériel est fourni "tel quel" par We Are Cas. Il n'y a aucune garantie, expresse ou implicite, quant à la qualité marchande ou à l'adéquation à un usage particulier concernant le matériel ou le code contenu dans les présentes. We Are Cas n'est pas responsable des erreurs dans ce matériel tel qu'il existe maintenant ou existera, et We Are Cas ne fournit pas de support technique pour celui-ci.
Banner
Le Conseil de l'Expert
Expert
Michael
Responsable de l'infrastructure Viya.
« L'intégration de Python au sein de workflows SAS est devenue une nécessité pour les data scientists souhaitant combiner la puissance du moteur de données SAS avec la richesse de l'écosystème open-source. Ce script illustre une méthode d'exécution "par tube" (PIPE), permettant de piloter un interpréteur Python externe tout en conservant une traçabilité complète dans le journal SAS. »