Pylance in VS Code reports undefined variable with import * - python

Using VSCode v1.61.0
I have a python package, a single folder named "tfmodules" with a whole lotta modules, and in the init.py I'm doing this:
from os.path import dirname, basename, isfile, join
import glob
modules = glob.glob(join(dirname(__file__), "*.py"))
__all__ = [ basename(f)[:-3] for f in modules if isfile(f) and not f.endswith('__init__.py')]
In my code I import it like so:
from tfmodules import *
Then I call the modules with something like this:
def write(aci_topology_model, provider_source, provider_version):
with open('fabric-bringup.tf', 'w') as f:
x = fabricbringup.tf_write_fabric_bringup(aci_topology_model, provider_source, provider_version)
f.write(x)
fabricbringup is a module in the package.
The code works just fine, but Pylance is throwing 36 reportUndefinedVariable instances, one for each module called.
The specific error (from one of the modules) is:
"fabricbringup" is not defined Pylance(reportUndefinedVariable)
I have selected the proper interpreter for the venv in vs code, and I tried adding this to the settings.json file:
"python.analysis.extraPaths": ["tfmodules", "/home/aj/projects/python/dcnet-aci-lld-convert/tfmodules"]
But I still get the errors from Pylance. What am I doing wrong? Thanks!

Considering you will not be adding any extensions at runtime how about creating a file that will generate all references directly to "__init__.py"?
if __name__ == "__main__":
from os.path import dirname, basename, isfile, join
import glob
modules = glob.glob(join(dirname(__file__), "*.py"))
print(join(dirname(__file__), "*.py"))
__all__ = ["\t\"" +basename(f)[:-3]+"\",\n" for f in modules if isfile(f) and not f.endswith('__init__.py') and not f.endswith('__add__manager.py')]
f = open(join(dirname(__file__), "__init__.py"), "a")
f.write("__all__ = [\n")
f.writelines(__all__)
f.write("]\n")
f.close()
Result will look something like this:
#(previous contents of __init__.py)
__all__ = [
"file1",
"file2",
]

Related

Executing external python script function

I have two scripts in the same folder:
5057_Basic_Flow_Acquire.xyzpy
5006_Basic_Flow_Execute.xyzpy
I need to call function run() from 5057_Basic_Flow_Acquire file in the 5006_Basic_Flow_Execute file.
I tried two approaches:
1.
import time
import os
import sys
import types
dir_path = os.path.dirname(os.path.realpath(__file__))
#os.chdir(str(dir_path))
sys.path.append(str(dir_path))
sensor = __import__('5057_Basic_Flow_Acquire')
import time
import os
import sys
import types
import importlib
import importlib.util
dir_path = os.path.dirname(os.path.realpath(__file__))
spec = importlib.util.spec_from_file_location('run', dir_path+'\\5057_Basic_Flow_Acquire')
module = importlib.util.module_from_spec(spec)
Pycharm is reporting this type of errors:
case:
ModuleNotFoundError: No module named '5057_Basic_Flow_Acquire'
case
AttributeError: 'NoneType' object has no attribute 'loader'
So in both cases module was not found.
Does someone have any suggestion?
You should rename your files to something like :
5057_Basic_Flow_Acquire_xyz.py
5006_Basic_Flow_Execute_xyz.py
so that they are recognized as modules and can be imported.
Then, in your 5057_Basic_Flow_Acquire_xyz module, you can import the run function with the following line :
from 5006_Basic_Flow_Execute_xyz import run
Both files are in the same directory, so you should be able to import without changing your PATH environment variable as the current directory is automatically added at the top of the list.

Importing lists from multiple files

In a little project I have following path-structure:
main.py
Data---
|
__init__.py
Actions_2016_01.py
Actions_2016_02.py
Actions_2016_03.py
... and so on...
Every 'Action_date.py' file includes a list called
data = [something_1, something_2, ...]
Now I am trying get all the data-lists of the 'Action_date.py' files to a single list in the 'main.py' file.
I tried something like
files = os.listdir(os.path.join(os.path.dirname(__name__), 'Data'))
all_data = []
for name in files:
if name.startswith('Actions'):
import Data.name
all_data.extend(name.data)
But this doesn't work at all... I'm getting
ImportError: No module named 'Data.name'
as output.
I found a solution. Simply have to use the importlib module.
You could make your Data package's __init_.py do the work:
def _import_modules():
""" Dynamically import certain modules in the package, extract data in each
of them, and store it in a module global named all_data.
"""
from fnmatch import fnmatch
import traceback
import os
global __all__
__all__ = []
global all_data
all_data = []
globals_, locals_ = globals(), locals()
# dynamically import the desired package modules
for filename in os.listdir(os.path.join(os.path.dirname(__name__), 'Data')):
# process desired python files in directory
if fnmatch(filename, 'Actions*.py'):
modulename = filename.split('.')[0] # filename without extension
package_module = '.'.join([__name__, modulename])
try:
module = __import__(package_module, globals_, locals_, [modulename])
except:
traceback.print_exc()
raise
all_data.extend(module.data)
__all__.append('all_data')
_import_modules()
Which would allow you to do this in main.py:
import Data
print(Data.all_data)
This is an adaption of my answer to the question How to import members of modules within a package?

How to change built_in module in python

I want to change os.path in os.py, but it failed. path is different in different platform.
os.py
import ntpath as path
sys.modules['os.path'] = path
from os.path import (curdir, pardir, sep, pathsep, defpath, extsep, altsep, devnull)
It turns out that
from os.path import (curdir, pardir, sep, pathsep, defpath, extsep, altsep,
devnull)
ImportError: No module named path
Your approach should work. Rename the subdirectory os in your current directory to my_os. Python finds your os directory first and tries to import from there.
Adding this line:
__future__ import absolute_import
to the beginning of the os.py avoids this problem by using absolute imports.
did you try with "__import__" function ?
import mtpath as path
os_path = __import__(path, globals(), locals(), ['curdir', 'pardir', 'sep', 'pathsep', 'defpath', 'extsep', 'altsep', 'devnull']
Then, you can use 'curdir' as :
os_path.curdir
Well, you can also asign it to 'curdir' name as in the documentation :
curdir = os_path.curdir
pardir = os_path.curdir
…

Zipimport with packages

I'm trying to package the pychess package into a zip file and import it with zipimport, but running into some issues.
I've packaged it into a zipfile with the following script, which works:
#!/usr/bin/env python
import zipfile
zf = zipfile.PyZipFile('../pychess.zip.mod', mode='w')
try:
zf.writepy('.')
finally:
zf.close()
for name in zf.namelist():
print name
However, I'm unable to do complicated imports in my code:
z = zipimport.zipimporter('./pychess.zip.mod')
#z.load_module('pychess') # zipimport.ZipImportError: can't find module 'pychess'
#z.load_module('Utils.lutils') # zipimport.ZipImportError: can't find module 'Utils.lutils'
Utils = z.load_module('Utils') # seems to work, but...
from Utils import lutils
#from Utils.lutils import LBoard # ImportError: No module named pychess.Utils.const
How can I import, e.g. pychess.Utils.lutils.LBoard from the zip file?
Here is the full list of modules I need to import:
import pychess
from pychess.Utils.lutils import LBoard
from pychess.Utils.const import *
from pychess.Utils.lutils import lmovegen
from pychess.Utils.lutils import lmove
Thanks!
Assuming you have an unpacked pychess, resulting in a pychess-0.10.1 directory in your current directory and that pychess-0.10.1/lib/pychess exists ( I got that directory from untarring pychess-0.10.1.tar.gz).
First run:
#!/usr/bin/env python
import os
import zipfile
os.chdir('pychess-0.10.1/lib')
zf = zipfile.PyZipFile('../../pychess.zip', mode='w')
try:
zf.writepy('pychess')
finally:
zf.close()
for name in zf.namelist():
print name
after that, this works:
#!/usr/bin/env python
import sys
sys.path.insert(0, 'pychess.zip')
from pychess.Utils.lutils import LBoard

Reload all modules in a directory

I need to reload all the python modules within a specified directory.
I've tried something like this:
import sys, os
import_folder = "C:\\myFolder"
sys.path.insert( 0 , import_folder )
for dir in os.listdir(import_folder):
name = os.path.splitext(dir)[0]
ext = os.path.splitext(dir)[1]
if ext == ".py":
import( eval(name) )
reload( eval(name) )
Anyone know how to do this correctly?
import os # we use os.path.join, os.path.basename
import sys # we use sys.path
import glob # we use glob.glob
import importlib # we use importlib.import_module
import_folder = 'C:\\myFolder'
sys.path.append(import_folder) # this tells python to look in `import_folder` for imports
for src_file in glob.glob(os.path.join(import_folder, '*.py')):
name = os.path.basename(src_file)[:-3]
importlib.import_module(name)
reload(sys.modules[name])
importlib.import_module(name)
There is the code. Now to the semantics of the whole thing: using importlib makes this a little bit more normal, but it still promotes some bugs. You can see that this breaks for source files in a subdirectory. What you should probably do is: import the package, (import the whole folder), and use the . operator like so:
import sys # we use sys.path
sys.path.append('C:\\')
import myFolder
...
myFolder.func1(foo)
myFolder.val
bar = myFolder.Class1()
Perhaps you should take a look at the documentation for modules, but don't forget to update the path to include the parent of the folder you want to import.

Categories