|
1 | | -# 111 |
| 1 | +# 1:1:1 |
2 | 2 |
|
3 | | -This example shows that a Python project may be organized using Bazel's [1:1:1](https://bazel.build/basics/dependencies#using_fine-grained_modules_and_the_111_rule) rule. |
| 3 | +This example shows a Python project using Bazel's [1:1:1](https://bazel.build/basics/dependencies#using_fine-grained_modules_and_the_111_rule) structure of "one BUILD file per Bazel package". Why is this interesting? Because the `1:1:1` structure is a common layout when using Bazel, especially when using [Gazelle](https://github.com/bazel-contrib/bazel-gazelle) to generate BUILD files. However, when generating manifests and artifacts for a package manager, we typically do not want to generate at the granularity of the Bazel package level but instead at the "project level" - Poppy handles this translation. |
4 | 4 |
|
5 | | -Note that this works well for Python projects because the wheel file construction is external to Bazel. On the other hand, this doesn't work well for Java based projects because the jar file building is done by Bazel (and so with 1:1:1 we'd end up with too many jar files - they would have to be merged into a single jar before being uploaded to the package manager). |
6 | 5 |
|
| 6 | +## Looking around |
7 | 7 |
|
8 | | -## The pyproject.toml file |
| 8 | +This example consists of 2 libraries, [communicator](communicator) and [computer](computer). |
| 9 | +- `communicator` - has modules [phone](communicator/phone) and [caller](communicator/caller). The phone module has [111 mode enabled](communicator/phone/md/pyproject.in): `generation_mode` is set to `dynamic_111`. The `caller` module depends on the `phone` module. |
| 10 | +- `computer` - has modules [amiga](computer/amiga) and [user](computer/user). Both modules have 111 mode enabled. The `user` module depends on the `amiga` module. |
| 11 | +- Library dependencies: `communicator` depends on `computer`; this link exists bcause `phone` depends on `amiga` [here](communicator/phone/src/phone/emulator/BUILD). |
9 | 12 |
|
10 | | -Run this command: |
| 13 | +The following `poppy` command shows how both libraries are related: |
11 | 14 |
|
12 | 15 | ``` |
13 | | -bazel run @poppy//package/py -- -l examples/python/111 -a gen |
| 16 | +bazel run //:query -- --package examples/python/111/communicator --library_release_plan_tree |
| 17 | +
|
| 18 | +examples/python/111/communicator ++ 2.0.1 |
| 19 | + examples/python/111/computer ++ 1.0.1 |
| 20 | +
|
| 21 | +++ artifact has never been released |
| 22 | +``` |
| 23 | + |
| 24 | + |
| 25 | +## About 1:1:1 mode |
| 26 | + |
| 27 | +Support for `1:1:1` package structure must be set explicitly in the manifest file: `generation_mode = "dynamic_111"` [example](communicator/phone/md/pyproject.in). |
| 28 | +Additionally, the manifest file must specify an "aggregation" target that has as dependencies all child `1:1:1` targets, in that example linked below that is configured by `target_name = "venv"`. For Python, this works well with a `venv` target. Note that if the `venv` target includes tests, those should be excluded explicitly (in the linked example, that is done using `excluded_dependency_paths = ["tests"]`. |
| 29 | +Finally, the module structure must follow the modern Python project structure with top level `src` and `tests` directories. |
| 30 | + |
| 31 | + |
| 32 | +## The 1:1:1 manifest |
| 33 | + |
| 34 | +The generated manifest (pyproject.toml) aggregates all dependencies from child Bazel packages if they are: |
| 35 | +- External (pip) dependencies |
| 36 | +- Source dependencies that point outside of the 1:1:1 module |
| 37 | + |
| 38 | +As an example, generate the `communicator` library manifest files: |
| 39 | + |
14 | 40 | ``` |
| 41 | +bazel run //:gen -- --package examples/python/111/communicator --destdir /tmp/py |
| 42 | +``` |
| 43 | + |
| 44 | +Since `communicator` depends on `computer`, and each library has 2 modules, 4 manifests are generated. |
| 45 | + |
| 46 | +The `communicator/phone` manifest at `/tmp/py/examples/python/111/communicator/phone/pyproject.toml` lists these dependencies: |
15 | 47 |
|
16 | | -Note [111_mode is enabled](md/pyproject.in) and that the child Bazel packages do not define any Poppy related metadata - dependencies declared in child Bazel packages' BUILD.bazel files are "pushed up" to, and included in, the `pyproject.toml` file generated for the `111` project. |
| 48 | +- `uvicorn[standard]>=0.34.0` brought in through [communicator/phone/src/phone/ringtone/BUILD](communicator/phone/src/phone/ringtone/BUILD) |
0 commit comments