I've seemingly read through all the threads and documentation with no avail.
I'd like to send a csv from one non-SAS server to a SAS server through a stored process which will return some output. This appears to be trivial to do when using non-file parameters, but impossible when using a csv.
For instance, assuming a python non-SAS backend, using the requests library I logon and then call the testprint_sp stored process.
base_url = "https://mybaseurl" login_url = base_url + "/SASLogon/login" s = requests.Session() r = s.get(login_url, verify=False) data = {"username": "uname", "password":"pwd123"} r = s.post(login_url, data=data) execute_url = base_url + "/SASStoredProcess/do?_program=/User Folders/my folder/testprint_sp" data = {'num':20} r = s.post(execute_url, data=data)
Or after logging on, simply browsing to
https://mybaseurl/SASStoredProcess/do?_program=/User Folders/my folder/testprint_sp&num=20
This is great but it fails when I try to send a csv.
filename = "D:/Documents/testfile.csv" files = {'file': ('myfile', open(filename, 'rb'))} r = s.post(execute_url, data=data, files=files)
All of the _WEBIN_% macro variables are missing.
Now, there is a workaround which is to build an html form within a sas stored process.
<form action="StoredProcessWebApplicationURL" method="post" enctype="multipart/form-data"> <input type="hidden" name="_program" value="/Path/StoredProcessName"> <table border="0" cellpadding="5"> <tr> <th>Choose a file to upload:</th> <td><input type="file" name="myfile"></td> </tr> <tr> <td colspan="2" align="center"><input type="submit" value="OK"></td> </tr> </table>
But this adds the extra step of having a client using the form and browsing to a specific file. I'd like the data to be automatically sent to SAS without having an html form built in a SAS procedure.
Any help is greatly appreciated.
Ted,
Are you sure you're setting the headers properly in your POST request from Python? The Content Type needs to be set to multipart/form-data.
http://stackoverflow.com/questions/68477/send-file-using-post-from-a-python-script
has an example where the header is set correctly in Python. It also suggests the 'poster' library which seems pretty nifty, rather than doing it all manually.
If you submit a form with an upload component from the browser, as per the STP form with input type "file", I think the browser automatically sets the header of Content-type: multipart/form-data. This is how SAS will know that you're uploading a file as part of the post request. Otherwise, the default content type in the header for a POST is set to application/x-www-form-encoded (I think).
As per top answer from http://stackoverflow.com/questions/4526273/what-does-enctype-multipart-form-data-mean:
When you make a POST request, you have to encode the data that forms the body of the request in some way.
HTML forms provide three methods of encoding.
application/x-www-form-urlencoded
(the default)multipart/form-data
text/plain
Work was being done on adding application/json
, but that has been abandoned.
The specifics of the formats don't matter to most developers. The important points are:
When you are writing client-side code, all you need to know is use multipart/form-data
when your form includes any <input type="file">
elements.
When you are writing server-side code: Use a prewritten form handling library (e.g. Perl's CGI->param
or the one exposed by PHP's $_POST
superglobal) and it will take care of the differences for you. Don't bother trying to parse the raw input received by the server.
Never use text/plain
.
Hope this helps.
Nik
Join us for SAS Innovate 2025, our biggest and most exciting global event of the year, in Orlando, FL, from May 6-9. Sign up by March 14 for just $795.
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.