sassoftware / saspy

A Python interface module to the SAS System. It works with Linux, Windows, and Mainframe SAS as well as with SAS in Viya.
https://sassoftware.github.io/saspy
Other
373 stars 150 forks source link

Import error in sasioiom.py #334

Closed ageorgou closed 3 years ago

ageorgou commented 3 years ago

Describe the bug In Windows, connecting to a session using IOM results in an AttributeError from importlib.

To Reproduce Steps to reproduce the behavior:

  1. Specify a configuration to connect to a local Windows session over IOM in sascfg_personal.py:
    winlocal = {'java'      : 'java'
            }
  2. Start an interactive Python shell
  3. import saspy
  4. Try to start a session
    >>> sas = saspy.SASsession()
    Using SAS Config named: winlocal
    Pandas module not available. Setting results to HTML
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "C:\Users\Anastasis\anaconda3\envs\sas\lib\site-packages\saspy\sasbase.py
    ", line 497, in __init__
    self._io = SASsessionIOM(sascfgname=self.sascfg.name, sb=self, **kwargs)
    File "C:\Users\Anastasis\anaconda3\envs\sas\lib\site-packages\saspy\sasioiom.p
    y", line 263, in __init__
    self.sascfg   = SASconfigIOM(self, **kwargs)
    File "C:\Users\Anastasis\anaconda3\envs\sas\lib\site-packages\saspy\sasioiom.p
    y", line 146, in __init__
    cpath = importlib.util.find_spec(self.__module__).origin.replace('sasioiom.p
    y','java')+sep
    AttributeError: module 'importlib' has no attribute 'util'

Expected behavior The call should return a SASsession object.

Desktop (please complete the following information):

Additional context This seems it has to do with how the importlib.util submodule is imported. According to the answer to a very similar bug report, the correct usage would be to change the import in https://github.com/sassoftware/saspy/blob/6410d6f397bca81c5b259abaa95d0fac54702a17/saspy/sasioiom.py#L141-L147 to

import importlib.util

Because of how submodules are imported on different platforms, this may only affect Windows (as mentioned in the linked bug report), or particular version of Python.

I have tried this locally and it seems to work fine. This is the only usage of importlib in the module. Happy to open a pull request with this!

tomweber-sas commented 3 years ago

Wow, that's crazy. I have to imagine that python broke this in a version between what you're running and what I'm running? I happen to have 3.6.0 on my windows box. Haha I had to double take on that; that's the version of saspy right now too, lol! I've never seen a problem with this, but clearly you are having it with your version of python.

Seems completely innocuous to just add the '.util' to the import changing import importlib
to be import importlib.util

so, that's an easy fix. I'm happy to make that change! If you'd like to add that as a PR, go for it; you found it, you can get to fix it if you want :) I'm actually on vacation this coming week, but can easily deal with this either way, even so. You're choice

Thanks! Tom

Here's what happens on my system, FYI:

C:\Users\sastpw>python
Python 3.6.0 |Anaconda 4.3.0 (64-bit)| (default, Dec 23 2016, 11:57:41) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import saspy
>>> sas = saspy.SASsession()
Please enter the name of the SAS Config you wish to run. Available Configs are: ['default', 'SASgrid', 'http', 'httptest', 'ssh', 'httpfred', 'grid', 'tdi', 'iomj', 'iomc', 'iomjwin', 'winiomj', 'winiomjwin', 'winlocal', 'gridiom', 'wingridiom', 'zos', 'zos2', 'winzos', 'winzos2', 'winiomIWA', 'winiomjcom', 'pune', 'pune2', 'notpune', 'iomcom', 'iomcom_loc', 'iomcom_auth', 'itviya', 'carrie1', 'testmkt', 'testmktCOM', 'oda', 'odadev'] winiomj
SAS Connection established. Subprocess id is 8020

No encoding value provided. Will try to determine the correct encoding.
Setting encoding to utf_8 based upon the SAS session encoding value of utf-8.

>>> sas
Access Method         = IOM
SAS Config name       = winiomj
SAS Config file       = C:\ProgramData\Anaconda3\lib\site-packages\saspy\sascfg_personal.py
WORK Path             = /sastmp/SAS_work528B00001B2F_tom64-5/SAS_work1A6F00001B2F_tom64-5/
SAS Version           = 9.04.01M4D11092016
SASPy Version         = 3.6.0
Teach me SAS          = False
Batch                 = False
Results               = Pandas
SAS Session Encoding  = utf-8
Python Encoding value = utf_8
SAS process Pid value = 6959

>>> import importlib
>>> importlib.util.find_spec('saspy')
ModuleSpec(name='saspy', loader=<_frozen_importlib_external.SourceFileLoader object at 0x0000013095072048>, origin='C:\\ProgramData\\Anaconda3\\lib\\site-packages\\saspy\\__init__.py', submodule_search_locations=['C:\\ProgramData\\Anaconda3\\lib\\site-packages\\saspy'])
>>> import importlib.util
>>> importlib.util.find_spec('saspy')
ModuleSpec(name='saspy', loader=<_frozen_importlib_external.SourceFileLoader object at 0x0000013095072048>, origin='C:\\ProgramData\\Anaconda3\\lib\\site-packages\\saspy\\__init__.py', submodule_search_locations=['C:\\ProgramData\\Anaconda3\\lib\\site-packages\\saspy'])
>>> import importlib as boo
>>> boo.util.find_spec('saspy')
ModuleSpec(name='saspy', loader=<_frozen_importlib_external.SourceFileLoader object at 0x0000013095072048>, origin='C:\\ProgramData\\Anaconda3\\lib\\site-packages\\saspy\\__init__.py', submodule_search_locations=['C:\\ProgramData\\Anaconda3\\lib\\site-packages\\saspy'])
>>>
ageorgou commented 3 years ago

That's very strange! I'm still getting the same error on my machine if I use 3.6 (or at least 3.6.2 onwards) or even 3.5. I even tried it on a Red Hat-like virtual machine (on AWS) and it's still the same!

Python 3.5.9 (default, Aug 31 2020, 18:43:21)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-28)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import importlib
>>> importlib.util
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: module 'importlib' has no attribute 'util'
>>> importlib.util.find_spec
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: module 'importlib' has no attribute 'util'
>>> import sys
>>> sys.version
'3.5.9 (default, Aug 31 2020, 18:43:21) \n[GCC 4.8.5 20150623 (Red Hat 4.8.5-28)]'
>>> import importlib.util
>>> importlib.util.find_spec
<function find_spec at 0x7f22862ba6a8>

It must either be very inconsistent across systems, or something that's changed in patch versions: all the versions I could find, even 3.4.7, were released after 3.6.0. It sounds like it's something that only works "accidentally"! I've found another example from Python itself where it seems the intended usage is to import the submodule itself.

I'll open a PR but there's no rush on this from me.

ageorgou commented 3 years ago

For what it's worth, I managed to try with 3.6.0 and that's also failing for me, with the same version you seem to be using.

Python 3.6.0 |Continuum Analytics, Inc.| (default, Dec 23 2016, 11:57:41) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import importlib
>>> importlib.util.find_spec
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: module 'importlib' has no attribute 'util'