Description
It appears that (binary!) imports from markupsafe._speedups have side-effects in a pylint invocation. The file that is linted attempts to import a missing package in a try-except clause. A common invocation of pylint produces empty (plug-in) reports if markupsafe is imported before pylint is linting (e.g. imported by a pylint plugin). However, output is produced as expected if either:
- the missing import is installed; or
- the
try block is replaced by a non-import statement (e.g. raise ValueError); or
markupsafe.__init__ is modified to prefer imports from markupsafe._native; or
- one imports a Cython package, e.g.
ormsgpack, instead of markupsafe.
The first two observations may help in determining the root issue, but are not the problem themselves. The second two observations are what made me report the issue at MarkupSafe, as that suggests that the issue is specific to this package. However: I don't know where the root cause is, so I'm submitting this issue to both MarkupSafe and Pylint and trust that the community has a more complete understanding of the powers at play.
The issue at Pylint (copy of this issue): https://github.com/PyCQA/pylint/issues/8026.
This issue lies at the root of https://gitlab.com/smueller18/pylint-gitlab/-/issues/18.
Setup
I have two files in the same directory: invoke_pytest.py and my_module.py
# invoke_pytest.py
import markupsafe # this import is not used -- it can only contribute side-effects or invoke pylint side-effects!
from pylint import run_pylint
run_pylint(
argv=[
"--output-format=pylint_junit.JUnitReporter:pylint-report.xml",
"my_module.py",
]
)
# my_module.py
try:
import gmpy2
except ImportError:
pass
I have a virtual environment in which I installed pylint pylint-junit markupsafe. pylint-junit is merely needed to show that a pylint plugin becomes unable to produce output. The issue surfaced originally in pylint-gitlab, which has markupdown as a dependency through jinja2.
$ python invoke_pytest.py; head pylint-report.xml
Expected output
After commenting import markupsafe from invoke_pytest.py, the output is as expected:
$ python invoke_pytest.py; head pylint-report.xml
<?xml version="1.0" ?>
<testsuites disabled="0" errors="0" failures="2" tests="4" time="0.0">
<testsuite disabled="0" errors="0" failures="0" name="Command line or configuration file" skipped="0" tests="1" time="0">
<testcase name="Command line or configuration file:0:0" classname="pylint">
<system-out>All checks passed for: None</system-out>
</testcase>
</testsuite>
<testsuite disabled="0" errors="0" failures="2" name="my_module" skipped="0" tests="3" time="0">
<testcase name="my_module:0:0" classname="pylint" file="my_module.py">
<system-out>All checks passed for: my_module.py</system-out>
As mentioned above, the same output is achieved if markupsafe.__init__ is adjusted to not import from ._speedups.
Environment
Windows 10 -> WSL2 -> Ubuntu
$ python --version
Python 3.10.9
$ pip list
Package Version
----------------- -------
astroid 2.12.13
dill 0.3.6
isort 5.11.4
junit-xml-2 1.9
lazy-object-proxy 1.9.0
MarkupSafe 2.1.1
mccabe 0.7.0
pip 22.3.1
platformdirs 2.6.2
pylint 2.15.9
pylint-junit 0.3.2
setuptools 65.5.0
six 1.16.0
tomli 2.0.1
tomlkit 0.11.6
wrapt 1.14.1
I understand that the example is not quite minimal yet -- there is a lot of pylint stuff under the hood. Again, let me emphasize that I reach out to both communities and I hope to jointly reduce the example shortly.
I want to finish this report by stating that I appreciate all your efforts, keep up the good work!