-
Notifications
You must be signed in to change notification settings - Fork 540
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Bazel breaks python import with __init__.py #55
Comments
/cc @ulfjack |
Let me know whether this a real issue or just misunderstanding on my part if the former I would like to provide a fix for this. |
It's a legacy behavior from the internal version of Bazel (Blaze), for Google's particular Python peculiarities. It should definitely be cleaned up in Bazel, but it will be a breaking change, so it would probably need to be mediated by a flag or per-target attribute, as you suggest. |
Running into a similar problem with our Python project, the extra |
We are seeing the same issue with the cc @duggelz |
If someone sends a change to add a flag to Bazel or a tag to py_binary / py_test, I'm happy to review it. Unfortunately, I won't be able to spend any time on this myself. |
Introduce a new attribute to py_binary and py_test to control whether to create `__init__.py` or not. Fixes bazelbuild/rules_python#55
@ulfjack I have a PR ready for review bazelbuild/bazel#4470, please take a look. |
Just to clarify the patch above only fix one issue we still need to introduce the other fix which makes python package namespaces works which is by introducing |
FYI, I'm also seeing the issue with |
Lukacs just added a Python integration test in bb9f19d4d819a751fbfbe11b2a7827c05680944d (no idea how to reference that from here). |
Introduce a new attribute to py_binary and py_test to control whether to create `__init__.py` or not. Fixes bazelbuild/rules_python#55
*** Reason for rollback *** Breaks Kokoro and I accidentally submitted the change without presubmit checks. *** Original change description *** Make __init__.py files creation optional Introduce a new attribute to py_binary and py_test to control whether to create `__init__.py` or not. Fixes bazelbuild/rules_python#55 Closes #4470. PiperOrigin-RevId: 185676592
When should we expect the feature to be released? It seems the commit was rolled back. Should the issue be reopened? |
*** Reason for rollback *** Remove example changes; those need to build with the last Bazel release. *** Original change description *** Automated rollback of commit 0f9c6ea. *** Reason for rollback *** Breaks Kokoro and I accidentally submitted the change without presubmit checks. *** Original change description *** Make __init__.py files creation optional Introduce a new attribute to py_binary and py_test to control whether to create `__init__.py` or not. Fixes bazelbuild/rules_python#55 Closes #4470. PiperOrigin-RevId: 185806241
It was rolled back, rolled forward, rolled back again, and then rolled forward again. bazelbuild/bazel@e9c885a will hopefully stick this time? |
The second bug around |
It's good that you brought that up because first, the previous bug fix provided doesn't fix fully the namespace issue as mentioned here #55 (comment), maybe we should reopen the issue, as I am planning to provide a fix over the weekend for the namespace issue unless someone beat me to it. Now concerning the fix itself, fixing python_stub_template.txt, does work (b/c we use that fix with our workaround) however it only works, in this case |
So is this merged? |
@fejta -- yep, you set |
See github.com/bazelbuild/rules_python/issues/55 for details.
System information:
Description
I have few examples of how Bazel introduce
__init__.py
in places where none was and by doing this it breaks python import, e.g.Python dependencies that are package namespaces.
An example is
zope.interface
package, which is a dependency ofpyramid
library same forzope.deprecation
, we have some code that both when tests and one code is run it fails withModuleNotFoundError: No module named 'zope.interface'
.I spend some time investigating this issue and the result of my investigation lead to two conclusions:
__init__.py
files and break namespacingLet's looks at each one of them in details:
Bazel introduce
__init__.py
files and break namespacingLooking at what wheel contains (using
unzip -l ....whl
) and how the directory is layout is in the.cache/bazel/<...>/external/pypi__zope_interface_4_4_0/
, we see the same structure:While if you look inside the
.runfiles
of apy_binary
orpy_test
rule you will see some__init__.py
files being introduced e.g. inls bazel-out/k8-fastbuild/bin/<some-repository-path>/default_test.runfiles/pypi__zope_interface_4_4_0/
Those
__init__.py
break the logic inside.pth
that make sure that a package namespace is created.Python namespaces wheels installed in no-site directories wouldn't work
The above is not all the story, because even if you remove
__init__,py
files, still namespace packages likezope.interface
will not work as they should be b/c this later relay on the fact that the.pth
files are executed which patch python module's__path__
of the given package (and that no__init__.py
file exists in the subdirectory hence the first issue), however.pth
files (likezope.interface-4.4.0-py3.6-nspkg.pth
) are only parsed if the enclosing directory is considered a site directory as mentioned by documentation here:Which refer to the paragraph before where it said.
Now long story, short, the
.pth
files are not parsed just by adding a directory toPYTHONPATH
which is what the runner here, instead you will want to do add something like:Running tests with pytest
We are using pytest as a test runner, but for some of our existing code, switching to Bazel is breaking the tests, reason for this is again because of the introduced
__init__.py
files.To give more details, our monorepo has the following structure:
Inside
BUILD.bazel
we have rules to run tests by calling a python script that use pytest, again the same issue is that import is broken in some of our code that relies on import side effect (not good but hard to change) b/c same python modules get imported twice with different__name__
one islibraries.python.some_library...
and another time withsome_library....
and this is due to first pytest autodiscovery magic but mostly because Bazel introduce__init__.py
files inlibraries/
folder andlibraries/python/
folder, which sadly confuse pytest.Workarounds
So far, we are working around the later issue by misusing
--run_under
Bazel flag to patch.runfiles
and delete__init__.py
in those places where they shouldn't be any.To give an idea of the snippet of the code that we have in the script passed to
--run_under
here it is:It's really ugly but fixes the test. However the workaround is harder to implement when we integrate with
py_image
rule from docker_rules.Proposed solution
I still don't understand why inserting
__init__.py
is needed and in which case, but IMHO such changes mess up with the way Python work and worst create a different environment than the one you see, so my proposal maybe adds a new flag in Bazel test and build to skip the__init__.py
creation or maybe better (read local control) add a flag topy_binary
andpy_test
rules to skip auto__init__.py
creation, thoughts?N.B. While Bazel has been great addon to our stack and I am very grateful to the effort the community put in to make it better, I am a bit unhappy with the fact that python rules are written not as Bazel extensions (using Skylar) but in Java, because this way fixing issues like the above is not as easy as forking repository changing code and changing WORKSPACE to use fork :(
The text was updated successfully, but these errors were encountered: