mkdocstrings: Circular dependency with `mkdocstrings-python-legacy`

First off, great work on this project.

We recently converted our API docs at https://docs.ibis-project.org over to mkdocstrings and are extremely happy with the results, so thank you for all the work that you do here.

Describe the bug

We are using poetry2nix to manage dependencies for development environments.

poetry2nix will turn poetry.lock into nix expressions each of which maps to a single Python package.

To do this, poetry2nix will traverse the transitive closure of the set of dependencies specified in poetry.lock. However, it is unable to do so when a project has mkdocstrings==0.18 as a dependency because mkdocstrings 0.18 depends on mkdocstrings-python-legacy which itself depends on mkdocstrings 0.18, resulting in infinite recursion.

To Reproduce Steps to reproduce the behavior:

  1. Install nix
  2. Download the files in this gist into a directory
  3. Run nix build

Expected behavior

I expect this to work with poetry2nix without infinite recursion.

Information (please complete the following information):

  • OS: NixOS
  • Browser: Brave
  • mkdocstrings version: 0.18.0

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 4
  • Comments: 21 (9 by maintainers)

Most upvoted comments

We were able to get the conda-forge package built with all the dependencies needed. I documented the process in conda-forge/mkdocstrings-feedstock#19, but everything is up to date now!

Here’s the (unrelated) griffe issue. Linking here in case anyone hits it later: https://github.com/mkdocstrings/griffe/issues/72.

This works with poetry2nix now, with the following caveat: you can’t use the extras field to add the python handler like this

mkdocstrings = { version = "...", extras = ["python"] }

Instead, you have to add the handler as a separate dependency:

mkdocstrings = "..."
mkdocstrings-python = "..."

After that, I’m able to get past infinite recursion though griffe is failing to handle __all__ generated by the public library but I’ll open a separate issue for that.

mkdocstrings is working perfectly with Bazel now 🥳!

Thanks for your great work!

Hi all, just released v0.19, which does not directly depend on mkdocstrings-python-legacy anymore. I would appreciate if you could try again your different tools to see if that still poses a cyclic issue or not.

If this installs properly with normal python tooling, can’t it be a bug in poetry2nix?

@pawamoy Circling back here, I think making mkdocstrings-python-legacy a true optional dependency will suffice!

I tested this by removing the dependency by from poetry.lock, and poetry2nix is able to run.

@hadim Thanks for the explanation, that’s reassuring. In your case, I believe including no extras at all would be fine since users can explicitely depend on the handlers themselves. Same question to you @cpcloud @adisbladis, will poetry2nix/nix choke on the extras, even once the legacy handler is not hard-depended on anymore?

Would you mind elaborating a bit on the rationale for the circularity? It seems like mkdocstrings should be installable without any dependency (including an optional one) on mkdocstrings-python-legacy, while mkdocstrings-python-legacy definitely requires mkdocstrings.

Sure!

In fact, removing the dependency on mkdocstrings-python-legacy is planned. It’s only here for the transition: previously the legacy Python handler was part of mkdocstrings, and now it lives in this other mkdocstrings-python-legacy project. To give some time to users to adapt, mkdocstrings still hard-depends on it while providing the python-legacy extra (which is a no-op in this context since the legacy handler is always installed).

When imported, the legacy handler warns users that the extra will become mandatory in the next release. This is to make sure nobody gets a bad surprise while upgrading, as I believe the way to deprecate things is, well, to use [deprecation/user] warnings for a short period at least.

It brings us to this: next version of mkdocstrings will only optionally depend on mkdocstrings-python-legacy, which I believe is better supported by other infrastructures tooling, and would not result in infinite recursion?

As to why the circular dependency in the first place: extras are convenient and allow us to depend on mkdocstrings[crystal,python]. Reciprocally, these crystal and python handlers depend on mkdocstrings to make sure both mkdocstrings’ and the handlers’ versions are compatible.