Using Pylint with PyModule generated using PyO3 and maturin - python

Pylint will not recognize any of the functions from a PyModule that I created using PyO3 and maturin. All of the functions import and run fine in the python code base, but for some reason Pylint is throwing E1011: no-member warnings.
Below is a (likely) incomplete dummy example, but is provided in order to show the way I am decorating using pymodule and pyfunction:
#[pyfunction]
fn add_nums(
_py: Python<'_>,
a: f32,
b: f32,
) -> PyResult<f32> {
let res:f32 = a+b;
Ok(res)
}
#[pymodule]
fn my_module(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_pyfunction!(add_nums, m)?)?;
Ok(())
}
Then if I build that using maturin build --release and install the module, from the resulting wheelfile, into my python environment and import into a script:
import my_module
my_module.add_nums(5, 6) # ignore that these are not f32 - irrelevant this is a dummy example
If I then run pylint on that file (from terminal - VS Code pylint extension actually does not complain about this...), I end up with something like: E1101: Module 'my_module' has no 'add-nums' member (no-member) even though the code (not this code - but the real code which I cannot include here) runs just fine.
Has anyone successfully built wheelfiles using maturin, used them in another project, then had Pylint play nicely with that project and recognize that the methods do actually exist?

Pylint has a extension-pkg-allow-list setting which you can use to inspect non-python modules. It will need to load the extension into pylint's interpreter though, which is why it's not enabled by default.
There's also requests to support (and lint) pyi, but AFAIK that's not supported yet, cf #2873 and #4987.
Before Pylint 2.8, the setting is extension-pkg-whitelist.

Similar to the answer by #Masklinn except it looks like the term 'extension-pkg-whitelist' exists in older versions and later the 'extension-pkg-allow-list' does not (though it was introduced for obvious societal reasons).
add the following into the [MASTER] section of your .pylintrc:
[MASTER]
# A comma-separated list of package or module names from where C extensions may
# be loaded. Extensions are loading into the active Python interpreter and may
# run arbitrary code.
extension-pkg-allow-list=
my_module
for versions where this is not supported (someone please update which version it changed here) use the extension-pkg-whitelist instead.

Related

How to configure mypy to ignore a stub file for a specific module?

I installed a "dnspython" package with "pip install dnspython" under Ubuntu 22.10 and made a following short script:
#!/usr/bin/env python3
import dns.zone
import dns.query
zone = dns.zone.Zone("example.net")
dns.query.inbound_xfr("10.0.0.1", zone)
for (name, ttl, rdata) in zone.iterate_rdatas("SOA"):
serial_nr = rdata.serial
When I check this code snippet with mypy(version 0.990), then it reports an error: Module has no attribute "inbound_xfr" [attr-defined] for line number 7.
According to mypy documentation, if a Python file and a stub file are both present in the same directory on the search path, then only the stub file is used. In case of "dnspython", the stub file query.pyi is present in the dns package and the stub file indeed has no attribute "inbound_xfr". When I rename or remove the stub file, then the query.py Python file is used instead of the stub file and mypy no longer complains about missing attribute.
I guess this is a "dnspython" bug? Is there a way to tell to mypy that for query module, the stub file should be ignored?
I would recommend ignoring only the specific wrong line, not the whole module.
dns.query.inbound_xfr("10.0.0.1", zone) # type: ignore[attr-defined]
This will suppress attr-defined error message that is generated on that line. If you're going to take this approach, I'd also recommend running mypy with the --warn-unused-ignores flag, which will report any redundant and unused # type: ignore statements (for example, after updating the library).
Is there a way to tell to mypy that for query module, the stub file should be ignored?
No. Stub files have precedence over modules. Even if you pass the entire path of the stub file to --exclude, it will still see it.
You want to disable a language construct created specifically for definitions, which doesn't seem very logical.
I guess this is a "dnspython" bug?
Yes.
First of all, there is a option --exclude PATTERN to ignore files or directory to check.
According that doc, you should use --follow-imports option to skip the import module checked by mypy:
In particular, --exclude does not affect mypy’s import following.
You can use a per-module follow_imports config option to additionally avoid mypy from following imports and checking code you do not wish to be checked.
Another way, you could configure the Stub files in a specific directory, and using it by export MYPYPATH.

Python & vscode: prob to import another module/package/class

I've some prob to setup my vscode project in python. I try to create a test to test my car module. But, I've always the error
no module found when I try to run ( test_whendrivecar.py)
test_whendrivecare inherited to context.context inherited to baseclasstest ( just some struct of GivenWhenThen test).
I tried to setup in sys.path(c:/users/me/drive) , but that doesn't work to run my test. I 've againt the error no module 'baseclasstest' found or no module 'car' found.
I 've same prob if I tried to create a module on same level that car directory.
here my project struc :
vscode 1.39.2
python 3.7.3
env: create by conda
test framework: unittest
what I tried:
put the path in settings.json "python.autoComplete.extraPaths" - > doesn't work
put the path in launch.json "env": "PYTHONPATH": -> doesn't work
can you help my ? I thought that is easy to use custom module/package in python.
Ohhh I know, python 3.3+ doesn't need init.py I just put that to be sure.
I looking on google, but I don't found anything to help me.
Try to add from drive.car.car import "your class" in your test

Which lib do I import to use create_shortcut() in Python?

I am trying to use the create_shortcut() function in a post-installation script in Python 3.2, per http://docs.python.org/distutils/builtdist.html#the-postinstallation-script . Every time I try to run the function, i get the following:
NameError: name 'create_shortcut' is not defined
I feel like I am missing an import, but I can't seem to find any documentation anywhere on how to get this working.
EDIT
I should have specified earlier my final goal and my environment. I am building an .msi running the following:
python setup.py bdist_msi --initial-target-dir="C:\path\to\install" --install-script="install.py"
The install.py file lives in the same directory as my setup.py.
The final goal is to have a .msi file that installs the application in the specified directory and creates a Start Menu item in a specified location. It would be a nice to have if the installer allows the user to select to create the Start Menu shortcut or a desktop shortcut.
Postinstallation script is to run in the native Windows installation routine.
Fuctions get_special_folder_path, directory_created, directory_created and create_shortcut are not pythonic: for example, they cannot be called as keyword-argument pairs - only positionally. The functions are defined at https://github.com/python/cpython/blob/master/PC/bdist_wininst/install.c
A routine for the shorcut creation acts as a wrapper around system interface IShellLink ( "lives" in shell32.dll ) and starts at line 504:
static PyObject *CreateShortcut(PyObject *self, PyObject *args)
{...
and then is linked at line 643:
PyMethodDef meth[] = {
{"create_shortcut", CreateShortcut, METH_VARARGS, NULL},
{"get_special_folder_path", GetSpecialFolderPath, METH_VARARGS, NULL},
...
};
In your local installation the above C code is already compiled in the executables:
C:\Python26\Lib\distutils\command\wininst-6.0.exe
C:\Python26\Lib\distutils\command\wininst-7.1.exe
C:\Python26\Lib\distutils\command\wininst-8.0.exe
C:\Python26\Lib\distutils\command\wininst-9.0.exe
C:\Python26\Lib\distutils\command\wininst-9.0-amd64.exe
So, answer: There is no python lib to import the function create_shortcut(), it is available as-is only inside a Windows postinstallation script.
If you want to support both automatic and manual postinstall scenarios, look at the pywin32 workaround:
https://github.com/mhammond/pywin32/blob/master/pywin32_postinstall.py line 80
try:
create_shortcut
except NameError:
# Create a function with the same signature as create_shortcut provided
# by bdist_wininst
def create_shortcut(path, description, filename,
arguments="", workdir="", iconpath="", iconindex=0):
import pythoncom
from win32com.shell import shell, shellcon
ilink = pythoncom.CoCreateInstance(shell.CLSID_ShellLink, None,
pythoncom.CLSCTX_INPROC_SERVER,
shell.IID_IShellLink)
ilink.SetPath(path)
ilink.SetDescription(description)
if arguments:
ilink.SetArguments(arguments)
if workdir:
ilink.SetWorkingDirectory(workdir)
if iconpath or iconindex:
ilink.SetIconLocation(iconpath, iconindex)
# now save it.
ipf = ilink.QueryInterface(pythoncom.IID_IPersistFile)
ipf.Save(filename, 0)
As the documentation says:
Starting with Python 2.3, a postinstallation script can be specified with the --install-script option. The basename of the script must be specified, and the script filename must also be listed in the scripts argument to the setup function.
These are windows only options, you need to use it when you build a executable installer of your module. Try:
python setup.py bdist_wininst --help
python setup.py bdist_wininst --install-script postinst.py --pre-install-script preinst.py
This file needs to go in the "script" section of your setup.py file.
Some functions especially useful in this context are available as additional built-in functions in the installation script.
This means you don't have to import any module.

Python for .NET: ImportError: No module named warnings

I am trying to embed python 2.6 in .NET 4.0.
Following the very minimal documentation in "Python for .NET", I wrote a fairly straightforward code as follows:
const string pythonModulePath = #"C:\Projects\PythonImport\PythonImport\test.py";
Environment.SetEnvironmentVariable("PYTHONHOME", Path.GetDirectoryName(python
ModulePath));
PythonEngine.Initialize();
var oldWorkingDirectory = Directory.GetCurrentDirectory();
var currWorkingDirectory = Path.GetDirectoryName(pythonModulePath);
Directory.SetCurrentDirectory(currWorkingDirectory);
var pyPlugin = PythonEngine.ImportModule(Path.GetFileNameWithoutExtension(python
ModulePath));
if (pyPlugin == null)
{
throw new PythonException();
}
Directory.SetCurrentDirectory(oldWorkingDirectory);
Even if test.py is empty I get an import error saying "No module named warnings".
'import site' failed; use -v for traceback
Unhandled Exception: Python.Runtime.PythonException: ImportError : No module nam
ed warnings
The reason becomes apparent when you run test.py using "python -v" (verbose mode). Notice that python calls #cleanup[2] warnings.
Why is Python .NET not able to resolve warnings? The module is present in Lib directory.
Any ideas?
I think by default the Python Engine does not set the paths you need automatically.
http://www.voidspace.org.uk/ironpython/custom_executable.shtml has an example for embedding ironpython. Looks like you are missing something like
PythonEngine engine = new PythonEngine();
engine.AddToPath(Path.GetDirectoryName(Application.ExecutablePath));
engine.AddToPath(MyPathToStdLib);
Unless I know where and if Ironpython is installed, I prefer to find all of the standard modules I need, compile them to a IPyStdLibDLL and then do th following from my code
import clr
clr.addReference("IPyStdLib")
import site
#SilentGhost I don't know if you figured this out, but you need to set your PYTHONPATH environment variable rather than your PYTHONHOME variable. I, too, had the problem, set the environment variable with the ol' Environment.SetVariable("PYTHONPATH", ...) and everything worked out well in the end.
Good luck with the Python.NET.
I'm working with the 2.4 version of Python.NET with Python 3.6 and I had similar issues. I didn't have much luck setting environment variables at runtime but I found the following approach worked.
I found Python.NET was picking up all packages in the folders defined in the static PythonEngine.PythonPath variable. If you have other directories set in the PYTHONPATH system variable, it will also include these too.
To include module directories at runtime you can do something like
PythonEngine.PythonPath = PythonEngine.PythonPath + ";" + moduleDirectory;
using (Py.GIL())
{
dynamic module = Py.Import("moduleName");
...etc
}
Make sure you set the PythonEngine.PythonPath variable before making any calls to the python engine.
Also needed to restart visual studio to see any system variable changes take effect when debugging.
As a side note, I also found that my \Python36\Lib\site-packages folder path needed to be added to PYTHONPATH to pick up anything installed through pip.

How do I find the location of Python module sources?

How do I learn where the source file for a given Python module is installed? Is the method different on Windows than on Linux?
I'm trying to look for the source of the datetime module in particular, but I'm interested in a more general answer as well.
For a pure python module you can find the source by looking at themodule.__file__.
The datetime module, however, is written in C, and therefore datetime.__file__ points to a .so file (there is no datetime.__file__ on Windows), and therefore, you can't see the source.
If you download a python source tarball and extract it, the modules' code can be found in the Modules subdirectory.
For example, if you want to find the datetime code for python 2.6, you can look at
Python-2.6/Modules/datetimemodule.c
You can also find the latest version of this file on github on the web at
https://github.com/python/cpython/blob/main/Modules/_datetimemodule.c
Running python -v from the command line should tell you what is being imported and from where. This works for me on Windows and Mac OS X.
C:\>python -v
# installing zipimport hook
import zipimport # builtin
# installed zipimport hook
# C:\Python24\lib\site.pyc has bad mtime
import site # from C:\Python24\lib\site.py
# wrote C:\Python24\lib\site.pyc
# C:\Python24\lib\os.pyc has bad mtime
import os # from C:\Python24\lib\os.py
# wrote C:\Python24\lib\os.pyc
import nt # builtin
# C:\Python24\lib\ntpath.pyc has bad mtime
...
I'm not sure what those bad mtime's are on my install!
I realize this answer is 4 years late, but the existing answers are misleading people.
The right way to do this is never __file__, or trying to walk through sys.path and search for yourself, etc. (unless you need to be backward compatible beyond 2.1).
It's the inspect module—in particular, getfile or getsourcefile.
Unless you want to learn and implement the rules (which are documented, but painful, for CPython 2.x, and not documented at all for other implementations, or 3.x) for mapping .pyc to .py files; dealing with .zip archives, eggs, and module packages; trying different ways to get the path to .so/.pyd files that don't support __file__; figuring out what Jython/IronPython/PyPy do; etc. In which case, go for it.
Meanwhile, every Python version's source from 2.0+ is available online at http://hg.python.org/cpython/file/X.Y/ (e.g., 2.7 or 3.3). So, once you discover that inspect.getfile(datetime) is a .so or .pyd file like /usr/local/lib/python2.7/lib-dynload/datetime.so, you can look it up inside the Modules directory. Strictly speaking, there's no way to be sure of which file defines which module, but nearly all of them are either foo.c or foomodule.c, so it shouldn't be hard to guess that datetimemodule.c is what you want.
If you're using pip to install your modules, just pip show $module the location is returned.
The sys.path list contains the list of directories which will be searched for modules at runtime:
python -v
>>> import sys
>>> sys.path
['', '/usr/local/lib/python25.zip', '/usr/local/lib/python2.5', ... ]
from the standard library try imp.find_module
>>> import imp
>>> imp.find_module('fontTools')
(None, 'C:\\Python27\\lib\\site-packages\\FontTools\\fontTools', ('', '', 5))
>>> imp.find_module('datetime')
(None, 'datetime', ('', '', 6))
datetime is a builtin module, so there is no (Python) source file.
For modules coming from .py (or .pyc) files, you can use mymodule.__file__, e.g.
> import random
> random.__file__
'C:\\Python25\\lib\\random.pyc'
Here's a one-liner to get the filename for a module, suitable for shell aliasing:
echo 'import sys; t=__import__(sys.argv[1],fromlist=[\".\"]); print(t.__file__)' | python -
Set up as an alias:
alias getpmpath="echo 'import sys; t=__import__(sys.argv[1],fromlist=[\".\"]); print(t.__file__)' | python - "
To use:
$ getpmpath twisted
/usr/lib64/python2.6/site-packages/twisted/__init__.pyc
$ getpmpath twisted.web
/usr/lib64/python2.6/site-packages/twisted/web/__init__.pyc
In the python interpreter you could import the particular module and then type help(module). This gives details such as Name, File, Module Docs, Description et al.
Ex:
import os
help(os)
Help on module os:
NAME
os - OS routines for Mac, NT, or Posix depending on what system we're on.
FILE
/usr/lib/python2.6/os.py
MODULE DOCS
http://docs.python.org/library/os
DESCRIPTION
This exports:
- all functions from posix, nt, os2, or ce, e.g. unlink, stat, etc.
- os.path is one of the modules posixpath, or ntpath
- os.name is 'posix', 'nt', 'os2', 'ce' or 'riscos'
et al
On windows you can find the location of the python module as shown below:i.e find rest_framework module
New in Python 3.2, you can now use e.g. code_info() from the dis module:
http://docs.python.org/dev/whatsnew/3.2.html#dis
Check out this nifty "cdp" command to cd to the directory containing the source for the indicated Python module:
cdp () {
cd "$(python -c "import os.path as _, ${1}; \
print _.dirname(_.realpath(${1}.__file__[:-1]))"
)"
}
Just updating the answer in case anyone needs it now, I'm at Python 3.9 and using Pip to manage packages. Just use pip show, e.g.:
pip show numpy
It will give you all the details with the location of where pip is storing all your other packages.
On Ubuntu 12.04, for example numpy package for python2, can be found at:
/usr/lib/python2.7/dist-packages/numpy
Of course, this is not generic answer
Another way to check if you have multiple python versions installed, from the terminal.
$ python3 -m pip show pyperclip
Location: /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-
$ python -m pip show pyperclip
Location: /Users/umeshvuyyuru/Library/Python/2.7/lib/python/site-packages
Not all python modules are written in python. Datetime happens to be one of them that is not, and (on linux) is datetime.so.
You would have to download the source code to the python standard library to get at it.
For those who prefer a GUI solution: if you're using a gui such as Spyder (part of the Anaconda installation) you can just right-click the module name (such as "csv" in "import csv") and select "go to definition" - this will open the file, but also on the top you can see the exact file location ("C:....csv.py")
If you are not using interpreter then you can run the code below:
import site
print (site.getsitepackages())
Output:
['C:\\Users\\<your username>\\AppData\\Local\\Programs\\Python\\Python37', 'C:\\Users\\<your username>\\AppData\\Local\\Programs\\Python\\Python37\\lib\\site-packages']
The second element in Array will be your package location. In this case:
C:\Users\<your username>\AppData\Local\Programs\Python\Python37\lib\site-packages
In an IDE like Spyder, import the module and then run the module individually.
enter image description here
as written above
in python just use help(module)
ie
import fractions
help(fractions)
if your module, in the example fractions, is installed then it will tell you location and info about it, if its not installed it says module not available
if its not available it doesn't come by default with python in which case you can check where you found it for download info

Categories

Resources