If you don't have google-cloud-bigquery nor google-cloud-datastore installed in your user or system -level libs, then this code will fail on a basic bazel test //...:
(repro for issue ali5h/rules_pip#35)
macosx-10-15-5:bazel-pip-import-namespace allanc$ bazel clean && bazel test //...
INFO: Starting clean.
INFO: Analyzed target //:test_ns (41 packages loaded, 1777 targets configured).
INFO: Found 1 test target...
FAIL: //:test_ns (see /private/var/tmp/_bazel_allanc/a49d8885b6fea93ab0d1c9501f98ba01/execroot/__main__/bazel-out/darwin-fastbuild/testlogs/test_ns/test.log)
Target //:test_ns up-to-date:
bazel-bin/test_ns
INFO: Elapsed time: 1.728s, Critical Path: 1.23s
INFO: 2 processes: 2 darwin-sandbox.
INFO: Build completed, 1 test FAILED, 6 total actions
//:test_ns FAILED in 0.7s
/private/var/tmp/_bazel_allanc/a49d8885b6fea93ab0d1c9501f98ba01/execroot/__main__/bazel-out/darwin-fastbuild/testlogs/test_ns/test.log
INFO: Build completed, 1 test FAILED, 6 total actions
macosx-10-15-5:bazel-pip-import-namespace allanc$ cat /private/var/tmp/_bazel_allanc/a49d8885b6fea93ab0d1c9501f98ba01/execroot/__main__/bazel-out/darwin-fastbuild/testlogs/test_ns/test.log
exec ${PAGER:-/usr/bin/less} "$0" || exit 1
Executing tests from //:test_ns
-----------------------------------------------------------------------------
Traceback (most recent call last):
File "/private/var/tmp/_bazel_allanc/a49d8885b6fea93ab0d1c9501f98ba01/sandbox/darwin-sandbox/5/execroot/__main__/bazel-out/darwin-fastbuild/bin/test_ns.runfiles/__main__/test_ns.py", line 3, in <module>
from google.cloud import datastore
ImportError: cannot import name 'datastore' from 'google.cloud' (unknown location)
macosx-10-15-5:bazel-pip-import-namespace allanc$
Note that google.cloud.datastore is provided by google-cloud-datastore-1.25.0
google.cloud.datastore is provided by @ali5h_pip
@ali5h_pip compiles its deliverable from requirements.txt
requirements.txt is pip-compile'd from requirements.in
@ali5h_pip:google-cloud-datastore is provided to the test build by dependency in BUILD: `requirement("google-cloud-datastore"),
It's suggested that the directory for google.cloud.bigquery is eclipsing the directory for google.cloud.datastore
ali5h tested in: (export PYTHONPATH="" ; export PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/allanc/bin ; bash -x bazel-out/darwin-fastbuild/bin/test_ns.runfiles/bazel_tools/tools/python/py3wrapper.sh) * "mac, python 3.8"
- "also tested on linux" (unsure what version)
In helping me debug, ali5h asked about a docker container to repro -- this was like the ultimately-controlled buildenv.
This container works:
docker run --rm -it \
-w /code -v $(pwd):/code \
-e LC_ALL=C.UTF-8 -e LANG=C.UTF-8 \
l.gcr.io/google/bazel:3.3.0 \
test //...
In my non-docker environment (macOS-10.15.5, Python-3.7.3 from XCode) I was still getting failures, and bazel test -s //... gave no immediate help, but helped identify the wrapper:
- Look for
TEST_SRCDIR, which isPYTHON_RUNFILESas well
bazel-pip-import-namespace allanc$ test -s //...
INFO: Analyzed target //:test_ns (0 packages loaded, 0 targets configured).
INFO: Found 1 test target...
SUBCOMMAND: # //:test_ns [action 'Testing //:test_ns', configuration: 12c9f5b38ca9023465976bb4b98a011d02814ec73529bdcfee2e76a895d9598f]
(cd /private/var/tmp/_bazel_allanc/a49d8885b6fea93ab0d1c9501f98ba01/execroot/__main__ && \
exec env - \
EXPERIMENTAL_SPLIT_XML_GENERATION=1 \
JAVA_RUNFILES=bazel-out/darwin-fastbuild/bin/test_ns.runfiles \
PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/allanc/bin:/usr/local/snap/Python.framework/Versions/3.8/bin \
PYTHON_RUNFILES=bazel-out/darwin-fastbuild/bin/test_ns.runfiles \
RUNFILES_DIR=bazel-out/darwin-fastbuild/bin/test_ns.runfiles \
RUN_UNDER_RUNFILES=1 \
TEST_BINARY=./test_ns \
TEST_INFRASTRUCTURE_FAILURE_FILE=bazel-out/darwin-fastbuild/testlogs/test_ns/test.infrastructure_failure \
TEST_LOGSPLITTER_OUTPUT_FILE=bazel-out/darwin-fastbuild/testlogs/test_ns/test.raw_splitlogs/test.splitlogs \
TEST_PREMATURE_EXIT_FILE=bazel-out/darwin-fastbuild/testlogs/test_ns/test.exited_prematurely \
TEST_SIZE=medium \
TEST_SRCDIR=bazel-out/darwin-fastbuild/bin/test_ns.runfiles \
TEST_TARGET=//:test_ns \
TEST_TIMEOUT=300 \
TEST_TMPDIR=_tmp/ab2e2aa63a202e32a87097fdb942a1ac \
TEST_UNDECLARED_OUTPUTS_ANNOTATIONS=bazel-out/darwin-fastbuild/testlogs/test_ns/test.outputs_manifest/ANNOTATIONS \
TEST_UNDECLARED_OUTPUTS_ANNOTATIONS_DIR=bazel-out/darwin-fastbuild/testlogs/test_ns/test.outputs_manifest \
TEST_UNDECLARED_OUTPUTS_DIR=bazel-out/darwin-fastbuild/testlogs/test_ns/test.outputs \
TEST_UNDECLARED_OUTPUTS_MANIFEST=bazel-out/darwin-fastbuild/testlogs/test_ns/test.outputs_manifest/MANIFEST \
TEST_UNDECLARED_OUTPUTS_ZIP=bazel-out/darwin-fastbuild/testlogs/test_ns/test.outputs/outputs.zip \
TEST_UNUSED_RUNFILES_LOG_FILE=bazel-out/darwin-fastbuild/testlogs/test_ns/test.unused_runfiles_log \
TEST_WARNINGS_OUTPUT_FILE=bazel-out/darwin-fastbuild/testlogs/test_ns/test.warnings \
TEST_WORKSPACE=__main__ \
TZ=UTC \
XML_OUTPUT_FILE=bazel-out/darwin-fastbuild/testlogs/test_ns/test.xml \
external/bazel_tools/tools/test/test-setup.sh ./test_ns)
SUBCOMMAND: # //:test_ns [action 'Testing //:test_ns', configuration: 12c9f5b38ca9023465976bb4b98a011d02814ec73529bdcfee2e76a895d9598f]
(cd /private/var/tmp/_bazel_allanc/a49d8885b6fea93ab0d1c9501f98ba01/execroot/__main__ && \
exec env - \
PATH=/usr/bin:/bin \
TEST_BINARY=./test_ns \
TEST_NAME=//:test_ns \
TEST_SHARD_INDEX=0 \
TEST_TOTAL_SHARDS=0 \
external/bazel_tools/tools/test/generate-xml.sh bazel-out/darwin-fastbuild/testlogs/test_ns/test.log bazel-out/darwin-fastbuild/testlogs/test_ns/test.xml 0 1)
FAIL: //:test_ns (see /private/var/tmp/_bazel_allanc/a49d8885b6fea93ab0d1c9501f98ba01/execroot/__main__/bazel-out/darwin-fastbuild/testlogs/test_ns/test.log)
Target //:test_ns up-to-date:
bazel-bin/test_ns
INFO: Elapsed time: 0.700s, Critical Path: 0.60s
INFO: 2 processes: 2 darwin-sandbox.
INFO: Build completed, 1 test FAILED, 2 total actions
//:test_ns FAILED in 0.2s
/private/var/tmp/_bazel_allanc/a49d8885b6fea93ab0d1c9501f98ba01/execroot/__main__/bazel-out/darwin-fastbuild/testlogs/test_ns/test.log
INFO: Build completed, 1 test FAILED, 2 total actions
- OK,
TEST_SRCDIR=bazel-out/darwin-fastbuild/bin/test_ns.runfiles - relative to build directory
...so I tried:
(export PYTHONPATH="" ; \
export PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/allanc/bin ;
bash -x bazel-out/darwin-fastbuild/bin/test_ns.runfiles/bazel_tools/tools/python/py3wrapper.sh)
This gave an interactive shell (and with a bit of help from@yarbelk on stackoverflow (https://stackoverflow.com/a/14050282/1712731) I got a clue:
>>> import importlib
>>> print(importlib.util.find_spec("google.cloud.datastore"))
None
>>> print(importlib.util.find_spec("google.cloud")
ModuleSpec(name='google.cloud', loader=<_frozen_importlib_external._NamespaceLoader object at 0x10ee5f710>, submodule_search_locations=_NamespacePath(['/Users/allanc/Library/Python/3.7/lib/python/site-packages/google/cloud']))
The error seems to be a mix of two things:
- Non-hermetic: the local environment is tainting the build, and needs to be removes or sanitized
- The namespace issue in python: the first matching namespace ('google') was changed, and on failure, did not check any other
- BONUS: the things we needed in the
bazlbuild were not installed on the hsot system, and should not be.
Eliminate the namespace in local system dependencies. At most naive, this is a simple deletion of the google namespace:
python3 -m pip uninstall google-<whatever is there>
If that doesn't remove the python/site-packages/google directory, go harder:
rm -fr /Users/allanc/Library/Python/3.7/lib/python/site-packages/google
Note that this can affect the use of google.* python libs later, so this may not be ideal, but it can be mitigated by -- for example -- using only Python-3.8 for bazel builds, and using Python-3.7 for local hacking; or, fiddling with the PATH so that when building with bazel, the /usr/bin/python3 resolves to a really sparse site-packages path. It's the python3 binary in the path, not the PYTHONPATH, but you can set a specific absolute path in your WORKSPACE file:
ali5h_import(
...
python_interpreter = "/usr/local/hermetic/super-clean/python3",
...
)
Lastly, the option that is most predictable yet can take a while to build (ensure you have a local build-cache server): There's an example of building a new, clean python3 as part of the build process. This is the slowest, yet most reliable result.
TODO: track it down and ptovide a reference
post-deletion (note that the command deleted from my personal python site-packages, not system), I have:
>>> import importlib
>>> print(importlib.util.find_spec("google.cloud.datastore"))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/importlib/util.py", line 94, in find_spec
parent = __import__(parent_name, fromlist=['__path__'])
ModuleNotFoundError: No module named 'google'