:::{default-domain} bzl :::
Sometimes PyPI packages contain dependency cycles. For instance, a particular version of sphinx (this is no longer the case in the latest version as of 2024-06-02) depends on sphinxcontrib-serializinghtml. When using them as requirement()s, ala
py_binary( name = "doctool", ... deps = [ requirement("sphinx"), ], )
Bazel will protest because it doesn't support cycles in the build graph --
ERROR: .../external/pypi_sphinxcontrib_serializinghtml/BUILD.bazel:44:6: in alias rule @pypi_sphinxcontrib_serializinghtml//:pkg: cycle in dependency graph:
//:doctool (...)
@pypi//sphinxcontrib_serializinghtml:pkg (...)
.-> @pypi_sphinxcontrib_serializinghtml//:pkg (...)
| @pypi_sphinxcontrib_serializinghtml//:_pkg (...)
| @pypi_sphinx//:pkg (...)
| @pypi_sphinx//:_pkg (...)
`-- @pypi_sphinxcontrib_serializinghtml//:pkg (...)
The experimental_requirement_cycles attribute allows you to work around these issues by specifying groups of packages which form cycles. pip_parse will transparently fix the cycles for you and provide the cyclic dependencies simultaneously.
... experimental_requirement_cycles = { "sphinx": [ "sphinx", "sphinxcontrib-serializinghtml", ] }, )
pip_parse supports fixing multiple cycles simultaneously, however, cycles must be distinct. apache-airflow, for instance, has dependency cycles with a number of its optional dependencies, which means those optional dependencies must all be a part of the airflow cycle. For instance:
... experimental_requirement_cycles = { "airflow": [ "apache-airflow", "apache-airflow-providers-common-sql", "apache-airflow-providers-postgres", "apache-airflow-providers-sqlite", ] } )
Alternatively, one could resolve the cycle by removing one leg of it.
For example, while apache-airflow-providers-sqlite is “baked into” the Airflow package, apache-airflow-providers-postgres is not and is an optional feature. Rather than listing apache-airflow[postgres] in your requirements.txt, which would expose a cycle via the extra, one could either manually depend on apache-airflow and apache-airflow-providers-postgres separately as requirements. Bazel rules which need only apache-airflow can take it as a dependency, and rules which explicitly want to mix in apache-airflow-providers-postgres now can.
Alternatively, one could use rules_python's patching features to remove one leg of the dependency manually, for instance, by making apache-airflow-providers-postgres not explicitly depend on apache-airflow or perhaps apache-airflow-providers-common-sql.