Skip to content

Instantly share code, notes, and snippets.

@dududko
Last active July 10, 2025 01:02
Show Gist options
  • Save dududko/4cacb6172f069b0e439af69328bce907 to your computer and use it in GitHub Desktop.
Save dududko/4cacb6172f069b0e439af69328bce907 to your computer and use it in GitHub Desktop.
The example on how to enable autocompletion for python code in bazel workspace in VS Code. The concept of this solution is to create a repository based on `requirements_lock.txt` file that will contain symbolic links to external python packages in bazel workspace. This approach allows to keep the `.vscode/settings.json` file small.
{
// Enable autocompletion for Python
"python.analysis.extraPaths": ["${workspaceFolder}/external/+vs_code_python_autocompletion+py_deps"],
}
genrule(
name = "force_fetch",
srcs = ["@py_deps//:readme.txt"], # This forces Bazel to fetch @py_deps
outs = ["dummy.txt"],
cmd = "echo 'Fetched' > $@",
)
# vs_code_python_autocompletion
vs_code_python_autocompletion = use_extension("//:vs_code_python_autocompletion.bzl", "vs_code_python_autocompletion", dev_dependency = True)
use_repo(vs_code_python_autocompletion, "py_deps")
vs_code_python_autocompletion.requirements(
hub_name = HUB_NAME,
python_version = DEFAULT_PYTHON,
requirements_lock = "//:requirements_lock.txt",
)
load("@rules_python//python/private:semver.bzl", "semver")
# Implementation of the repository rule
def _vs_code_python_autocompletion_repo_impl(repo_ctx):
for k in repo_ctx.attr.pypi_dependencies:
package = repo_ctx.attr.pypi_dependencies[k]
# For each python package create symbolic link to the external repository
repo_ctx.symlink(repo_ctx.path(k).get_child("../site-packages").get_child(package), package)
# Create an empty readme file in the repository
repo_ctx.file("readme.txt", "")
# Generate a BUILD.bazel file
repo_ctx.file("BUILD.bazel", """exports_files(["readme.txt"])""")
# Define the repository rule
vs_code_python_autocompletion_repo = repository_rule(
implementation = _vs_code_python_autocompletion_repo_impl,
doc = "Creates symbolic links to Python packages for VS Code autocompletion",
attrs = {
"pypi_dependencies": attr.label_keyed_string_dict(
mandatory = True,
doc = "A dictionary of pypi dependencies to be symlinked",
),
},
)
# Implementation of the module extension
def _vs_code_python_autocompletion_impl(module_ctx):
tags = module_ctx.modules[0].tags.requirements[0]
# Extract the attribute values
hub_name = tags.hub_name
python_version = tags.python_version
requirements_lock = module_ctx.read(tags.requirements_lock).splitlines()
# Normalize the Python version
python_version = semver(python_version)
python_version = "{}{}".format(python_version.major, python_version.minor)
deps = {}
for line in requirements_lock:
line = line.strip()
# Ignore empty lines or comments or --hash lines
if line and not line.startswith("#") and not line.startswith("--hash"):
package = line.split("==")[0] # Extract the package name (before '==')
package = package.strip().replace("-", "_") # Normalize name
deps["@@rules_python++pip+pypi_313_" + package] = package
print("@@rules_python++pip+{hub_name}_{python_version}_{package}".format(
hub_name = hub_name,
python_version = python_version,
package = package,
))
# Call the repository rule to create the necessary symbolic links
vs_code_python_autocompletion_repo(
name = "py_deps",
pypi_dependencies = deps,
)
# Define the module extension
vs_code_python_autocompletion = module_extension(
implementation = _vs_code_python_autocompletion_impl,
doc = "Creates symbolic links to Python packages for VS Code autocompletion based on requirements_lock.txt",
tag_classes = {
"requirements": tag_class(
attrs = {
"requirements_lock": attr.label(
mandatory = True,
doc = "The requirements lock file",
allow_single_file = True,
),
"hub_name": attr.string(
mandatory = True,
doc = "The name of the hub to use for the requirements",
),
"python_version": attr.string(
mandatory = True,
doc = "The Python version to use for the requirements",
),
},
),
},
)
@dududko
Copy link
Author

dududko commented Feb 24, 2025

Here is the example for numpy and pandas

> cat requirements.in
numpy==2.2.3
pandas
> ls -l $(bazel info output_base)/external/+vs_code_python_autocompletion+py_deps
total 8
-rwxr-xr-x@ 1 user  wheel   29 Feb 24 17:59 BUILD.bazel
-rw-r--r--@ 1 user  wheel    0 Feb 24 17:59 REPO.bazel
lrwxr-xr-x@ 1 user  wheel  125 Feb 24 17:59 numpy -> /private/var/tmp/_bazel_user/0e2399913bde8328a5ba4fadfa8adce4/external/rules_python++pip+pypi_313_numpy/site-packages/numpy
lrwxr-xr-x@ 1 user  wheel  127 Feb 24 17:59 pandas -> /private/var/tmp/_bazel_user/0e2399913bde8328a5ba4fadfa8adce4/external/rules_python++pip+pypi_313_pandas/site-packages/pandas
lrwxr-xr-x@ 1 user  wheel  145 Feb 24 17:59 python_dateutil -> /private/var/tmp/_bazel_user/0e2399913bde8328a5ba4fadfa8adce4/external/rules_python++pip+pypi_313_python_dateutil/site-packages/python_dateutil
lrwxr-xr-x@ 1 user  wheel  123 Feb 24 17:59 pytz -> /private/var/tmp/_bazel_user/0e2399913bde8328a5ba4fadfa8adce4/external/rules_python++pip+pypi_313_pytz/site-packages/pytz
-rwxr-xr-x@ 1 user  wheel    0 Feb 24 17:59 readme.txt
lrwxr-xr-x@ 1 user  wheel  121 Feb 24 17:59 six -> /private/var/tmp/_bazel_user/0e2399913bde8328a5ba4fadfa8adce4/external/rules_python++pip+pypi_313_six/site-packages/six
lrwxr-xr-x@ 1 user  wheel  127 Feb 24 17:59 tzdata -> /private/var/tmp/_bazel_user/0e2399913bde8328a5ba4fadfa8adce4/external/rules_python++pip+pypi_313_tzdata/site-packages/tzdata

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment