Open calliecameron opened 1 year ago
FYI I'm adding mypy to rules_lint: https://github.com/aspect-build/rules_lint/issue/79
Thank, I'll keep an eye on that. Working link: https://github.com/aspect-build/rules_lint/issues/79.
In the meantime I found a workaround - running mypy from a stub python script, rather than using the entry_point. py_test sets up the environment so that mypy can find everything, including the type stubs if specified.
$ ls -A
.bazelversion BUILD MODULE.bazel WORKSPACE bar.py foo.py lint.bzl mypy_stub.py requirements.txt
$ cat .bazelversion
6.2.1
$ cat BUILD
load("@rules_python//python:pip.bzl", "compile_pip_requirements")
load("@pip//:requirements.bzl", "requirement")
load("@rules_python//python:defs.bzl", "py_library")
load("lint.bzl", "py_library_with_lint")
compile_pip_requirements(
name = "requirements",
requirements_in = "requirements.txt",
requirements_txt = "requirements_lock.txt",
tags = ["requires-network"],
)
py_library_with_lint(
name = "foo",
srcs = ["foo.py"],
deps = [
":bar",
requirement("tabulate"),
],
type_stub_deps = [requirement("types-tabulate")],
)
py_library(
name = "bar",
srcs = ["bar.py"],
)
$ cat MODULE.bazel
module(
name = "example",
version = "0.0.0",
)
bazel_dep(
name = "rules_python",
version = "0.24.0",
)
python = use_extension("@rules_python//python/extensions:python.bzl", "python")
python.toolchain(
python_version = "3.10",
)
pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip")
pip.parse(
hub_name = "pip",
python_version = "3.10",
requirements_lock = "//:requirements_lock.txt",
)
use_repo(pip, "pip", "pip_310")
$ cat WORKSPACE
$ cat bar.py
def bar(s: str) -> str:
return s + "!"
$ cat foo.py
import sys
import tabulate
import bar
def foo() -> str:
return bar.bar(tabulate.tabulate([["foo"]]))
$ cat lint.bzl
load("@rules_python//python:defs.bzl", "py_library", "py_test")
load("@pip//:requirements.bzl", "requirement")
def py_library_with_lint(name, type_stub_deps=None, **kwargs):
py_library(
name = name,
**kwargs
)
srcs = kwargs.get("srcs", [])
deps = kwargs.get("deps", [])
type_stub_deps = type_stub_deps or []
py_test(
name = name + "_mypy_test",
srcs = ["mypy_stub.py"],
main = "//:mypy_stub.py",
deps = deps + type_stub_deps + [requirement("mypy")],
data = srcs,
args = [
"--strict",
"--explicit-package-bases",
"--scripts-are-modules",
] + ["$(location %s)" % src for src in srcs],
)
$ cat mypy_stub.py
# from https://mypy.readthedocs.io/en/stable/extending_mypy.html
import sys
from mypy import api
result = api.run(sys.argv[1:])
if result[0]:
print('\nType checking report:\n')
print(result[0]) # stdout
if result[1]:
print('\nError report:\n')
print(result[1]) # stderr
print('\nExit status:', result[2])
sys.exit(result[2])
$ cat requirements.txt
mypy == 1.4.1
tabulate == 0.9.0
types-tabulate == 0.9.0.2
Then as before:
$ touch requirements_lock.txt
$ bazel run --enable_bzlmod :requirements.update
$ bazel test --enable_bzlmod :all
and the test passes.
This issue has been automatically marked as stale because it has not had any activity for 180 days. It will be closed if no further activity occurs in 30 days. Collaborators can add an assignee to keep this open indefinitely. Thanks for your contributions to rules_python!
I'll keep this open for pyi file inclusion in py_library. I am not sure if there is a good story yet, so it may be useful to consider these in rules_python.
I'm trying to write a test that runs mypy. I thought I had the following working in rules_python 0.22.0:
I would then do the following:
...and the mypy test would pass. Now it turns out this only ever worked because I was running
bazel test
from inside a virtualenv where I'd runpip install -r requirements.txt
. I.e. because I was using the system python, not a hermetic toolchain,types-tabulate
installed in the virtualenv was leaking into the test environment, and the test was passing. If I deactivate the virtualenv, the test fails - and addingrequirement("types-tabulate")
to the library doesn't help.Switching to rules_python 0.24.0, with the following diff:
...and running:
...the test fails, regardless of whether I'm in the virtualenv or not, with:
...because the new version of rules_python uses a toolchain by default, and isn't leaking types-tabulate from the virtualenv into the test environment. Note that the standard library import and local import work fine, only the pip-installed stubs are missing.
I'd like to use a toolchain anyway, so I can pin a specific python version, so now my question is: how do I do this properly? Is using a stub shell script the right way to call an entry_point in a test, and how do I get mypy to find the pip-installed stubs?
I'm doing a similar thing with a pylint test, and it's failing with errors like
[E0401(import-error), ] Unable to import 'tabulate'
. On the other hand, linters that don't follow imports (e.g. black) work fine.OS: Ubuntu 22.04 Bazel version: 6.2.1 rules_python version: 0.24.0