Hi
I'm making a connection to a remote SAS Workspace Server using IOM Bridge:
import win32com.client objFactory = win32com.client.Dispatch("SASObjectManager.ObjectFactoryMulti2") objServerDef = win32com.client.Dispatch("SASObjectManager.ServerDef") objServerDef.MachineDNSName = "servername" objServerDef.Port = 8591 # workspace server port objServerDef.Protocol = 2 # 2 = IOM protocol objServerDef.BridgeSecurityPackage = "Username/Password" objServerDef.ClassIdentifier = "workspace server id" objSAS = objFactory.CreateObjectByServer("SASApp", True, objServerDef, "uid", "pw") program = "ods listing;proc means data=sashelp.cars mean mode min max; run;" objSAS.LanguageService.Submit(program) _list = objSAS.LanguageService.FlushList(999999) print(_list) log = objSAS.LanguageService.FlushLog(999999) print(log) objSAS.Close()
It work fine. But I cant seem to find the right attribut for CreateObjectByServer, when trying with a Stored Process Server (when I change 'Port' and 'ClassIdentifier'):
import win32com.client objFactory = win32com.client.Dispatch("SASObjectManager.ObjectFactoryMulti2") objServerDef = win32com.client.Dispatch("SASObjectManager.ServerDef") objServerDef.MachineDNSName = "servername" objServerDef.Port = 8601 # stored process server port objServerDef.Protocol = 2 # 2 = IOM protocol objServerDef.BridgeSecurityPackage = "Username/Password" objServerDef.ClassIdentifier = "stp server id" objSAS = objFactory.CreateObjectByServer("SASApp", True, objServerDef, "uid", "pw") objSAS.StoredProcessService.Repository("path", "stp", "params") _list = objSAS.LanguageService.FlushList(999999) print(_list) log = objSAS.LanguageService.FlushLog(999999) print(log) objSAS.Close()
When trying the above I get:
AttributeError: CreateObjectByServer.StoredProcessService
I cant seem to find much documentation IOM to Stored Process Servers. Anyone got any suggestions?
Firstly, thanks @ChrisHemedinger for the call out! Probably wouldn't have come across this for some time otherwise.
Looks like you have seen my gist's about using win32com.client in Python to interact with SAS, adapted from examples shared by @ChrisHemedinger in Powershell.
https://gist.github.com/FriedEgg/9085229
Been quite a while since someone has ever brought up this topic.
@_what_ the biggest issue you are having is the objSAS is not the object type you are expecting... So, objSAS.StoredProcessService doesn't exist. Beyond that, Repository is a property, not a method. You need to use Execute method or ExecuteWithResults method in the StoredProcessService. Beyond that, things start to get specific to what your stored process does. A rudimentary example to correct what you are directly doing would be...
objSAS = objFactory.CreateObjectByServer("SASApp", True, objServerDef, "uid", "pw") objSAS.ServerWorkSpace.LanguageService.StoredProcessService.Repository = "path" objSAS.ServerWorkSpace.LanguageService.StoredProcessService.Execute("stp", "param=value") log = objSAS.ServerWorkSpace.LanguageService.FlushLog(999999) print(log) objSAS.ServerWorkSpace.Close()
However, I believe this is unlikely to be the method by which to get you what you want (which I do not know at this time)
The documentation is pretty rubbish, which you can blame @ChrisHemedinger for the most comprehensive source however would be the chm (Windows Help Files) included with SAS Integration Technologies Client. sas.chm, sasoman.chm and similar. StoredProcessService.chm includes .NET examples, some of which may involve items you go not license, however.
Editor's note: The SASPy project has been updated to support IOM via the Windows client (using win32). You can use the project as-is or examine the source to adapt for your own Python-to-SAS connection.
The way that you shared your code implies that the StoredProcess server ID in the ObjectServerDef varies. It doesn't -- but maybe you already know that. The StoredProcess class ID (you didn't list it) can be discovered in SAS with:
proc iomoperate;
list types;
quit;
Output:
SAS Stored Process Server Short type name : StoredProcess Class identifier : 15931e31-667f-11d5-8804-00c04f35ac8c
You might need to set the security package to "Negotiate". And depending on security settings, the Server name must match exactly with what's in metadata. You might try also setting the ObjectServerDef.Name and .LogicalName values, gleaning those from the metadata definition.
Any encryption set? You would also need to set the BridgeEncryptionLevel and BridgeEncryptionAlgorithm.
Finally, using the object you get back directly as a Workspace might be an issue. I know that in .NET we need to cast to a Workspace object, which has the effect of doing a QueryInterface to get the Workspace interface from the server object. Not sure what the equivalent is in Python or if it's needed.
I'm using SAS Integration Technologies Configuration Wizard to get the information needed. It is not possible to set the security package to "Negotiate" when I've selected Stored Process Server (only Username/Password).
I've included the following (couldn't get BridgeEncryptionLevel to work):
objServerDef.Name = "SASApp - Stored Process Server" objServerDef.LogicalName = "SASApp - Logical Stored Process Server" #objServerDef.BridgeEncryptionLevel = "Credentials" objServerDef.BridgeEncryptionAlgorithm = "SASProprietary"
As I understand your last statement, the problem is I can't use 'CreateObjectByServer', when using a Stored Process server. Maybe som Python wizard can help here.
There doesn't seem to be many Python programmers on here 🙂
I'll call out @FriedEgg who I know has some experience with this.
Also, SAS does offer an official integration from Python to SAS called SASPy. This allows you to connect to a SAS session, run code, exchange data with pandas, and more. However, it does not offer integration with a Stored Process server or other parts of the SAS infrastructure.
Sounds great. Thank you.
I know about SASPy, but as you point out, I can't use it for STP Server.
Firstly, thanks @ChrisHemedinger for the call out! Probably wouldn't have come across this for some time otherwise.
Looks like you have seen my gist's about using win32com.client in Python to interact with SAS, adapted from examples shared by @ChrisHemedinger in Powershell.
https://gist.github.com/FriedEgg/9085229
Been quite a while since someone has ever brought up this topic.
@_what_ the biggest issue you are having is the objSAS is not the object type you are expecting... So, objSAS.StoredProcessService doesn't exist. Beyond that, Repository is a property, not a method. You need to use Execute method or ExecuteWithResults method in the StoredProcessService. Beyond that, things start to get specific to what your stored process does. A rudimentary example to correct what you are directly doing would be...
objSAS = objFactory.CreateObjectByServer("SASApp", True, objServerDef, "uid", "pw") objSAS.ServerWorkSpace.LanguageService.StoredProcessService.Repository = "path" objSAS.ServerWorkSpace.LanguageService.StoredProcessService.Execute("stp", "param=value") log = objSAS.ServerWorkSpace.LanguageService.FlushLog(999999) print(log) objSAS.ServerWorkSpace.Close()
However, I believe this is unlikely to be the method by which to get you what you want (which I do not know at this time)
The documentation is pretty rubbish, which you can blame @ChrisHemedinger for the most comprehensive source however would be the chm (Windows Help Files) included with SAS Integration Technologies Client. sas.chm, sasoman.chm and similar. StoredProcessService.chm includes .NET examples, some of which may involve items you go not license, however.
Editor's note: The SASPy project has been updated to support IOM via the Windows client (using win32). You can use the project as-is or examine the source to adapt for your own Python-to-SAS connection.
Thanks @FriedEgg.
That worked for 1 execution. The second time I run the program I get an exception.
<Exception><SASMessage severity="Error">The outcall request initiated on the bridge protocol engine listen thread. This request cannot proceed due to possible server deadlock.</SASMessage></Exception>
And the I can't run stored processes (STP: The STP MVA scope for context cannot be accessed.) and I need to restart SAS. Do you have an idea what the problem is?
Thanks for chiming in @FriedEgg. The StoredProcessService.chm does have good documentation about a .NET library that provides a layer of abstraction on this function. However, it's not a COM library (like you're using from Python). Not sure what it would take to use this .NET library from Python.
Another approach to accomplishing your goal might be PROC STP. Just use your already-working SAS Workspace instance to run PROC STP and create a package for output, which you can then download if needed.
Thanks for your suggestion @ChrisHemedinger.
My intention was to e.g. use this method execute code and get the output data from the SAS Platform to a Python application. And since the Stored Process Server is always 'active', I assume it is preferred and will react fast to requests.
This could also be accomplished by using the SAS Stored Process Web Application and webout, but that seems like an extra step. I imagine the IOM method has better performance.
@_what_, I highly recommend abandoning your current thoughts in favor of far simpler implementations. Stored Processes can be easily interacted with from Python as web services. IOM isn't going to provide a significant lift in performance, especially when you aren't interacting with it through a native client (read Java or .NET).
If you are intent on utilizing IOM from Python and your goal is not to use existing stored procedures, then I'd recommend ignoring that self-imposed requirement and use a Workspace Server, or Pooled Workspace Server if the spin-up cost you seem to be worried about really if a problem.
In this way, you could use SASPy, which doesn't use pywin32 and is thus more portable, officially supported, etc...
That being said, I have a gist showing how to use a Workspace Server (or Pooled ...) to run SAS code, producing html5 results and streaming those results to Python using the SAS Com Object IOM client and pywin32 instead of the Java backend that SASPy employs.
https://gist.github.com/FriedEgg/7dce842d09087f62e4ba04d4667c4ebc
Yeah, you're probably right. Still, would be nice to get it to work.
I'll accept your first answer as the solution. It did work, even though it created a deadlock 🙂
Thank you both for your help @ChrisHemedinger @FriedEgg
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.