python module root

1,846 views
Skip to first unread message

neu...@planet.com

unread,
Jun 24, 2016, 9:02:53 PM6/24/16
to bazel-discuss
Hello bazel people, I'm having trouble packaging Python modules. I have a module named `foo`, but it seems to be built as `app.foo`, allowing me to write `from app.foo import bar` but not `from foo import bar` which is what I want. Is this something configurable?

I have the following directory structure.

```
$ find .
.
./app
./app/foo
./app/foo/__init__.py
./app/foo/BUILD
./app/foo/tests
./app/foo/tests/foo_test.py
./WORKSPACE
```

These are the contents of my files.

```
$ find app -type f -exec echo -- \; -print -exec cat {} \; -exec echo \;
--
app/foo/__init__.py
def bar():
return 'hello'

--
app/foo/BUILD
py_library(name = "foo", srcs = glob(["**/*.py"]))
py_test(name = "foo_test", srcs = ["tests/foo_test.py"], deps = [":foo"])

--
app/foo/tests/foo_test.py
import unittest
from foo import bar

class FooTests(unittest.TestCase):
def test_bar(self):
assert bar() == 'hello'

if __name__ == '__main__':
unittest.main()
```

This is the error.

```
$ bazel test app/foo:foo_test --verbose_failures --test_output=all
INFO: Found 1 test target...
FAIL: //app/foo:foo_test (...).
INFO: From Testing //app/foo:foo_test:
==================== Test output for //app/foo:foo_test:
Traceback (most recent call last):
File "/private/var/tmp/.../tmp/bazel-out/local-fastbuild/bin/app/foo/foo_test.runfiles/__main__/app/foo/tests/foo_test.py", line 2, in <module>
from foo import bar
ImportError: No module named foo
================================================================================
Target //app/foo:foo_test up-to-date:
bazel-bin/app/foo/foo_test
INFO: Elapsed time: 0.145s, Critical Path: 0.06s
//app/foo:foo_test FAILED in 0.1s
/private/var/tmp/.../tmp/bazel-out/local-fastbuild/testlogs/app/foo/foo_test/test.log

Executed 1 out of 1 tests: 1 fails locally.
```

Dmitry Lomov

unread,
Jun 27, 2016, 8:01:40 AM6/27/16
to neu...@planet.com, bazel-discuss
I do not think it is configurable. What is wrong with putting foo on the top level?
(alternatively, file a feature request)

HTH,
Dmitry


--
You received this message because you are subscribed to the Google Groups "bazel-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to bazel-discus...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/bazel-discuss/fca2cdcc-037f-417f-ab78-c93b7ba318d4%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Google Germany GmbH
Erika-Mann-Straße 33, 80636 München, Germany

neu...@planet.com

unread,
Jun 27, 2016, 12:49:44 PM6/27/16
to bazel-discuss, neu...@planet.com
OK, good to know. We're looking at consolidating our projects into a single repo and they are just structured this way.

Onath Claridge

unread,
Jun 27, 2016, 1:40:30 PM6/27/16
to bazel-discuss, neu...@planet.com
You could potentially auto-generate a "foo" namespace package at the top level. You'd use a genrule to create foo/__init__.py (not app/foo/__init__.py), and within that file, update the __path__ variable to include your app/foo directory.

Cheers,
Onath

Neuman Vong

unread,
Jun 27, 2016, 1:56:55 PM6/27/16
to Onath Claridge, bazel-discuss
Thanks, Onath. I'll try that the next time I get time to experiment with this. Alternatively, is there a recommended project structure for projects that I can simply imitate? That way things could "just work" out of the box. I imagine Bazel was designed for monorepo type scenarios in mind. How would this look with multiple Python projects?

Brian Silverman

unread,
Jun 27, 2016, 2:27:15 PM6/27/16
to Neuman Vong, Onath Claridge, bazel-discuss
Would setting imports do what you want? I think imports = [ 'app' ] works for your example.

Neuman Vong

unread,
Jun 27, 2016, 2:40:05 PM6/27/16
to Brian Silverman, Onath Claridge, bazel-discuss
Hi Brian, it doesn't seem to change anything. I changed app/foo/BUILD to add imports to py_test only, py_library only, and finally to both, all resulted in the same output.

$ cat app/foo/BUILD
py_library(name = "foo", srcs = glob(["**/*.py"]))
py_test(name = "foo_test", srcs = ["tests/foo_test.py"], deps = [":foo"], imports = ["app"])

Did I understand your suggestion?

Doug Greiman

unread,
Jun 27, 2016, 7:22:50 PM6/27/16
to bazel-discuss, bsilve...@gmail.com, clar...@google.com
"imports" is relative to the BUILD file, and you probably want to put it on the py_library instead of the py_test, so something like:

py_library(name = "foo", srcs = glob(["**/*.py"], imports=[".."])

py_test(name = "foo_test", srcs = ["tests/foo_test.py"], deps = [":foo"])

Brian Silverman

unread,
Jun 27, 2016, 7:27:13 PM6/27/16
to Doug Greiman, bazel-discuss, Onath Claridge
It is indeed relative to the BUILD file. However, using .. won't work. If you want to import app/foo/something.py as foo.something, you need to write a py_library(name = "foo", srcs = ["foo/something.py"], imports = ["."]) in app/BUILD.
Reply all
Reply to author
Forward
0 new messages