The smallest possible setup demonstrating the py plugin: one Python package, stdlib-only imports, a smoke test. No internal cross-package references, no PyPI deps.
.
├── app.py # imports json, pathlib, os.path, dataclasses (all stdlib)
├── app_test.py # imports `app` AND a fixture from `conftest`
├── conftest.py # shared pytest-style fixtures
├── BUILD.bazel # gazelle_bin + py_library + py_test + :conftest (generated by gazelle)
└── MODULE.bazel # rules_python + local_path_override on gazelle_py
py_libraryrule generated withsrcs = ["app.py"]and nodeps(all imports are stdlib).py_testrule generated withsrcs = ["app_test.py"],main = "app_test.py", anddeps = [":conftest", ":myapp"](the sibling library plus the dedicated conftest target, resolved via the first-party RuleIndex and the ancestor-conftest synthesis).conftest.pyis extracted into its ownpy_librarynamed:conftestwithtestonly = True— NOT bundled into:myapp's srcs (the rules_python-style layout).gazelle:py_visibility //visibility:publicdirective carries to the library rule.
bazel run //:gazelle # generate/update BUILD files
bazel test //... # run the smoke testThe BUILD.bazel here is checked in pre-generated; running bazel run //:gazelle -- update -mode=diff should report no changes.