diff --git a/saspy/doc/source/adding-procedures.rst b/saspy/doc/source/adding-procedures.rst index f9dcf068..bf5a2edb 100644 --- a/saspy/doc/source/adding-procedures.rst +++ b/saspy/doc/source/adding-procedures.rst @@ -2,12 +2,12 @@ .. Copyright SAS Institute -************************ +======================== Contributing new methods -************************ +======================== Overview --------- +======== This module is broken into product areas that largely follow the SAS product areas. There are many many procedures, which translate to object methods, that are not currently included in the package. The aim of this document is to outline the @@ -21,7 +21,7 @@ minutes for subsequent methods. Your contribution and feedback is greatly appreciated! Process -======= +~~~~~~~ To add a new procedure follow these steps: diff --git a/saspy/doc/source/advanced-topics.rst b/saspy/doc/source/advanced-topics.rst index 772324a0..bae0cfc6 100644 --- a/saspy/doc/source/advanced-topics.rst +++ b/saspy/doc/source/advanced-topics.rst @@ -11,9 +11,8 @@ Advanced topics In this chapter we will explore more detailed explanations of specific functionality. -**************** Using Batch mode -**************** +================ Batch mode is meant to be used when you want to automate your code as Python scripts. @@ -64,9 +63,8 @@ than this few lines of code, you can have the results updated and refreshed by j re-running the script. -********* Prompting -********* +========= There are two types of prompting that can be performed; meaning to stop processing and prompt the user for input and then resume processing. @@ -188,9 +186,8 @@ at runtime for values you want to use in the code, and those values can be kept around and used later in the code, or hidden and inaccessible afterward. -*************************************************************** Moving values between Python Variables and SAS Macro Variables -*************************************************************** +============================================================== There are two methods on the SASsession object you can use to transfer values between Python and SAS. symget() and symput(). To get a value from a SAS Macro Variable and assign it to a Python variable you @@ -213,9 +210,8 @@ https://github.com/sassoftware/saspy-examples/blob/main/SAS_contrib/Using_SYMGET -******************************************************** Moving data between Python and SAS - datatype conversion -******************************************************** +======================================================== SASPy has methods to load data from a SAS Data Set (or View) into Python as a Pandas dataframe, as well as the reverse; loading a dataframe into a SAS Data Set. This is all documented in the API doc and some @@ -265,9 +261,8 @@ become missing values in SAS. -********************************** Dates, Times and Datetimes, Oh my! -********************************** +================================== The sd2df and df2sd methods transfer data between SAS Data Sets and Pandas dataframes. For most cases, if you start with a SAS dataset and import it to a dataframe, then send it back to SAS, @@ -362,9 +357,8 @@ https://github.com/sassoftware/saspy-examples/blob/main/Issue_examples/Issue279. -*********************************** Advanced sd2df and df2sd techniques -*********************************** +=================================== The sd2df and df2sd methods transfer data between SAS Data Sets and Pandas dataframes. For most cases, you don't need to specify extra options. But, there are extra options to cover a variety of specific @@ -492,9 +486,8 @@ https://github.com/sassoftware/saspy/issues/279 to see where this fuctionality c -****************************************************************************** Slow performance loading SAS data into a Pandas DataFrame ( to_df(), sd2df() ) -****************************************************************************** +============================================================================== UPDATE!!! @@ -538,9 +531,8 @@ and newlines, which Pandas can have parsing problem with reading CSV file create -***************************************************************** Slow performance loading a DataFrame into a SAS data set; df2sd() -***************************************************************** +================================================================= df2sd (dataframe2sasdata) has two main steps, which were both done internal to the method. The second is transferring the data but the first is figureing out the necessary metadata to be able to correctly define the SAS Data Set being created. This requires @@ -686,9 +678,8 @@ Here are a few example cases showing this. -***************************************************************************** Using Proc Iomoperate to find Object Spawner hosts and Workspace Server ports -***************************************************************************** +============================================================================= If you already use a client to connect to IOM servers, you may have the host and port to OMR (the SAS Metadata Server), but not necessarily those of the Object Spawners or Workspace Servers. @@ -782,9 +773,8 @@ convention for these is to use the 'Server context :' value as the config name. to know which server you will be connecting to. -************************************************************** Disconnecting from an IOM session and reconnecting back to it. -************************************************************** +============================================================== The IOM access method has the ability to disconnect from the workspace server and reconnect to it (the same one); IF the reconnect setting is configured for that workspace @@ -818,9 +808,8 @@ a single process, and each time a disconnect happens a new toke is created. But, specific case, so it is now available. -******************************************************************* Configuring Grid Option Sets to have saspy run on a specific Queue. -******************************************************************* +=================================================================== Working with Grid Options Sets is documented here (the 'Doc' referred to below): http://support.sas.com/documentation/cdl/en/gridref/67371/HTML/default/viewer.htm#n1inymfs0b7go2n147xdknz0ygpx.htm @@ -847,9 +836,8 @@ in to the grid options mapping wizard (the first part of the document referenced should now be available to choose and you can set this up as you want. -**************************************************************** Automatic checking for ERROR: in the LOG and the warnings module -**************************************************************** +================================================================ Based upon an enhancement request, as of version 3.6.7, SASPy now checks for 'ERROR:' and issues a message via the warnings module to inform you that you should take a look at the log and see if there was a problem. SASPy methods won't blindly fail just by finding @@ -964,9 +952,8 @@ Hopefully you will find this enhancement useful. It would be great if each thing not the case. So, checking the log is something that's necessary sometimes. Hopefully this warning when an ERROR is seen, will make this easier. -********************************************* saspy.logger from logging.logger as of V3.7.5 -********************************************* +============================================= Per a user request to get rid of using print() for variaous messages, and use the logging facility instead, I've replaced all non-interactive prints() in saspy (print is still used for prompting, as it needs to be) with @@ -1100,9 +1087,8 @@ Here's just a little example of a programm showing some of this. -*************************************************** SASsession object as a context manager as of V3.7.5 -*************************************************** +=================================================== A user contributed, via PR #401, the ability for a SASsession object to be used as a context manage for the 'with' statement (see https://docs.python.org/3.9/reference/datamodel.html#context-managers). @@ -1177,9 +1163,9 @@ Here's a live example showing that the Session was terminated after the with con >>> -************** Jupyter magics -************** +============== + Jupyter Notebooks have what they call Magics, which let you submit code from a diferent language than the kernel of the notebook, or provide other functionality. SASPy supports a few magics that you can use if you are in a Jupyter Notebook. They simply allow you to submit explicit SAS code diff --git a/saspy/doc/source/api.rst b/saspy/doc/source/api.rst index e1cd5530..694e4dfc 100644 --- a/saspy/doc/source/api.rst +++ b/saspy/doc/source/api.rst @@ -2,9 +2,9 @@ .. Copyright SAS Institute -************* +============= API Reference -************* +============= .. automodule:: saspy :members: @@ -13,30 +13,27 @@ API Reference :show-inheritance: SAS Session Object ------------------- -.. autoclass:: SASsession +================== +.. autoclass:: saspy.sasbase.SASsession :members: SAS Data Object ---------------- - +=============== .. autoclass:: saspy.sasdata.SASdata :members: Procedure Syntax Statements ---------------------------- - +=========================== .. autoclass:: saspy.sasproccommons.SASProcCommons :members: - SAS Results ------------ +=========== .. autoclass:: saspy.sasresults.SASresults :members: SAS Procedures --------------- +============== Utility ~~~~~~~ @@ -51,7 +48,6 @@ Machine Learning (SAS Enterprise Miner) .. autoclass:: saspy.sasml.SASml :members: -.. autosummary:: saspy.sasml.SASml Statistics ~~~~~~~~~~ @@ -80,7 +76,7 @@ SAS Viya VDMML SASPy Scripts -------------- +============= run_sas.py ~~~~~~~~~~ diff --git a/saspy/doc/source/conf.py b/saspy/doc/source/conf.py index a67fe999..ad123cbc 100644 --- a/saspy/doc/source/conf.py +++ b/saspy/doc/source/conf.py @@ -50,11 +50,13 @@ autodoc_default_flags = ['show-inheritance'] autoclass_content = 'class' -intersphinx_mapping = {'python': ('https://docs.python.org/', None), - 'pandas': ('http://pandas.pydata.org/pandas-docs/stable/', None), - 'numpy': ('http://docs.scipy.org/doc/numpy/', None), - 'scipy': ('http://docs.scipy.org/doc/scipy/reference/', None), - 'matplotlib': ('http://matplotlib.sourceforge.net/', None)} +intersphinx_mapping = {'python': ('https://docs.python.org/3', None), + 'pandas': ('https://pandas.pydata.org/pandas-docs/stable/', None), + 'numpy': ('https://docs.scipy.org/doc/numpy/', None), + 'scipy': ('https://docs.scipy.org/doc/scipy/reference/', None), +# 'matplotlib': ('https://matplotlib.sourceforge.net/', None) + } + # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -151,7 +153,12 @@ html_theme_options = { # Toc options 'collapse_navigation': False, + 'sticky_navigation': True, 'navigation_depth': 5, + 'includehidden': True, + 'titles_only': False, + 'globaltoc_maxdepth' : 5, + } @@ -327,4 +334,4 @@ # Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'https://docs.python.org/': None} +#intersphinx_mapping = {'https://docs.python.org/3': None} diff --git a/saspy/doc/source/configuration.rst b/saspy/doc/source/configuration.rst index d56ada23..5190a36a 100644 --- a/saspy/doc/source/configuration.rst +++ b/saspy/doc/source/configuration.rst @@ -1,7 +1,7 @@ -=============== +============= Configuration -=============== +============= This module can connect and start different kinds of SAS sessions. It can connect to SAS on Unix, Mainframe, and Windows. It can connect to a local SAS session or remote session. diff --git a/saspy/doc/source/getting-started.rst b/saspy/doc/source/getting-started.rst index 9e24e7f2..085ea61b 100644 --- a/saspy/doc/source/getting-started.rst +++ b/saspy/doc/source/getting-started.rst @@ -3,26 +3,26 @@ .. currentmodule:: saspy -*************** +=============== Getting started -*************** +=============== -This is an interface module to the SAS System. It connects to SAS 9.4 -(released July 2013) or newer and enables Python programmers to take +This is an interface module to the SAS System. It connects to SAS 9.4 +(released July 2013) or newer and enables Python programmers to take advantage of their licensed SAS infrastructure through Python 3.x. -The interface is designed to enable programmers to use Python +The interface is designed to enable programmers to use Python syntax and constructs to interact with SAS. The interface makes SAS the analytical engine--or "calculator" for data analysis. In its most simple -form, it is a code translator that accepts Python commands and +form, it is a code translator that accepts Python commands and converts them into SAS language statements. The statements are run, and then the results are returned to Python to be displayed or accessed. -This is an open source project. Your contributions are appreciated +This is an open source project. Your contributions are appreciated and encouraged. Please open issues in gitlab for problems that you see! The rest of this section demonstrates how to use this module with a simple example. -The example uses `Kaggle Resources Analytics +The example uses `Kaggle Resources Analytics `_ data. We now have a saspy-examples gityhub repo: @@ -36,7 +36,7 @@ as it walks you through the various capabilities of saspy. You can even download then upload it into your Jupyter and run it. It uses SASHELP tables, so it should run on your system already. You can edit it and play around with it directly on your system. The direct link to it is: https://github.com/sassoftware/saspy-examples/blob/main/SAS_contrib/saspy_example_github.ipynb - + Initial import ============== @@ -51,18 +51,18 @@ If you have not, refer to that section for more information. Start a SAS session =================== -In the following code we start a SAS session named ``sas`` using the default +In the following code we start a SAS session named ``sas`` using the default configuration. Each SAS session is a connection to a separate SAS instance. -The cfgname parameter specifies the configuration definition (in sascfg_personal.py) +The cfgname parameter specifies the configuration definition (in sascfg_personal.py) to use for the connection to SAS. -If sascfg_personal.py has only one connection definition, then you do not need to +If sascfg_personal.py has only one connection definition, then you do not need to specify the cfgname parameter. If the file has more than one connection -definition and you do not specify the one to use with cfgname, you are -prompted for the connection to use. +definition and you do not specify the one to use with cfgname, you are +prompted for the connection to use. -After a connection is made and a SAS session is started, a note that is +After a connection is made and a SAS session is started, a note that is similar to the the one below is displayed. .. code-block:: ipython3 @@ -77,7 +77,7 @@ similar to the the one below is displayed. Any of the keys in the configuration definition can be supplied as parameters on the SASsession() method. This allows you to change these values at run time, -without having to edit the configuration file. However, whether you are allowed +without having to edit the configuration file. However, whether you are allowed to override keys that are defined in the config def, is controlled by one of the configuration options (also in the sascfg[_personal].py); lock_down. If lock_down is True, the only keys you can supply as parameters on SASsession() are ones that @@ -97,21 +97,21 @@ override things at run time: } - sas = saspy.SASsession(cfgname='ssh', + sas = saspy.SASsession(cfgname='ssh', options=["-fullstimer", "-autoexec", "/home/my.autoexec.sas"], host="'other.host.with.sas") Load data into SAS ================== -Data can be loaded easily from many sources. The following examples show +Data can be loaded easily from many sources. The following examples show the most common methods. In each case, ``hr`` is a SASdata object that represents a SAS data set. CSV ---- -In the following example, the CSV file is accessible to Python. The +~~~ +In the following example, the CSV file is accessible to Python. The ``sas`` object reads the CSV file and creates a SAS data set in the SAS session. @@ -121,7 +121,7 @@ SAS session. Pandas DataFrame ----------------- +~~~~~~~~~~~~~~~~ In the following example, the CSV file is accessible to Python. First, the CSV file is read into a data frame. Then the ``sas`` object reads the data frame and creates a SAS data set in the SAS session. @@ -129,20 +129,20 @@ reads the data frame and creates a SAS data set in the SAS session. .. code-block:: ipython3 hr_pd = pd.read_csv("./HR_comma_sep.csv") - hr = sas.df2sd(hr_pd) # the short form of: hr = sas.dataframe2sasdata(hr_pd) + hr = sas.df2sd(hr_pd) # the short form of: hr = sas.dataframe2sasdata(hr_pd) Existing SAS data set ---------------------- +~~~~~~~~~~~~~~~~~~~~~ In the following example, no data file is accessible to Python. An existing SAS data set that is accessible to the SAS session is associated with the ``hr`` object. .. code-block:: ipython3 - hr = sas.sasdata('hr', 'mylibref') + hr = sas.sasdata('hr', 'mylibref') - # or simply: hr = sas.sasdata('hr') + # or simply: hr = sas.sasdata('hr') # ...if hr.sas7bdat is in your 'work' or 'user' library Explore the data @@ -152,38 +152,38 @@ The following examples show common methods. See the :doc:`api` for a complete list. List the variables ------------------- +~~~~~~~~~~~~~~~~~~ .. code-block:: ipython3 hr.columnInfo() See the first observations --------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: ipython3 hr.head() Summary of numeric columns --------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: ipython3 hr.means() Basic bar chart ---------------- +~~~~~~~~~~~~~~~ .. code-block:: ipython3 hr.bar('salary') Basic histogram ---------------- +~~~~~~~~~~~~~~~ .. code-block:: ipython3 hr.hist('last_evaluation') Basic heatmap -------------- +~~~~~~~~~~~~~ .. code-block:: ipython3 hr.heatmap('last_evaluation', 'satisfaction_level') @@ -191,6 +191,7 @@ Basic heatmap Submit SAS code directly from Python session ============================================ + The proceeding examples demonstrate commonly used Python methods that are available with this module. @@ -220,10 +221,11 @@ render the respective output for you. Split the data into training and test ===================================== + Partitioning data is essential to avoid overfitting during model development. This can be achieved using the partition method. In this example, the data is partitioned in-place -and performs stratified sampling, based on the variable +and performs stratified sampling, based on the variable 'left.' If you do not specify a variable or the variable is an interval, then simple random sampling (SRS) is done. @@ -239,16 +241,17 @@ We create two partitions: test and training. Build an analytical model ========================= + One of the key activities for this module is analytical modeling. The SAS system is capable of modeling in a number of distinct areas (statistics, machine learning, econometric time series, and so on). -These capabilities are organized similarly to make it easier -for users. Grouping functionality also avoids cluttered tab-complete +These capabilities are organized similarly to make it easier +for users. Grouping functionality also avoids cluttered tab-complete lists with methods that you might not have licensed. -The session object has methods to create an instance for each supported -product. +The session object has methods to create an instance for each supported +product. * STAT (SAS/STAT) * ETS (SAS/ETS) @@ -266,19 +269,19 @@ Here is a code example to create an object for each product: qc = sas.sasqc() util = sas.sasutil() -Each of these objects contains a set of methods that perform analytical -functions, namely modeling. These methods closely follow the SAS procedures -for naming and organization. +Each of these objects contains a set of methods that perform analytical +functions, namely modeling. These methods closely follow the SAS procedures +for naming and organization. -.. note:: The existing list of methods is not an exhaustive list of the +.. note:: The existing list of methods is not an exhaustive list of the SAS procedures that are available with each product. Please - consider contributing the methods you've written to do your work. + consider contributing the methods you've written to do your work. The :doc:`api` documentation shows how to add a method that corresponds to a SAS procedure. The API has a complete list of methods for each object. -You can use the ``dir()`` function to see a list of the available methods. -For example, ``dir(stat)`` provides a list of the methods that are available. +You can use the ``dir()`` function to see a list of the available methods. +For example, ``dir(stat)`` provides a list of the methods that are available. **Not** all of the methods correspond to a procedure but the vast majority do. .. code-block:: python @@ -305,8 +308,8 @@ For example, ``dir(stat)`` provides a list of the methods that are available. -To build a model, you need to supply the required parameters to the modeling -method. I'll start with an example then explain the syntax. We'll continue +To build a model, you need to supply the required parameters to the modeling +method. I'll start with an example then explain the syntax. We'll continue using the HR data from above. .. code-block:: ipython3 @@ -326,11 +329,11 @@ t1 A string that represents the target variable. inputs - A dictionary that represents the model inputs with two keys--interval and + A dictionary that represents the model inputs with two keys--interval and nominal--which represent the interval and nominal variables respectively to consider for modeling. -Here is another way to specify the same as above--using the nominal parameter +Here is another way to specify the same as above--using the nominal parameter and a list of inputs. The target variable is now a dictionary. .. code-block:: ipython3 @@ -345,7 +348,7 @@ and a list of inputs. The target variable is now a dictionary. rf_model = ml.forest(data=hr, target=t1, input=inputs, nominals = nom) -Here is another way--using the nominal parameter and a string of inputs. The +Here is another way--using the nominal parameter and a string of inputs. The target is a list (nominals must be a list). .. code-block:: ipython3 @@ -361,12 +364,12 @@ target is a list (nominals must be a list). More about the target and input parameters ------------------------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ These rules apply to both target and input: * The parameters accept strings (str), lists (list), or dictionaries (dict) types. -* The target and input parameters are modified by a nominals parameter to +* The target and input parameters are modified by a nominals parameter to identify the proper variables treatment. * The nominals parameter must be a list type or you receive a syntax warning. * Variables are treated as nominals if any of the following are met: @@ -375,27 +378,27 @@ These rules apply to both target and input: * The variable is specified in the nominals list. * The variable is paired with dictionary key ``'nominal'``. -.. note:: If a variable is a SAS character type then it does not need to be - specified in the nominals parameter but does need to be assigned - to the ``'nominal'`` dictionary key if you use the dictionary +.. note:: If a variable is a SAS character type then it does not need to be + specified in the nominals parameter but does need to be assigned + to the ``'nominal'`` dictionary key if you use the dictionary object type. Evaluating model diagnostics ============================ -Perhaps the most important part of modeling is evaluating the quality of the +Perhaps the most important part of modeling is evaluating the quality of the model. This is made very easy by leveraging the rich graphical and tabular output of `SAS ODS `_. -The output of a model in is a :any:`SASresults` object. It contains all -the ODS tables and graphics that were produced by the SAS procedure. You can +The output of a model in is a :any:`SASresults` object. It contains all +the ODS tables and graphics that were produced by the SAS procedure. You can see all the available objects by using ``dir()`` or tab-complete on the object. .. code-block:: python dir(rf_model) -The returned list shows the available diagnostic output for this model. The +The returned list shows the available diagnostic output for this model. The output lists vary slightly, depending on the modeling algorithm, the settings, and the target type (nominal or interval). @@ -410,8 +413,8 @@ and the target type (nominal or interval). 'PERFORMANCEINFO', 'VARIABLEIMPORTANCE'] -To view a particular diagnostic, submit it as shown below. The default objects -for tables are Pandas DataFrames and for plots are HTML graphics. You can use +To view a particular diagnostic, submit it as shown below. The default objects +for tables are Pandas DataFrames and for plots are HTML graphics. You can use use the ``results`` option to choose HTML for tables too, if you choose. .. code-block:: python @@ -434,7 +437,7 @@ Below is an example where the variable name left is typed incorrectly as lefty. SubmissionError: ERRORS found in SAS log: ERROR: Variable LEFTY not found. -We can see a brief detail of the error but if more context is needed, you can +We can see a brief detail of the error but if more context is needed, you can see the entire log for the model submission with code like the following: .. code-block:: ipython3 diff --git a/saspy/doc/source/index.rst b/saspy/doc/source/index.rst index b92a742a..04954fff 100644 --- a/saspy/doc/source/index.rst +++ b/saspy/doc/source/index.rst @@ -4,9 +4,9 @@ .. image:: https://user-images.githubusercontent.com/17710182/171252212-4af121a6-72d9-4234-b6cf-2a0d31eb8bf7.png -***** +===== SASPy -***** +===== **Date**: |today| **Version**: |version| @@ -17,9 +17,8 @@ SASPy **Example Repo:** ``_ -************* What is this? -************* +============= This module provides Python APIs to the SAS system. You can start a SAS session and run analytics from Python through a combination of @@ -39,9 +38,8 @@ control are organized in Python classes. See :doc:`getting-started` for programming examples. -************ Dependencies -************ +============ - Python3.4 or higher. - SAS 9.4 or higher. SAS Viya 3.1 or higher is also supported. @@ -53,6 +51,8 @@ releases. .. toctree:: + :maxdepth: 5 + :hidden: install configuration diff --git a/saspy/doc/source/license.rst b/saspy/doc/source/license.rst index 17526cdf..e7f51a36 100644 --- a/saspy/doc/source/license.rst +++ b/saspy/doc/source/license.rst @@ -3,11 +3,10 @@ .. _license: -:tocdepth: 2 -******* +======= License -******* +======= Apache 2.0 ========== @@ -15,12 +14,11 @@ Apache 2.0 :Date: January 2004 :URL: http://www.apache.org/licenses/ ------------------------------------------------------------- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION ------------------------------------------------------------- +============================================================ 1. Definitions. ---------------- +~~~~~~~~~~~~~~~ **"License"** shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. @@ -77,7 +75,7 @@ behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. ------------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, @@ -86,7 +84,7 @@ publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. ---------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~ Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, @@ -102,7 +100,7 @@ patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. ------------------- +~~~~~~~~~~~~~~~~~~ You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, @@ -139,7 +137,7 @@ provided that You meet the following conditions: the conditions stated in this License. 5. Submission of Contributions. -------------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and @@ -149,7 +147,7 @@ of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. --------------- +~~~~~~~~~~~~~~ This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for @@ -157,7 +155,7 @@ reasonable and customary use in describing the origin of the Work and reproducing the content of the ``NOTICE`` file. 7. Disclaimer of Warranty. --------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~ Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an **"AS IS" @@ -169,7 +167,7 @@ using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. ---------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~ In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate @@ -182,7 +180,7 @@ or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. ----------------------------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or @@ -196,7 +194,7 @@ of your accepting any such warranty or additional liability. **END OF TERMS AND CONDITIONS** APPENDIX: How to apply the Apache License to your work ------------------------------------------------------- +====================================================== To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own diff --git a/saspy/doc/source/limitations.rst b/saspy/doc/source/limitations.rst index e1b0e48b..5f3a0840 100644 --- a/saspy/doc/source/limitations.rst +++ b/saspy/doc/source/limitations.rst @@ -13,15 +13,15 @@ require special handling to be able to work correctly. Hopefully this will be a It was initiated while working on `Issue 294 `_. That issue was about running batch SAS scripts via the submit() method and some problems that ensued. - + Let me preface this section by describing some aspects of saspy that warrant this section. saspy was designed to be a python interface to an interactive SAS session. Its many methods generate -SAS code, which it submits to the SAS session and then retrieves both the SASLOG (LOG) and any listing/results +SAS code, which it submits to the SAS session and then retrieves both the SASLOG (LOG) and any listing/results (LST) and then provides that back as objects or by directly rendering in interactive sessions. Many methods require saspy to query the SAS session to gather information about session, data, configuration, the environment, and other things. There is no API for these 'queries'. Rather, saspy generates specific -SAS code to gather this information and has it written to the LOG to then parse out on the Python side +SAS code to gather this information and has it written to the LOG to then parse out on the Python side after retirving the LOG. That is a common mode of access. This, then, demands that saspy have access to the LOG. That is perhaps the first, most important requirement. @@ -36,12 +36,11 @@ is implemented very differently, yet they each provide the same functionality an to the best of my ability to make that the case. Any divergences between those will also be identified here. -****** SASLOG -****** +====== Proc Printto ------------- +~~~~~~~~~~~~ Let's start with the first requirement that saspy has access to the SAS Log. SAS has a procedure which allows you to redirect the LOG and/or LST out from under the currently existing locations, to files or other locations: @@ -50,7 +49,7 @@ allows you to redirect the LOG and/or LST out from under the currently existing If this is used to redirect the LST, then you just won't get any results back from any methods in saspy. Your choice, I suppose. However, if redirecting the LOG, then saspy may hang, may have any number of failures or exceptions in various methods, and will generally be useless other than for other submit() methods, which won't -return anything. +return anything. Not the intent of the design. However, intent not being everything, providing a way to allow for the use of this, if needed, while addressing this restriction is possible. This would be considered a work around. @@ -61,7 +60,7 @@ successfully use Proc Printto within a saspy submit() method, you are simply req return the LOG and LST back to saspy which will then continue to function correctly. Of course, you won't get any part of the log or any results that happened while the redirection was enabled, but you knew that. Keep reading to see, below, that 'you' don't have to do this, there's an option on submit(..., printto=True) which will do this -for you. +for you. One parting though on this is that you can use saspy's download() method to pull the file(s) you redirected things to back to the client and then access them in saspy. Don't know why you would, but you could. Maybe there's a use @@ -69,12 +68,11 @@ case where that makes sense. -************************************ Terminating SAS out from under saspy -************************************ +==================================== %abort macro and abort statement --------------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SAS also has statements you can submit which will cause the SAS session to immediately terminate; yes, really. So, if you execute one of these statements, guess what? The interactive SAS session saspy that started and is connected to @@ -84,17 +82,17 @@ that executed SAS :) (lol) Well, executed the statement that terminated SAS. The SAS macro `%abort `_ and the data step statement `abort `_ each have various arguments which cause them to behave differently, and depending upon how the SASsession was started the -behavior can vary as well. +behavior can vary as well. There are two general behaviors these statements can produce. The first ts to terminate SAS. The other is to stop processing (some) remaining code that was submitted, but not terminate the SAS session. This second behavior is complicated by the nature of -the SAS session itself. As termination of the SAS session is pretty cut and dry, the following will be addressing the second behavior. +the SAS session itself. As termination of the SAS session is pretty cut and dry, the following will be addressing the second behavior. Canceling submitted statements ------------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ There are two variations of this second behavior. The first variation is when you supply no argument to the abort statement -or macro. In this case it only stops executing the current macro and/or data step, but any following submitted statements +or macro. In this case it only stops executing the current macro and/or data step, but any following submitted statements continue to be executed normally. This case is generally not a problem for any access method of saspy. The second variant is specifying the CANCEL argument: '[%]abort CANCEL;'. This version stops executing all of the following @@ -109,12 +107,11 @@ is a single 'submit'. In this case, the SASsession is no longer functional; it w terminated it (endsas()). That is a SASism, and nothing that can be changed or fixed from the Python side to solve this. -************* Perfect Storm -************* +============= Combining proc printto and abort cancel ---------------------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ What happens if you issue a the following code, having proc printto to redirect LOG/LST, and have an abort CANCEL, which gets executed, and you have the undo for the proc printto (proc printto;run;) at the end of your code? @@ -123,7 +120,7 @@ and you have the undo for the proc printto (proc printto;run;) at the end of you >>> sas.submitLOG(''' proc printto LOG='./mylogfile';run; - + /* some SAS code */ /* some conditional check which turns out to be true */ @@ -140,7 +137,7 @@ and you have the undo for the proc printto (proc printto;run;) at the end of you So, in this case, the 'undo' won't happen so saspy won't have it's LOG back. In this case, you could -code it in your program before each 'abort cancel;' that could execute. +code it in your program before each 'abort cancel;' that could execute. So, for IOM and HTTP, this will solve this case: @@ -148,7 +145,7 @@ So, for IOM and HTTP, this will solve this case: >>> sas.submitLOG(''' proc printto LOG='./mylogfile';run; - + /* some SAS code */ /* some conditional check which turns out to be true - return the log before canceling */ @@ -167,7 +164,7 @@ So, for IOM and HTTP, this will solve this case: printto= option on submit methods ---------------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Now, odds are that if you are submitting code like this, you didn't type it into saspy. You probably are reading in some existing SAS batch script (.sas file) and just submitting it, as is. You may not diff --git a/saspy/doc/source/troubleshooting.rst b/saspy/doc/source/troubleshooting.rst index 112e0594..dae8ce98 100644 --- a/saspy/doc/source/troubleshooting.rst +++ b/saspy/doc/source/troubleshooting.rst @@ -13,9 +13,8 @@ there are some cases where you might not have everything working right. We've tr for diagnosing and fixing those issues here. -*********************************** Connection and configuration issues -*********************************** +=================================== Although setup and configuration is pretty simple, if you do have something not quite right, it may be hard to figure out what's wrong. That's when you come to this chapter. @@ -31,7 +30,7 @@ documentation and so does :doc:`install`. Common diagnostics ------------------- +~~~~~~~~~~~~~~~~~~ Although each access method has its own ways something can go wrong, there are some common diagnostics you will get and can use to track down the issue. @@ -95,7 +94,7 @@ various connection methods, see what the errors look like, and how you can deter STDIO ------ +~~~~~ There are only a couple of things that can go wrong here. First, this only works on Unix, not Windows, so if you're having problems getting to to work from Windows, well there you go. @@ -123,7 +122,7 @@ If you see that error, go read the configuration doc here: :doc:`configuration` STDIO over SSH --------------- +~~~~~~~~~~~~~~ The same issues in STDIO above are true here, with one extra component: ssh. The 'saspath' value has to be right, and it has to be right on the remote Linux machine that you are ssh'ing to. That might not be the same path @@ -216,7 +215,7 @@ For instance, everything seems set up correctly but after running ssh it just sa IOM ---- +~~~ This access method has the most possibilities of having something misconfigured, because it has more components that all have to connect together. But, it also has the most diagnostics to help you out. @@ -230,7 +229,7 @@ There are three things that are likely to be the problem. Java problems -^^^^^^^^^^^^^ +------------- This error is descibed below: @@ -277,7 +276,7 @@ there is no c:\\java command to execute. Classpath problems -^^^^^^^^^^^^^^^^^^ +------------------ So what about CLASSPATH problems? Here are three cases. The first is just the wrong path, so Java won't be able to find the main class to run. The second case has a valid classpath, but is missing one of the IOM jars. The third is a case with EG versions of the jars, not from a SAS 9 install. @@ -504,7 +503,7 @@ back to the python process, which isn't running, thus the connection error. But IOM specific errors -^^^^^^^^^^^^^^^^^^^ +------------------- So if Java is coming up, but you still fail to connect, then it is a problem connecting to IOM. The IOM Error message will be reported, followed by the command that was trying to be run. Below @@ -800,13 +799,12 @@ So, hopefully this has shown you how to diagnose connection and configuration pr have any problems, it should just work! -********************* Problems running code -********************* +===================== My model didn't run -------------------- +~~~~~~~~~~~~~~~~~~~ When you run an analytical method there are a number of things that occur. The goal is to have informative messages when things go wrong and in this section we'll explain what his happening