{"id":7699,"library":"saspy","title":"SASPy (SAS Python Interface)","description":"SASPy is an open-source Python package that provides an interface to the SAS System, allowing Python programmers to leverage their licensed SAS infrastructure. It enables bi-directional data exchange between pandas DataFrames and SAS datasets, submission of SAS code, and access to SAS analytical capabilities like machine learning and econometrics. Currently at version 5.105.1, the library maintains an active release cadence with frequent updates addressing new features, enhancements, and bug fixes.","status":"active","version":"5.105.1","language":"en","source_language":"en","source_url":"https://github.com/sassoftware/saspy","tags":["SAS","data analytics","interoperability","data science","enterprise","dataframe","analytics"],"install":[{"cmd":"pip install saspy","lang":"bash","label":"PyPI"},{"cmd":"conda install -c conda-forge saspy","lang":"bash","label":"Conda-forge"}],"dependencies":[{"reason":"Extensive integration for data exchange with SAS datasets.","package":"pandas"},{"reason":"Required for IOM (Integrated Object Model) access method to connect to SAS.","package":"Java Development Kit (JDK)","optional":true},{"reason":"Required for Apache Arrow support and Arrow-based Parquet conversion (added in v5.105.0).","package":"pyarrow","optional":true}],"imports":[{"note":"While 'from saspy import SASsession' works, 'import saspy' is the more common and recommended pattern as SASPy's functionality is typically accessed via the top-level `saspy` object and its `SASsession` instance.","wrong":"from saspy import SASsession","symbol":"SASsession","correct":"import saspy\nsas = saspy.SASsession()"}],"quickstart":{"code":"import saspy\nimport pandas as pd\nimport os\n\n# NOTE: SASPy requires a configuration file (sascfg_personal.py) to define connection details.\n# This file is typically located in your Python site-packages/saspy directory or ~/.config/saspy/.\n# For example, using a 'winlocal' configuration (defined in sascfg_personal.py):\n# sas = saspy.SASsession(cfgname='winlocal')\n# If only one configuration is defined, or if running in an interactive environment that supports prompts:\nsas = saspy.SASsession()\n\nprint(f\"SAS Connection established: {sas.SASsessionid}\")\n\n# Example: Submit SAS code and get results\nresult = sas.submit(\"proc print data=sashelp.class(obs=5); run;\")\nprint(\"SAS Log:\\n\", result['LOG'])\nprint(\"SAS Listing:\\n\", result['LST'])\n\n# Example: Transfer a pandas DataFrame to SAS\ndata_df = pd.DataFrame({\n    'col1': [1, 2, 3],\n    'col2': ['A', 'B', 'C']\n})\n\nsas_data_obj = sas.dataframe2sasdata(data_df, 'WORK.mydata')\nprint(f\"DataFrame '{data_df.shape}' transferred to SAS library WORK as 'mydata'.\")\n\n# Example: Read SAS data back into a pandas DataFrame\nretrieved_df = sas.sasdata('mydata', libref='WORK').to_dataframe()\nprint(f\"Retrieved DataFrame head:\\n{retrieved_df.head()}\")\n\nsas.endsas()","lang":"python","description":"This quickstart demonstrates how to establish a connection to a SAS session, submit arbitrary SAS code, and exchange data between a pandas DataFrame and a SAS dataset. It highlights the importance of the `sascfg_personal.py` configuration file for defining SAS connection details."},"warnings":[{"fix":"Upgrade SASPy to version 5.104.1 or newer. If upgrading is not possible, ensure dataframes passed to `dataframe2sasdata` have `None` values converted to empty strings or other non-NaN representations.","message":"With Pandas 3.0.0, a change was made to store `None` as `NaN`, which caused `dataframe2sasdata` to throw exceptions. This was fixed in SASPy v5.104.1.","severity":"breaking","affected_versions":"pandas 3.0.0, saspy < 5.104.1"},{"fix":"Always copy `sascfg.py` to `sascfg_personal.py` and place your configurations in the `_personal` file. This file will not be overwritten by upgrades. The file can be located in your Python site-packages/saspy directory or in `~/.config/saspy/`.","message":"SASPy relies on `sascfg_personal.py` for connection configurations. If you modify the original `sascfg.py` instead of creating `sascfg_personal.py`, your configurations might be overwritten during a SASPy upgrade.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Avoid using `proc printto` in SAS code submitted via SASPy, or ensure `proc printto; run;` is used to revert log/listing redirection *before* any SASPy methods that require log access.","message":"Using `proc printto` in submitted SAS code to redirect the SAS Log or Listing can cause SASPy to hang, fail, or not return results, as SASPy parses the log for operational information.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Exercise caution with `ABORT` statements. If necessary, ensure they are handled within the SAS session logic to prevent termination if possible, or gracefully handle connection loss in Python.","message":"SAS `ABORT` statements (e.g., `%abort`, `data _null_; abort;`) can unexpectedly terminate the connected SAS session, breaking the SASPy connection and leading to further errors.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"Verify the `sascfg_personal.py` file exists and has correct connection parameters for your SAS environment. Ensure SAS is running and accessible from the Python client. For IOM, check Java installation and classpath. For SSH, verify SSH credentials and host reachability. Run the connection command manually (provided in the error message for some access methods) for more detailed diagnostics.","cause":"This is a general connection error, often due to incorrect or missing `sascfg_personal.py` configuration, unreachable SAS server, or issues with Java (for IOM) or SSH (for STDIO over SSH) settings.","error":"SAS Connection failed. No connection established. Double check your settings in sascfg_personal.py file."},{"fix":"Review the specific SASPy method call (e.g., `sasdata.sort()`) and its documentation. Ensure all required parameters and SAS dataset options are correctly passed. If using `submit()`, carefully check the SAS code for syntax errors or misplaced statements.","cause":"Often occurs when SAS-specific options (like `dsopts`) are expected by a SASPy method but not provided, or when a SAS statement is syntactically incorrect or out of context for the SAS session.","error":"RuntimeError: ERROR 180-322: Statement is not valid or it is used out of proper order."},{"fix":"Provide credentials using an `.authinfo` file (recommended for non-interactive environments) or by setting them in your `sascfg_personal.py` configuration, rather than relying on interactive prompts. Ensure the `.authinfo` file has appropriate permissions (e.g., 600 for SSH).","cause":"SASPy attempts to prompt for authentication credentials (e.g., username/password) in a non-interactive Python environment (like a script or some Jupyter setups) that cannot handle user input.","error":"StdinNotImplementedError: raw_input was called, but this frontend does not support input requests."},{"fix":"Ensure that the necessary encryption JAR files are present in your SASPy Java deployment. Refer to the SASPy configuration documentation (sassoftware.github.io/saspy/configuration.html) for specific instructions on obtaining and placing these JARs for your SAS version and access method.","cause":"This error is specific to IOM connections, particularly with SAS OnDemand for Academics (ODA) running SAS 9.4M7+, and indicates missing or outdated Java encryption JAR files required for the connection.","error":"We failed in getConnection An exception was thrown during the encryption key exchange."}]}