BookmarkSubscribeRSS Feed

Installing SASPy Kernel for Jupyter Notebooks and Jupyter Lab

Started ‎05-30-2018 by
Modified ‎05-25-2020 by
Views 28,587

The SAS Kernel SASPy allows you to program in SAS using Jupyter Notebooks and Jupyter Lab. Jupyter Notebooks and Jupyter Lab both allow you to incorporate cells with Markdown with cells with executable code. This can be very helpful for learning and studying SAS programming. Here's an example of what SAS Code can look like in these interfaces:

  • Jupyter Notebook:
    Notebooks.PNG
  • Jupyter Lab:

3.pngThis article will walk you through the step-by-step process of installing Anaconda to access Jupyter Notebooks/Jupyter Lab and installing and configuring the SAS Kernel. These instructions only cover the case where you have SAS installed locally, but please note that SAS University Edition already has built-in support for Jupyter Notebooks.

 

Download Anaconda to Access Jupyter Notebook and Jupyter Lab

  1. Go to this website: https://www.anaconda.com/download/

  2. Click on "Windows" at the top of the webpage. To install the latest Python version (3.x), click the "Download" button.

anaconda.png

  1. Open the .exe file that was downloaded. Follow Anaconda installation instructions, no modifications or changes to file paths should need to be made.
  2. Once the download is complete, open Anaconda Navigator (no desktop icon will be created so you will need to find it on your machine). You will be asked if you want to provide Anaconda with more information, you can choose whether you would like to do that or not. Click “Launch” on either Jupyter Notebook or Jupyter Lab.1.png
  3. Notice that when launching either Jupyter Lab or Jupyter Notebook for the first time, your only option for creating new files will be “Python.”

 

Install SAS Kernel Package

You have now successfully set up Anaconda and Jupyter Notebook/Lab and can use either Jupyter Notebook or Jupyter Lab to write Python code. The following instructions will walk you through the set up required to be able to write SAS code in either Jupyter Notebook or Jupyter Lab.

  1. Open the Anaconda Prompt.
  2. Type:
    pip install sas_kernel
  3. Now, go back to Jupyter Notebook or Jupyter Lab. Notice that for a new file, you now have the option to choose “SAS” as your language. (You may need to refresh or restart Jupyter Notebook/Lab)
    • Jupyter Notebook:saspy.PNG
    • Jupyter Lab:2.png

       

Make Necessary Changes to Configuration File

You have now installed the SAS kernel, but it is not yet configured to access your SAS license on your machine. The next steps will do just that.

  1. Locate your sascfg.py configuration file. You can do this by using the same Anaconda Prompt we used earlier. Type:
    python
    import saspy
    saspy.SAScfg
    This is case-sensitive. See the example below. The file path returned to you will tell you where your sascfg.py configuration file is located. Navigate to that file in your file system.python.PNG

     

  1. It is a good idea to create a “personal” configuration file instead of making changes to the original. If you reinstall, the original sascfg.py can get overwritten. If you make a personal one, this will save your changes from being overwritten. You can do this by duplicating the file sascfg.py and renaming it sascfg_personal.py. Make sure the new file is saved to the same directory as the old one.
  2. Open the sascfg_personal.py file in a text editor (I used Notepad++). Locate the portion of the file containing SAS_config_names, it will look like this.

    config1.png

     

  3. The comment in line 32 shows all of the different options for the config name. If you’re doing a local windows install like I was, you will choose ‘winlocal’. Make the necessary edit in the configuration file, seen belowconfig2.png 

  4. Locate the portion of the file containing the class path variables. For a local windows install, these are those lines that start with “cpW.” You will need to edit these paths to reflect the paths of the same files on your own machine. For the first 4 files, the only thing that needs to be changed in those paths are the digits in the red box in the photo above. For the 5th file (saspyiom.jar), you should locate the correct path and input it in the quotes (using double backslashes).classpaths.PNG

     

  5. Now, you must change the java file path. In the picture below, the green box contains the spot where you will need to paste the path to your java.exe file that is associated with your SAS install. Locate the file and paste in the path, as seen belowjava1.PNG

     java2.PNG

     

 

 

 

 

 

 

 

Add sspiauth.dll To Your System PATH Environment Variable

  1. Locate the sspiauth.dll file for your SAS install. It is probably here:

 

C:\Program Files\SASHome\SASFoundation\9.4\core\sasext

 

  1. Navigate to your desktop, and right click on the “Computer” icon. Choose “Properties,” then click “Advanced Settings.” Finally, click “Environment Variables” as shown below.System Properties.PNG

     

  2. Look at "System Variables" (not your User Variables). Highlight “PATH” and click “Edit.”systemvariables.PNG

  3. Click "New." Now, paste in the path to the folder that contains your sspiauth.dll file. Do not include the file name in the path, for example: 

    C:\Program Files\SASHome\SASFoundation\9.4\core\sasext

     Click "OK."

 

Restart Computer, Log Back in to Jupyter Notebook or Jupyter Lab, and Open a New SAS Notebook

You should now be able to run SAS code in your Jupyter Notebook, enjoy!

 

Additional Resources

Run SAS Programs in Jupyter Notebook

SAS Kernel

SASPy Installation

SASPy Configuration

Coding in Python using SAS University Edition

Comments

This is great stuff, @OliviaWright!

@RandyMullis Thank you so much! I had a bit of trouble with the configuration when I was doing this myself so I thought folks might benefit from these instructions. 🙂

Hi @OliviaWright!

 

I find your comment very helpful! However, when I try to set up SAS on Jupyter Notebook from a Windows system, I run into an error when executing the "pip install sas_kernel" from the Anaconda prompt. This error is also mentioned in this post: https://github.com/sassoftware/sas_kernel/issues/12, where it is mentioned that SASpy is only for Linux. However, from your post I see that you installed this on Windows too. Do you know the issue, and do you have any help for me?

 

Thanks in advance!

Hi @avuik! Thanks for your question. I believe that windows support was not available at the time of the question you linked from GitHub, but it is now! That documentation is here: https://sassoftware.github.io/sas_kernel/install.html#windows-install-assuming-sas-already-installed...

 

I have reached out to someone about your error, as I'm not sure what could be causing it. I'll let you know what I hear!

 Hey @avuik. I'm not sure what error you are getting trying to install the SAS_kernel. It was a couple of years ago that saspy and the SAS_kernel (Jupyter Kernel) wasn't supported on Windows. It has been now for the past couple of years. I'd be happy to help you out with this. Do you mind opening an issue on the saspy issues (https://github.com/sassoftware/saspy/issues). It is easier for me to keep track of it there. If not, I can use this thread; your choice.

Can you show me what error you are getting? What version of python you're using? ...

 

Thanks,

Tom

Thank you so much, @sastpw!

Hi @sastpw! Thanks for the quick reply. I want to use saspy on my work laptop, and I found out by asking around that the problem is due to a restricted internet access from my laptop, making it impossible for me to connect to server to pip install. 

However, there is a web debugging proxy package called fiddler that might help me out. I gonna try that first to see if this fixes the issue. If there is anything else, I'll let you know! 

 

Thanks anyway for the help!

Hey, There's an easier way if you can download from the repo's themselves. If you just go to the repo:

https://github.com/sassoftware/saspy

https://github.com/sassoftware/sas_kernel

and click download, on them, you get a zip file that you can extract to your local drive.

You can then CD to saspy directory; should see files like README.md and setup.py in that level of the directory structure.

then you just do

pip install .

that's a dot (.) which just means current directory.

then do the same for the sas_kernel.after you've done saspy.

There are a couple dependencies that saspy requires, but as you have anaconda installed, those should already be there (hopefully).

Give that a try and let me know how it goes!

 

Thanks,

tom

 

Hi Tom,
I actually got pip install working using fiddler, so I was able to install saspy and sas_kernel both, but anyway thanks for your help again.
I'm now struggling with the step "Make Necessary Changes to Configuration File", mostly steps 5 and 6, as I can't really track down the locations of the .jar files in sascfg.py of which you should change the path. I only can find the saspyiom.jar file, but the first four don't seem to be there. I also cannot track the sspiauth.dll file mentioned in the next step.

Do you know any other approach to fix this?

Thanks!

Do you have SAS installed on your machine? Or are you planning on connecting to a remote workspace server?

I you have it on your machine, they are in the SAS installation. But, it sounds like you don't. The jars can be copied to your machine from whatever SAS installation you will be using; they will be there.

I explored providing then in the saspy repo, but as some of these jars support encryption and such, it's a legal issue to have them available w/out a license, which is covered by the actual SAS license for a real install. So I can't provide them via github.

Any SAS install on your site will have them and you can copy them to your machine from there. They are compatible between windows and linux, os it can be a linux install and that's ok.

 

Tom

SAS is not installed locally but on a workspace server, so that explains why I can't find the jar files locally. I'll try to find them on the server and copy them to my local machine, hope that will make it work.

Thanks again for the help!

Yes, that will work for the jars. You need to know the host where the Object spawner (that spawns the workspace server you're trying to connect to), is running, and the workspace server port it's listening on. If you have multiple App Servers defined, then you need the name of the one you're trying to connect to. This is all in the config doc, so it should be straight forward. It's always completely obvious once you have it working 🙂

https://sassoftware.github.io/saspy/install.html#iom

https://sassoftware.github.io/saspy/install.html#remote

 

If you have any trouble, I'm right here to help.

 

Tom

 

Hello,

I installed SASPy kernel on Jupyter Lab following the easy-to-follow steps that were earlier posted to this site by Olivia Wright (edited by Beverly Brown). Thanks to them!

 

Then I ran the following code in Jupyter Lab setting.

**************************************************

import saspy
import pandas as pd
sas = saspy.SASsession(cfgname='winlocal')
cars = sas.sasdata("CARS","SASHELP")
cars.describe()

 

*********************************

Issue: I  get this message and don't get the desired output.

The SAS Config name specified was not found. Please enter the SAS Config you wish to use. Available
Configs are: ''default'].

I have the following .jar files in the appropriate folders, and they are specified in the SAScfg_personal.py file:

            sas.svc.connection.jar              log4j.jar                    sas.security.sspi.jar                    sas.core.jar

 

 The SAScfg_personal.py also includes these:

           cpW += ";C:\\Anaconda\\Lib\\site-packages\\saspy\\java\\saspyiom.jar"

 

          winlocal = {'java' : 'C:\\Program Files\\SASHome\\SASPrivateJavaRuntimeEnvironment\\9.4\\jre\\bin\\java',
          'encoding' : 'windows-1252',
          'classpath' : cpW
          }

[I also tried java.exe (file name rather than the file location above). I get the same message.]

 

Any help toward resolving the issue would be highly appreciated.

Thanks,

 

Pradip Muhuri

@sastpw Do you have any ideas for helping @muhuri solve their problem? 🙂

@OliviaWright , @muhuri ,

 

while we wait for @sastpw I would like to see if I can help here.

 

In one hand, I can see the error is

Available Configs are: ''default']

For me, this means that the list of SAS_config_names does not seem correct, or there is a typo somewhere.

 

The model to follow looks like:

SAS_config_names=['default', 'config1', 'config2']

 

And for what I understand, in this case it should be similar to this:

SAS_config_names=['default', 'cpW']

 

Edit: or, as following this article, SAS_config_names=['default', 'winlocal']

@muhuri , yes, I can help with that. I believe that your sascfg_personal.py file is not being found. Where is it? and what is it named (it's case sensitive). You can submit the following to see what is being found and see yours is in there or not. If it does find yours then the problem would likely be that you need to add the name of the configuration definition your using (winlocal in this case) to the SAS_config_names in your file (I expect winlocal is the only one you're using?): 

SAS_config_names   = ['winlocal']

To see what is being found, try these and see what you get (in a Jupyter notebook, submit these each in their own cell):

import saspy

saspy

saspy.sascfg

saspy.sascfg_personal

saspy.sasbase.SAScfg

 

If it is that your file isn't being found, but everything else looks right, you can either put your file in the python search path so it will be found, or specify it on the SASsession(cfgfile='path to your sascfg_personal.py'). That last one (saspy.sasbase.SAScfg) is the file it's using by default.

 

Let me know what you find, and we'll get you up and running!

Tom

Hi JuanS_OCS - That was a typo - an extra single quote(') in my origianl posting. Sorry for the confusion. It was as follows:

 

Available Configs are: 'default'

Thanks for your tips with the debugging of my code.

 

Hi sastpw, Thank you so much for your helpful code.

 

1. Per your suggestions,  I have changed SAS_config_names = ['default'] to  SAS_config_names = ['winlocal'in my sascfg_personal.py file.

 

2. I also implemented your code as shown below. Please note that the code in lines 5 and 10 below throws errors. Any further thoughts toward resolving the issues?

 

import saspy
In [4]:
saspy
Out[4]:
<module 'saspy' from 'C:\\Users\\pmuhuri\\AppData\\Local\\Continuum\\anaconda3\\lib\\site-packages\\saspy\\__init__.py'>
In [5]:
saspy.sascfg
 
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-5-f446d9ef8fd1> in <module>
----> 1 saspy.sascfg

AttributeError: module 'saspy' has no attribute 'sascfg

 

saspy.sascfg_personal
Out[6]:
<module 'saspy.sascfg_personal' from 'C:\\Users\\pmuhuri\\AppData\\Local\\Continuum\\anaconda3\\lib\\site-packages\\saspy\\sascfg_personal.py'>
In [7]:
saspy.sasbase.SAScfg
Out[7]:
<module 'saspy.sascfg_personal' from 'C:\\Users\\pmuhuri\\AppData\\Local\\Continuum\\anaconda3\\lib\\site-packages\\saspy\\sascfg_personal.py'>
In [10]:
import saspy
import pandas as pd
sas = saspy.SASsession(cfgfile='C:\\Users\\pmuhuri\\AppData\\Local\\Continuum\\anaconda3\\lib\\site-packages\\saspy\\sascfg_personal.py')
cars = sas.sasdata("CARS","SASHELP")
cars.describe()
 
Using SAS Config named: winlocal
Java Error:
Error: Could not find or load main class pyiom.saspy2j


Subprocess failed to start. Double check your settings in sascfg_personal.py file.
(The remaining part of the log is not shown here.)

@muhuri , that's all good. It is finding your _personal file. And now it is using the configuration definition you configured.

The error you are getting now is about your classpath. There is something wrong with that. It isn't finding the jar that is in the saspy module.I don't see what you have in your config file. If you don't mind posting that (the classpath and the config definition) I can see what might be the problem with that.

 

The error in 5 is expected (it will either be 5 or 6 depending on which file it found). 10 is the classpath issue.

 

Something else you can easily try is to give the autoconfig script a try. I haven't documented this in the install/config doc yet, but there is an example in the saspy-examples repo: https://github.com/sassoftware/saspy-examples/blob/master/SAS_contrib/autocfg.ipynb

 

You would want to specify a different name for the file it creats and then see if that file works, and/or compare what it comes up with to what you have. 

 

In either case, if I can see what you have, I'll be able to further diagnose..

Thanks!

Tom

from saspy import autocfg
autocfg.main('my_cfg.py')
 
Generated configurations file: my_cfg.py
In [6]:
import saspy
sas = saspy.SASsession(cfgfile='my_cfg.py')
sas

 

This would be the example to try with the autocfg so you don't overwrite your _personal config file.

 

Tom 

Hello Tom,

 

For further diagnosis of the issue, I am presenting the code cells (in light of your suggestions) and the output below. There is an issue with code cell 13 below.

 

I look forward to receiving your further guidance for resolition of the issue.

 

Thank you so much for your continued support.

 

Pradip

 

from saspy import autocfg
autocfg.main('my_cfg.py')
 
CFGFILE ALREADY EXISTS: my_cfg.py
In [11]:
import saspy
sas = saspy.SASsession(cfgfile='my_cfg.py')
 
Using SAS Config named: autogen_winlocal
SAS Connection terminated. Subprocess id was 6092
SAS Connection established. Subprocess id is 5436

In [12]:
from saspy import autocfg
autocfg.main()
 
CFGFILE ALREADY EXISTS: C:\Users\pmuhuri\AppData\Local\Continuum\anaconda3\lib\site-packages\saspy\sascfg_personal.py
In [13]:
import saspy
sas = saspy.SASsession()
sas
 
Using SAS Config named: winlocal
Java Error:
Error: Could not find or load main class pyiom.saspy2j


Subprocess failed to start. Double check your settings in sascfg_personal.py file.

Attempted to run program C:\Program Files\SASHome\SASPrivateJavaRuntimeEnvironment\9.4\jre\bin\java with the following parameters:['C:\\Program Files\\SASHome\\SASPrivateJavaRuntimeEnvironment\\9.4\\jre\\bin\\java', '-classpath', 'C:\\Program Files\\SASHome\\SASDeploymentManager\\9.4\\products\\deploywiz__94492__prt__xx__sp0__1\\deploywiz\\sas.svc.connection.jar;C:\\Program Files\\SASHome\\SASDeploymentManager\\9.4\\products\\deploywiz__94492__prt__xx__sp0__1\\deploywiz\\log4j.jar;C:\\Program Files\\SASHome\\SASDeploymentManager\\9.4\\products\\deploywiz__94492__prt__xx__sp0__1\\deploywiz\\sas.security.sspi.jar;C:\\Program Files\\SASHome\\SASDeploymentManager\\9.4\\products\\deploywiz__94492__prt__xx__sp0__1\\deploywiz\\sas.core.jar;C:\\ProgramData\\Anaconda3\\Lib\\site-packages\\saspy\\java\\saspyiom.jar', 'pyiom.saspy2j', '-host', 'localhost', '-stdinport', '60445', '-stdoutport', '60446', '-stderrport', '60447', '-zero', '-lrecl', '1048576', '']

If no Java Error above, try running the following command (where saspy is running) manually to see if it's a problem starting Java:
C:\Program Files\SASHome\SASPrivateJavaRuntimeEnvironment\9.4\jre\bin\java -classpath "C:\Program Files\SASHome\SASDeploymentManager\9.4\products\deploywiz__94492__prt__xx__sp0__1\deploywiz\sas.svc.connection.jar;C:\Program Files\SASHome\SASDeploymentManager\9.4\products\deploywiz__94492__prt__xx__sp0__1\deploywiz\log4j.jar;C:\Program Files\SASHome\SASDeploymentManager\9.4\products\deploywiz__94492__prt__xx__sp0__1\deploywiz\sas.security.sspi.jar;C:\Program Files\SASHome\SASDeploymentManager\9.4\products\deploywiz__94492__prt__xx__sp0__1\deploywiz\sas.core.jar;C:\ProgramData\Anaconda3\Lib\site-packages\saspy\java\saspyiom.jar" pyiom.saspy2j -host localhost -stdinport 60445 -stdoutport 60446 -stderrport 60447 -zero -lrecl 1048576  

Out[13]:
Access Method         = IOM
SAS Config name       = winlocal
WORK Path             = 
SAS Version           = 
SASPy Version         = 2.4.1
Teach me SAS          = False
Batch                 = False
Results               = Pandas
SAS Session Encoding  = 
Python Encoding value = windows-1252
SAS process Pid value = None
In [14]:
fd = open('C:\\Users\\pmuhuri\\AppData\\Local\\Continuum\\anaconda3\\lib\\site-packages\\saspy\\sascfg_personal.py')
print(fd.read())
fd.close()
 
#
# Copyright SAS Institute
#
#  Licensed under the Apache License, Version 2.0 (the License);
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.
#

# THIS IS AN EXAMPLE CONFIG FILE. PLEASE CREATE YOUR OWN sascfg_personal.py FILE USWING THE APPROPRIATE TEMPLATES FROM BELOW
# SEE THE CONFIGURATION DOC AT https://sassoftware.github.io/saspy/install.html#configuration


# Configuration Names for SAS - python List
# This is the list of allowed configuration definitions that can be used. The definition are defined below.
# if there is more than one name in the list, and cfgname= is not specified in SASsession(), then the user
# will be prompted to choose which configuration to use.
#
# The various options for the different access methods can be specified on the SASsession() i.e.:
# sas = SASsession(cfgname='default', options='-fullstimer', user='me')
#
# Based upon the lock_down configuration option below, you may or may not be able to override option
# that are defined already. Any necessary option (like user, pw for IOM or HTTP) that are not defined will be 
# prompted for at run time. To dissallow overrides of as OPTION, when you don't have a value, simply
# specify options=''. This way it's specified so it can't be overridden, even though you don't have any
# specific value you want applied.
# 
#SAS_config_names = ['default', 'ssh', 'iomlinux', 'iomwin', 'winlocal', 'winiomlinux', 'winiomwin', 'http']
#

SAS_config_names=['winlocal']

# Configuration options for saspy - python Dict
# valid key are:
# 
# 'lock_down' - True | False. True = Prevent runtime overrides of SAS_Config values below
#
# 'verbose'   - True | False. True = Allow print statements for debug type messages
#
SAS_config_options = {'lock_down': False,
                      'verbose'  : True
                     }

# Configuration options for SAS output. By default output is HTML 5.0 (using "ods html5" statement) but certain templates might not work 
# properly with HTML 5.0 so it can also be set to HTML 4.0 instead (using "ods html" statement). This option will only work when using IOM
# in local mode. Note that HTML 4.0 will generate images separately which clutters the workspace and if you download the notebook as HTML, 
# the HTML file will need to be put in the same folder as the images for them to appear.
# valid key are:
# 
# 'output' = ['html5', 'html']
#
SAS_output_options = {'output' : 'html5'}


# Configuration Definitions
#
# For STDIO and STDIO over SSH access methods
# These need path to SASHome and optional startup options - python Dict
# The default path to the sas start up script is: /opt/sasinside/SASHome/SASFoundation/9.4/sas
# A usual install path is: /opt/sasinside/SASHome
#
# Since python uses utf-8, running SAS with encoding=utf-8 is the expected use case. By default Unix SAS runs in Latin1 (iso-8859-1),
# which does not work well as utf-8. So, transcoding has been implemented in the python layer. The 'encoding' option can be specified to match
# the SAS session encoding (see https://docs.python.org/3.5/library/codecs.html#standard-encodings for python encoding values). latin1 is appropriate
# for the default Unix SAS session encoding
#                                                                                                         
# valid keys are:
# 'saspath'  - [REQUIRED] path to SAS startup script i.e.: /opt/sasinside/SASHome/SASFoundation/9.4/sas
# 'options'  - SAS options to include in the start up command line - Python List
# 'encoding' - This is the python encoding value that matches the SAS session encoding your SAS session is using 
#
# For passwordless ssh connection, the following are also reuqired:
# 'ssh'     - [REQUIRED] the ssh command to run
# 'host'    - [REQUIRED] the host to connect to
#
# Additional valid keys for ssh:
# 'port'    - [integer] the remote ssh port
# 'tunnel'  - [integer] local port to open via reverse tunnel, if remote host cannot otherwise reach this client
#
default  = {'saspath'  : '/opt/sasinside/SASHome/SASFoundation/9.4/bin/sas_u8'
            }

ssh      = {'saspath' : '/opt/sasinside/SASHome/SASFoundation/9.4/bin/sas_en',
            'ssh'     : '/usr/bin/ssh',
            'host'    : 'remote.linux.host', 
            'encoding': 'latin1',
            'options' : ["-fullstimer"]
            }


# For IOM (Grid Manager or any IOM) and Local Windows via IOM access method
# These configuration definitions are for connecting over IOM. This is designed to be used to connect to a SAS Grid, via Grid Manager
# and also to connect to a local Windows SAS session. The client side (python and java) for this access method can be either Linux or Windows.
# The STDIO access method above is only for Linux. PC SAS requires this IOM interface.
#
# The absence of the iomhost option triggers local Windows SAS mode. In this case none of 'iomhost', 'iomport', 'omruser', 'omrpw' are needed.
# a local SAS session is started up and connected to.
#
# Since python uses utf-8, running SAS with encoding=utf-8 is the expected use case. By default Windows SAS runs in WLatin1 (windows-1252),
# which does not work well as utf-8. So, transcoding has been implemented in the python layer. The 'encoding' option can be specified to match
# the SAS session encoding (see https://docs.python.org/3.5/library/codecs.html#standard-encodings for python encoding values). windows-1252 is appropriate
# for the default Windows SAS session encoding
#                                                                                                         
# Since this IOM access method uses the Java IOM client, a classpath is required for the java process to find the necessary jars. Use the template below
# to build out a classpath variable and assign that to the 'classpath' option in the configuration definition. The IOM client jars are delivered as part
# of a Base SAS install, so should be available in any SAS install. The saspyiom.jar is available in the saspy repo/install. 
#
# NONE OF THE PATHS IN THESE EAMPLES ARE RIGHT FOR YOUT INSTALL. YOU HAVE TO CHANGE THE PATHS TO BE CORRECT FOR YOUR INSTALLATION 
#
# valid keys are:
# 'java'      - [REQUIRED] the path to the java executable to use
# 'iomhost'   - [REQUIRED for remote IOM case, Don't specify to use a local Windows Session] the resolvable host name, or ip to the IOM server to connect to
# 'iomport'   - [REQUIRED for remote IOM case, Don't specify to use a local Windows Session] the port IOM is listening on
# 'authkey'   - identifier for user/password credentials to read from .authinfo file. Eliminates prompting for credentials.
# 'omruser'   - not suggested        [REQUIRED for remote IOM case but PROMPTED for at runtime] Don't specify to use a local Windows Session
# 'omrpw'     - really not suggested [REQUIRED for remote IOM case but PROMPTED for at runtime] Don't specify to use a local Windows Session
# 'encoding'  - This is the python encoding value that matches the SAS session encoding of the IOM server you are connecting to
# 'classpath' - [REQUIRED] classpath to IOM client jars and saspy client jar.
# 'appserver' - name of physical workspace server (when more than one app server defined in OMR) i.e.: 'SASApp - Workspace Server'
# 'sspi'      - boolean. use IWA instead of user/pw to connect to the IOM workspace server


# build out a local classpath variable to use below for Linux clients  CHANGE THE PATHS TO BE CORRECT FOR YOUR INSTALLATION 
cpL  =  "/opt/sasinside/SASHome/SASDeploymentManager/9.4/products/deploywiz__94400__prt__xx__sp0__1/deploywiz/sas.svc.connection.jar"
cpL += ":/opt/sasinside/SASHome/SASDeploymentManager/9.4/products/deploywiz__94400__prt__xx__sp0__1/deploywiz/log4j.jar"
cpL += ":/opt/sasinside/SASHome/SASDeploymentManager/9.4/products/deploywiz__94400__prt__xx__sp0__1/deploywiz/sas.security.sspi.jar"
cpL += ":/opt/sasinside/SASHome/SASDeploymentManager/9.4/products/deploywiz__94400__prt__xx__sp0__1/deploywiz/sas.core.jar"
cpL += ":/opt/github/saspy/java/saspyiom.jar"

iomlinux = {'java'      : '/usr/bin/java',
            'iomhost'   : 'linux.iom.host',
            'iomport'   : 8591,
            'encoding'  : 'latin1',
            'classpath' : cpL
            }           

iomwin   = {'java'      : '/usr/bin/java',
            'iomhost'   : 'windows.iom.host',
            'iomport'   : 8591,
            'encoding'  : 'windows-1252',
            'classpath' : cpL
            }

         
# build out a local classpath variable to use below for Windows clients   CHANGE THE PATHS TO BE CORRECT FOR YOUR INSTALLATION 
cpW  =  "C:\\Program Files\\SASHome\\SASDeploymentManager\\9.4\\products\\deploywiz__94492__prt__xx__sp0__1\\deploywiz\\sas.svc.connection.jar"
cpW += ";C:\\Program Files\\SASHome\\SASDeploymentManager\\9.4\\products\\deploywiz__94492__prt__xx__sp0__1\\deploywiz\\log4j.jar"
cpW += ";C:\\Program Files\\SASHome\\SASDeploymentManager\\9.4\\products\\deploywiz__94492__prt__xx__sp0__1\\deploywiz\\sas.security.sspi.jar"
cpW += ";C:\\Program Files\\SASHome\\SASDeploymentManager\\9.4\\products\\deploywiz__94492__prt__xx__sp0__1\\deploywiz\\sas.core.jar"
cpW += ";C:\\ProgramData\\Anaconda3\\Lib\\site-packages\\saspy\\java\\saspyiom.jar"

# And, if you've configured IOM to use Encryption, you need these client side jars.
#cpW += ";C:\\Program Files\\SASHome\\SASVersionedJarRepository\\eclipse\\plugins\\sas.rutil_904300.0.0.20150204190000_v940m3\\sas.rutil.jar"
#cpW += ";C:\\Program Files\\SASHome\\SASVersionedJarRepository\\eclipse\\plugins\\sas.rutil.nls_904300.0.0.20150204190000_v940m3\\sas.rutil.nls.jar"
#cpW += ";C:\\Program Files\\SASHome\\SASVersionedJarRepository\\eclipse\\plugins\\sastpj.rutil_6.1.0.0_SAS_20121211183517\\sastpj.rutil.jar"


winlocal = {'java'      : 'C:\\Program Files\\SASHome\\SASPrivateJavaRuntimeEnvironment\\9.4\\jre\\bin\\java',
            'encoding'  : 'windows-1252',
            'classpath' : cpW
            }

winiomlinux = {'java'   : 'java',
            'iomhost'   : 'linux.iom.host',
            'iomport'   : 8591,
            'encoding'  : 'latin1',
            'classpath' : cpW
            }

winiomwin  = {'java'    : 'java',
            'iomhost'   : 'windows.iom.host',
            'iomport'   : 8591,
            'encoding'  : 'windows-1252',
            'classpath' : cpW
            }

winiomIWA  = {'java'    : 'java',
            'iomhost'   : 'windows.iom.host',
            'iomport'   : 8591,
            'encoding'  : 'windows-1252',
            'classpath' : cpW,
            'sspi'      : True
            }


In [ ]:
 

I'm not completely clear on that output. It says you already had a file named my_cfg.py, but was that just that you ran it more than once? It shows it connected, and that it disconnected another session. Did that auto config actually work? What was in the file?

 

I see that when using your _personal file, it get's the error about the saspy jar not being found. I see in your file (that you show the contents of), that the path to that jar doesn't match where you have saspy installed. Your output shows that saspy is at:

C:\\Users\\pmuhuri\\AppData\\Local\\Continuum\\anaconda3\\lib\\site-packages\\saspy

but in your config file, you specified:

cpW += ";C:\\ProgramData\\Anaconda3\\Lib\\site-packages\\saspy\\java\\saspyiom.jar"

That's the cause of the error about that jar not being found.

 

What's in the my_cfg.py file? It looked like it worked but I don't see any code being run to know?

import saspy
sas = saspy.SASsession(cfgfile='my_cfg.py')
 
Using SAS Config named: autogen_winlocal
SAS Connection terminated. Subprocess id was 6092
SAS Connection established. Subprocess id is 5436

 

Thanks,

Tom

Hi Tom,

You are absolutely correct that the error about that jar not being found is due to an incorrectly named path (for the saspyiom.jar file) specified in my sascfg_personal file. With the resolution of the issue, my SASPy code has now worked fine and given me the desired output.

 

I wanted to thank you for taking the time to explain how to diagnose this kind of problem.  

 

Pradip Muhuri

****************************************************

Below are the final code cells (your original code in my aplication) and the content.

 

from saspy import autocfg
autocfg.main()
 
CFGFILE ALREADY EXISTS: C:\Users\pmuhuri\AppData\Local\Continuum\anaconda3\lib\site-packages\saspy\sascfg_personal.py
In [2]:
import saspy
sas = saspy.SASsession()
sas
 
Using SAS Config named: winlocal
SAS Connection established. Subprocess id is 9016

Out[2]:
Access Method         = IOM
SAS Config name       = winlocal
WORK Path             = C:\Users\pmuhuri\AppData\Local\Temp\SAS Temporary Files\_TD8284_CCASTA-HWJP0G2_\Prc2\
SAS Version           = 9.04.01M5P09132017
SASPy Version         = 2.4.1
Teach me SAS          = False
Batch                 = False
Results               = Pandas
SAS Session Encoding  = wlatin1
Python Encoding value = windows-1252
SAS process Pid value = 8284

 

Great, glad to hear it!

And just to be clear on the usage of the autocfg, this is only something that needs to be run once; it creates the sascfg_personal.py file for you, by default. If you were to rename the one you created and run it with no parameters, it will create one for you 

CFGFILE ALREADY EXISTS: C:\Users\pmuhuri\AppData\Local\Continuum\anaconda3\lib\site-packages\saspy\sascfg_personal.py

As you see, yours was already there, so it didn't replace it. You can try renaming yours and then running it and see what the generated config file looks like. I believe it will be a working config file too, based upon the previous reply. You should also find the my_cfg.py file in whatever the current directory that your jupyter session was running in. That was created when you ran it as:

autocfg.main('my_cfg.py')

 

Either way, you have a working config, and you don't need to run that autocfg anymore, you can just go straight to:

import saspy

sas = saspy.SASsession()

sas

...  # the rest of what you want to do

 

Thanks!

Tom

Hello,

 

While I successfully installed SASPy for local windows PC SAS in one of my laptops just 3 days ago (with guidance and support from  sastpw/Tom), I now find some issues with a similar installation in my second laptop.

 

Issues:

(1) There is no SAS kernel in JupyterLab although Python kernel exists.

 

(2) I installed SASPy as well as SAS_kernel using the pip method. At the prompt, I submitted this: Jupyter kernelspec list and found the following.

Available kernels:

  python3    C:\Anaconda3\share\jupyter\kernels\python3

 

I was also expecting this: sas    C:\Anaconda3\share\jupyter\kernels\sas. Contrary to my expectation, I can't find this folder.

 

I could not figure out what I was doing wrong with the SASPy installation in my second laptop.

 

Any help toward resolving the issues would be greatly appreciated.

 

Thanks,

 

@muhuri , what is the status of the saspy install on the second laptop? Is it up and running? 

As for the sas_kernel, if you did the pip install but the kernelspec list doesn't show anything, then the log (output) from running 'pip install sas_kernel' would be the thing to see. 

Hi sastpw. Thanks for your reply.  Below is the log (output) from running 'pip install sas_kernel'.  What should I look for in the log?

 

*******************************

(base) C:\Users\Pradip Muhuri>pip install sas_kernel
Requirement already satisfied: sas_kernel in c:\anaconda3\lib\site-packages (2.2.0)
Requirement already satisfied: jupyter-client>=4.4.0 in c:\anaconda3\lib\site-packages (from sas_kernel) (5.2.4)
Requirement already satisfied: pygments in c:\anaconda3\lib\site-packages (from sas_kernel) (2.3.1)
Requirement already satisfied: saspy>=2.2.7 in c:\anaconda3\lib\site-packages (from sas_kernel) (2.4.2)
Requirement already satisfied: ipython>=4.0.0 in c:\anaconda3\lib\site-packages (from sas_kernel) (7.2.0)
Requirement already satisfied: metakernel>=0.18.0 in c:\anaconda3\lib\site-packages (from sas_kernel) (0.20.14)
Requirement already satisfied: jupyter-core in c:\anaconda3\lib\site-packages (from jupyter-client>=4.4.0->sas_kernel) (4.4.0)
Requirement already satisfied: python-dateutil>=2.1 in c:\anaconda3\lib\site-packages (from jupyter-client>=4.4.0->sas_kernel) (2.7.5)
Requirement already satisfied: tornado>=4.1 in c:\anaconda3\lib\site-packages (from jupyter-client>=4.4.0->sas_kernel) (5.1.1)
Requirement already satisfied: traitlets in c:\anaconda3\lib\site-packages (from jupyter-client>=4.4.0->sas_kernel) (4.3.2)
Requirement already satisfied: pyzmq>=13 in c:\anaconda3\lib\site-packages (from jupyter-client>=4.4.0->sas_kernel) (17.1.2)
Requirement already satisfied: prompt-toolkit<2.1.0,>=2.0.0 in c:\anaconda3\lib\site-packages (from ipython>=4.0.0->sas_kernel) (2.0.7)
Requirement already satisfied: colorama; sys_platform == "win32" in c:\anaconda3\lib\site-packages (from ipython>=4.0.0->sas_kernel) (0.4.1)
Requirement already satisfied: decorator in c:\anaconda3\lib\site-packages (from ipython>=4.0.0->sas_kernel) (4.3.0)
Requirement already satisfied: backcall in c:\anaconda3\lib\site-packages (from ipython>=4.0.0->sas_kernel) (0.1.0)
Requirement already satisfied: pickleshare in c:\anaconda3\lib\site-packages (from ipython>=4.0.0->sas_kernel) (0.7.5)
Requirement already satisfied: jedi>=0.10 in c:\anaconda3\lib\site-packages (from ipython>=4.0.0->sas_kernel) (0.13.2)
Requirement already satisfied: setuptools>=18.5 in c:\anaconda3\lib\site-packages (from ipython>=4.0.0->sas_kernel) (40.6.3)
Requirement already satisfied: pexpect>=4.2 in c:\anaconda3\lib\site-packages (from metakernel>=0.18.0->sas_kernel) (4.6.0)
Requirement already satisfied: ipykernel<6.0 in c:\anaconda3\lib\site-packages (from metakernel>=0.18.0->sas_kernel) (5.1.0)
Requirement already satisfied: six>=1.5 in c:\anaconda3\lib\site-packages (from python-dateutil>=2.1->jupyter-client>=4.4.0->sas_kernel) (1.12.0)
Requirement already satisfied: ipython-genutils in c:\anaconda3\lib\site-packages (from traitlets->jupyter-client>=4.4.0->sas_kernel) (0.2.0)
Requirement already satisfied: wcwidth in c:\anaconda3\lib\site-packages (from prompt-toolkit<2.1.0,>=2.0.0->ipython>=4.0.0->sas_kernel) (0.1.7)
Requirement already satisfied: parso>=0.3.0 in c:\anaconda3\lib\site-packages (from jedi>=0.10->ipython>=4.0.0->sas_kernel) (0.3.1)
Requirement already satisfied: ptyprocess>=0.5 in c:\anaconda3\lib\site-packages (from pexpect>=4.2->metakernel>=0.18.0->sas_kernel) (0.6.0)

Well, looking for an error or something unusual. That appears clean, although it didn't really install anything as it thinks everything's up to date, I would try uninstalling sas_kernel and then installing it again and look at the log. I can't tell what the original install log output would have been.

Is saspy installed and working?

 

Thanks,

Tom

Hello Tom.

I have uninstalled sas_kernel as well as SASPy and then reinstalled them.

I then did the following:

Spoiler
 

(base) C:\Users\Pradip Muhuri>jupyter kernelspec list
Available kernels:
python3 C:\Anaconda3\share\jupyter\kernels\python3

 

Issues:  On Jupyter notebook launcher, I see the Python kernel but not the SAS kernel. I can't run even a Python job in Jupyter Lab setting on this laptop although there are no issues with SASPy and SAS runs in the other laptop. 

Any further help would be appreciated.

Thanks,

Pradip

            

 

Well, I really don't have anything to go on. Can I see the log from the install? When you say ' I can't run even a Python job in Jupyter Lab setting on this laptop', you mean any python code? What happens? Can you show what error you get?

Thanks,

Tom

Hello Tom,

 

Please see my responses below - (1), (2), and (3) below.

Thanks,

(1) Below is the log from running pip install sas_kernel.

 

(base) C:\Users\Pradip Muhuri>pip install sas_kernel

Requirement already satisfied: sas_kernel in c:\anaconda3\lib\site-packages (2.2.0)

Requirement already satisfied: jupyter-client>=4.4.0 in c:\anaconda3\lib\site-packages (from sas_kernel) (5.2.4)

Requirement already satisfied: saspy>=2.2.7 in c:\anaconda3\lib\site-packages (from sas_kernel) (2.4.3)

Requirement already satisfied: ipython>=4.0.0 in c:\anaconda3\lib\site-packages (from sas_kernel) (7.2.0)

Requirement already satisfied: metakernel>=0.18.0 in c:\anaconda3\lib\site-packages (from sas_kernel) (0.20.14)

Requirement already satisfied: pygments in c:\anaconda3\lib\site-packages (from sas_kernel) (2.3.1)

Requirement already satisfied: pyzmq>=13 in c:\anaconda3\lib\site-packages (from jupyter-client>=4.4.0->sas_kernel) (17.1.2)

Requirement already satisfied: traitlets in c:\anaconda3\lib\site-packages (from jupyter-client>=4.4.0->sas_kernel) (4.3.2)

Requirement already satisfied: jupyter-core in c:\anaconda3\lib\site-packages (from jupyter-client>=4.4.0->sas_kernel) (4.4.0)

Requirement already satisfied: tornado>=4.1 in c:\anaconda3\lib\site-packages (from jupyter-client>=4.4.0->sas_kernel) (5.1.1)

Requirement already satisfied: python-dateutil>=2.1 in c:\anaconda3\lib\site-packages (from jupyter-client>=4.4.0->sas_kernel) (2.7.5)

Requirement already satisfied: setuptools>=18.5 in c:\anaconda3\lib\site-packages (from ipython>=4.0.0->sas_kernel) (40.6.3)

Requirement already satisfied: colorama; sys_platform == "win32" in c:\anaconda3\lib\site-packages (from ipython>=4.0.0->sas_kernel) (0.4.1)

Requirement already satisfied: jedi>=0.10 in c:\anaconda3\lib\site-packages (from ipython>=4.0.0->sas_kernel) (0.13.2)

Requirement already satisfied: prompt-toolkit<2.1.0,>=2.0.0 in c:\anaconda3\lib\site-packages (from ipython>=4.0.0->sas_kernel) (2.0.7)

Requirement already satisfied: pickleshare in c:\anaconda3\lib\site-packages (from ipython>=4.0.0->sas_kernel) (0.7.5)

Requirement already satisfied: backcall in c:\anaconda3\lib\site-packages (from ipython>=4.0.0->sas_kernel) (0.1.0)

Requirement already satisfied: decorator in c:\anaconda3\lib\site-packages (from ipython>=4.0.0->sas_kernel) (4.3.0)

Requirement already satisfied: pexpect>=4.2 in c:\anaconda3\lib\site-packages (from metakernel>=0.18.0->sas_kernel) (4.6.0)

Requirement already satisfied: ipykernel<6.0 in c:\anaconda3\lib\site-packages (from metakernel>=0.18.0->sas_kernel) (5.1.0)

Requirement already satisfied: ipython-genutils in c:\anaconda3\lib\site-packages (from traitlets->jupyter-client>=4.4.0->sas_kernel) (0.2.0)

Requirement already satisfied: six in c:\anaconda3\lib\site-packages (from traitlets->jupyter-client>=4.4.0->sas_kernel) (1.12.0)

Requirement already satisfied: parso>=0.3.0 in c:\anaconda3\lib\site-packages (from jedi>=0.10->ipython>=4.0.0->sas_kernel) (0.3.1)

Requirement already satisfied: wcwidth in c:\anaconda3\lib\site-packages (from prompt-toolkit<2.1.0,>=2.0.0->ipython>=4.0.0->sas_kernel) (0.1.7)

Requirement already satisfied: ptyprocess>=0.5 in c:\anaconda3\lib\site-packages (from pexpect>=4.2->metakernel>=0.18.0->sas_kernel) (0.6.0)

 

 

(2) Below is the log from running pip install saspy.

 

(base) C:\Users\Pradip Muhuri>pip install saspy

Requirement already satisfied: saspy in c:\anaconda3\lib\site-packages (2.4.3)

Requirement already satisfied: ipython>=4.0.0 in c:\anaconda3\lib\site-packages (from saspy) (7.2.0)

Requirement already satisfied: pygments in c:\anaconda3\lib\site-packages (from saspy) (2.3.1)

Requirement already satisfied: backcall in c:\anaconda3\lib\site-packages (from ipython>=4.0.0->saspy) (0.1.0)

Requirement already satisfied: prompt-toolkit<2.1.0,>=2.0.0 in c:\anaconda3\lib\site-packages (from ipython>=4.0.0->saspy) (2.0.7)

Requirement already satisfied: jedi>=0.10 in c:\anaconda3\lib\site-packages (from ipython>=4.0.0->saspy) (0.13.2)

Requirement already satisfied: traitlets>=4.2 in c:\anaconda3\lib\site-packages (from ipython>=4.0.0->saspy) (4.3.2)

Requirement already satisfied: decorator in c:\anaconda3\lib\site-packages (from ipython>=4.0.0->saspy) (4.3.0)

Requirement already satisfied: colorama; sys_platform == "win32" in c:\anaconda3\lib\site-packages (from ipython>=4.0.0->saspy) (0.4.1)

Requirement already satisfied: pickleshare in c:\anaconda3\lib\site-packages (from ipython>=4.0.0->saspy) (0.7.5)

Requirement already satisfied: setuptools>=18.5 in c:\anaconda3\lib\site-packages (from ipython>=4.0.0->saspy) (40.6.3)

Requirement already satisfied: wcwidth in c:\anaconda3\lib\site-packages (from prompt-toolkit<2.1.0,>=2.0.0->ipython>=4.0.0->saspy) (0.1.7)

Requirement already satisfied: six>=1.9.0 in c:\anaconda3\lib\site-packages (from prompt-toolkit<2.1.0,>=2.0.0->ipython>=4.0.0->saspy) (1.12.0)

Requirement already satisfied: parso>=0.3.0 in c:\anaconda3\lib\site-packages (from jedi>=0.10->ipython>=4.0.0->saspy) (0.3.1)

Requirement already satisfied: ipython-genutils in c:\anaconda3\lib\site-packages (from traitlets>=4.2->ipython>=4.0.0->saspy) (0.2.0)

 

(3) When I submit my Python code in Jupyter Lab setting, I get a dead kernel ("No Kernel").

 

 

Those logs show that each had already been installed, so they did nothing. They aren't the logs from the attempt that actually tried to install the packages; so there's really nothing that shows if there were any problems or not when it did install these. If jupyter itself doesn't work, then there's really no telling if saspy and sas_kernel would work. I really have no idea what's wrong with that system. Maybe uninstall/delete anaconda and start fresh? Does python work, outside of jupyter? you can run saspy from a python shell - it doesn't require jupyter. Did you restart jupyter after trying to install the other packages? Roboot your pc? 

 

(1) I have uninstalled and then installed Anaconda twice.

(2) I have run saspy from the Anaconda python shell. There appear to some problems - ImportError and NameError.

The log from that run is shown below.

*****************************************************************************************************************************

C:\Anaconda3>python

Python 3.7.1 (default, Dec 10 2018, 22:54:23) [MSC v.1915 64 bit (AMD64)] :: Anaconda, Inc. on win32

Type "help", "copyright", "credits" or "license" for more information.

>>> import saspy

>>> import pandas as pd

Traceback (most recent call last):

  File "<stdin>", line 1, in <module>

  File "C:\Anaconda3\lib\site-packages\pandas\__init__.py", line 19, in <module>

    "Missing required dependencies {0}".format(missing_dependencies))

ImportError: Missing required dependencies ['numpy']

>>> sas = saspy.SASsession(cfgname = 'winlocal')

SAS Connection established. Subprocess id is 8288

 

>>> mydata = sas.sasdata('class', 'sashelp')

>>> mydata.head()

Traceback (most recent call last):

  File "<stdin>", line 1, in <module>

  File "C:\Anaconda3\lib\site-packages\saspy\sasdata.py", line 212, in head

    return self._returnPD(code, '_head')

  File "C:\Anaconda3\lib\site-packages\saspy\sasdata.py", line 163, in _returnPD

    pd = self.sas._io.sasdata2dataframe(tablename, libref)

  File "C:\Anaconda3\lib\site-packages\saspy\sasioiom.py", line 1642, in sasdata2dataframe

    tdf = pd.DataFrame.from_records(r, columns=varlist)

NameError: name 'pd' is not defined

 

******************

(3) Also please note that I two versions of Python in my computer.

************************************************

C:\Anaconda3>where python

C:\Anaconda3\python.exe

C:\Users\Pradip Muhuri\AppData\Local\Programs\Python\Python37\python.exe

*********************************************

Any help would be appreciated.

Thanks,

Pradip

 

 

Hello,

Please ignore my previous posting.

 

Running  the code from a different python shell suggests that Python/SASPy  is working.

 

***************************

(base) C:\Users\Pradip Muhuri>python
Python 3.7.1 (default, Dec 10 2018, 22:54:23) [MSC v.1915 64 bit (AMD64)] :: Anaconda, Inc. on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import saspy
>>> import pandas as pd
>>> sas = saspy.SASsession(cfgname = 'winlocal')
SAS Connection established. Subprocess id is 3668

>>> mydata = sas.sasdata('class', 'sashelp')
>>> mydata.head()
Name Sex Age Height Weight
0 Alfred M 14 69.0 112.5
1 Alice F 13 56.5 84.0
2 Barbara F 13 65.3 98.0
3 Carol F 14 62.8 102.5
4 Henry M 14 63.5 102.5

 

********************

Issues: Python in Jupyter Lab does not work - dead kernel ("No kernel"). On the Jupyter Lab Launcher page, there is no SAS  logo.

 

Any help would be appreciated.

 

Thanks,

 

Pradip

 

I think if you went to one version of python installed on that machine then you would have better luck. Then when you install something, you know where it was installed and when you run something you know you're running what you installed. I think things are mixed up between your different python installations.

1) I uninstalled both versions of Python and then installed Anaconda Distribution of Python. Now I only have one installation of Python. 

(base) C:\Users\Pradip Muhuri>where python
C:\Anaconda3\python.exe

 

2)  SASPy works fine outside of Jupyter.

 

3) Issue: I don't see the kernal for SAS when I do the following:

(base) C:\Users\Pradip Muhuri>jupyter kernelspec list
Available kernels:
python3 C:\Anaconda3\share\jupyter\kernels\python3

 

4) Issue: Running Jupyter Lab gives me the following log as well as dead kernel

 

AttributeError: module 'pickle' has no attribute 'HIGHEST_PROTOCOL'
[W 16:00:42.567 LabApp] KernelRestarter: restart failed
[W 16:00:42.567 LabApp] Kernel fe8ad58e-6457-4d69-9ea5-1a0a47c515bb died, removing from map.
[W 16:00:52.657 LabApp] Timeout waiting for kernel_info reply from 2f35a595-4817-4179-b0b6-995c4ff8986d
[E 16:00:52.699 LabApp] Error opening stream: HTTP 404: Not Found (Kernel does not exist: 2f35a595-4817-4179-b0b6-995c4ff8986d)
[E 16:00:52.711 LabApp] Error opening stream: HTTP 404: Not Found (Kernel does not exist: 2f35a595-4817-4179-b0b6-995c4ff8986d)

 

Any thoughts toward resolving the issue?

 

Thanks,

 

 

 

Well, that should help at least. I don't know why Jupyter doesn't work. But given it doesn't work, the sas_kernel not showing up could be subordinate to that. But, I've still never see the log from trying to install the sas_kernel (one where it actually tried to install), to see if there's anything in there that could help diagnose this. So, I still really don't have any ideas on that part yet either. Jupyter would certainly need to work before trying to diagnose whether the sas_kernel installs right though. As you see on your other machine where this all works, there really not much to that. If saspy is set up and working. you just install the sas_kernel and it uses saspy, so there's not much to go wrong. Figuring out why Jupyter doesn't work is the first thing that has to be resolved.

I'm having issues getting this working. 

I'm attempting to install this on a windows 10 machine.

I'm running SAS 9.4 (TS1M4 MBCS3170)

After installing anaconda, when I run python --version from cmd prompt, I get "Python 3.7.4"

FYI - when I downloaded Anaconda (Now version 3.7) it installs under C:\Users\username\appData\local\Continuum\anaconda3, not directly in C.

 

When I attempt to run the command (in anaconda prompt): pip install sas_kernal, Iget a message that says:

ERROR: could not find a version that satisfies the requirement sas_kernal (from versions: none)

 

'pip install saspy' works fine.

 

I tried downloading the packages direclty from github and running: pip install . (as recommended in the comments above)

Again, saspy seems to install ok.

When trying in SAS_kernal, I get a very verbose log statement that says (among other things) NameError: name 'install_kernal_spec' is not defined

 

Hi @tf11, sorry you're having trouble! You'll get help much faster if you post your question on one of the product forums in here, like the SAS Studio Community: https://communities.sas.com/t5/SAS-Studio/bd-p/sas_studio More experts are monitoring the forums than comments on an older library article.

Hi @tf11 ! Is it possible that your problem is misspelling kernel as kernal? Sorry I can’t be much more help if it isn’t that, and you can follow @BeverlyBrown advice to make a new post. 🙂

I am really a newbie here to Python and Jupyter.

 

I followed the "instructions" offered in this article but using the common examples in a Jupyter Notebook  Code box  give me SILENCE! 

 

Like I said, I am new. I uninstalled and reinstalled to make sure that I did not miss any steps, creating the sascfg_personal.py config file per my SAS 9.4 installation. Jupyter Notebook, invoking the SAS kernel, but I still received the same silent treatment.

 

I need a hint, for how to troubleshoot.

 

In revising the sascfg_personal.py file, one thing that I did was to indicate that my SAS install is not in c:\Program Files\SASHome\ ... , but in c:\Program Files\SAS . I did not tinker with any other *.py files.

 

Any help will be appreciated -- my current sascfg_personal.py file is below:

 

#
# Copyright SAS Institute
#
#  Licensed under the Apache License, Version 2.0 (the License);
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.
#

# THIS IS AN EXAMPLE CONFIG FILE. PLEASE CREATE YOUR OWN sascfg_personal.py FILE USING THE APPROPRIATE TEMPLATES FROM BELOW
# SEE THE CONFIGURATION DOC AT https://sassoftware.github.io/saspy/install.html#configuration


# Configuration Names for SAS - python List
# This is the list of allowed configuration definitions that can be used. The definition are defined below.
# if there is more than one name in the list, and cfgname= is not specified in SASsession(), then the user
# will be prompted to choose which configuration to use.
#
# The various options for the different access methods can be specified on the SASsession() i.e.:
# sas = SASsession(cfgname='default', options='-fullstimer', user='me')
#
# Based upon the lock_down configuration option below, you may or may not be able to override option
# that are defined already. Any necessary option (like user, pw for IOM or HTTP) that are not defined will be 
# prompted for at run time. To dissallow overrides of as OPTION, when you don't have a value, simply
# specify options=''. This way it's specified so it can't be overridden, even though you don't have any
# specific value you want applied.
# 
#SAS_config_names = ['default', 'ssh', 'iomlinux', 'iomwin', 'winlocal', 'winiomlinux', 'winiomwin', 'httpsviya', 'httpviya', 'iomcom']
#

SAS_config_names=['winlocal']

# Configuration options for saspy - python Dict
# valid key are:
# 
# 'lock_down' - True | False. True = Prevent runtime overrides of SAS_Config values below
#
# 'verbose'   - True | False. True = Allow print statements for debug type messages
#
SAS_config_options = {'lock_down': False,
                      'verbose'  : True
                     }

# Configuration options for SAS output. By default output is HTML 5.0 (using "ods html5" statement) but certain templates might not work 
# properly with HTML 5.0 so it can also be set to HTML 4.0 instead (using "ods html" statement). This option will only work when using IOM
# in local mode. Note that HTML 4.0 will generate images separately which clutters the workspace and if you download the notebook as HTML, 
# the HTML file will need to be put in the same folder as the images for them to appear.
# valid key are:
# 
# 'output' = ['html5', 'html']
#
SAS_output_options = {'output' : 'html5'}


# Configuration Definitions
#
# For STDIO and STDIO over SSH access methods
# These need path to SAS and optional startup options - python Dict
# The default path to the sas start up script is: /opt/sasinside/SAS/SASFoundation/9.4/sas
# A usual install path is: /opt/sasinside/SAS
#
# Since python uses utf-8, running SAS with encoding=utf-8 is the expected use case. By default Unix SAS runs in Latin1 (iso-8859-1),
# which does not work well as utf-8. So, transcoding has been implemented in the python layer. The 'encoding' option can be specified to match
# the SAS session encoding (see https://docs.python.org/3.5/library/codecs.html#standard-encodings for python encoding values). latin1 is appropriate
# for the default Unix SAS session encoding
#                                                                                                         
# valid keys are:
# 'saspath'  - [REQUIRED] path to SAS startup script i.e.: /opt/sasinside/SAS/SASFoundation/9.4/sas
# 'options'  - SAS options to include in the start up command line - Python List
# 'encoding' - This is the python encoding value that matches the SAS session encoding your SAS session is using 
#
# For passwordless ssh connection, the following are also reuqired:
# 'ssh'     - [REQUIRED] the ssh command to run
# 'host'    - [REQUIRED] the host to connect to
#
# Additional valid keys for ssh:
# 'port'    - [integer] the remote ssh port
# 'tunnel'  - [integer] local port to open via reverse tunnel, if remote host cannot otherwise reach this client
#
default  = {'saspath'  : '/opt/sasinside/SAS/SASFoundation/9.4/bin/sas_u8'
            }

ssh      = {'saspath' : '/opt/sasinside/SAS/SASFoundation/9.4/bin/sas_en',
            'ssh'     : '/usr/bin/ssh',
            'host'    : 'remote.linux.host', 
            'encoding': 'latin1',
            'options' : ["-fullstimer"]
            }


# For IOM (Grid Manager or any IOM) and Local Windows via IOM access method
# These configuration definitions are for connecting over IOM. This is designed to be used to connect to a SAS Grid, via Grid Manager
# and also to connect to a local Windows SAS session. The client side (python and java) for this access method can be either Linux or Windows.
# The STDIO access method above is only for Linux. PC SAS requires this IOM interface.
#
# The absence of the iomhost option triggers local Windows SAS mode. In this case none of 'iomhost', 'iomport', 'omruser', 'omrpw' are needed.
# a local SAS session is started up and connected to.
#
# Since python uses utf-8, running SAS with encoding=utf-8 is the expected use case. By default Windows SAS runs in WLatin1 (windows-1252),
# which does not work well as utf-8. So, transcoding has been implemented in the python layer. The 'encoding' option can be specified to match
# the SAS session encoding (see https://docs.python.org/3.5/library/codecs.html#standard-encodings for python encoding values). windows-1252 is appropriate
# for the default Windows SAS session encoding
#                                                                                                         
# Since this IOM access method uses the Java IOM client, a classpath is required for the java process to find the necessary jars. Use the template below
# to build out a classpath variable and assign that to the 'classpath' option in the configuration definition. The IOM client jars are delivered as part
# of a Base SAS install, so should be available in any SAS install. The saspyiom.jar is available in the saspy repo/install. 
#
# NONE OF THE PATHS IN THESE EAMPLES ARE RIGHT FOR YOUT INSTALL. YOU HAVE TO CHANGE THE PATHS TO BE CORRECT FOR YOUR INSTALLATION 
#
# valid keys are:
# 'java'      - [REQUIRED] the path to the java executable to use
# 'iomhost'   - [REQUIRED for remote IOM case, Don't specify to use a local Windows Session] the resolvable host name, or ip to the IOM server to connect to
# 'iomport'   - [REQUIRED for remote IOM case, Don't specify to use a local Windows Session] the port IOM is listening on
# 'authkey'   - identifier for user/password credentials to read from .authinfo file. Eliminates prompting for credentials.
# 'omruser'   - not suggested        [REQUIRED for remote IOM case but PROMPTED for at runtime] Don't specify to use a local Windows Session
# 'omrpw'     - really not suggested [REQUIRED for remote IOM case but PROMPTED for at runtime] Don't specify to use a local Windows Session
# 'encoding'  - This is the python encoding value that matches the SAS session encoding of the IOM server you are connecting to
# 'classpath' - [REQUIRED] classpath to IOM client jars and saspy client jar.
# 'appserver' - name of physical workspace server (when more than one app server defined in OMR) i.e.: 'SASApp - Workspace Server'
# 'sspi'      - boolean. use IWA instead of user/pw to connect to the IOM workspace server


# build out a local classpath variable to use below for Linux clients  CHANGE THE PATHS TO BE CORRECT FOR YOUR INSTALLATION 
cpL  =  "/opt/sasinside/SAS/SASDeploymentManager/9.4/products/deploywiz__94400__prt__xx__sp0__1/deploywiz/sas.svc.connection.jar"
cpL += ":/opt/sasinside/SAS/SASDeploymentManager/9.4/products/deploywiz__94400__prt__xx__sp0__1/deploywiz/log4j.jar"
cpL += ":/opt/sasinside/SAS/SASDeploymentManager/9.4/products/deploywiz__94400__prt__xx__sp0__1/deploywiz/sas.security.sspi.jar"
cpL += ":/opt/sasinside/SAS/SASDeploymentManager/9.4/products/deploywiz__94400__prt__xx__sp0__1/deploywiz/sas.core.jar"
cpL += ":/opt/github/saspy/java/saspyiom.jar"

iomlinux = {'java'      : '/usr/bin/java',
            'iomhost'   : 'linux.iom.host',
            'iomport'   : 8591,
            'encoding'  : 'latin1',
            'classpath' : cpL
            }           

iomwin   = {'java'      : '/usr/bin/java',
            'iomhost'   : 'windows.iom.host',
            'iomport'   : 8591,
            'encoding'  : 'windows-1252',
            'classpath' : cpL
            }

         
# build out a local classpath variable to use below for Windows clients   CHANGE THE PATHS TO BE CORRECT FOR YOUR INSTALLATION 
cpW  =  "C:\\Program Files\\SAS\\SASDeploymentManager\\9.4\\products\\deploywiz__94474__prt__xx__sp0__1\\deploywiz\\sas.svc.connection.jar"
cpW += ";C:\\Program Files\\SAS\\SASDeploymentManager\\9.4\\products\\deploywiz__94474__prt__xx__sp0__1\\deploywiz\\log4j.jar"
cpW += ";C:\\Program Files\\SAS\\SASDeploymentManager\\9.4\\products\\deploywiz__94474__prt__xx__sp0__1\\deploywiz\\sas.security.sspi.jar"
cpW += ";C:\\Program Files\\SAS\\SASDeploymentManager\\9.4\\products\\deploywiz__94474__prt__xx__sp0__1\\deploywiz\\sas.core.jar"
cpW += ";C:\\ProgramData\\Anaconda3\\Lib\\site-packages\\saspy\\java\\saspyiom.jar"

# These jars provide CORBA support for Java 10+ which no longer provides CORBA itself.  CHANGE THE PATHS TO BE CORRECT FOR YOUR INSTALLATION 
cpW += ";C:\\ProgramData\\Anaconda3\\Lib\\site-packages\\saspy\\java\\thirdparty\\glassfish-corba-internal-api.jar"
cpW += ";C:\\ProgramData\\Anaconda3\\Lib\\site-packages\\saspy\\java\\thirdparty\\glassfish-corba-omgapi.jar"
cpW += ";C:\\ProgramData\\Anaconda3\\Lib\\site-packages\\saspy\\java\\thirdparty\\glassfish-corba-orb.jar"
cpW += ";C:\\ProgramData\\Anaconda3\\Lib\\site-packages\\saspy\\java\\thirdparty\\pfl-basic.jar"
cpW += ";C:\\ProgramData\\Anaconda3\\Lib\\site-packages\\saspy\\java\\thirdparty\\pfl-tf.jar"

# And, if you've configured IOM to use Encryption, you need these client side jars.  CHANGE THE PATHS TO BE CORRECT FOR YOUR INSTALLATION 
#cpW += ";C:\\Program Files\\SAS\\SASVersionedJarRepository\\eclipse\\plugins\\sas.rutil_904300.0.0.20150204190000_v940m3\\sas.rutil.jar"
#cpW += ";C:\\Program Files\\SAS\\SASVersionedJarRepository\\eclipse\\plugins\\sas.rutil.nls_904300.0.0.20150204190000_v940m3\\sas.rutil.nls.jar"
#cpW += ";C:\\Program Files\\SAS\\SASVersionedJarRepository\\eclipse\\plugins\\sastpj.rutil_6.1.0.0_SAS_20121211183517\\sastpj.rutil.jar"


winlocal = {'java'      : 'C:\\Program Files\\SAS\\SASPrivateJavaRuntimeEnvironment\\9.4\\jre\\bin\\java.exe'
            'encoding'  : 'windows-1252',
            'classpath' : cpW
            }

winiomlinux = {'java'   : 'java',
            'iomhost'   : 'linux.iom.host',
            'iomport'   : 8591,
            'encoding'  : 'latin1',
            'classpath' : cpW
            }

winiomwin  = {'java'    : 'java',
            'iomhost'   : 'windows.iom.host',
            'iomport'   : 8591,
            'encoding'  : 'windows-1252',
            'classpath' : cpW
            }

winiomIWA  = {'java'    : 'java',
            'iomhost'   : 'windows.iom.host',
            'iomport'   : 8591,
            'encoding'  : 'windows-1252',
            'classpath' : cpW,
            'sspi'      : True
            }


# For Remote and Local IOM access methods using COM interface
# These configuration definitions are for connecting over IOM using COM. This
# access method is for Windows clients connecting to remote hosts. Local
# SAS instances may also be supported.
#
# This access method does not require a Java dependency.
#
# Valid Keys:
#   iomhost     - Required for remote connections only. The Resolvable SAS
#                 server dns name.
#   iomport     - Required for remote connections only. The SAS workspace
#                 server port. Generally 8591 on standard remote
#                 installations. For local connections, 0 is the default.
#   class_id    - Required for remote connections only. The IOM workspace
#                 server class identifier. Use `PROC IOMOPERATE` to identify
#                 the correct value. This option is ignored on local connections.
#   provider    - [REQUIRED] IOM provider. "sas.iomprovider" is recommended.
#   encoding    - This is the python encoding value that matches the SAS
#                 session encoding of the IOM server.
#   omruser     - SAS user. This option is ignored on local connections.
#   omrpw       - SAS password. This option is ignored on local connections.
#   authkey     - Identifier for credentials to read from .authinfo file.

iomcom = {
    'iomhost': 'mynode.mycompany.org',
    'iomport': 8591,
    'class_id': '440196d4-90f0-11d0-9f41-00a024bb830c',
    'provider': 'sas.iomprovider',
    'encoding': 'windows-1252'}


# HTTP access method to connect to the Compute Service
# These need ip addr, other values will be prompted for - python Dict
# valid keys are:
# 'ip'      - [REQUIRED] host address 
# 'port'    - port; the code Defaults this to based upon the 'ssl' key; 443 default else 80
# 'ssl'     - whether to use HTTPS or just HTTP protocal. Default is True, using ssl and poort 443
# 'context' - context name defined on the compute service  [PROMTED for at runtime if more than one defined]
# 'authkey' - identifier for user/password credentials to read from .authinfo file. Eliminates prompting for credentials.
# 'options' - SAS options to include (no '-' (dashes), just option names and values)
# 'user'    - not suggested [REQUIRED but PROMTED for at runtime]
# 'pw'      - really not suggested [REQUIRED but PROMTED for at runtime]
# 
#
             
httpsviya = {'ip'      : 'sastpw.rndk8s.openstack.sas.com',
             'context' : 'Data Mining compute context',
             'authkey' : 'viya_user-pw',
             'options' : ["fullstimer", "memsize=1G"]
             }

httpviya = {'ip'      : 'sastpw.rndk8s.openstack.sas.com',
            'ssl'     : False,  # this will use port 80
            'context' : 'Data Mining compute context',
            'authkey' : 'viya_user-pw',
            'options' : ["fullstimer", "memsize=1G"]
            }

Thank you. Also, if there is someone I should really get in touch with, please let me know.

... a bit more ...

 

I started my J Notebook from a DOS Command Prompt (as admin), and received this:

 

[I 09:31:28.030 NotebookApp] Creating new notebook in
[I 09:31:29.500 NotebookApp] Kernel started: 34a0aaa7-5f16-468d-a91b-641f69be8267
[IPKernelApp] ERROR | Exception in message handler:
Traceback (most recent call last):
  File "C:\ProgramData\Anaconda3\lib\site-packages\ipykernel\kernelbase.py", line 272, in dispatch_shell
    yield gen.maybe_future(handler(stream, idents, msg))
  File "C:\ProgramData\Anaconda3\lib\site-packages\tornado\gen.py", line 735, in run
    value = future.result()
  File "C:\ProgramData\Anaconda3\lib\site-packages\tornado\gen.py", line 209, in wrapper
    yielded = next(result)
  File "C:\ProgramData\Anaconda3\lib\site-packages\ipykernel\kernelbase.py", line 542, in execute_request
    user_expressions, allow_stdin,
  File "C:\ProgramData\Anaconda3\lib\site-packages\metakernel\_metakernel.py", line 395, in do_execute
    retval = self.do_execute_direct(code)
  File "C:\ProgramData\Anaconda3\lib\site-packages\sas_kernel\kernel.py", line 148, in do_execute_direct
    self._get_lst_len()
  File "C:\ProgramData\Anaconda3\lib\site-packages\sas_kernel\kernel.py", line 73, in _get_lst_len
    res = self.mva.submit(code)
AttributeError: 'NoneType' object has no attribute 'submit'
[I 09:32:06.130 NotebookApp] Saving file at /Untitled.ipynb
[I 09:32:06.156 NotebookApp] Starting buffering for 34a0aaa7-5f16-468d-a91b-641f69be8267:712de6dd5c3b4eda96ca614a5440d847
[W 09:32:08.821 NotebookApp] Forbidden
[W 09:32:08.822 NotebookApp] 403 GET /api/sessions?_=1580576843744 (::1) 1.00ms referer=http://localhost:8888/tree
[W 09:32:08.824 NotebookApp] Forbidden
[W 09:32:08.824 NotebookApp] 403 GET /api/terminals?_=1580576843745 (::1) 1.00ms referer=http://localhost:8888/tree
[W 09:32:11.839 NotebookApp] 403 POST /api/shutdown (::1) 12.01ms referer=http://localhost:8888/tree
[I 09:51:36.991 NotebookApp] Interrupted...
[I 09:51:36.995 NotebookApp] Shutting down 1 kernel
Traceback (most recent call last):
  File "C:\ProgramData\Anaconda3\Scripts\jupyter-notebook-script.py", line 10, in <module>
    sys.exit(main())
  File "C:\ProgramData\Anaconda3\lib\site-packages\jupyter_core\application.py", line 267, in launch_instance
    return super(JupyterApp, cls).launch_instance(argv=argv, **kwargs)
  File "C:\ProgramData\Anaconda3\lib\site-packages\traitlets\config\application.py", line 664, in launch_instance
    app.start()
  File "C:\ProgramData\Anaconda3\lib\site-packages\notebook\notebookapp.py", line 1863, in start
    self.cleanup_kernels()
  File "C:\ProgramData\Anaconda3\lib\site-packages\notebook\notebookapp.py", line 1695, in cleanup_kernels
    self.kernel_manager.shutdown_all()
  File "C:\ProgramData\Anaconda3\lib\site-packages\jupyter_client\multikernelmanager.py", line 160, in shutdown_all
    self.finish_shutdown(kid)
  File "C:\ProgramData\Anaconda3\lib\site-packages\jupyter_client\multikernelmanager.py", line 33, in wrapped
    r = method(*args, **kwargs)
  File "C:\ProgramData\Anaconda3\lib\site-packages\jupyter_client\manager.py", line 282, in finish_shutdown
    time.sleep(pollinterval)
KeyboardInterrupt

 

Hey @ymthum , it looks like you haven't configured the classpath in the saspy config file. As it seems you're trying to run with a local SAS install on your pc, you can try using the autocfg to generate a working config file. You can find examples of this here: https://github.com/sassoftware/saspy-examples/blob/master/SAS_contrib/autocfg.ipynb and the actual configurations instruction for saspy here: https://sassoftware.github.io/saspy/install.html#iom-using-java. 

The SAS_kernel uses saspy, so getting saspy running is the first step before trying to use the sas_kernel. 

You can also post an issue on saspy to get more direct help on it here: https://github.com/sassoftware/saspy/issues

 

 

For newbies like me to Jupyter-lab and SAS in April 2021 :

 

I  got stuck for a week in installing sas kernel. My jupyter lab just cannot show SAS kernel after I installed saspy and sas_kernel successfully.

 

- Systen: Windows 7

- Python: 3.8.5

- saspy: 3.6.7

 

The problem is the new release of sas kernel (2.4.6), which I installed  through pip or pip3, does not work!

Install it from github directory with command

 

pip install git+https://git@github.com/sassoftware/sas_kernel.git@main

You will get sas_kernel 2.4.5, and then it works!

 

The lesson is NEVER to install software that is just released, instead to install a stable version.

 

Besides, if you are also struggling with SASpy set up, you only need to do two steps in 2021

 

1. change SAS_config_names=['default'] into SAS_config_names=['winlocal']

 

2. copy sspiauth.dll from C:\Program Files\SASHome\SASFoundation\9.4\core\sasext

and put it in your java directory, such as C:\Program Files\Java\jdk-16.0.1\bin (do not add its directory to PATH, which does not work).

Version history
Last update:
‎05-25-2020 07:20 PM
Updated by:

sas-innovate-2024.png

Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.

Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.

 

Register now!

Free course: Data Literacy Essentials

Data Literacy is for all, even absolute beginners. Jump on board with this free e-learning  and boost your career prospects.

Get Started

Article Tags