From f710efa50d4217ed2a56e14d25e8c7022e456240 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Anjos?= Date: Fri, 5 Jul 2024 13:42:56 +0200 Subject: [PATCH] Initial commit --- .flake8 | 7 + .gitignore | 27 + .gitlab-ci.yml | 7 + .pre-commit-config.yaml | 60 + .readthedocs.yaml | 17 + .reuse/dep5 | 11 + LICENSES/BSD-3-Clause.txt | 11 + README.md | 21 + doc/api.rst | 21 + doc/cli.rst | 68 + doc/conf.py | 117 + doc/index.rst | 38 + doc/install.rst | 70 + doc/links.rst | 20 + doc/usage.rst | 291 ++ pixi.lock | 4429 ++++++++++++++++++++++++ pyproject.toml | 169 + src/auto_intersphinx/__init__.py | 323 ++ src/auto_intersphinx/catalog.json | 931 +++++ src/auto_intersphinx/catalog.py | 686 ++++ src/auto_intersphinx/check_packages.py | 213 ++ src/auto_intersphinx/cli.py | 38 + src/auto_intersphinx/dump_objects.py | 81 + src/auto_intersphinx/update_catalog.py | 226 ++ tests/conftest.py | 13 + tests/data/catalog.json | 39 + tests/data/requirements.txt | 7 + tests/test_auto_intersphinx.py | 314 ++ tests/test_check_packages.py | 143 + tests/test_dump_objects.py | 30 + tests/test_update_catalog.py | 283 ++ 31 files changed, 8711 insertions(+) create mode 100644 .flake8 create mode 100644 .gitignore create mode 100644 .gitlab-ci.yml create mode 100644 .pre-commit-config.yaml create mode 100644 .readthedocs.yaml create mode 100644 .reuse/dep5 create mode 100644 LICENSES/BSD-3-Clause.txt create mode 100644 README.md create mode 100644 doc/api.rst create mode 100644 doc/cli.rst create mode 100644 doc/conf.py create mode 100644 doc/index.rst create mode 100644 doc/install.rst create mode 100644 doc/links.rst create mode 100644 doc/usage.rst create mode 100644 pixi.lock create mode 100644 pyproject.toml create mode 100644 src/auto_intersphinx/__init__.py create mode 100644 src/auto_intersphinx/catalog.json create mode 100644 src/auto_intersphinx/catalog.py create mode 100644 src/auto_intersphinx/check_packages.py create mode 100644 src/auto_intersphinx/cli.py create mode 100644 src/auto_intersphinx/dump_objects.py create mode 100644 src/auto_intersphinx/update_catalog.py create mode 100644 tests/conftest.py create mode 100644 tests/data/catalog.json create mode 100644 tests/data/requirements.txt create mode 100644 tests/test_auto_intersphinx.py create mode 100644 tests/test_check_packages.py create mode 100644 tests/test_dump_objects.py create mode 100644 tests/test_update_catalog.py diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..789d792 --- /dev/null +++ b/.flake8 @@ -0,0 +1,7 @@ +# SPDX-FileCopyrightText: Copyright © 2022 Idiap Research Institute +# +# SPDX-License-Identifier: BSD-3-Clause + +[flake8] +max-line-length = 80 +ignore = E501,W503,E302,E402,E203 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..eb85b01 --- /dev/null +++ b/.gitignore @@ -0,0 +1,27 @@ +# SPDX-FileCopyrightText: Copyright © 2022 Idiap Research Institute +# +# SPDX-License-Identifier: BSD-3-Clause + +*~ +*.swp +*.pyc +*.egg-info +.nfs* +.coverage* +*.DS_Store +.envrc +coverage.xml +test_results.xml +junit-coverage.xml +html/ +build/ +doc/api/ +dist/ +cache/ +.venv/ +_citools/ +_work/ +.mypy_cache/ +.pytest_cache/ +changelog.md +.pixi/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..e83d3a9 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,7 @@ +# SPDX-FileCopyrightText: Copyright © 2022 Idiap Research Institute +# +# SPDX-License-Identifier: BSD-3-Clause + +include: + - project: software/dev-profile + file: /gitlab/pixi.yml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..7def6bb --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,60 @@ +# SPDX-FileCopyrightText: Copyright © 2022 Idiap Research Institute +# +# SPDX-License-Identifier: BSD-3-Clause + +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +repos: + - repo: https://github.com/psf/black + rev: 24.4.2 + hooks: + - id: black + - repo: https://github.com/pycqa/docformatter + rev: v1.7.5 + hooks: + - id: docformatter + - repo: https://github.com/pycqa/isort + rev: 5.13.2 + hooks: + - id: isort + - repo: https://github.com/pycqa/flake8 + rev: 7.0.0 + hooks: + - id: flake8 + - repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.10.0 + hooks: + - id: mypy + args: [ + --install-types, + --non-interactive, + --no-strict-optional, + --ignore-missing-imports, + ] + - repo: https://github.com/asottile/pyupgrade + rev: v3.15.2 + hooks: + - id: pyupgrade + args: [--py38-plus] + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.6.0 + hooks: + - id: check-ast + - id: check-added-large-files + - id: check-toml + - id: check-yaml + - id: check-json + - id: debug-statements + - id: check-case-conflict + - id: trailing-whitespace + - id: end-of-file-fixer + - id: debug-statements + - repo: https://github.com/fsfe/reuse-tool + rev: v3.0.2 + hooks: + - id: reuse + exclude: | + (?x)( + ^.pixi/| + ^.pixi.lock| + ) diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000..67ba8c6 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,17 @@ +# SPDX-FileCopyrightText: Copyright © 2023 Idiap Research Institute +# +# SPDX-License-Identifier: BSD-3-Clause + +version: 2 + +build: + os: "ubuntu-22.04" + tools: + python: "3.11" + +python: + install: + - method: pip + path: . + extra_requirements: + - doc diff --git a/.reuse/dep5 b/.reuse/dep5 new file mode 100644 index 0000000..a34c22c --- /dev/null +++ b/.reuse/dep5 @@ -0,0 +1,11 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: auto-intersphinx +Upstream-Contact: André Anjos +Source: https://gitlab.idiap.ch/bob/auto-intersphinx/ + +Files: + pixi.lock + src/auto_intersphinx/catalog.json + tests/data/* +Copyright: Copyright © 2022 Idiap Research Institute +License: BSD-3-Clause diff --git a/LICENSES/BSD-3-Clause.txt b/LICENSES/BSD-3-Clause.txt new file mode 100644 index 0000000..086d399 --- /dev/null +++ b/LICENSES/BSD-3-Clause.txt @@ -0,0 +1,11 @@ +Copyright (c) . + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..2a9a327 --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ + + +[![latest-docs](https://img.shields.io/badge/docs-latest-orange.svg)](https://auto-intersphinx.readthedocs.io/en/latest/) +[![build](https://gitlab.idiap.ch/software/auto-intersphinx/badges/main/pipeline.svg)](https://gitlab.idiap.ch/software/auto-intersphinx/commits/main) +[![coverage](https://gitlab.idiap.ch/software/auto-intersphinx/badges/main/coverage.svg)](https://www.idiap.ch/software/biosignal/docs/software/auto-intersphinx/main/coverage/index.html) +[![repository](https://img.shields.io/badge/gitlab-project-0000c0.svg)](https://gitlab.idiap.ch/software/auto-intersphinx) + +# Automatically Links Package Documentation from Their Names + +This package contains a [Sphinx](https://www.sphinx-doc.org/) plugin that can +fill +[intersphinx](https://www.sphinx-doc.org/en/main/usage/extensions/intersphinx.html) +mappings based on package names. It simplifies the use of that plugin by +removing the need of knowing URLs for various API catologs you may want to +cross-reference. + +For installation and usage instructions, check-out our documentation. diff --git a/doc/api.rst b/doc/api.rst new file mode 100644 index 0000000..2ce53ce --- /dev/null +++ b/doc/api.rst @@ -0,0 +1,21 @@ +.. SPDX-FileCopyrightText: Copyright © 2022 Idiap Research Institute +.. +.. SPDX-License-Identifier: BSD-3-Clause + +.. _auto_intersphinx.api: + +============ + Python API +============ + +This section includes information for using the Python API of +``auto-intersphinx``. + +.. autosummary:: + :toctree: api + + auto_intersphinx + auto_intersphinx.catalog + + +.. include:: links.rst diff --git a/doc/cli.rst b/doc/cli.rst new file mode 100644 index 0000000..3c71b7a --- /dev/null +++ b/doc/cli.rst @@ -0,0 +1,68 @@ +.. SPDX-FileCopyrightText: Copyright © 2022 Idiap Research Institute +.. +.. SPDX-License-Identifier: BSD-3-Clause + +======================== + Command-line Interface +======================== + +This section includes information for using scripts shipped with +``auto-intersphinx``. + + +auto-intersphinx +---------------- + +.. argparse:: + :module: auto_intersphinx.cli + :func: make_parser + :prog: auto-intersphinx + :nosubcommands: + :nodescription: + + Commands to handle sphinx catalogs. + + Sub-commands: + + * :ref:`auto_intersphinx.cli.check_packages`: Discover documentation cross-references for packages + * :ref:`auto_intersphinx.cli.dump_objects`: Dumps all the objects given an (inter) Sphinx inventory URL + * :ref:`auto_intersphinx.cli.update_catalog`: Discover documentation cross-references for packages + + +.. _auto_intersphinx.cli.check_packages: + +check-packages +-------------- + +.. argparse:: + :module: auto_intersphinx.cli + :func: make_parser + :prog: auto-intersphinx + :path: check-packages + + +.. _auto_intersphinx.cli.dump_objects: + +dump-objects +------------ + +.. argparse:: + :module: auto_intersphinx.cli + :func: make_parser + :prog: auto-intersphinx + :path: dump-objects + + +.. _auto_intersphinx.cli.update_catalog: + +update-catalog +-------------- + +.. argparse:: + :module: auto_intersphinx.cli + :func: make_parser + :prog: auto-intersphinx + :path: update-catalog + + +.. include:: links.rst diff --git a/doc/conf.py b/doc/conf.py new file mode 100644 index 0000000..8c19027 --- /dev/null +++ b/doc/conf.py @@ -0,0 +1,117 @@ +# SPDX-FileCopyrightText: Copyright © 2022 Idiap Research Institute +# +# SPDX-License-Identifier: BSD-3-Clause + +import os +import time + +from importlib.metadata import distribution + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +needs_sphinx = "1.3" + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = [ + "sphinx.ext.todo", + "sphinx.ext.autodoc", + "sphinx.ext.autosummary", + "sphinx.ext.doctest", + "sphinx.ext.napoleon", + "sphinx.ext.viewcode", + "auto_intersphinx", + "sphinx_autodoc_typehints", + "sphinx_copybutton", + "sphinx_inline_tabs", + "sphinxarg.ext", +] + +# Be picky about warnings +nitpicky = True + +# Ignores stuff we can't easily resolve on other project's sphinx manuals +nitpick_ignore = [] + +# Allows the user to override warnings from a separate file +if os.path.exists("nitpick-exceptions.txt"): + for line in open("nitpick-exceptions.txt"): + if line.strip() == "" or line.startswith("#"): + continue + dtype, target = line.split(None, 1) + target = target.strip() + nitpick_ignore.append((dtype, target)) + +# Always includes todos +todo_include_todos = True + +# Generates auto-summary automatically +autosummary_generate = True + +# Create numbers on figures with captions +numfig = True + +# If we are on OSX, the 'dvipng' path maybe different +dvipng_osx = "/Library/TeX/texbin/dvipng" +if os.path.exists(dvipng_osx): + pngmath_dvipng = dvipng_osx + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["_templates"] + +# The suffix of source filenames. +source_suffix = ".rst" + +# The main toctree document. +master_doc = "index" + +# General information about the project. +project = "auto-intersphinx" +package = distribution(project) + +copyright = f"{time.strftime('%Y')}, Idiap Research Institute" # noqa: A001 + +# The short X.Y version. +version = package.version +# The full version, including alpha/beta/rc tags. +release = version + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ["links.rst"] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = "sphinx" +pygments_dark_style = "monokai" + +# A list of ignored prefixes for module index sorting. +# modindex_common_prefix = [] + +# Some variables which are useful for generated material +project_variable = project.replace(".", "_") +short_description = package.metadata["Summary"] +owner = ["Idiap Research Institute"] + +# -- Options for HTML output --------------------------------------------------- + +html_theme = "furo" + +html_theme_options = { + "source_edit_link": f"https://gitlab.idiap.ch/software/{project}/-/edit/main/doc/{{filename}}", +} + +html_title = f"{project} {release}" + +# -- Post configuration -------------------------------------------------------- + +# Default processing flags for sphinx +autodoc_member_order = "bysource" +autodoc_default_options = { + "members": True, + "undoc-members": True, + "show-inheritance": True, +} + +auto_intersphinx_packages = [("python", "3"), "sphinx", "requests", "packaging"] +auto_intersphinx_catalog = "catalog.json" diff --git a/doc/index.rst b/doc/index.rst new file mode 100644 index 0000000..533b352 --- /dev/null +++ b/doc/index.rst @@ -0,0 +1,38 @@ +.. SPDX-FileCopyrightText: Copyright © 2022 Idiap Research Institute +.. +.. SPDX-License-Identifier: BSD-3-Clause + +.. _auto_intersphinx: + +============================================================ + Automatically Links Package Documentation from Their Names +============================================================ + +.. todolist:: + +This package contains a Sphinx_ plugin that can fill intersphinx_ mappings +based on package names. It simplifies the use of that plugin by removing the +need of knowing URLs for various API catologs you may want to cross-reference. + + +Documentation +------------- + +.. toctree:: + :maxdepth: 2 + + install + usage + cli + api + + +Indices and tables +------------------ + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + + +.. include:: links.rst diff --git a/doc/install.rst b/doc/install.rst new file mode 100644 index 0000000..49d749a --- /dev/null +++ b/doc/install.rst @@ -0,0 +1,70 @@ +.. SPDX-FileCopyrightText: Copyright © 2022 Idiap Research Institute +.. +.. SPDX-License-Identifier: BSD-3-Clause + +.. _auto_intersphinx.install: + +============== + Installation +============== + +Installation may follow one of two paths: deployment or development. Choose the +relevant tab for details on each of those installation paths. + + +.. tab:: Deployment (pip/uv) + + Install using pip_, or your preferred Python project management solution (e.g. + uv_, rye_ or poetry_). + + **Stable** release, from PyPI: + + .. code:: sh + + pip install auto-intersphinx + + **Latest** development branch, from its git repository: + + .. code:: sh + + pip install git+https://gitlab.idiap.ch/software/auto-intersphinx@main + + +.. tab:: Deployment (pixi) + + Use pixi_ to add this package as a dependence: + + .. code:: sh + + pixi add auto-intersphinx + + +.. tab:: Development + + Checkout the repository, and then use pixi_ to setup a full development + environment: + + .. code:: sh + + git clone git@gitlab.idiap.ch:software/auto-intersphinx + pixi install --frozen + + .. tip:: + + The ``--frozen`` flag will ensure that the latest lock-file available + with sources is used. If you'd like to update the lock-file to the + latest set of compatible dependencies, remove that option. + + If you use `direnv to setup your pixi environment + `_ + when you enter the directory containing this package, you can use a + ``.envrc`` file similar to this: + + .. code:: sh + + watch_file pixi.lock + export PIXI_FROZEN="true" + eval "$(pixi shell-hook)" + + +.. include:: links.rst diff --git a/doc/links.rst b/doc/links.rst new file mode 100644 index 0000000..18c6282 --- /dev/null +++ b/doc/links.rst @@ -0,0 +1,20 @@ +.. SPDX-FileCopyrightText: Copyright © 2022 Idiap Research Institute +.. +.. SPDX-License-Identifier: BSD-3-Clause + +.. _idiap: http://www.idiap.ch +.. _python: http://www.python.org +.. _pip: https://pip.pypa.io/en/stable/ +.. _uv: https://github.com/astral-sh/uv +.. _rye: https://github.com/astral-sh/rye +.. _poetry: https://python-poetry.org +.. _pixi: https://pixi.sh +.. _mamba: https://mamba.readthedocs.io/en/latest/index.html +.. _sphinx: https://www.sphinx-doc.org/ +.. _intersphinx: https://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html +.. _readthedocs: https://readthedocs.org +.. _pypi: https://pypi.org +.. _docker-py: https://docker-py.readthedocs.io/en/stable/ +.. _docker: https://pypi.org/project/docker/ +.. _pytorch: https://pytorch.org +.. _torch: https://pypi.org/project/torch/ diff --git a/doc/usage.rst b/doc/usage.rst new file mode 100644 index 0000000..513258a --- /dev/null +++ b/doc/usage.rst @@ -0,0 +1,291 @@ +.. SPDX-FileCopyrightText: Copyright © 2022 Idiap Research Institute +.. +.. SPDX-License-Identifier: BSD-3-Clause + +.. _auto_intersphinx.usage: + +======= + Usage +======= + +To use this extension, first enable it on your ``conf.py`` file for Sphinx_: + +.. code-block:: python + + extensions += ["auto_intersphinx"] + + +You do not need to both enable this extension and ``sphinx.ext.intersphinx`` +because this extension will load that automatically. + +Once you have enabled the extension, create a single variable with the names of +the packages you want to cross-reference: + +.. code-block:: python + + auto_intersphinx_packages = ["sphinx", "requests", "packaging"] + + +Optionally, add a catalog file path (relative to ``conf.py``) that will be used +to cache any lookups we may have to do during Sphinx_ document building. + +.. code-block:: python + + auto_intersphinx_catalog = "catalog.json" + + +How does it work? +----------------- + +Auto-intersphinx works by automatically populating ``intersphinx_mapping`` +dictionary using URLs that are stored in the built-in JSON catalog of URLs or +your own. If URLs for a package are not found on these catalogs, +auto-intersphinx checks the installed Python packages and then tries to go +online searching for those cross-references. Here is the rough algorithm, +performed for each entry in the ``auto_intersphinx_packages`` list: + +1. If an intersphinx_ URL for the given package on the user catalog, that is + used prioritarily, and the ``intersphinx_mapping`` for that package is + filled and the algorithm continues with the next package. +2. Else, we check the built-in catalog, distributed with auto-intersphinx. If + an URL for the package is found there, then we fill-in + ``intersphinx_mapping`` and continue. +3. Else, we check the current Python environment, searching for the package + metadata and attached documentation URLs the project may declare. Many + projects declare their Sphinx_ documents this way. If an URL is found, it + is checked for an ``objects.inv`` file existing there (not downloaded at + this point), and if that exists, it added to the user catalog, allowing it + to be added to the ``intersphinx_mapping``. If successful, the algorithm + then goes to the next package. +4. If you get to this point, then auto-intersphinx will look for the package's + "versions" page in https://readthedocs.org. If one is found, then we + download the information on that page, which includes documentation pointers + and store these in the user catalog. We do not check for ``objects.inv`` + file at those URLs since readthedocs_ documents are all Sphinx_-compatible. + If successful, the algorithm adds the ``intersphinx_mapping`` entry for the + package, and then goes to the next package. +5. Finally, if nothing else worked, we will look at the project metadata for + the package at https://pypi.org. PyPI_ metadata often contains + documentation URL for packages. If that is the case, we test it for the + presence of an ``objects.inv`` file and, if successful, add that information + to the user catalog. If successful, the algorithm populates the + ``intersphinx_mapping``, and goes to the next package. + + At this point, if we still do not find the relevant documentation for the + package, auto-intersphinx will generate a build error which will cause + Sphinx_ to exit with an error condition at the end of the processing. + +By the end of the processing, if the user catalog was changed with respect to +the state registered on the disk, and a filename has been defined by setting +``auto_intersphinx_catalog``, it is saved back to that file (a backup is +created if needed), so that the next lookup will not require probing remote +resources. You may commit this JSON file to your repository and keep it there. + + +The Catalog +----------- + +The lookup algorithm above may be optimised/improved/fixed in several ways. To +avoid unnecessary lookups, it is recommended to setup your own catalog of +entries to covering all your documentation needs. Setting up +``auto_intersphinx_catalog`` may help you kick-starting this work. + +Moreover, often, names of packages as they are known in Python, at readthedocs_ +or PyPI_, may differ from the package name you typically use while importing +such package. This may lead the lookup algorithm to search for incorrect +entries in these environments. Here is a list of issues one can typically find +while trying to create a coherent set of ``intersphinx_mapping`` entries: + + * **Package names may be different than what you use for importing them + into your code**. For example, you may import ``docker`` in your code, + however the readthedocs_ entry for this package lives under the name + docker-py_. The PyPI version of the package is placed under docker_. The + famous machine learning package pytorch_ is distributed as torch_ inside + PyPI_. + + * **Packages may not explicitly define their documentation URLs, or be + available on readthedocs_**. For example, pytorch_ has a broken set of + links on readthedocs_, and self-hosts their own documentation. + + * **Packges may not be available while you build your documentation**, and + therefore may not be looked-up at the current environment. + +The URL catalog format has been designed to accomodate these exceptions and +skip automated (online) searches if possible. It is a JSON file that contains +a dictionary, mapping names you'd use as inputs in +``auto_intersphinx_packages`` to another dictionary composed of two keys: +``versions`` and ``sources``. Here is an example: + +.. code-block:: json + + { + "click": { + "versions": { + "latest": "https://click.palletsprojects.com/en/latest/", + "8.1.x": "https://click.palletsprojects.com/en/8.1.x/", + "8.0.x": "https://click.palletsprojects.com/en/8.0.x/", + }, + "sources": {} + }, + "docker": { + "versions": { + "latest": "https://docker-py.readthedocs.io/en/latest/", + "stable": "https://docker-py.readthedocs.io/en/stable/", + "5.0.3": "https://docker-py.readthedocs.io/en/5.0.3/", + "5.0.2": "https://docker-py.readthedocs.io/en/5.0.2/", + "5.0.1": "https://docker-py.readthedocs.io/en/5.0.1/", + "5.0.0": "https://docker-py.readthedocs.io/en/5.0.0/", + }, + "sources": { + "readthedocs": "docker-py" + } + }, + "numpy": { + "versions": { + "latest": "https://numpy.org/devdocs/", + "stable": "https://numpy.org/doc/stable/", + "1.23.x": "https://numpy.org/doc/1.23/", + "1.22.x": "https://numpy.org/doc/1.22/", + "1.21.x": "https://numpy.org/doc/1.21/" + }, + "sources": { + "pypi": "numpy" + } + } + } + +The ``versions`` entry of each package determine version name to URL mappings. +When you do not explicitly request a particular version number catalog to be +linked for a package, the ``stable`` (or ``latest``) versions are used. The +``sources`` entry indicate where information for this package can be found. +Examples are ``environment``, ``readthedocs`` or ``pypi``. The values +correspond to the name that should ber looked up on those services for finding +information about that package. + +In the example above, the package ``click`` has 3 versions encoded in the +catalog, the user can ask for. Furthermore, no online services have +information about this package (probably the user hard-coded those URLs after +inspection). The various versions of the package docker documentation may be +obtained on readthedocs_ under the name ``docker-py``. Finally, ``numpy`` +information may be obtained at PyPI_, under the name ``numpy``. + + +Bootstrapping a Catalog +======================= + +A new user catalog is typically saved on the directory containing the file +``conf.py``, if the user specified the Sphinx_ configuration parameter +``auto_intersphinx_catalog`` with a relative path name (e.g. ``catalog.json``). +However, the user may create and maintain their own catalog file using +command-line utilities shiped with this package. + +To bootstrap a new catalog from scratch, specifying the list of packages to +lookup and populate it with, and use the program +:ref:`auto_intersphinx.cli.update_catalog`: + +.. code-block:: sh + + auto-intersphinx-update-catalog -vvv --catalog=catalog.json numpy requests click + +This will create a new file called ``catalog.json`` on your directory, and will +try to apply the lookup algorithm explained above to find sources of +documentation for these packages. You may hand-edit or improve this catalog +later. + +.. tip:: + + You may bootstrap a new catalog from either a list of packages, as above, or + by providing the path (or URL) of a pip-requirements style file. The + command-line application ``auto-intersphinx-update-catalog`` will parse such + a file, search for resources, and fill-in a catalog. + + +.. tip:: + + Read the application documentation with ``auto-intersphinx-update-catalog + --help`` for usage instructions. + + +Updating a Catalog +================== + +To update an existing catalog, use the command-line application +:ref:`auto_intersphinx.cli.update_catalog`: + +.. code-block:: sh + + auto-intersphinx update-catalog -vvv --self --catalog=catalog.json + +This will read the current information available in the existing catalog, and +will search the sources once more for updated information. Naturally, packages +with no sources (empty ``sources``) entries, will **not** be updated. + + +Browsing for Documentation +-------------------------- + +You may ask the command-line application +:ref:`auto_intersphinx.cli.check_packages` to display where documentation +information may be found for a package. For example: + +.. code-block:: sh + + $ auto-intersphinx check-packages numpy + Found numpy in builtin catalog: + | { + | "latest": "https://numpy.org/devdocs/", + | "stable": "https://numpy.org/doc/stable/", + | "1.23.4": "https://numpy.org/doc/1.23/", + | "1.23.x": "https://numpy.org/doc/1.23/", + | "1.22.x": "https://numpy.org/doc/1.22/", + | "1.21.x": "https://numpy.org/doc/1.21/", + | "1.20.x": "https://numpy.org/doc/1.20/" + | } + +You may ask this tool to keep going and find all sources of information for a +package: + +.. code-block:: sh + + $ auto-intersphinx-check-packages numpy --keep-going + Found numpy in builtin catalog: + | { + | "latest": "https://numpy.org/devdocs/", + | "stable": "https://numpy.org/doc/stable/", + | "1.23.4": "https://numpy.org/doc/1.23/", + | "1.23.x": "https://numpy.org/doc/1.23/", + | "1.22.x": "https://numpy.org/doc/1.22/", + | "1.21.x": "https://numpy.org/doc/1.21/", + | "1.20.x": "https://numpy.org/doc/1.20/" + | } + Found numpy documentation in readthedocs.org: + | { + | "latest": "https://numpy.readthedocs.io/en/latest/", + | "main": "https://numpy.readthedocs.io/en/main/" + | } + Looking up all PyPI versions of numpy - this may be long... + Found numpy documentation in PyPI: + | { + | "1.23.4": "https://numpy.org/doc/1.23/" + | } + +Which may display more information about the package's various sources. The +flag ``--keep-going`` may also be used at ``auto-intersphinx-update-catalog`` +to complete information about a package. While here the ``versions`` +dictionary are displayed in sections, while updating the catalogs, the +resulting ``versions`` dictionaries are merged together. Of course, you still +have the option to copy-and-paste information from the above output, directly +to your catalog. + + +Inspecting intersphinx Inventories +---------------------------------- + +It is sometimes useful to inspect the contents of ``objects.inv`` files +available locally or remotely. To this end, we provide a CLI application +called :ref:`auto_intersphinx.cli.dump_objects`, that can be used to dump the +contents of both local or remote inventories. Read the application +documentation with ``--help``, to discover usage examples. + + +.. include:: links.rst diff --git a/pixi.lock b/pixi.lock new file mode 100644 index 0000000..39ea0a7 --- /dev/null +++ b/pixi.lock @@ -0,0 +1,4429 @@ +version: 5 +environments: + build-ci: + channels: + - url: https://conda.anaconda.org/conda-forge/ + packages: + linux-64: + - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/alabaster-0.7.16-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/anyio-4.3.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/babel-2.14.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/backports-1.0-pyhd8ed1ab_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/backports.tarfile-1.0.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.1.0-py312h30efb56_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hd590300_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.2.2-hbcca054_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2024.2.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cffi-1.16.0-py312hf06ca03_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.3.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.1.7-unix_pyh707e725_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cmarkgfm-0.8.0-py312h98912ed_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/cryptography-42.0.7-py312hbcc2302_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/dbus-1.13.6-h5008d03_3.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.3.8-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/docutils-0.21.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/editables-0.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.0-pyhd8ed1ab_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/expat-2.6.2-h59595ed_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.14.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/h11-0.14.0-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.1.0-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/hatch-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/hatchling-1.24.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.0.0-pyh9f0ad1d_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/httpcore-1.0.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/httpx-0.27.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.0.1-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/hyperlink-21.0.0-pyhd3deb0d_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/icu-73.2-h59595ed_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.7-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/imagesize-1.4.1-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-7.1.0-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-7.1.0-hd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.classes-3.4.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.context-5.3.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.functools-4.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jeepney-0.8.0-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/keyring-25.2.0-pyha804496_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.40-h55db66e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.2-h59595ed_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.2-h7f98852_5.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-13.2.0-h77fa898_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.80.0-hf2295e7_6.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-13.2.0-h77fa898_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.17-hd590300_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hd590300_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.45.3-h2797004_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-13.2.0-hc0a3c3a_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.12.6-h232c23b_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxslt-1.1.39-h76b75d6_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.2.13-hd590300_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lxml-5.2.1-py312hb90d8a5_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-3.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-2.1.5-py312h98912ed_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/more-itertools-10.2.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.4.20240210-h59595ed_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nh3-0.2.17-py312h4b3b743_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.3.0-hd590300_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-24.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-0.12.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.43-hcad00b1_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pexpect-4.9.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.2.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ptyprocess-0.7.0-pyhd3deb0d_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.18.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.3-hab00c5b_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.12-4_cp312.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2024.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/readme_renderer-42.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.31.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-toolbelt-1.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/rfc3986-2.0.0-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/rich-13.7.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/secretstorage-3.3.3-py312h7900ff3_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-69.5.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/shellingham-1.5.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sniffio-1.3.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/snowballstemmer-2.2.0-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinx-7.3.7-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-applehelp-1.0.8-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-devhelp-1.0.6-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-htmlhelp-2.0.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-jsmath-1.0.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-qthelp-1.0.7-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-serializinghtml-1.1.10-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-w-1.0.0-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/tomlkit-0.12.4-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/trove-classifiers-2024.4.10-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/twine-5.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.11.0-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2024a-h0c530f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.2.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/userpath-1.7.0-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/uv-0.1.40-h0ea3d13_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/versioningit-3.1.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.26.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.17.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.22.0-py312hd58854c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.5-hfc55251_0.conda + osx-arm64: + - conda: https://conda.anaconda.org/conda-forge/noarch/alabaster-0.7.16-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/anyio-4.3.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/babel-2.14.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/backports-1.0-pyhd8ed1ab_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/backports.tarfile-1.0.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-python-1.1.0-py312h9f69965_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h93a5062_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ca-certificates-2024.2.2-hf0a4a13_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2024.2.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cffi-1.16.0-py312h8e38eb3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.3.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.1.7-unix_pyh707e725_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cmarkgfm-0.8.0-py312h02f2b3b_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.3.8-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/docutils-0.21.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/editables-0.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.0-pyhd8ed1ab_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.14.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/h11-0.14.0-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.1.0-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/hatch-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/hatchling-1.24.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.0.0-pyh9f0ad1d_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/httpcore-1.0.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/httpx-0.27.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.0.1-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/hyperlink-21.0.0-pyhd3deb0d_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-73.2-hc8870d7_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.7-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/imagesize-1.4.1-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-7.1.0-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-7.1.0-hd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.classes-3.4.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.context-5.3.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.functools-4.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/keyring-25.2.0-pyh534df25_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-17.0.6-h5f092b4_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.6.2-hebf3989_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.4.2-h3422bc3_5.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libiconv-1.17-h0d3ecfb_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.45.3-h091b4b1_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libxml2-2.12.6-h0d0cfa8_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libxslt-1.1.39-h223e5b9_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.2.13-h53f4e23_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lxml-5.2.1-py312h8f698c5_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-3.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/markupsafe-2.1.5-py312he37b823_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/more-itertools-10.2.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.4.20240210-h078ce10_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nh3-0.2.17-py312h5280bc4_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.3.0-h0d3ecfb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-24.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-0.12.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pexpect-4.9.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.2.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ptyprocess-0.7.0-pyhd3deb0d_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.18.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.12.3-h4a7b5fc_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python_abi-3.12-4_cp312.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2024.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.2-h92ec313_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/readme_renderer-42.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.31.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-toolbelt-1.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/rfc3986-2.0.0-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/rich-13.7.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-69.5.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/shellingham-1.5.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sniffio-1.3.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/snowballstemmer-2.2.0-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinx-7.3.7-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-applehelp-1.0.8-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-devhelp-1.0.6-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-htmlhelp-2.0.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-jsmath-1.0.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-qthelp-1.0.7-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-serializinghtml-1.1.10-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h5083fa2_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-w-1.0.0-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/tomlkit-0.12.4-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/trove-classifiers-2024.4.10-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/twine-5.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.11.0-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2024a-h0c530f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.2.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/userpath-1.7.0-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/uv-0.1.40-hc069d6b_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/versioningit-3.1.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.26.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/xz-5.2.6-h57fd34a_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.17.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstandard-0.22.0-py312h7975427_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.5-h4f39d0f_0.conda + default: + channels: + - url: https://conda.anaconda.org/conda-forge/ + indexes: + - https://pypi.org/simple + packages: + linux-64: + - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/alabaster-0.7.16-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/anyio-4.3.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/attrs-23.2.0-pyh71513ae_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/babel-2.14.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/backports-1.0-pyhd8ed1ab_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/backports.tarfile-1.0.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/beautifulsoup4-4.12.3-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/binaryornot-0.4.4-py_1.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/boolean.py-4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.1.0-py312h30efb56_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hd590300_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.2.2-hbcca054_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2024.2.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cffi-1.16.0-py312hf06ca03_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.3.1-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/chardet-5.2.0-py312h7900ff3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.3.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.1.7-unix_pyh707e725_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cmarkgfm-0.8.0-py312h98912ed_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/commonmark-0.9.1-py_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.5.1-py312h9a8786e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cryptography-42.0.7-py312hbcc2302_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/dbus-1.13.6-h5008d03_3.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.3.8-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/docutils-0.21.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/editables-0.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.0-pyhd8ed1ab_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/expat-2.6.2-h59595ed_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/fancycompleter-0.9.1-py312h7900ff3_1007.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.14.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/furo-2024.5.6-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/future-1.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/h11-0.14.0-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.1.0-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/hatch-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/hatchling-1.24.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.0.0-pyh9f0ad1d_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/httpcore-1.0.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/httpx-0.27.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.0.1-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/hyperlink-21.0.0-pyhd3deb0d_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/icu-73.2-h59595ed_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.5.36-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.7-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/imagesize-1.4.1-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-7.1.0-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-7.1.0-hd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.classes-3.4.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.context-5.3.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.functools-4.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jeepney-0.8.0-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/keyring-25.2.0-pyha804496_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.40-h55db66e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.2-h59595ed_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.2-h7f98852_5.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-13.2.0-h77fa898_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.80.0-hf2295e7_6.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-13.2.0-h77fa898_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.17-hd590300_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hd590300_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.45.3-h2797004_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-13.2.0-hc0a3c3a_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.12.6-h232c23b_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxslt-1.1.39-h76b75d6_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.2.13-hd590300_5.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/license-expression-30.1.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lxml-5.2.1-py312hb90d8a5_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-3.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-2.1.5-py312h98912ed_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/more-itertools-10.2.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.4.20240210-h59595ed_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/nh3-0.2.17-py312h4b3b743_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.8.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.3.0-hd590300_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-24.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-0.12.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.43-hcad00b1_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pdbpp-0.10.3-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/pexpect-4.9.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.2.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-3.7.0-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ptyprocess-0.7.0-pyhd3deb0d_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.18.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pyrepl-0.9.0-py312h98912ed_9.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-8.2.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-5.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.3-hab00c5b_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-debian-0.1.36-py_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.12-4_cp312.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2024.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.1-py312h98912ed_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/readme_renderer-42.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.31.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-toolbelt-1.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/reuse-3.0.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/rfc3986-2.0.0-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/rich-13.7.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ruff-0.4.3-py312h5715c7c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/secretstorage-3.3.3-py312h7900ff3_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-69.5.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/shellingham-1.5.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/sniffio-1.3.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/snowballstemmer-2.2.0-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/soupsieve-2.5-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinx-7.3.7-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinx-argparse-0.4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinx-autodoc-typehints-2.1.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinx-basic-ng-1.0.0b2-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinx-copybutton-0.5.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinx-inline-tabs-2023.4.21-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-applehelp-1.0.8-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-devhelp-1.0.6-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-htmlhelp-2.0.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-jsmath-1.0.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-qthelp-1.0.7-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-serializinghtml-1.1.10-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-w-1.0.0-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/tomlkit-0.12.4-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/trove-classifiers-2024.4.10-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/twine-5.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.11.0-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2024a-h0c530f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ukkonen-1.0.1-py312h8572e83_4.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.2.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/userpath-1.7.0-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/uv-0.1.40-h0ea3d13_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/versioningit-3.1.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.26.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wmctrl-0.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h7f98852_2.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.17.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.22.0-py312hd58854c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.5-hfc55251_0.conda + - pypi: . + osx-arm64: + - conda: https://conda.anaconda.org/conda-forge/noarch/alabaster-0.7.16-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/anyio-4.3.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/attrs-23.2.0-pyh71513ae_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/babel-2.14.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/backports-1.0-pyhd8ed1ab_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/backports.tarfile-1.0.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/beautifulsoup4-4.12.3-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/binaryornot-0.4.4-py_1.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/boolean.py-4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-python-1.1.0-py312h9f69965_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h93a5062_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ca-certificates-2024.2.2-hf0a4a13_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2024.2.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cffi-1.16.0-py312h8e38eb3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.3.1-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/chardet-5.2.0-py312h81bd7bf_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.3.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.1.7-unix_pyh707e725_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cmarkgfm-0.8.0-py312h02f2b3b_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/commonmark-0.9.1-py_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/coverage-7.5.1-py312h7e5086c_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.3.8-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/docutils-0.21.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/editables-0.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.0-pyhd8ed1ab_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/fancycompleter-0.9.1-py312h81bd7bf_1007.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.14.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/furo-2024.5.6-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/future-1.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/h11-0.14.0-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.1.0-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/hatch-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/hatchling-1.24.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.0.0-pyh9f0ad1d_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/httpcore-1.0.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/httpx-0.27.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.0.1-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/hyperlink-21.0.0-pyhd3deb0d_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-73.2-hc8870d7_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.5.36-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.7-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/imagesize-1.4.1-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-7.1.0-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-7.1.0-hd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.classes-3.4.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.context-5.3.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jaraco.functools-4.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/keyring-25.2.0-pyh534df25_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-17.0.6-h5f092b4_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.6.2-hebf3989_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.4.2-h3422bc3_5.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libiconv-1.17-h0d3ecfb_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.45.3-h091b4b1_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libxml2-2.12.6-h0d0cfa8_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libxslt-1.1.39-h223e5b9_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.2.13-h53f4e23_5.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/license-expression-30.1.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lxml-5.2.1-py312h8f698c5_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-3.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/markupsafe-2.1.5-py312he37b823_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/more-itertools-10.2.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.4.20240210-h078ce10_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/nh3-0.2.17-py312h5280bc4_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.8.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.3.0-h0d3ecfb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-24.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-0.12.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pdbpp-0.10.3-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/pexpect-4.9.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.2.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-3.7.0-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ptyprocess-0.7.0-pyhd3deb0d_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.18.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyrepl-0.9.0-py312he37b823_9.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-8.2.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-5.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.12.3-h4a7b5fc_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-debian-0.1.36-py_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python_abi-3.12-4_cp312.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2024.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyyaml-6.0.1-py312h02f2b3b_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.2-h92ec313_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/readme_renderer-42.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.31.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-toolbelt-1.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/reuse-3.0.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/rfc3986-2.0.0-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/rich-13.7.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ruff-0.4.3-py312h3402d49_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-69.5.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/shellingham-1.5.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/sniffio-1.3.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/snowballstemmer-2.2.0-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/soupsieve-2.5-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinx-7.3.7-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinx-argparse-0.4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinx-autodoc-typehints-2.1.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinx-basic-ng-1.0.0b2-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinx-copybutton-0.5.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinx-inline-tabs-2023.4.21-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-applehelp-1.0.8-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-devhelp-1.0.6-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-htmlhelp-2.0.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-jsmath-1.0.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-qthelp-1.0.7-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-serializinghtml-1.1.10-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h5083fa2_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-w-1.0.0-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/tomlkit-0.12.4-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/trove-classifiers-2024.4.10-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/twine-5.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.11.0-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2024a-h0c530f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ukkonen-1.0.1-py312h389731b_4.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.2.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/userpath-1.7.0-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/uv-0.1.40-hc069d6b_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/versioningit-3.1.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.26.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wmctrl-0.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/xz-5.2.6-h57fd34a_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/yaml-0.2.5-h3422bc3_2.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.17.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstandard-0.22.0-py312h7975427_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.5-h4f39d0f_0.conda + - pypi: . + qa-ci: + channels: + - url: https://conda.anaconda.org/conda-forge/ + packages: + linux-64: + - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/alabaster-0.7.16-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/babel-2.14.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/binaryornot-0.4.4-py_1.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/boolean.py-4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.1.0-py312h30efb56_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hd590300_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.2.2-hbcca054_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2024.2.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cffi-1.16.0-py312hf06ca03_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.3.1-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/chardet-5.2.0-py312h7900ff3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.3.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.3.8-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/docutils-0.21.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.14.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/icu-73.2-h59595ed_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.5.36-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.7-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/imagesize-1.4.1-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-7.1.0-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.40-h55db66e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.2-h59595ed_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.2-h7f98852_5.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-13.2.0-h77fa898_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-13.2.0-h77fa898_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.17-hd590300_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hd590300_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.45.3-h2797004_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-13.2.0-hc0a3c3a_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.12.6-h232c23b_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxslt-1.1.39-h76b75d6_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.2.13-hd590300_5.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/license-expression-30.1.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lxml-5.2.1-py312hb90d8a5_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-2.1.5-py312h98912ed_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.4.20240210-h59595ed_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.8.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.3.0-hd590300_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-24.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.2.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-3.7.0-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.18.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.3-hab00c5b_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-debian-0.1.36-py_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.12-4_cp312.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2024.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.1-py312h98912ed_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.31.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/reuse-3.0.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ruff-0.4.3-py312h5715c7c_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-69.5.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/snowballstemmer-2.2.0-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinx-7.3.7-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-applehelp-1.0.8-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-devhelp-1.0.6-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-htmlhelp-2.0.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-jsmath-1.0.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-qthelp-1.0.7-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-serializinghtml-1.1.10-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2024a-h0c530f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ukkonen-1.0.1-py312h8572e83_4.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.2.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.26.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h7f98852_2.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.17.0-pyhd8ed1ab_0.conda + osx-arm64: + - conda: https://conda.anaconda.org/conda-forge/noarch/alabaster-0.7.16-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/babel-2.14.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/binaryornot-0.4.4-py_1.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/boolean.py-4.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-python-1.1.0-py312h9f69965_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h93a5062_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ca-certificates-2024.2.2-hf0a4a13_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2024.2.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cffi-1.16.0-py312h8e38eb3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.3.1-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/chardet-5.2.0-py312h81bd7bf_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.3.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.3.8-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/docutils-0.21.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.14.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-73.2-hc8870d7_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.5.36-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.7-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/imagesize-1.4.1-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-7.1.0-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-17.0.6-h5f092b4_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.6.2-hebf3989_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.4.2-h3422bc3_5.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libiconv-1.17-h0d3ecfb_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.45.3-h091b4b1_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libxml2-2.12.6-h0d0cfa8_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libxslt-1.1.39-h223e5b9_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.2.13-h53f4e23_5.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/license-expression-30.1.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lxml-5.2.1-py312h8f698c5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/markupsafe-2.1.5-py312he37b823_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.4.20240210-h078ce10_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.8.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.3.0-h0d3ecfb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-24.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.2.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-3.7.0-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.18.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.12.3-h4a7b5fc_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-debian-0.1.36-py_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python_abi-3.12-4_cp312.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2024.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyyaml-6.0.1-py312h02f2b3b_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.2-h92ec313_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.31.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/reuse-3.0.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ruff-0.4.3-py312h3402d49_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-69.5.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/snowballstemmer-2.2.0-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinx-7.3.7-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-applehelp-1.0.8-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-devhelp-1.0.6-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-htmlhelp-2.0.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-jsmath-1.0.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-qthelp-1.0.7-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-serializinghtml-1.1.10-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h5083fa2_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2024a-h0c530f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ukkonen-1.0.1-py312h389731b_4.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.2.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.26.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/xz-5.2.6-h57fd34a_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/yaml-0.2.5-h3422bc3_2.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.17.0-pyhd8ed1ab_0.conda + test-ci-alternative: + channels: + - url: https://conda.anaconda.org/conda-forge/ + indexes: + - https://pypi.org/simple + packages: + linux-64: + - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/alabaster-0.7.16-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/babel-2.14.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.1.0-py311hb755f60_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hd590300_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.2.2-hbcca054_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2024.2.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.3.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.5.1-py311h331c9d8_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/docutils-0.21.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.0-pyhd8ed1ab_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/icu-73.2-h59595ed_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.7-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/imagesize-1.4.1-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-7.1.0-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.40-h55db66e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.2-h59595ed_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.2-h7f98852_5.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-13.2.0-h77fa898_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-13.2.0-h77fa898_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.17-hd590300_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hd590300_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.45.3-h2797004_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-13.2.0-hc0a3c3a_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.12.6-h232c23b_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxslt-1.1.39-h76b75d6_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.2.13-hd590300_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lxml-5.2.1-py311hc0a218f_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-2.1.5-py311h459d7ec_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.4.20240210-h59595ed_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.3.0-hd590300_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-24.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.18.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-8.2.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-5.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.11.9-hb806964_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.11-4_cp311.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2024.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.31.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-69.5.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/snowballstemmer-2.2.0-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinx-7.3.7-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-applehelp-1.0.8-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-devhelp-1.0.6-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-htmlhelp-2.0.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-jsmath-1.0.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-qthelp-1.0.7-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-serializinghtml-1.1.10-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2024a-h0c530f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.2.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.17.0-pyhd8ed1ab_0.conda + - pypi: . + osx-arm64: + - conda: https://conda.anaconda.org/conda-forge/noarch/alabaster-0.7.16-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/babel-2.14.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-python-1.1.0-py311ha891d26_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h93a5062_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ca-certificates-2024.2.2-hf0a4a13_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2024.2.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.3.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/coverage-7.5.1-py311hd3f4193_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/docutils-0.21.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.0-pyhd8ed1ab_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-73.2-hc8870d7_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.7-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/imagesize-1.4.1-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-7.1.0-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.4-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-17.0.6-h5f092b4_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.6.2-hebf3989_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.4.2-h3422bc3_5.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libiconv-1.17-h0d3ecfb_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.45.3-h091b4b1_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libxml2-2.12.6-h0d0cfa8_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libxslt-1.1.39-h223e5b9_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.2.13-h53f4e23_5.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lxml-5.2.1-py311h1f7f111_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/markupsafe-2.1.5-py311h05b510d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.4.20240210-h078ce10_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.3.0-h0d3ecfb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-24.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.18.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-8.2.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-5.0.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.11.9-h932a869_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python_abi-3.11-4_cp311.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2024.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.2-h92ec313_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.31.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-69.5.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/snowballstemmer-2.2.0-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinx-7.3.7-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-applehelp-1.0.8-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-devhelp-1.0.6-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-htmlhelp-2.0.5-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-jsmath-1.0.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-qthelp-1.0.7-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-serializinghtml-1.1.10-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h5083fa2_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2024a-h0c530f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.2.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/xz-5.2.6-h57fd34a_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.17.0-pyhd8ed1ab_0.conda + - pypi: . +packages: +- kind: conda + name: _libgcc_mutex + version: '0.1' + build: conda_forge + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 + sha256: fe51de6107f9edc7aa4f786a70f4a883943bc9d39b3bb7307c04c41410990726 + md5: d7c89558ba9fa0495403155b64376d81 + license: None + size: 2562 + timestamp: 1578324546067 +- kind: conda + name: _openmp_mutex + version: '4.5' + build: 2_gnu + build_number: 16 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 + sha256: fbe2c5e56a653bebb982eda4876a9178aedfc2b545f25d0ce9c4c0b508253d22 + md5: 73aaf86a425cc6e73fcf236a5a46396d + depends: + - _libgcc_mutex 0.1 conda_forge + - libgomp >=7.5.0 + constrains: + - openmp_impl 9999 + license: BSD-3-Clause + license_family: BSD + size: 23621 + timestamp: 1650670423406 +- kind: conda + name: alabaster + version: 0.7.16 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/alabaster-0.7.16-pyhd8ed1ab_0.conda + sha256: fd39ad2fabec1569bbb0dfdae34ab6ce7de6ec09dcec8638f83dad0373594069 + md5: def531a3ac77b7fb8c21d17bb5d0badb + depends: + - python >=3.9 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/alabaster + size: 18365 + timestamp: 1704848898483 +- kind: conda + name: anyio + version: 4.3.0 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/anyio-4.3.0-pyhd8ed1ab_0.conda + sha256: 86aca4a31c09f9b4dbdb332cd9a6a7dbab62ca734d3f832651c0ab59c6a7f52e + md5: ac95aa8ed65adfdde51132595c79aade + depends: + - exceptiongroup >=1.0.2 + - idna >=2.8 + - python >=3.8 + - sniffio >=1.1 + - typing_extensions >=4.1 + constrains: + - trio >=0.23 + - uvloop >=0.17 + license: MIT + license_family: MIT + purls: + - pkg:pypi/anyio + size: 102331 + timestamp: 1708355504396 +- kind: conda + name: attrs + version: 23.2.0 + build: pyh71513ae_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/attrs-23.2.0-pyh71513ae_0.conda + sha256: 77c7d03bdb243a048fff398cedc74327b7dc79169ebe3b4c8448b0331ea55fea + md5: 5e4c0743c70186509d1412e03c2d8dfa + depends: + - python >=3.7 + license: MIT + license_family: MIT + purls: + - pkg:pypi/attrs + size: 54582 + timestamp: 1704011393776 +- kind: pypi + name: auto-intersphinx + version: 1.0.4.dev11+g20d1f8f.d20240508 + path: . + sha256: 7b8004adf596a6fa50ef135e886a23b0654f5262f227dafc2e14e9499782fc55 + requires_dist: + - lxml + - packaging + - requests + - sphinx + - furo ; extra == 'doc' + - sphinx-argparse ; extra == 'doc' + - sphinx-autodoc-typehints ; extra == 'doc' + - sphinx-copybutton ; extra == 'doc' + - sphinx-inline-tabs ; extra == 'doc' + - pre-commit ; extra == 'qa' + - pytest ; extra == 'test' + - pytest-cov ; extra == 'test' + requires_python: '>=3.10' + editable: true +- kind: conda + name: babel + version: 2.14.0 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/babel-2.14.0-pyhd8ed1ab_0.conda + sha256: 8584e3da58e92b72641c89ff9b98c51f0d5dbe76e527867804cbdf03ac91d8e6 + md5: 9669586875baeced8fc30c0826c3270e + depends: + - python >=3.7 + - pytz + - setuptools + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/babel + size: 7609750 + timestamp: 1702422720584 +- kind: conda + name: backports + version: '1.0' + build: pyhd8ed1ab_3 + build_number: 3 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/backports-1.0-pyhd8ed1ab_3.conda + sha256: 711602276ae39276cb0faaca6fd0ac851fff0ca17151917569174841ef830bbd + md5: 54ca2e08b3220c148a1d8329c2678e02 + depends: + - python >=2.7 + license: BSD-3-Clause + license_family: BSD + size: 5950 + timestamp: 1669158729416 +- kind: conda + name: backports.tarfile + version: 1.0.0 + build: pyhd8ed1ab_1 + build_number: 1 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/backports.tarfile-1.0.0-pyhd8ed1ab_1.conda + sha256: 7ba30f32daad2e7ca251508525185ba170eedc14123572611c2acf261c7956b3 + md5: c747b1d79f136013c3b7ebcba876afa6 + depends: + - backports + - python >=3.8 + license: MIT + license_family: MIT + purls: + - pkg:pypi/backports-tarfile + size: 31951 + timestamp: 1712700751335 +- kind: conda + name: beautifulsoup4 + version: 4.12.3 + build: pyha770c72_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/beautifulsoup4-4.12.3-pyha770c72_0.conda + sha256: 7b05b2d0669029326c623b9df7a29fa49d1982a9e7e31b2fea34b4c9a4a72317 + md5: 332493000404d8411859539a5a630865 + depends: + - python >=3.6 + - soupsieve >=1.2 + license: MIT + license_family: MIT + purls: + - pkg:pypi/beautifulsoup4 + size: 118200 + timestamp: 1705564819537 +- kind: conda + name: binaryornot + version: 0.4.4 + build: py_1 + build_number: 1 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/binaryornot-0.4.4-py_1.tar.bz2 + sha256: 8f65c16a9f85285e1f704a26d4c5ced25f46544f5cc20dc8a4aebd7796f8011a + md5: a556fa60840fcb9dd739d186bfd252f7 + depends: + - chardet + - python + license: BSD-3-Clause + license_family: BSD + size: 378445 + timestamp: 1531097907306 +- kind: conda + name: boolean.py + version: '4.0' + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/boolean.py-4.0-pyhd8ed1ab_0.conda + sha256: 7b3ee20479c6a169137ed6129e1a83941a51c25c71e5c2470787805595fc664b + md5: 46250fe31e1cdc42a316bbd2ec870e24 + depends: + - python >=3.6 + license: BSD-2-Clause + license_family: BSD + purls: + - pkg:pypi/boolean-py + size: 28706 + timestamp: 1690384476510 +- kind: conda + name: brotli-python + version: 1.1.0 + build: py311ha891d26_1 + build_number: 1 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-python-1.1.0-py311ha891d26_1.conda + sha256: 2d78c79ccf2c17236c52ef217a4c34b762eb7908a6903d94439f787aac1c8f4b + md5: 5e802b015e33447d1283d599d21f052b + depends: + - libcxx >=15.0.7 + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + constrains: + - libbrotlicommon 1.1.0 hb547adb_1 + license: MIT + license_family: MIT + purls: + - pkg:pypi/brotli + size: 343332 + timestamp: 1695991223439 +- kind: conda + name: brotli-python + version: 1.1.0 + build: py311hb755f60_1 + build_number: 1 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.1.0-py311hb755f60_1.conda + sha256: 559093679e9fdb6061b7b80ca0f9a31fe6ffc213f1dae65bc5c82e2cd1a94107 + md5: cce9e7c3f1c307f2a5fb08a2922d6164 + depends: + - libgcc-ng >=12 + - libstdcxx-ng >=12 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + constrains: + - libbrotlicommon 1.1.0 hd590300_1 + license: MIT + license_family: MIT + purls: + - pkg:pypi/brotli + size: 351340 + timestamp: 1695990160360 +- kind: conda + name: brotli-python + version: 1.1.0 + build: py312h30efb56_1 + build_number: 1 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.1.0-py312h30efb56_1.conda + sha256: b68706698b6ac0d31196a8bcb061f0d1f35264bcd967ea45e03e108149a74c6f + md5: 45801a89533d3336a365284d93298e36 + depends: + - libgcc-ng >=12 + - libstdcxx-ng >=12 + - python >=3.12.0rc3,<3.13.0a0 + - python_abi 3.12.* *_cp312 + constrains: + - libbrotlicommon 1.1.0 hd590300_1 + license: MIT + license_family: MIT + purls: + - pkg:pypi/brotli + size: 350604 + timestamp: 1695990206327 +- kind: conda + name: brotli-python + version: 1.1.0 + build: py312h9f69965_1 + build_number: 1 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-python-1.1.0-py312h9f69965_1.conda + sha256: 3418b1738243abba99e931c017b952771eeaa1f353c07f7d45b55e83bb74fcb3 + md5: 1bc01b9ffdf42beb1a9fe4e9222e0567 + depends: + - libcxx >=15.0.7 + - python >=3.12.0rc3,<3.13.0a0 + - python >=3.12.0rc3,<3.13.0a0 *_cpython + - python_abi 3.12.* *_cp312 + constrains: + - libbrotlicommon 1.1.0 hb547adb_1 + license: MIT + license_family: MIT + purls: + - pkg:pypi/brotli + size: 343435 + timestamp: 1695990731924 +- kind: conda + name: bzip2 + version: 1.0.8 + build: h93a5062_5 + build_number: 5 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h93a5062_5.conda + sha256: bfa84296a638bea78a8bb29abc493ee95f2a0218775642474a840411b950fe5f + md5: 1bbc659ca658bfd49a481b5ef7a0f40f + license: bzip2-1.0.6 + license_family: BSD + size: 122325 + timestamp: 1699280294368 +- kind: conda + name: bzip2 + version: 1.0.8 + build: hd590300_5 + build_number: 5 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hd590300_5.conda + sha256: 242c0c324507ee172c0e0dd2045814e746bb303d1eb78870d182ceb0abc726a8 + md5: 69b8b6202a07720f448be700e300ccf4 + depends: + - libgcc-ng >=12 + license: bzip2-1.0.6 + license_family: BSD + size: 254228 + timestamp: 1699279927352 +- kind: conda + name: ca-certificates + version: 2024.2.2 + build: hbcca054_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.2.2-hbcca054_0.conda + sha256: 91d81bfecdbb142c15066df70cc952590ae8991670198f92c66b62019b251aeb + md5: 2f4327a1cbe7f022401b236e915a5fef + license: ISC + size: 155432 + timestamp: 1706843687645 +- kind: conda + name: ca-certificates + version: 2024.2.2 + build: hf0a4a13_0 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/ca-certificates-2024.2.2-hf0a4a13_0.conda + sha256: 49bc3439816ac72d0c0e0f144b8cc870fdcc4adec2e861407ec818d8116b2204 + md5: fb416a1795f18dcc5a038bc2dc54edf9 + license: ISC + size: 155725 + timestamp: 1706844034242 +- kind: conda + name: certifi + version: 2024.2.2 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/certifi-2024.2.2-pyhd8ed1ab_0.conda + sha256: f1faca020f988696e6b6ee47c82524c7806380b37cfdd1def32f92c326caca54 + md5: 0876280e409658fc6f9e75d035960333 + depends: + - python >=3.7 + license: ISC + purls: + - pkg:pypi/certifi + size: 160559 + timestamp: 1707022289175 +- kind: conda + name: cffi + version: 1.16.0 + build: py312h8e38eb3_0 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/cffi-1.16.0-py312h8e38eb3_0.conda + sha256: 1544403cb1a5ca2aeabf0dac86d9ce6066d6fb4363493643b33ffd1b78038d18 + md5: 960ecbd65860d3b1de5e30373e1bffb1 + depends: + - libffi >=3.4,<4.0a0 + - pycparser + - python >=3.12.0rc3,<3.13.0a0 + - python >=3.12.0rc3,<3.13.0a0 *_cpython + - python_abi 3.12.* *_cp312 + license: MIT + license_family: MIT + purls: + - pkg:pypi/cffi + size: 284245 + timestamp: 1696002181644 +- kind: conda + name: cffi + version: 1.16.0 + build: py312hf06ca03_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/cffi-1.16.0-py312hf06ca03_0.conda + sha256: 5a36e2c254603c367d26378fa3a205bd92263e30acf195f488749562b4c44251 + md5: 56b0ca764ce23cc54f3f7e2a7b970f6d + depends: + - libffi >=3.4,<4.0a0 + - libgcc-ng >=12 + - pycparser + - python >=3.12.0rc3,<3.13.0a0 + - python_abi 3.12.* *_cp312 + license: MIT + license_family: MIT + purls: + - pkg:pypi/cffi + size: 294523 + timestamp: 1696001868949 +- kind: conda + name: cfgv + version: 3.3.1 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.3.1-pyhd8ed1ab_0.tar.bz2 + sha256: fbc03537a27ef756162c49b1d0608bf7ab12fa5e38ceb8563d6f4859e835ac5c + md5: ebb5f5f7dc4f1a3780ef7ea7738db08c + depends: + - python >=3.6.1 + license: MIT + license_family: MIT + purls: + - pkg:pypi/cfgv + size: 10788 + timestamp: 1629909423398 +- kind: conda + name: chardet + version: 5.2.0 + build: py312h7900ff3_1 + build_number: 1 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/chardet-5.2.0-py312h7900ff3_1.conda + sha256: 584804790b465c8e28b3c3fcea8e774cb659fe479afd8adc0d39406e8c220194 + md5: af3980cc4690716a5510c8a08cb06238 + depends: + - python >=3.12.0rc3,<3.13.0a0 + - python_abi 3.12.* *_cp312 + license: LGPL-2.1-only + license_family: GPL + purls: + - pkg:pypi/chardet + size: 260197 + timestamp: 1695468803539 +- kind: conda + name: chardet + version: 5.2.0 + build: py312h81bd7bf_1 + build_number: 1 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/chardet-5.2.0-py312h81bd7bf_1.conda + sha256: 2451501ec933017ff77c18436884baa90b289420c43ad4bdb4fe60d55e5dcdfd + md5: ea728c39b7453cb5f7177bc44ee22c73 + depends: + - python >=3.12.0rc3,<3.13.0a0 + - python >=3.12.0rc3,<3.13.0a0 *_cpython + - python_abi 3.12.* *_cp312 + license: LGPL-2.1-only + license_family: GPL + purls: + - pkg:pypi/chardet + size: 263585 + timestamp: 1695469015195 +- kind: conda + name: charset-normalizer + version: 3.3.2 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.3.2-pyhd8ed1ab_0.conda + sha256: 20cae47d31fdd58d99c4d2e65fbdcefa0b0de0c84e455ba9d6356a4bdbc4b5b9 + md5: 7f4a9e3fcff3f6356ae99244a014da6a + depends: + - python >=3.7 + license: MIT + license_family: MIT + purls: + - pkg:pypi/charset-normalizer + size: 46597 + timestamp: 1698833765762 +- kind: conda + name: click + version: 8.1.7 + build: unix_pyh707e725_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/click-8.1.7-unix_pyh707e725_0.conda + sha256: f0016cbab6ac4138a429e28dbcb904a90305b34b3fe41a9b89d697c90401caec + md5: f3ad426304898027fc619827ff428eca + depends: + - __unix + - python >=3.8 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/click + size: 84437 + timestamp: 1692311973840 +- kind: conda + name: cmarkgfm + version: 0.8.0 + build: py312h02f2b3b_3 + build_number: 3 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/cmarkgfm-0.8.0-py312h02f2b3b_3.conda + sha256: 2e95c3797cd2796f32de8408626d63cb1283f2b7b0826021d2e26cc58d9231a0 + md5: ffedee35be7a5015d09e2660a66b89c9 + depends: + - cffi >=1.0.0 + - python >=3.12.0rc3,<3.13.0a0 + - python >=3.12.0rc3,<3.13.0a0 *_cpython + - python_abi 3.12.* *_cp312 + license: MIT + license_family: MIT + purls: + - pkg:pypi/cmarkgfm + size: 113474 + timestamp: 1695670347968 +- kind: conda + name: cmarkgfm + version: 0.8.0 + build: py312h98912ed_3 + build_number: 3 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/cmarkgfm-0.8.0-py312h98912ed_3.conda + sha256: 1a9e60b18664c22f872435a1d2b1d727e37ea4159736b116afff364b9577dc02 + md5: 0c9c09134b2fb151c2bd8181b2c56080 + depends: + - cffi >=1.0.0 + - libgcc-ng >=12 + - python >=3.12.0rc3,<3.13.0a0 + - python_abi 3.12.* *_cp312 + license: MIT + license_family: MIT + purls: + - pkg:pypi/cmarkgfm + size: 135963 + timestamp: 1695669875921 +- kind: conda + name: colorama + version: 0.4.6 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2 + sha256: 2c1b2e9755ce3102bca8d69e8f26e4f087ece73f50418186aee7c74bef8e1698 + md5: 3faab06a954c2a04039983f2c4a50d99 + depends: + - python >=3.7 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/colorama + size: 25170 + timestamp: 1666700778190 +- kind: conda + name: commonmark + version: 0.9.1 + build: py_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/commonmark-0.9.1-py_0.tar.bz2 + sha256: 10577f82bafd5d37f0c3f2122272d0dc1f2d133655c2bdd1a3cd5f910d0bd4c5 + md5: 6aa0173c14befcd577ded130cf6f22f5 + depends: + - future >=0.14.0 + - python + license: BSD 3-Clause + license_family: BSD + purls: + - pkg:pypi/commonmark + size: 47354 + timestamp: 1570221752112 +- kind: conda + name: coverage + version: 7.5.1 + build: py311h331c9d8_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.5.1-py311h331c9d8_0.conda + sha256: 2ecb21dc0efec42419c50f63daf1db0d6910f47db1b2653ebc5c43f76302024e + md5: 9f35e13e3b9e05e153b78f42662061f6 + depends: + - libgcc-ng >=12 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + - tomli + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/coverage + size: 369007 + timestamp: 1714846741185 +- kind: conda + name: coverage + version: 7.5.1 + build: py311hd3f4193_0 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/coverage-7.5.1-py311hd3f4193_0.conda + sha256: 6eaa811402fc3433bd891179410a434d0826da1f44579eccccc9dbb632769403 + md5: 81834421a20531c880f6c0a5342f3922 + depends: + - __osx >=11.0 + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + - tomli + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/coverage + size: 368146 + timestamp: 1714846963260 +- kind: conda + name: coverage + version: 7.5.1 + build: py312h7e5086c_0 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/coverage-7.5.1-py312h7e5086c_0.conda + sha256: dc3d6d36edd2587da94cd0045ccf3460cf84ce77a40f62db4a75d3653e96c8d6 + md5: 08067b92914143861a65b650dd0af4d0 + depends: + - __osx >=11.0 + - python >=3.12,<3.13.0a0 + - python >=3.12,<3.13.0a0 *_cpython + - python_abi 3.12.* *_cp312 + - tomli + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/coverage + size: 359716 + timestamp: 1714846946149 +- kind: conda + name: coverage + version: 7.5.1 + build: py312h9a8786e_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.5.1-py312h9a8786e_0.conda + sha256: 272e507f0ea567ec4c9cf2621c27d34eec5aaa70ebea5d03d508b33b4497de17 + md5: 2d24a25dab0d00182eeed1ba9b64a12d + depends: + - libgcc-ng >=12 + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + - tomli + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/coverage + size: 360545 + timestamp: 1714846745949 +- kind: conda + name: cryptography + version: 42.0.7 + build: py312hbcc2302_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/cryptography-42.0.7-py312hbcc2302_0.conda + sha256: 91fa2d4229096ecffa36e71a33f2163d1138dc1ef98a0be20ba0e5905e420a85 + md5: 7bc0e1aae21b2e82d03959931f4294f0 + depends: + - cffi >=1.12 + - libgcc-ng >=12 + - openssl >=3.3.0,<4.0a0 + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + license: Apache-2.0 AND BSD-3-Clause AND PSF-2.0 AND MIT + license_family: BSD + purls: + - pkg:pypi/cryptography + size: 1978679 + timestamp: 1715044173081 +- kind: conda + name: dbus + version: 1.13.6 + build: h5008d03_3 + build_number: 3 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/dbus-1.13.6-h5008d03_3.tar.bz2 + sha256: 8f5f995699a2d9dbdd62c61385bfeeb57c82a681a7c8c5313c395aa0ccab68a5 + md5: ecfff944ba3960ecb334b9a2663d708d + depends: + - expat >=2.4.2,<3.0a0 + - libgcc-ng >=9.4.0 + - libglib >=2.70.2,<3.0a0 + license: GPL-2.0-or-later + license_family: GPL + size: 618596 + timestamp: 1640112124844 +- kind: conda + name: distlib + version: 0.3.8 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/distlib-0.3.8-pyhd8ed1ab_0.conda + sha256: 3ff11acdd5cc2f80227682966916e878e45ced94f59c402efb94911a5774e84e + md5: db16c66b759a64dc5183d69cc3745a52 + depends: + - python 2.7|>=3.6 + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/distlib + size: 274915 + timestamp: 1702383349284 +- kind: conda + name: docutils + version: 0.21.2 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/docutils-0.21.2-pyhd8ed1ab_0.conda + sha256: 362bfe3afaac18298c48c0c6a935641544077ce5105a42a2d8ebe750ad07c574 + md5: e8cd5d629f65bdf0f3bb312cde14659e + depends: + - python >=3.9 + license: CC-PDDC AND BSD-3-Clause AND BSD-2-Clause AND ZPL-2.1 + purls: + - pkg:pypi/docutils + size: 403226 + timestamp: 1713930478970 +- kind: conda + name: editables + version: '0.5' + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/editables-0.5-pyhd8ed1ab_0.conda + sha256: de160a7494e7bc72360eea6a29cbddf194d0a79f45ff417a4de20e6858cf79a9 + md5: 9873878e2a069bc358b69e9a29c1ecd5 + depends: + - python >=3.7 + license: MIT + license_family: MIT + purls: + - pkg:pypi/editables + size: 10988 + timestamp: 1705857085102 +- kind: conda + name: exceptiongroup + version: 1.2.0 + build: pyhd8ed1ab_2 + build_number: 2 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.0-pyhd8ed1ab_2.conda + sha256: a6ae416383bda0e3ed14eaa187c653e22bec94ff2aa3b56970cdf0032761e80d + md5: 8d652ea2ee8eaee02ed8dc820bc794aa + depends: + - python >=3.7 + license: MIT and PSF-2.0 + purls: + - pkg:pypi/exceptiongroup + size: 20551 + timestamp: 1704921321122 +- kind: conda + name: expat + version: 2.6.2 + build: h59595ed_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/expat-2.6.2-h59595ed_0.conda + sha256: 89916c536ae5b85bb8bf0cfa27d751e274ea0911f04e4a928744735c14ef5155 + md5: 53fb86322bdb89496d7579fe3f02fd61 + depends: + - libexpat 2.6.2 h59595ed_0 + - libgcc-ng >=12 + license: MIT + license_family: MIT + size: 137627 + timestamp: 1710362144873 +- kind: conda + name: fancycompleter + version: 0.9.1 + build: py312h7900ff3_1007 + build_number: 1007 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/fancycompleter-0.9.1-py312h7900ff3_1007.conda + sha256: 12f78c53b9dac0ecfb1650a339bf8b950ba8f127a108eb09c3adda44a79ef31c + md5: 9dfab523f1136690d861fe337034dbee + depends: + - pyrepl >=0.8.2 + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/fancycompleter + size: 26174 + timestamp: 1709160998274 +- kind: conda + name: fancycompleter + version: 0.9.1 + build: py312h81bd7bf_1007 + build_number: 1007 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/fancycompleter-0.9.1-py312h81bd7bf_1007.conda + sha256: 895d2bdd1e56d28be8be0a46adbce92fcdf08e1b0dca073b99f2f4b5211603f9 + md5: 3b30d90c8ca61010a6f85eb9ce2a049f + depends: + - pyrepl >=0.8.2 + - python >=3.12,<3.13.0a0 + - python >=3.12,<3.13.0a0 *_cpython + - python_abi 3.12.* *_cp312 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/fancycompleter + size: 26498 + timestamp: 1709161451678 +- kind: conda + name: filelock + version: 3.14.0 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/filelock-3.14.0-pyhd8ed1ab_0.conda + sha256: 6031be667e1b0cc0dee713f1cbca887cdee4daafa8bac478da33096f3147d38b + md5: 831d85ae0acfba31b8efd0f0d07da736 + depends: + - python >=3.7 + license: Unlicense + purls: + - pkg:pypi/filelock + size: 15902 + timestamp: 1714422911808 +- kind: conda + name: furo + version: 2024.5.6 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/furo-2024.5.6-pyhd8ed1ab_0.conda + sha256: 1c99f4b62b84b66b78a74d5781bf92c3ab1795c4d18476c4f7580dee0c8f3a07 + md5: c5d6d467e2d8a74cdd2a888d8e348950 + depends: + - beautifulsoup4 + - pygments >=2.7 + - python >=3.7 + - sphinx >=6.0,<8.0 + - sphinx-basic-ng + license: MIT + purls: + - pkg:pypi/furo + size: 83103 + timestamp: 1715029589799 +- kind: conda + name: future + version: 1.0.0 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/future-1.0.0-pyhd8ed1ab_0.conda + sha256: 8c918a63595ae01575b738ddf0bff10dc23a5002d4af4c8b445d1179a76a8efd + md5: 650a7807e689642dddd3590eb817beed + depends: + - python >=3.8 + license: MIT + license_family: MIT + purls: + - pkg:pypi/future + size: 364081 + timestamp: 1708610254418 +- kind: conda + name: h11 + version: 0.14.0 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/h11-0.14.0-pyhd8ed1ab_0.tar.bz2 + sha256: 817d2c77d53afe3f3d9cf7f6eb8745cdd8ea76c7adaa9d7ced75c455a2c2c085 + md5: b21ed0883505ba1910994f1df031a428 + depends: + - python >=3 + - typing_extensions + license: MIT + license_family: MIT + purls: + - pkg:pypi/h11 + size: 48251 + timestamp: 1664132995560 +- kind: conda + name: h2 + version: 4.1.0 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/h2-4.1.0-pyhd8ed1ab_0.tar.bz2 + sha256: bfc6a23849953647f4e255c782e74a0e18fe16f7e25c7bb0bc57b83bb6762c7a + md5: b748fbf7060927a6e82df7cb5ee8f097 + depends: + - hpack >=4.0,<5 + - hyperframe >=6.0,<7 + - python >=3.6.1 + license: MIT + license_family: MIT + purls: + - pkg:pypi/h2 + size: 46754 + timestamp: 1634280590080 +- kind: conda + name: hatch + version: 1.10.0 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/hatch-1.10.0-pyhd8ed1ab_0.conda + sha256: c640173693bb4279977cb6f0ec5589080f8884c0b884425370a67333abfca96d + md5: b607d2f0443d35dc50251c50ea96fb10 + depends: + - click >=8.0.6 + - hatchling >=1.24.2 + - httpx >=0.22.0 + - hyperlink >=21.0.0 + - keyring >=23.5.0 + - packaging >=23.2 + - pexpect >=4.8,<5 + - platformdirs >=2.5.0 + - python >=3.8 + - rich >=11.2.0 + - shellingham >=1.4.0 + - tomli-w >=1.0 + - tomlkit >=0.11.1 + - userpath >=1.7,<2 + - uv >=0.1.35 + - virtualenv >=20.26.1 + - zstandard <1.0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/hatch + size: 174266 + timestamp: 1714687924505 +- kind: conda + name: hatchling + version: 1.24.2 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/hatchling-1.24.2-pyhd8ed1ab_0.conda + sha256: 1161601871d8aa6c5ff7719a277462cdf0160351a88f2a84a22d6ead3b90150f + md5: 28cef29029f6da70e7a987a76a3599a4 + depends: + - editables >=0.3 + - importlib-metadata + - packaging >=21.3 + - pathspec >=0.10.1 + - pluggy >=1.0.0 + - python >=3.7 + - tomli >=1.2.2 + - trove-classifiers + license: MIT + license_family: MIT + purls: + - pkg:pypi/hatchling + size: 63793 + timestamp: 1713757830609 +- kind: conda + name: hpack + version: 4.0.0 + build: pyh9f0ad1d_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/hpack-4.0.0-pyh9f0ad1d_0.tar.bz2 + sha256: 5dec948932c4f740674b1afb551223ada0c55103f4c7bf86a110454da3d27cb8 + md5: 914d6646c4dbb1fd3ff539830a12fd71 + depends: + - python + license: MIT + license_family: MIT + purls: + - pkg:pypi/hpack + size: 25341 + timestamp: 1598856368685 +- kind: conda + name: httpcore + version: 1.0.5 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/httpcore-1.0.5-pyhd8ed1ab_0.conda + sha256: 4025644200eefa0598e4600a66fd4804a57d9fd7054a5c8c45e508fd875e0b84 + md5: a6b9a0158301e697e4d0a36a3d60e133 + depends: + - anyio >=3.0,<5.0 + - certifi + - h11 >=0.13,<0.15 + - h2 >=3,<5 + - python >=3.8 + - sniffio 1.* + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/httpcore + size: 45816 + timestamp: 1711597091407 +- kind: conda + name: httpx + version: 0.27.0 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/httpx-0.27.0-pyhd8ed1ab_0.conda + sha256: fdaf341fb2630b7afe8238315448fc93947f77ebfa4da68bb349e1bcf820af58 + md5: 9f359af5a886fd6ca6b2b6ea02e58332 + depends: + - anyio + - certifi + - httpcore 1.* + - idna + - python >=3.8 + - sniffio + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/httpx + size: 64651 + timestamp: 1708531043505 +- kind: conda + name: hyperframe + version: 6.0.1 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.0.1-pyhd8ed1ab_0.tar.bz2 + sha256: e374a9d0f53149328134a8d86f5d72bca4c6dcebed3c0ecfa968c02996289330 + md5: 9f765cbfab6870c8435b9eefecd7a1f4 + depends: + - python >=3.6 + license: MIT + license_family: MIT + purls: + - pkg:pypi/hyperframe + size: 14646 + timestamp: 1619110249723 +- kind: conda + name: hyperlink + version: 21.0.0 + build: pyhd3deb0d_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/hyperlink-21.0.0-pyhd3deb0d_0.tar.bz2 + sha256: 026cb82ada41be9ee2836a2ace526e85c4603e77617887c41c6e62c9bde798b3 + md5: 1303beb57b40f8f4ff6fb1bb23bf0553 + depends: + - idna >=2.6 + - python + license: MIT + license_family: MIT + purls: + - pkg:pypi/hyperlink + size: 72732 + timestamp: 1610092261086 +- kind: conda + name: icu + version: '73.2' + build: h59595ed_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/icu-73.2-h59595ed_0.conda + sha256: e12fd90ef6601da2875ebc432452590bc82a893041473bc1c13ef29001a73ea8 + md5: cc47e1facc155f91abd89b11e48e72ff + depends: + - libgcc-ng >=12 + - libstdcxx-ng >=12 + license: MIT + license_family: MIT + size: 12089150 + timestamp: 1692900650789 +- kind: conda + name: icu + version: '73.2' + build: hc8870d7_0 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/icu-73.2-hc8870d7_0.conda + sha256: ff9cd0c6cd1349954c801fb443c94192b637e1b414514539f3c49c56a39f51b1 + md5: 8521bd47c0e11c5902535bb1a17c565f + license: MIT + license_family: MIT + size: 11997841 + timestamp: 1692902104771 +- kind: conda + name: identify + version: 2.5.36 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/identify-2.5.36-pyhd8ed1ab_0.conda + sha256: dc98ab2233d3ed3692499e2a06b027489ee317658cef9277ec23cab00236f31c + md5: ba68cb5105760379432cebc82b45af40 + depends: + - python >=3.6 + - ukkonen + license: MIT + license_family: MIT + purls: + - pkg:pypi/identify + size: 78375 + timestamp: 1713673091737 +- kind: conda + name: idna + version: '3.7' + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/idna-3.7-pyhd8ed1ab_0.conda + sha256: 9687ee909ed46169395d4f99a0ee94b80a52f87bed69cd454bb6d37ffeb0ec7b + md5: c0cc1420498b17414d8617d0b9f506ca + depends: + - python >=3.6 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/idna + size: 52718 + timestamp: 1713279497047 +- kind: conda + name: imagesize + version: 1.4.1 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/imagesize-1.4.1-pyhd8ed1ab_0.tar.bz2 + sha256: c2bfd7043e0c4c12d8b5593de666c1e81d67b83c474a0a79282cc5c4ef845460 + md5: 7de5386c8fea29e76b303f37dde4c352 + depends: + - python >=3.4 + license: MIT + license_family: MIT + purls: + - pkg:pypi/imagesize + size: 10164 + timestamp: 1656939625410 +- kind: conda + name: importlib-metadata + version: 7.1.0 + build: pyha770c72_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-7.1.0-pyha770c72_0.conda + sha256: cc2e7d1f7f01cede30feafc1118b7aefa244d0a12224513734e24165ae12ba49 + md5: 0896606848b2dc5cebdf111b6543aa04 + depends: + - python >=3.8 + - zipp >=0.5 + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/importlib-metadata + size: 27043 + timestamp: 1710971498183 +- kind: conda + name: importlib_metadata + version: 7.1.0 + build: hd8ed1ab_0 + subdir: noarch + noarch: generic + url: https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-7.1.0-hd8ed1ab_0.conda + sha256: 01dc057a45dedcc742a71599f67c7383ae2bf873be6018ebcbd06ac8d994dedb + md5: 6ef2b72d291b39e479d7694efa2b2b98 + depends: + - importlib-metadata >=7.1.0,<7.1.1.0a0 + license: Apache-2.0 + license_family: APACHE + size: 9444 + timestamp: 1710971502542 +- kind: conda + name: importlib_resources + version: 6.4.0 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.4.0-pyhd8ed1ab_0.conda + sha256: c6ae80c0beaeabb342c5b041f19669992ae6e937dbec56ced766cb035900f9de + md5: c5d3907ad8bd7bf557521a1833cf7e6d + depends: + - python >=3.8 + - zipp >=3.1.0 + constrains: + - importlib-resources >=6.4.0,<6.4.1.0a0 + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/importlib-resources + size: 33056 + timestamp: 1711041009039 +- kind: conda + name: iniconfig + version: 2.0.0 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda + sha256: 38740c939b668b36a50ef455b077e8015b8c9cf89860d421b3fff86048f49666 + md5: f800d2da156d08e289b14e87e43c1ae5 + depends: + - python >=3.7 + license: MIT + license_family: MIT + purls: + - pkg:pypi/iniconfig + size: 11101 + timestamp: 1673103208955 +- kind: conda + name: jaraco.classes + version: 3.4.0 + build: pyhd8ed1ab_1 + build_number: 1 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/jaraco.classes-3.4.0-pyhd8ed1ab_1.conda + sha256: 538b1c6df537a36c63fd0ed83cb1c1c25b07d8d3b5e401991fdaff261a4b5b4d + md5: 7b756504d362cbad9b73a50a5455cafd + depends: + - more-itertools + - python >=3.8 + license: MIT + license_family: MIT + purls: + - pkg:pypi/jaraco-classes + size: 12223 + timestamp: 1713939433204 +- kind: conda + name: jaraco.context + version: 5.3.0 + build: pyhd8ed1ab_1 + build_number: 1 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/jaraco.context-5.3.0-pyhd8ed1ab_1.conda + sha256: 9e2aeacb1aed3ab4fc5883a357e8a874e12f687af300f8708ec12de2995e17d2 + md5: 72d7ad2dcd0f37eccb2ee35a1c8f6aaa + depends: + - backports.tarfile + - python >=3.8 + license: MIT + license_family: MIT + purls: + - pkg:pypi/jaraco-context + size: 12456 + timestamp: 1714372284922 +- kind: conda + name: jaraco.functools + version: 4.0.0 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/jaraco.functools-4.0.0-pyhd8ed1ab_0.conda + sha256: d2e866fd22a48eaa2f795b6a3b0bf16f066293322ce04dd65cca36267160ead6 + md5: 547670a612fd335eaa5ffbf0fa75cb64 + depends: + - more-itertools + - python >=3.8 + license: MIT + license_family: MIT + purls: + - pkg:pypi/jaraco-functools + size: 15192 + timestamp: 1701695329516 +- kind: conda + name: jeepney + version: 0.8.0 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/jeepney-0.8.0-pyhd8ed1ab_0.tar.bz2 + sha256: 16639759b811866d63315fe1391f6fb45f5478b823972f4d3d9f0392b7dd80b8 + md5: 9800ad1699b42612478755a2d26c722d + depends: + - python >=3.7 + license: MIT + license_family: MIT + purls: + - pkg:pypi/jeepney + size: 36895 + timestamp: 1649085298891 +- kind: conda + name: jinja2 + version: 3.1.4 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.4-pyhd8ed1ab_0.conda + sha256: 27380d870d42d00350d2d52598cddaf02f9505fb24be09488da0c9b8d1428f2d + md5: 7b86ecb7d3557821c649b3c31e3eb9f2 + depends: + - markupsafe >=2.0 + - python >=3.7 + license: BSD-3-Clause + purls: + - pkg:pypi/jinja2 + size: 111565 + timestamp: 1715127275924 +- kind: conda + name: keyring + version: 25.2.0 + build: pyh534df25_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/keyring-25.2.0-pyh534df25_0.conda + sha256: 29ffedc5e90f850a66007174f3785eb6a322a93cc6df9e8c9a7646f7761c694a + md5: acaf59f096327bc5757c91303cae99ca + depends: + - __osx + - importlib_metadata >=4.11.4 + - importlib_resources + - jaraco.classes + - jaraco.context + - jaraco.functools + - python >=3.8 + license: MIT + license_family: MIT + purls: + - pkg:pypi/keyring + size: 36710 + timestamp: 1714167932993 +- kind: conda + name: keyring + version: 25.2.0 + build: pyha804496_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/keyring-25.2.0-pyha804496_0.conda + sha256: 3a6dc8525071aa1016b81d24ee3845a2c26280b863392d7551b40a6c8d0f60c0 + md5: 7a14341f0ed09e83e28b28140f058ae0 + depends: + - __linux + - importlib_metadata >=4.11.4 + - importlib_resources + - jaraco.classes + - jaraco.context + - jaraco.functools + - jeepney >=0.4.2 + - python >=3.8 + - secretstorage >=3.2 + license: MIT + license_family: MIT + purls: + - pkg:pypi/keyring + size: 36608 + timestamp: 1714167807674 +- kind: conda + name: ld_impl_linux-64 + version: '2.40' + build: h55db66e_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.40-h55db66e_0.conda + sha256: ef969eee228cfb71e55146eaecc6af065f468cb0bc0a5239bc053b39db0b5f09 + md5: 10569984e7db886e4f1abc2b47ad79a1 + constrains: + - binutils_impl_linux-64 2.40 + license: GPL-3.0-only + license_family: GPL + size: 713322 + timestamp: 1713651222435 +- kind: conda + name: libcxx + version: 17.0.6 + build: h5f092b4_0 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-17.0.6-h5f092b4_0.conda + sha256: 119d3d9306f537d4c89dc99ed99b94c396d262f0b06f7833243646f68884f2c2 + md5: a96fd5dda8ce56c86a971e0fa02751d0 + depends: + - __osx >=11.0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + size: 1248885 + timestamp: 1715020154867 +- kind: conda + name: libexpat + version: 2.6.2 + build: h59595ed_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.2-h59595ed_0.conda + sha256: 331bb7c7c05025343ebd79f86ae612b9e1e74d2687b8f3179faec234f986ce19 + md5: e7ba12deb7020dd080c6c70e7b6f6a3d + depends: + - libgcc-ng >=12 + constrains: + - expat 2.6.2.* + license: MIT + license_family: MIT + size: 73730 + timestamp: 1710362120304 +- kind: conda + name: libexpat + version: 2.6.2 + build: hebf3989_0 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.6.2-hebf3989_0.conda + sha256: ba7173ac30064ea901a4c9fb5a51846dcc25512ceb565759be7d18cbf3e5415e + md5: e3cde7cfa87f82f7cb13d482d5e0ad09 + constrains: + - expat 2.6.2.* + license: MIT + license_family: MIT + size: 63655 + timestamp: 1710362424980 +- kind: conda + name: libffi + version: 3.4.2 + build: h3422bc3_5 + build_number: 5 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.4.2-h3422bc3_5.tar.bz2 + sha256: 41b3d13efb775e340e4dba549ab5c029611ea6918703096b2eaa9c015c0750ca + md5: 086914b672be056eb70fd4285b6783b6 + license: MIT + license_family: MIT + size: 39020 + timestamp: 1636488587153 +- kind: conda + name: libffi + version: 3.4.2 + build: h7f98852_5 + build_number: 5 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.2-h7f98852_5.tar.bz2 + sha256: ab6e9856c21709b7b517e940ae7028ae0737546122f83c2aa5d692860c3b149e + md5: d645c6d2ac96843a2bfaccd2d62b3ac3 + depends: + - libgcc-ng >=9.4.0 + license: MIT + license_family: MIT + size: 58292 + timestamp: 1636488182923 +- kind: conda + name: libgcc-ng + version: 13.2.0 + build: h77fa898_7 + build_number: 7 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-13.2.0-h77fa898_7.conda + sha256: 62af2b89acbe74a21606c8410c276e57309c0a2ab8a9e8639e3c8131c0b60c92 + md5: 72ec1b1b04c4d15d4204ece1ecea5978 + depends: + - _libgcc_mutex 0.1 conda_forge + - _openmp_mutex >=4.5 + constrains: + - libgomp 13.2.0 h77fa898_7 + license: GPL-3.0-only WITH GCC-exception-3.1 + size: 775806 + timestamp: 1715016057793 +- kind: conda + name: libglib + version: 2.80.0 + build: hf2295e7_6 + build_number: 6 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.80.0-hf2295e7_6.conda + sha256: d2867a1515676f3b64265420598badb2e4ad2369d85237fb276173a99959eb37 + md5: 9342e7c44c38bea649490f72d92c382d + depends: + - libffi >=3.4,<4.0a0 + - libgcc-ng >=12 + - libiconv >=1.17,<2.0a0 + - libzlib >=1.2.13,<1.3.0a0 + - pcre2 >=10.43,<10.44.0a0 + constrains: + - glib 2.80.0 *_6 + license: LGPL-2.1-or-later + size: 3942450 + timestamp: 1713639388280 +- kind: conda + name: libgomp + version: 13.2.0 + build: h77fa898_7 + build_number: 7 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/libgomp-13.2.0-h77fa898_7.conda + sha256: 781444fa069d3b50e8ed667b750571cacda785761c7fc2a89ece1ac49693d4ad + md5: abf3fec87c2563697defa759dec3d639 + depends: + - _libgcc_mutex 0.1 conda_forge + license: GPL-3.0-only WITH GCC-exception-3.1 + size: 422336 + timestamp: 1715015995979 +- kind: conda + name: libiconv + version: '1.17' + build: h0d3ecfb_2 + build_number: 2 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/libiconv-1.17-h0d3ecfb_2.conda + sha256: bc7de5097b97bcafcf7deaaed505f7ce02f648aac8eccc0d5a47cc599a1d0304 + md5: 69bda57310071cf6d2b86caf11573d2d + license: LGPL-2.1-only + size: 676469 + timestamp: 1702682458114 +- kind: conda + name: libiconv + version: '1.17' + build: hd590300_2 + build_number: 2 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.17-hd590300_2.conda + sha256: 8ac2f6a9f186e76539439e50505d98581472fedb347a20e7d1f36429849f05c9 + md5: d66573916ffcf376178462f1b61c941e + depends: + - libgcc-ng >=12 + license: LGPL-2.1-only + size: 705775 + timestamp: 1702682170569 +- kind: conda + name: libnsl + version: 2.0.1 + build: hd590300_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hd590300_0.conda + sha256: 26d77a3bb4dceeedc2a41bd688564fe71bf2d149fdcf117049970bc02ff1add6 + md5: 30fd6e37fe21f86f4bd26d6ee73eeec7 + depends: + - libgcc-ng >=12 + license: LGPL-2.1-only + license_family: GPL + size: 33408 + timestamp: 1697359010159 +- kind: conda + name: libsqlite + version: 3.45.3 + build: h091b4b1_0 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.45.3-h091b4b1_0.conda + sha256: 4337f466eb55bbdc74e168b52ec8c38f598e3664244ec7a2536009036e2066cc + md5: c8c1186c7f3351f6ffddb97b1f54fc58 + depends: + - libzlib >=1.2.13,<1.3.0a0 + license: Unlicense + size: 824794 + timestamp: 1713367748819 +- kind: conda + name: libsqlite + version: 3.45.3 + build: h2797004_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.45.3-h2797004_0.conda + sha256: e2273d6860eadcf714a759ffb6dc24a69cfd01f2a0ea9d6c20f86049b9334e0c + md5: b3316cbe90249da4f8e84cd66e1cc55b + depends: + - libgcc-ng >=12 + - libzlib >=1.2.13,<1.3.0a0 + license: Unlicense + size: 859858 + timestamp: 1713367435849 +- kind: conda + name: libstdcxx-ng + version: 13.2.0 + build: hc0a3c3a_7 + build_number: 7 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-13.2.0-hc0a3c3a_7.conda + sha256: 35f1e08be0a84810c9075f5bd008495ac94e6c5fe306dfe4b34546f11fed850f + md5: 53ebd4c833fa01cb2c6353e99f905406 + license: GPL-3.0-only WITH GCC-exception-3.1 + size: 3837704 + timestamp: 1715016117360 +- kind: conda + name: libuuid + version: 2.38.1 + build: h0b41bf4_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda + sha256: 787eb542f055a2b3de553614b25f09eefb0a0931b0c87dbcce6efdfd92f04f18 + md5: 40b61aab5c7ba9ff276c41cfffe6b80b + depends: + - libgcc-ng >=12 + license: BSD-3-Clause + license_family: BSD + size: 33601 + timestamp: 1680112270483 +- kind: conda + name: libxcrypt + version: 4.4.36 + build: hd590300_1 + build_number: 1 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda + sha256: 6ae68e0b86423ef188196fff6207ed0c8195dd84273cb5623b85aa08033a410c + md5: 5aa797f8787fe7a17d1b0821485b5adc + depends: + - libgcc-ng >=12 + license: LGPL-2.1-or-later + size: 100393 + timestamp: 1702724383534 +- kind: conda + name: libxml2 + version: 2.12.6 + build: h0d0cfa8_2 + build_number: 2 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/libxml2-2.12.6-h0d0cfa8_2.conda + sha256: a5c10af641d6accf3effb3c3a3c594d931bb374f9e3e796719f3ecf769cfb0fc + md5: 27577d561de7659487b062c363d8a527 + depends: + - icu >=73.2,<74.0a0 + - libiconv >=1.17,<2.0a0 + - libzlib >=1.2.13,<1.3.0a0 + - xz >=5.2.6,<6.0a0 + license: MIT + license_family: MIT + size: 588638 + timestamp: 1713314780561 +- kind: conda + name: libxml2 + version: 2.12.6 + build: h232c23b_2 + build_number: 2 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.12.6-h232c23b_2.conda + sha256: 0fd41df7211aae04f492c8550ce10238e8cfa8b1abebc2215a983c5e66d284ea + md5: 9a3a42df8a95f65334dfc7b80da1195d + depends: + - icu >=73.2,<74.0a0 + - libgcc-ng >=12 + - libiconv >=1.17,<2.0a0 + - libzlib >=1.2.13,<1.3.0a0 + - xz >=5.2.6,<6.0a0 + license: MIT + license_family: MIT + size: 704938 + timestamp: 1713314718258 +- kind: conda + name: libxslt + version: 1.1.39 + build: h223e5b9_0 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/libxslt-1.1.39-h223e5b9_0.conda + sha256: 2f1d99ef3fb960f23a63f06cf65ee621a5594a8b4616f35d9805be44617a92af + md5: 560c9cacc33e927f55b998eaa0cb1732 + depends: + - libxml2 >=2.12.1,<3.0.0a0 + license: MIT + license_family: MIT + size: 225705 + timestamp: 1701628966565 +- kind: conda + name: libxslt + version: 1.1.39 + build: h76b75d6_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/libxslt-1.1.39-h76b75d6_0.conda + sha256: 684e9b67ef7b9ca0ca993762eeb39705ec58e2e7f958555c758da7ef416db9f3 + md5: e71f31f8cfb0a91439f2086fc8aa0461 + depends: + - libgcc-ng >=12 + - libxml2 >=2.12.1,<3.0.0a0 + license: MIT + license_family: MIT + size: 254297 + timestamp: 1701628814990 +- kind: conda + name: libzlib + version: 1.2.13 + build: h53f4e23_5 + build_number: 5 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.2.13-h53f4e23_5.conda + sha256: ab1c8aefa2d54322a63aaeeefe9cf877411851738616c4068e0dccc66b9c758a + md5: 1a47f5236db2e06a320ffa0392f81bd8 + constrains: + - zlib 1.2.13 *_5 + license: Zlib + license_family: Other + size: 48102 + timestamp: 1686575426584 +- kind: conda + name: libzlib + version: 1.2.13 + build: hd590300_5 + build_number: 5 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.2.13-hd590300_5.conda + sha256: 370c7c5893b737596fd6ca0d9190c9715d89d888b8c88537ae1ef168c25e82e4 + md5: f36c115f1ee199da648e0597ec2047ad + depends: + - libgcc-ng >=12 + constrains: + - zlib 1.2.13 *_5 + license: Zlib + license_family: Other + size: 61588 + timestamp: 1686575217516 +- kind: conda + name: license-expression + version: 30.1.1 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/license-expression-30.1.1-pyhd8ed1ab_0.conda + sha256: 72fa44117cfd8e76274d4350a75c0badf269550ee32772efe6d77628f7569539 + md5: b64341a51378dcd6924388737c5aac6f + depends: + - boolean.py >=4.0.0 + - python >=3.7 + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/license-expression + size: 93614 + timestamp: 1690394219675 +- kind: conda + name: lxml + version: 5.2.1 + build: py311h1f7f111_0 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/lxml-5.2.1-py311h1f7f111_0.conda + sha256: dda220fe6744340de4731a0eb3f9d35c1f5d36d9dba71163ca9b577556c1d3f9 + md5: 78184339d2e86545a7358a16e159b10f + depends: + - __osx >=11.0 + - libxml2 >=2.12.6,<3.0a0 + - libxslt >=1.1.39,<2.0a0 + - libzlib >=1.2.13,<1.3.0a0 + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + license: BSD-3-Clause and MIT-CMU + purls: + - pkg:pypi/lxml + size: 1151614 + timestamp: 1713572970551 +- kind: conda + name: lxml + version: 5.2.1 + build: py311hc0a218f_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/lxml-5.2.1-py311hc0a218f_0.conda + sha256: a6ebc6bd1e0fe96a42109741f7d6b7bff89fadd348f10ca540ea7be77ea44b8d + md5: 7ce0d777858ab997d5cc83beaac6043f + depends: + - libgcc-ng >=12 + - libxml2 >=2.12.6,<3.0a0 + - libxslt >=1.1.39,<2.0a0 + - libzlib >=1.2.13,<1.3.0a0 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + license: BSD-3-Clause and MIT-CMU + purls: + - pkg:pypi/lxml + size: 1386690 + timestamp: 1713572746881 +- kind: conda + name: lxml + version: 5.2.1 + build: py312h8f698c5_0 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/lxml-5.2.1-py312h8f698c5_0.conda + sha256: f38d4af8de94a46335bcde3b1a5fc10d40992023e61c969142de0e9dd719ae0a + md5: 93e9a75ec1b7df64c653986c27b1b78f + depends: + - __osx >=11.0 + - libxml2 >=2.12.6,<3.0a0 + - libxslt >=1.1.39,<2.0a0 + - libzlib >=1.2.13,<1.3.0a0 + - python >=3.12,<3.13.0a0 + - python >=3.12,<3.13.0a0 *_cpython + - python_abi 3.12.* *_cp312 + license: BSD-3-Clause and MIT-CMU + purls: + - pkg:pypi/lxml + size: 1149527 + timestamp: 1713573008455 +- kind: conda + name: lxml + version: 5.2.1 + build: py312hb90d8a5_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/lxml-5.2.1-py312hb90d8a5_0.conda + sha256: 38395a99140602aec3b2e979deffca9485fad503d7ea7ec882704652e5829878 + md5: d260ebc72791a941c239029ea631bd44 + depends: + - libgcc-ng >=12 + - libxml2 >=2.12.6,<3.0a0 + - libxslt >=1.1.39,<2.0a0 + - libzlib >=1.2.13,<1.3.0a0 + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + license: BSD-3-Clause and MIT-CMU + purls: + - pkg:pypi/lxml + size: 1400706 + timestamp: 1713572667229 +- kind: conda + name: markdown-it-py + version: 3.0.0 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-3.0.0-pyhd8ed1ab_0.conda + sha256: c041b0eaf7a6af3344d5dd452815cdc148d6284fec25a4fa3f4263b3a021e962 + md5: 93a8e71256479c62074356ef6ebf501b + depends: + - mdurl >=0.1,<1 + - python >=3.8 + license: MIT + license_family: MIT + purls: + - pkg:pypi/markdown-it-py + size: 64356 + timestamp: 1686175179621 +- kind: conda + name: markupsafe + version: 2.1.5 + build: py311h05b510d_0 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/markupsafe-2.1.5-py311h05b510d_0.conda + sha256: 3f2127bd8788dc4b7c3d6d65ae4b7d2f8c7d02a246fc17b819390edeca53fd93 + md5: a27177455a9d29f4ac9d687a489e5d52 + depends: + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + constrains: + - jinja2 >=3.0.0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/markupsafe + size: 26578 + timestamp: 1706900556332 +- kind: conda + name: markupsafe + version: 2.1.5 + build: py311h459d7ec_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-2.1.5-py311h459d7ec_0.conda + sha256: 14912e557a6576e03f65991be89e9d289c6e301921b6ecfb4e7186ba974f453d + md5: a322b4185121935c871d201ae00ac143 + depends: + - libgcc-ng >=12 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + constrains: + - jinja2 >=3.0.0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/markupsafe + size: 27502 + timestamp: 1706900084436 +- kind: conda + name: markupsafe + version: 2.1.5 + build: py312h98912ed_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-2.1.5-py312h98912ed_0.conda + sha256: 273d8efd6c089c534ccbede566394c0ac1e265bfe5d89fe76e80332f3d75a636 + md5: 6ff0b9582da2d4a74a1f9ae1f9ce2af6 + depends: + - libgcc-ng >=12 + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + constrains: + - jinja2 >=3.0.0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/markupsafe + size: 26685 + timestamp: 1706900070330 +- kind: conda + name: markupsafe + version: 2.1.5 + build: py312he37b823_0 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/markupsafe-2.1.5-py312he37b823_0.conda + sha256: 61480b725490f68856dd14e646f51ffc34f77f2c985bd33e3b77c04b2856d97d + md5: ba3a8f8cf8bbdb81394275b1e1d271da + depends: + - python >=3.12,<3.13.0a0 + - python >=3.12,<3.13.0a0 *_cpython + - python_abi 3.12.* *_cp312 + constrains: + - jinja2 >=3.0.0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/markupsafe + size: 26382 + timestamp: 1706900495057 +- kind: conda + name: mdurl + version: 0.1.2 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_0.conda + sha256: 64073dfb6bb429d52fff30891877b48c7ec0f89625b1bf844905b66a81cce6e1 + md5: 776a8dd9e824f77abac30e6ef43a8f7a + depends: + - python >=3.6 + license: MIT + license_family: MIT + purls: + - pkg:pypi/mdurl + size: 14680 + timestamp: 1704317789138 +- kind: conda + name: more-itertools + version: 10.2.0 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/more-itertools-10.2.0-pyhd8ed1ab_0.conda + sha256: 9e49e9484ff279453f0b55323a3f0c7cb97440c74f69eecda1f4ad29fae5cd3c + md5: d5c98e9706fdc5328d49a9bf2ce5fb42 + depends: + - python >=3.8 + license: MIT + license_family: MIT + purls: + - pkg:pypi/more-itertools + size: 54469 + timestamp: 1704738585811 +- kind: conda + name: ncurses + version: 6.4.20240210 + build: h078ce10_0 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.4.20240210-h078ce10_0.conda + sha256: 06f0905791575e2cd3aa961493c56e490b3d82ad9eb49f1c332bd338b0216911 + md5: 616ae8691e6608527d0071e6766dcb81 + license: X11 AND BSD-3-Clause + size: 820249 + timestamp: 1710866874348 +- kind: conda + name: ncurses + version: 6.4.20240210 + build: h59595ed_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.4.20240210-h59595ed_0.conda + sha256: aa0f005b6727aac6507317ed490f0904430584fa8ca722657e7f0fb94741de81 + md5: 97da8860a0da5413c7c98a3b3838a645 + depends: + - libgcc-ng >=12 + license: X11 AND BSD-3-Clause + size: 895669 + timestamp: 1710866638986 +- kind: conda + name: nh3 + version: 0.2.17 + build: py312h4b3b743_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/nh3-0.2.17-py312h4b3b743_0.conda + sha256: 60067873dda1f5433fee8e2b7c02a32785153d2be73c75cfffae47ca4566a9c2 + md5: cfa305e03624c82d451a5ef250960bbd + depends: + - libgcc-ng >=12 + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + license: MIT + license_family: MIT + purls: + - pkg:pypi/nh3 + size: 607053 + timestamp: 1711545731955 +- kind: conda + name: nh3 + version: 0.2.17 + build: py312h5280bc4_0 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/nh3-0.2.17-py312h5280bc4_0.conda + sha256: b5ff8a687db7ef51fe5f854fe37975f08b70a2ad0ff585d9444e4e3bd77b3d95 + md5: 7a6d211257e3d264516ae4d67ce181a4 + depends: + - python >=3.12,<3.13.0a0 + - python >=3.12,<3.13.0a0 *_cpython + - python_abi 3.12.* *_cp312 + constrains: + - __osx >=11.0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/nh3 + size: 582437 + timestamp: 1711545995406 +- kind: conda + name: nodeenv + version: 1.8.0 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.8.0-pyhd8ed1ab_0.conda + sha256: 1320306234552717149f36f825ddc7e27ea295f24829e9db4cc6ceaff0b032bd + md5: 2a75b296096adabbabadd5e9782e5fcc + depends: + - python 2.7|>=3.7 + - setuptools + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/nodeenv + size: 34358 + timestamp: 1683893151613 +- kind: conda + name: openssl + version: 3.3.0 + build: h0d3ecfb_0 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.3.0-h0d3ecfb_0.conda + sha256: 51f9be8fe929c2bb3243cd0707b6dfcec27541f8284b4bd9b063c288fc46f482 + md5: 25b0e522c3131886a637e347b2ca0c0f + depends: + - ca-certificates + constrains: + - pyopenssl >=22.1 + license: Apache-2.0 + license_family: Apache + size: 2888226 + timestamp: 1714466346030 +- kind: conda + name: openssl + version: 3.3.0 + build: hd590300_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.3.0-hd590300_0.conda + sha256: fdbf05e4db88c592366c90bb82e446edbe33c6e49e5130d51c580b2629c0b5d5 + md5: c0f3abb4a16477208bbd43a39bd56f18 + depends: + - ca-certificates + - libgcc-ng >=12 + constrains: + - pyopenssl >=22.1 + license: Apache-2.0 + license_family: Apache + size: 2895187 + timestamp: 1714466138265 +- kind: conda + name: packaging + version: '24.0' + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/packaging-24.0-pyhd8ed1ab_0.conda + sha256: a390182d74c31dfd713c16db888c92c277feeb6d1fe96ff9d9c105f9564be48a + md5: 248f521b64ce055e7feae3105e7abeb8 + depends: + - python >=3.8 + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/packaging + size: 49832 + timestamp: 1710076089469 +- kind: conda + name: pathspec + version: 0.12.1 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/pathspec-0.12.1-pyhd8ed1ab_0.conda + sha256: 4e534e66bfe8b1e035d2169d0e5b185450546b17e36764272863e22e0370be4d + md5: 17064acba08d3686f1135b5ec1b32b12 + depends: + - python >=3.7 + license: MPL-2.0 + license_family: MOZILLA + purls: + - pkg:pypi/pathspec + size: 41173 + timestamp: 1702250135032 +- kind: conda + name: pcre2 + version: '10.43' + build: hcad00b1_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.43-hcad00b1_0.conda + sha256: 766dd986a7ed6197676c14699000bba2625fd26c8a890fcb7a810e5cf56155bc + md5: 8292dea9e022d9610a11fce5e0896ed8 + depends: + - bzip2 >=1.0.8,<2.0a0 + - libgcc-ng >=12 + - libzlib >=1.2.13,<1.3.0a0 + license: BSD-3-Clause + license_family: BSD + size: 950847 + timestamp: 1708118050286 +- kind: conda + name: pdbpp + version: 0.10.3 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/pdbpp-0.10.3-pyhd8ed1ab_0.tar.bz2 + sha256: c3f3996853853501af5ee936ebbd5a3de2eb1e73a078c7d4c541dbd97b315248 + md5: 3efee795aeb50ae2ca1ac732b529e603 + depends: + - fancycompleter + - pygments + - python >=3.4 + - wmctrl + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/pdbpp + size: 25010 + timestamp: 1626016866544 +- kind: conda + name: pexpect + version: 4.9.0 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/pexpect-4.9.0-pyhd8ed1ab_0.conda + sha256: 90a09d134a4a43911b716d4d6eb9d169238aff2349056f7323d9db613812667e + md5: 629f3203c99b32e0988910c93e77f3b6 + depends: + - ptyprocess >=0.5 + - python >=3.7 + license: ISC + purls: + - pkg:pypi/pexpect + size: 53600 + timestamp: 1706113273252 +- kind: conda + name: pkginfo + version: 1.10.0 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.10.0-pyhd8ed1ab_0.conda + sha256: 3e833f907039646e34d23203cd5c9cc487a451d955d8c8d6581e18a8ccef4cee + md5: 8c6a4a704308f5d91f3a974a72db1096 + depends: + - python >=3.7 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pkginfo + size: 28142 + timestamp: 1709561205511 +- kind: conda + name: platformdirs + version: 4.2.1 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.2.1-pyhd8ed1ab_0.conda + sha256: 5718fef2954f016834058ae1d359e407ff8e2e847b35ab43d5d91bcf22d5578d + md5: d478a8a3044cdff1aa6e62f9269cefe0 + depends: + - python >=3.8 + license: MIT + license_family: MIT + purls: + - pkg:pypi/platformdirs + size: 20248 + timestamp: 1713912912262 +- kind: conda + name: pluggy + version: 1.5.0 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.5.0-pyhd8ed1ab_0.conda + sha256: 33eaa3359948a260ebccf9cdc2fd862cea5a6029783289e13602d8e634cd9a26 + md5: d3483c8fc2dc2cc3f5cf43e26d60cabf + depends: + - python >=3.8 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pluggy + size: 23815 + timestamp: 1713667175451 +- kind: conda + name: pre-commit + version: 3.7.0 + build: pyha770c72_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/pre-commit-3.7.0-pyha770c72_0.conda + sha256: b7a1d56fb1374df77019521bbcbe109ff17337181c4d392918e5ec1a10a9df87 + md5: 846ba0877cda9c4f11e13720cacd1968 + depends: + - cfgv >=2.0.0 + - identify >=1.0.0 + - nodeenv >=0.11.1 + - python >=3.9 + - pyyaml >=5.1 + - virtualenv >=20.10.0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pre-commit + size: 180574 + timestamp: 1711480432386 +- kind: conda + name: ptyprocess + version: 0.7.0 + build: pyhd3deb0d_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/ptyprocess-0.7.0-pyhd3deb0d_0.tar.bz2 + sha256: fb31e006a25eb2e18f3440eb8d17be44c8ccfae559499199f73584566d0a444a + md5: 359eeb6536da0e687af562ed265ec263 + depends: + - python + license: ISC + purls: + - pkg:pypi/ptyprocess + size: 16546 + timestamp: 1609419417991 +- kind: conda + name: pycparser + version: '2.22' + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyhd8ed1ab_0.conda + sha256: 406001ebf017688b1a1554b49127ca3a4ac4626ec0fd51dc75ffa4415b720b64 + md5: 844d9eb3b43095b031874477f7d70088 + depends: + - python >=3.8 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/pycparser + size: 105098 + timestamp: 1711811634025 +- kind: conda + name: pygments + version: 2.18.0 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/pygments-2.18.0-pyhd8ed1ab_0.conda + sha256: 78267adf4e76d0d64ea2ffab008c501156c108bb08fecb703816fb63e279780b + md5: b7f5c092b8f9800150d998a71b76d5a1 + depends: + - python >=3.8 + license: BSD-2-Clause + license_family: BSD + purls: + - pkg:pypi/pygments + size: 879295 + timestamp: 1714846885370 +- kind: conda + name: pyrepl + version: 0.9.0 + build: py312h98912ed_9 + build_number: 9 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/pyrepl-0.9.0-py312h98912ed_9.conda + sha256: 9e9d59e511c8a8e0792386bec59a87e584768f2856b1131191c6e98f50b03cc2 + md5: a56b87ccd13bc27b0e8ce66c75abe79e + depends: + - libgcc-ng >=12 + - ncurses + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + license: ISC + license_family: OTHER + purls: + - pkg:pypi/pyrepl + size: 104985 + timestamp: 1709131190353 +- kind: conda + name: pyrepl + version: 0.9.0 + build: py312he37b823_9 + build_number: 9 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/pyrepl-0.9.0-py312he37b823_9.conda + sha256: 41fd0010d8520d26a56e1585cc46b4bbcfbb94b9e3bcebcbe18885ea14a06fa6 + md5: 4c4540b6c01647e1737670f4f1142f7e + depends: + - ncurses + - python >=3.12,<3.13.0a0 + - python >=3.12,<3.13.0a0 *_cpython + - python_abi 3.12.* *_cp312 + license: ISC + license_family: OTHER + purls: + - pkg:pypi/pyrepl + size: 105769 + timestamp: 1709131653373 +- kind: conda + name: pysocks + version: 1.7.1 + build: pyha2e5f31_6 + build_number: 6 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2 + sha256: a42f826e958a8d22e65b3394f437af7332610e43ee313393d1cf143f0a2d274b + md5: 2a7de29fb590ca14b5243c4c812c8025 + depends: + - __unix + - python >=3.8 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/pysocks + size: 18981 + timestamp: 1661604969727 +- kind: conda + name: pytest + version: 8.2.0 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/pytest-8.2.0-pyhd8ed1ab_0.conda + sha256: 02227fea7b50132a75fb223c2d796306ffebd4dc6324897455f17cb54d16683d + md5: 088ff7e08f4f10a06190468048c2a353 + depends: + - colorama + - exceptiongroup >=1.0.0rc8 + - iniconfig + - packaging + - pluggy <2.0,>=1.5 + - python >=3.8 + - tomli >=1 + constrains: + - pytest-faulthandler >=2 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pytest + size: 257122 + timestamp: 1714308481448 +- kind: conda + name: pytest-cov + version: 5.0.0 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-5.0.0-pyhd8ed1ab_0.conda + sha256: 218306243faf3c36347131c2b36bb189daa948ac2e92c7ab52bb26cc8c157b3c + md5: c54c0107057d67ddf077751339ec2c63 + depends: + - coverage >=5.2.1 + - pytest >=4.6 + - python >=3.8 + - toml + license: MIT + license_family: MIT + purls: + - pkg:pypi/pytest-cov + size: 25507 + timestamp: 1711411153367 +- kind: conda + name: python + version: 3.11.9 + build: h932a869_0_cpython + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.11.9-h932a869_0_cpython.conda + sha256: a436ceabde1f056a0ac3e347dadc780ee2a135a421ddb6e9a469370769829e3c + md5: 293e0713ae804b5527a673e7605c04fc + depends: + - __osx >=11.0 + - bzip2 >=1.0.8,<2.0a0 + - libexpat >=2.6.2,<3.0a0 + - libffi >=3.4,<4.0a0 + - libsqlite >=3.45.3,<4.0a0 + - libzlib >=1.2.13,<1.3.0a0 + - ncurses >=6.4.20240210,<7.0a0 + - openssl >=3.2.1,<4.0a0 + - readline >=8.2,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + - xz >=5.2.6,<6.0a0 + constrains: + - python_abi 3.11.* *_cp311 + license: Python-2.0 + size: 14644189 + timestamp: 1713552154779 +- kind: conda + name: python + version: 3.11.9 + build: hb806964_0_cpython + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/python-3.11.9-hb806964_0_cpython.conda + sha256: 177f33a1fb8d3476b38f73c37b42f01c0b014fa0e039a701fd9f83d83aae6d40 + md5: ac68acfa8b558ed406c75e98d3428d7b + depends: + - bzip2 >=1.0.8,<2.0a0 + - ld_impl_linux-64 >=2.36.1 + - libexpat >=2.6.2,<3.0a0 + - libffi >=3.4,<4.0a0 + - libgcc-ng >=12 + - libnsl >=2.0.1,<2.1.0a0 + - libsqlite >=3.45.3,<4.0a0 + - libuuid >=2.38.1,<3.0a0 + - libxcrypt >=4.4.36 + - libzlib >=1.2.13,<1.3.0a0 + - ncurses >=6.4.20240210,<7.0a0 + - openssl >=3.2.1,<4.0a0 + - readline >=8.2,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + - xz >=5.2.6,<6.0a0 + constrains: + - python_abi 3.11.* *_cp311 + license: Python-2.0 + size: 30884494 + timestamp: 1713553104915 +- kind: conda + name: python + version: 3.12.3 + build: h4a7b5fc_0_cpython + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.12.3-h4a7b5fc_0_cpython.conda + sha256: c761fb3713ea66bce3889b33b6f400afb2dd192d1fc2686446e9d8166cfcec6b + md5: 8643ab37bece6ae8f112464068d9df9c + depends: + - __osx >=11.0 + - bzip2 >=1.0.8,<2.0a0 + - libexpat >=2.6.2,<3.0a0 + - libffi >=3.4,<4.0a0 + - libsqlite >=3.45.2,<4.0a0 + - libzlib >=1.2.13,<1.3.0a0 + - ncurses >=6.4.20240210,<7.0a0 + - openssl >=3.2.1,<4.0a0 + - readline >=8.2,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + - xz >=5.2.6,<6.0a0 + constrains: + - python_abi 3.12.* *_cp312 + license: Python-2.0 + size: 13207557 + timestamp: 1713206576646 +- kind: conda + name: python + version: 3.12.3 + build: hab00c5b_0_cpython + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.3-hab00c5b_0_cpython.conda + sha256: f9865bcbff69f15fd89a33a2da12ad616e98d65ce7c83c644b92e66e5016b227 + md5: 2540b74d304f71d3e89c81209db4db84 + depends: + - bzip2 >=1.0.8,<2.0a0 + - ld_impl_linux-64 >=2.36.1 + - libexpat >=2.6.2,<3.0a0 + - libffi >=3.4,<4.0a0 + - libgcc-ng >=12 + - libnsl >=2.0.1,<2.1.0a0 + - libsqlite >=3.45.2,<4.0a0 + - libuuid >=2.38.1,<3.0a0 + - libxcrypt >=4.4.36 + - libzlib >=1.2.13,<1.3.0a0 + - ncurses >=6.4.20240210,<7.0a0 + - openssl >=3.2.1,<4.0a0 + - readline >=8.2,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + - xz >=5.2.6,<6.0a0 + constrains: + - python_abi 3.12.* *_cp312 + license: Python-2.0 + size: 31991381 + timestamp: 1713208036041 +- kind: conda + name: python-debian + version: 0.1.36 + build: py_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/python-debian-0.1.36-py_0.tar.bz2 + sha256: 7006309bf371fffc81f875baa63c29ffb33bf8074fdd33d0d68154e58ea6c7ff + md5: 079bbbbc928d759853d44a1de630d3c1 + depends: + - chardet + - python + - six + license: GPL-3.0-or-later + license_family: GPL + purls: + - pkg:pypi/python-debian + size: 66742 + timestamp: 1572978048259 +- kind: conda + name: python_abi + version: '3.11' + build: 4_cp311 + build_number: 4 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.11-4_cp311.conda + sha256: 0be3ac1bf852d64f553220c7e6457e9c047dfb7412da9d22fbaa67e60858b3cf + md5: d786502c97404c94d7d58d258a445a65 + constrains: + - python 3.11.* *_cpython + license: BSD-3-Clause + license_family: BSD + size: 6385 + timestamp: 1695147338551 +- kind: conda + name: python_abi + version: '3.11' + build: 4_cp311 + build_number: 4 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/python_abi-3.11-4_cp311.conda + sha256: 4837089c477b9b84fa38a17f453e6634e68237267211b27a8a2f5ccd847f4e55 + md5: 8d3751bc73d3bbb66f216fa2331d5649 + constrains: + - python 3.11.* *_cpython + license: BSD-3-Clause + license_family: BSD + size: 6492 + timestamp: 1695147509940 +- kind: conda + name: python_abi + version: '3.12' + build: 4_cp312 + build_number: 4 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.12-4_cp312.conda + sha256: 182a329de10a4165f6e8a3804caf751f918f6ea6176dd4e5abcdae1ed3095bf6 + md5: dccc2d142812964fcc6abdc97b672dff + constrains: + - python 3.12.* *_cpython + license: BSD-3-Clause + license_family: BSD + size: 6385 + timestamp: 1695147396604 +- kind: conda + name: python_abi + version: '3.12' + build: 4_cp312 + build_number: 4 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/python_abi-3.12-4_cp312.conda + sha256: db25428e4f24f8693ffa39f3ff6dfbb8fd53bc298764b775b57edab1c697560f + md5: bbb3a02c78b2d8219d7213f76d644a2a + constrains: + - python 3.12.* *_cpython + license: BSD-3-Clause + license_family: BSD + size: 6508 + timestamp: 1695147497048 +- kind: conda + name: pytz + version: '2024.1' + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/pytz-2024.1-pyhd8ed1ab_0.conda + sha256: 1a7d6b233f7e6e3bbcbad054c8fd51e690a67b129a899a056a5e45dd9f00cb41 + md5: 3eeeeb9e4827ace8c0c1419c85d590ad + depends: + - python >=3.7 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pytz + size: 188538 + timestamp: 1706886944988 +- kind: conda + name: pyyaml + version: 6.0.1 + build: py312h02f2b3b_1 + build_number: 1 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/pyyaml-6.0.1-py312h02f2b3b_1.conda + sha256: b6b4027b89c17b9bbd8089aec3e44bc29f802a7d5668d5a75b5358d7ed9705ca + md5: a0c843e52a1c4422d8657dd76e9eb994 + depends: + - python >=3.12.0rc3,<3.13.0a0 + - python >=3.12.0rc3,<3.13.0a0 *_cpython + - python_abi 3.12.* *_cp312 + - yaml >=0.2.5,<0.3.0a0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pyyaml + size: 182705 + timestamp: 1695373895409 +- kind: conda + name: pyyaml + version: 6.0.1 + build: py312h98912ed_1 + build_number: 1 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.1-py312h98912ed_1.conda + sha256: 7f347a10a7121b08d79d21cd4f438c07c23479ea0c74dfb89d6dc416f791bb7f + md5: e3fd78d8d490af1d84763b9fe3f2e552 + depends: + - libgcc-ng >=12 + - python >=3.12.0rc3,<3.13.0a0 + - python_abi 3.12.* *_cp312 + - yaml >=0.2.5,<0.3.0a0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pyyaml + size: 196583 + timestamp: 1695373632212 +- kind: conda + name: readline + version: '8.2' + build: h8228510_1 + build_number: 1 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda + sha256: 5435cf39d039387fbdc977b0a762357ea909a7694d9528ab40f005e9208744d7 + md5: 47d31b792659ce70f470b5c82fdfb7a4 + depends: + - libgcc-ng >=12 + - ncurses >=6.3,<7.0a0 + license: GPL-3.0-only + license_family: GPL + size: 281456 + timestamp: 1679532220005 +- kind: conda + name: readline + version: '8.2' + build: h92ec313_1 + build_number: 1 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.2-h92ec313_1.conda + sha256: a1dfa679ac3f6007362386576a704ad2d0d7a02e98f5d0b115f207a2da63e884 + md5: 8cbb776a2f641b943d413b3e19df71f4 + depends: + - ncurses >=6.3,<7.0a0 + license: GPL-3.0-only + license_family: GPL + size: 250351 + timestamp: 1679532511311 +- kind: conda + name: readme_renderer + version: '42.0' + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/readme_renderer-42.0-pyhd8ed1ab_0.conda + sha256: 61e03765ebdb168fc8747e8183db4067b55888c89d59e0f4f53b5b4046846cda + md5: fdc16f5dc3a911d8f43f64f814a45961 + depends: + - cmarkgfm >=0.8.0 + - docutils >=0.13.1 + - nh3 >=0.2.14 + - pygments >=2.5.1 + - python >=3.8 + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/readme-renderer + size: 17373 + timestamp: 1694242843889 +- kind: conda + name: requests + version: 2.31.0 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/requests-2.31.0-pyhd8ed1ab_0.conda + sha256: 9f629d6fd3c8ac5f2a198639fe7af87c4db2ac9235279164bfe0fcb49d8c4bad + md5: a30144e4156cdbb236f99ebb49828f8b + depends: + - certifi >=2017.4.17 + - charset-normalizer >=2,<4 + - idna >=2.5,<4 + - python >=3.7 + - urllib3 >=1.21.1,<3 + constrains: + - chardet >=3.0.2,<6 + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/requests + size: 56690 + timestamp: 1684774408600 +- kind: conda + name: requests-toolbelt + version: 1.0.0 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/requests-toolbelt-1.0.0-pyhd8ed1ab_0.conda + sha256: 20eaefc5dba74ff6c31e537533dde59b5b20f69e74df49dff19d43be59785fa3 + md5: 99c98318c8646b08cc764f90ce98906e + depends: + - python >=3.6 + - requests >=2.0.1,<3.0.0 + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/requests-toolbelt + size: 43939 + timestamp: 1682953467574 +- kind: conda + name: reuse + version: 3.0.1 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/reuse-3.0.1-pyhd8ed1ab_0.conda + sha256: 72a0e7a88fa4d763fccae959585d83b696a41539bfc1ebd72b8e5582cf8c1dbe + md5: cfbbf3b2ba6d90fe13ec3b59dca5fa5f + depends: + - binaryornot + - boolean.py + - jinja2 + - license-expression + - python >=3.6 + - python-debian + - requests + - setuptools + license: GPL-3.0-or-later AND Apache-2.0 AND CC0-1.0 AND CC-BY-SA-4.0 + purls: + - pkg:pypi/reuse + size: 146563 + timestamp: 1705680540750 +- kind: conda + name: rfc3986 + version: 2.0.0 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/rfc3986-2.0.0-pyhd8ed1ab_0.tar.bz2 + sha256: dd6bfb7c4248ba7612f2e6e4a066d6804ba96dfcaeddf43475a2c846ccfcc396 + md5: d337886e38f965bf97aaec382ff6db00 + depends: + - python >=3.4 + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/rfc3986 + size: 34075 + timestamp: 1641825125307 +- kind: conda + name: rich + version: 13.7.1 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/rich-13.7.1-pyhd8ed1ab_0.conda + sha256: 2b26d58aa59e46f933c3126367348651b0dab6e0bf88014e857415bb184a4667 + md5: ba445bf767ae6f0d959ff2b40c20912b + depends: + - markdown-it-py >=2.2.0 + - pygments >=2.13.0,<3.0.0 + - python >=3.7.0 + - typing_extensions >=4.0.0,<5.0.0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/rich + size: 184347 + timestamp: 1709150578093 +- kind: conda + name: ruff + version: 0.4.3 + build: py312h3402d49_0 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/ruff-0.4.3-py312h3402d49_0.conda + sha256: 096cbdaab7d766b774c452c392fabbb47653ed4370400c2f620647a5187b7773 + md5: 61bd91af1cda46986708cddcdfdf635d + depends: + - __osx >=11.0 + - libcxx >=16 + - python >=3.12,<3.13.0a0 + - python >=3.12,<3.13.0a0 *_cpython + - python_abi 3.12.* *_cp312 + constrains: + - __osx >=11.0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruff + size: 5818141 + timestamp: 1714794574870 +- kind: conda + name: ruff + version: 0.4.3 + build: py312h5715c7c_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/ruff-0.4.3-py312h5715c7c_0.conda + sha256: 09dbfc6055263a14d1034f6571f5faf7201f5312363e03cb28703a85a19d6a28 + md5: 9a138fc0b732a0d2fd9c97e5fb304619 + depends: + - libgcc-ng >=12 + - libstdcxx-ng >=12 + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruff + size: 6301226 + timestamp: 1714793018454 +- kind: conda + name: secretstorage + version: 3.3.3 + build: py312h7900ff3_2 + build_number: 2 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/secretstorage-3.3.3-py312h7900ff3_2.conda + sha256: 0479e3f8c8e90049a6d92d4c7e67916c6d6cdafd11a1a31c54c785cce44aeb20 + md5: 39067833cbb620066d492f8bd6f11dbf + depends: + - cryptography + - dbus + - jeepney >=0.6 + - python >=3.12.0rc3,<3.13.0a0 + - python_abi 3.12.* *_cp312 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/secretstorage + size: 31766 + timestamp: 1695551875966 +- kind: conda + name: setuptools + version: 69.5.1 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/setuptools-69.5.1-pyhd8ed1ab_0.conda + sha256: 72d143408507043628b32bed089730b6d5f5445eccc44b59911ec9f262e365e7 + md5: 7462280d81f639363e6e63c81276bd9e + depends: + - python >=3.8 + license: MIT + license_family: MIT + purls: + - pkg:pypi/setuptools + size: 501790 + timestamp: 1713094963112 +- kind: conda + name: shellingham + version: 1.5.4 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/shellingham-1.5.4-pyhd8ed1ab_0.conda + sha256: 3c49a0a101c41b7cf6ac05a1872d7a1f91f1b6d02eecb4a36b605a19517862bb + md5: d08db09a552699ee9e7eec56b4eb3899 + depends: + - python >=3.7 + license: MIT + license_family: MIT + purls: + - pkg:pypi/shellingham + size: 14568 + timestamp: 1698144516278 +- kind: conda + name: six + version: 1.16.0 + build: pyh6c4a22f_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2 + sha256: a85c38227b446f42c5b90d9b642f2c0567880c15d72492d8da074a59c8f91dd6 + md5: e5f25f8dbc060e9a8d912e432202afc2 + depends: + - python + license: MIT + license_family: MIT + purls: + - pkg:pypi/six + size: 14259 + timestamp: 1620240338595 +- kind: conda + name: sniffio + version: 1.3.1 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/sniffio-1.3.1-pyhd8ed1ab_0.conda + sha256: bc12100b2d8836b93c55068b463190505b8064d0fc7d025e89f20ebf22fe6c2b + md5: 490730480d76cf9c8f8f2849719c6e2b + depends: + - python >=3.7 + license: Apache-2.0 + license_family: Apache + purls: + - pkg:pypi/sniffio + size: 15064 + timestamp: 1708953086199 +- kind: conda + name: snowballstemmer + version: 2.2.0 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/snowballstemmer-2.2.0-pyhd8ed1ab_0.tar.bz2 + sha256: a0fd916633252d99efb6223b1050202841fa8d2d53dacca564b0ed77249d3228 + md5: 4d22a9315e78c6827f806065957d566e + depends: + - python >=2 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/snowballstemmer + size: 58824 + timestamp: 1637143137377 +- kind: conda + name: soupsieve + version: '2.5' + build: pyhd8ed1ab_1 + build_number: 1 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/soupsieve-2.5-pyhd8ed1ab_1.conda + sha256: 54ae221033db8fbcd4998ccb07f3c3828b4d77e73b0c72b18c1d6a507059059c + md5: 3f144b2c34f8cb5a9abd9ed23a39c561 + depends: + - python >=3.8 + license: MIT + license_family: MIT + purls: + - pkg:pypi/soupsieve + size: 36754 + timestamp: 1693929424267 +- kind: conda + name: sphinx + version: 7.3.7 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/sphinx-7.3.7-pyhd8ed1ab_0.conda + sha256: 41101e2b0b8722087f06bd73251ba95ef89db515982b6a89aeebfa98ebcb65a1 + md5: 7b1465205e28d75d2c0e1a868ee00a67 + depends: + - alabaster >=0.7.14,<0.8.dev0 + - babel >=2.9 + - colorama >=0.4.5 + - docutils >=0.18.1,<0.22 + - imagesize >=1.3 + - importlib-metadata >=4.8 + - jinja2 >=3.0 + - packaging >=21.0 + - pygments >=2.14 + - python >=3.9 + - requests >=2.25.0 + - snowballstemmer >=2.0 + - sphinxcontrib-applehelp + - sphinxcontrib-devhelp + - sphinxcontrib-htmlhelp >=2.0.0 + - sphinxcontrib-jsmath + - sphinxcontrib-qthelp + - sphinxcontrib-serializinghtml >=1.1.9 + - tomli >=2.0 + license: BSD-2-Clause + license_family: BSD + purls: + - pkg:pypi/sphinx + size: 1345378 + timestamp: 1713555005540 +- kind: conda + name: sphinx-argparse + version: 0.4.0 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/sphinx-argparse-0.4.0-pyhd8ed1ab_0.conda + sha256: 43e1de645f9a67ad1c73025f2c6e853283dbf492d1cddb0bf3de1e9c80c9e4b8 + md5: 2e1c3e05b26995293e5f364d36c59125 + depends: + - commonmark >=0.5.6 + - python >=3.7 + - sphinx >=4.0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/sphinx-argparse + size: 17701 + timestamp: 1675619107465 +- kind: conda + name: sphinx-autodoc-typehints + version: 2.1.0 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/sphinx-autodoc-typehints-2.1.0-pyhd8ed1ab_0.conda + sha256: f331eda04d540a0ebdceea03faaef6f1a57db93cc1ac74a71512e6a20cd4e125 + md5: ab586f5de577d96a890f0ffc48de7956 + depends: + - python >=3.9 + - sphinx >=7.3.5 + license: MIT + license_family: MIT + purls: + - pkg:pypi/sphinx-autodoc-typehints + size: 23394 + timestamp: 1713418816794 +- kind: conda + name: sphinx-basic-ng + version: 1.0.0b2 + build: pyhd8ed1ab_1 + build_number: 1 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/sphinx-basic-ng-1.0.0b2-pyhd8ed1ab_1.conda + sha256: 3c7a6a8bb6c9921741ef940cd61ff1694beac3c95ca7e9ad4b0ea32e2f6ac2fa + md5: a631f5c7b7f5045448f966ad71aa2881 + depends: + - python >=3.7 + - sphinx >=4.0,<8.0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/sphinx-basic-ng + size: 20316 + timestamp: 1690475062890 +- kind: conda + name: sphinx-copybutton + version: 0.5.2 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/sphinx-copybutton-0.5.2-pyhd8ed1ab_0.conda + sha256: 7ea21f009792e7c69612ddba367afe0412b3fdff2e92f439e8cd222de4b40bfe + md5: ac832cc43adc79118cf6e23f1f9b8995 + depends: + - python >=3 + - sphinx >=1.8 + license: MIT + license_family: MIT + purls: + - pkg:pypi/sphinx-copybutton + size: 17801 + timestamp: 1681468271927 +- kind: conda + name: sphinx-inline-tabs + version: 2023.4.21 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/sphinx-inline-tabs-2023.4.21-pyhd8ed1ab_0.conda + sha256: 142f45bb224380f13f800ae3769f0d2aa3efcd9c49e5389b48863d03c08a801a + md5: 4addb035e43d09440597352079305513 + depends: + - beautifulsoup4 + - python >=3.6 + - sphinx >3 + license: MIT + license_family: MIT + purls: + - pkg:pypi/sphinx-inline-tabs + size: 12423 + timestamp: 1682112748389 +- kind: conda + name: sphinxcontrib-applehelp + version: 1.0.8 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-applehelp-1.0.8-pyhd8ed1ab_0.conda + sha256: 710013443a063518d587d2af82299e92ab6d6695edf35a676ac3a0ccc9e3f8e6 + md5: 611a35a27914fac3aa37611a6fe40bb5 + depends: + - python >=3.9 + - sphinx >=5 + license: BSD-2-Clause + license_family: BSD + purls: + - pkg:pypi/sphinxcontrib-applehelp + size: 29539 + timestamp: 1705126465971 +- kind: conda + name: sphinxcontrib-devhelp + version: 1.0.6 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-devhelp-1.0.6-pyhd8ed1ab_0.conda + sha256: 63a6b60653ef13a6712848f4b3c4b713d4b564da1dae571893f1a3659cde85f3 + md5: d7e4954df0d3aea2eacc7835ad12671d + depends: + - python >=3.9 + - sphinx >=5 + license: BSD-2-Clause + license_family: BSD + purls: + - pkg:pypi/sphinxcontrib-devhelp + size: 24474 + timestamp: 1705126153592 +- kind: conda + name: sphinxcontrib-htmlhelp + version: 2.0.5 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-htmlhelp-2.0.5-pyhd8ed1ab_0.conda + sha256: 512f393cfe34cb3de96ade7a7ad900d6278e2087a1f0e5732aa60fadee396d99 + md5: 7e1e7437273682ada2ed5e9e9714b140 + depends: + - python >=3.9 + - sphinx >=5 + license: BSD-2-Clause + license_family: BSD + purls: + - pkg:pypi/sphinxcontrib-htmlhelp + size: 33499 + timestamp: 1705118297318 +- kind: conda + name: sphinxcontrib-jsmath + version: 1.0.1 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-jsmath-1.0.1-pyhd8ed1ab_0.conda + sha256: d4337d83b8edba688547766fc80f1ac86d6ec86ceeeda93f376acc04079c5ce2 + md5: da1d979339e2714c30a8e806a33ec087 + depends: + - python >=3.5 + license: BSD-2-Clause + license_family: BSD + purls: + - pkg:pypi/sphinxcontrib-jsmath + size: 10431 + timestamp: 1691604844204 +- kind: conda + name: sphinxcontrib-qthelp + version: 1.0.7 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-qthelp-1.0.7-pyhd8ed1ab_0.conda + sha256: dd35b52f056c39081cd0ae01155174277af579b69e5d83798a33e9056ec78d63 + md5: 26acae54b06f178681bfb551760f5dd1 + depends: + - python >=3.9 + - sphinx >=5 + license: BSD-2-Clause + license_family: BSD + purls: + - pkg:pypi/sphinxcontrib-qthelp + size: 27005 + timestamp: 1705126340442 +- kind: conda + name: sphinxcontrib-serializinghtml + version: 1.1.10 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/sphinxcontrib-serializinghtml-1.1.10-pyhd8ed1ab_0.conda + sha256: bf80e4c0ff97d5e8e5f6db0831ba60007e820a3a438e8f1afd868aa516d67d6f + md5: e507335cb4ca9cff4c3d0fa9cdab255e + depends: + - python >=3.9 + - sphinx >=5 + license: BSD-2-Clause + license_family: BSD + purls: + - pkg:pypi/sphinxcontrib-serializinghtml + size: 28776 + timestamp: 1705118378942 +- kind: conda + name: tk + version: 8.6.13 + build: h5083fa2_1 + build_number: 1 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h5083fa2_1.conda + sha256: 72457ad031b4c048e5891f3f6cb27a53cb479db68a52d965f796910e71a403a8 + md5: b50a57ba89c32b62428b71a875291c9b + depends: + - libzlib >=1.2.13,<1.3.0a0 + license: TCL + license_family: BSD + size: 3145523 + timestamp: 1699202432999 +- kind: conda + name: tk + version: 8.6.13 + build: noxft_h4845f30_101 + build_number: 101 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda + sha256: e0569c9caa68bf476bead1bed3d79650bb080b532c64a4af7d8ca286c08dea4e + md5: d453b98d9c83e71da0741bb0ff4d76bc + depends: + - libgcc-ng >=12 + - libzlib >=1.2.13,<1.3.0a0 + license: TCL + license_family: BSD + size: 3318875 + timestamp: 1699202167581 +- kind: conda + name: toml + version: 0.10.2 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhd8ed1ab_0.tar.bz2 + sha256: f0f3d697349d6580e4c2f35ba9ce05c65dc34f9f049e85e45da03800b46139c1 + md5: f832c45a477c78bebd107098db465095 + depends: + - python >=2.7 + license: MIT + license_family: MIT + purls: + - pkg:pypi/toml + size: 18433 + timestamp: 1604308660817 +- kind: conda + name: tomli + version: 2.0.1 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2 + sha256: 4cd48aba7cd026d17e86886af48d0d2ebc67ed36f87f6534f4b67138f5a5a58f + md5: 5844808ffab9ebdb694585b50ba02a96 + depends: + - python >=3.7 + license: MIT + license_family: MIT + purls: + - pkg:pypi/tomli + size: 15940 + timestamp: 1644342331069 +- kind: conda + name: tomli-w + version: 1.0.0 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/tomli-w-1.0.0-pyhd8ed1ab_0.tar.bz2 + sha256: efb5f78a224c4bb14aab04690c9912256ea12c3a8b8413e60167573ce1282b02 + md5: 73506d1ab4202481841c68c169b7ef6c + depends: + - python >=3.7 + license: MIT + license_family: MIT + purls: + - pkg:pypi/tomli-w + size: 10052 + timestamp: 1638551820635 +- kind: conda + name: tomlkit + version: 0.12.4 + build: pyha770c72_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/tomlkit-0.12.4-pyha770c72_0.conda + sha256: 8d45c266bf919788abacd9828f4a2101d7216f6d4fc7c8d3417034fe0d795a18 + md5: 37c47ea93ef00dd80d880fc4ba21256a + depends: + - python >=3.7 + license: MIT + license_family: MIT + purls: + - pkg:pypi/tomlkit + size: 37173 + timestamp: 1709043886347 +- kind: conda + name: trove-classifiers + version: 2024.4.10 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/trove-classifiers-2024.4.10-pyhd8ed1ab_0.conda + sha256: cbc8e5c5f82b1eeff7aa21aaff77757336c1e6d64a4255b071c783acd60f4618 + md5: 9622d541e2314c0207bebdc0359fa478 + depends: + - python >=3.7 + license: Apache-2.0 + license_family: Apache + purls: + - pkg:pypi/trove-classifiers + size: 18444 + timestamp: 1712814840654 +- kind: conda + name: twine + version: 5.0.0 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/twine-5.0.0-pyhd8ed1ab_0.conda + sha256: 8dd14197546abf76980994db8d4e0ac861b395750d2968d259a38e80ed3e8013 + md5: e3482aff5aebc831cba9ac6b74395c6c + depends: + - importlib_metadata >=3.6 + - keyring >=15.1 + - pkginfo >=1.8.1 + - python >=3.8 + - readme_renderer >=35.0 + - requests >=2.20 + - requests-toolbelt >=0.8.0,!=0.9.0 + - rfc3986 >=1.4.0 + - rich >=12.0.0 + - urllib3 >=1.26.0 + license: Apache-2.0 + license_family: Apache + purls: + - pkg:pypi/twine + size: 32579 + timestamp: 1707690947551 +- kind: conda + name: typing_extensions + version: 4.11.0 + build: pyha770c72_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.11.0-pyha770c72_0.conda + sha256: a7e8714d14f854058e971a6ed44f18cc37cc685f98ddefb2e6b7899a0cc4d1a2 + md5: 6ef2fc37559256cf682d8b3375e89b80 + depends: + - python >=3.8 + license: PSF-2.0 + license_family: PSF + purls: + - pkg:pypi/typing-extensions + size: 37583 + timestamp: 1712330089194 +- kind: conda + name: tzdata + version: 2024a + build: h0c530f3_0 + subdir: noarch + noarch: generic + url: https://conda.anaconda.org/conda-forge/noarch/tzdata-2024a-h0c530f3_0.conda + sha256: 7b2b69c54ec62a243eb6fba2391b5e443421608c3ae5dbff938ad33ca8db5122 + md5: 161081fc7cec0bfda0d86d7cb595f8d8 + license: LicenseRef-Public-Domain + size: 119815 + timestamp: 1706886945727 +- kind: conda + name: ukkonen + version: 1.0.1 + build: py312h389731b_4 + build_number: 4 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/ukkonen-1.0.1-py312h389731b_4.conda + sha256: 7336cf66feba973207f4903c20b05c3c82e351246df4b6113f72d92b9ee55b81 + md5: 6407429e0969b58b8717dbb4c6c15513 + depends: + - cffi + - libcxx >=15.0.7 + - python >=3.12.0rc3,<3.13.0a0 + - python >=3.12.0rc3,<3.13.0a0 *_cpython + - python_abi 3.12.* *_cp312 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ukkonen + size: 13948 + timestamp: 1695549890285 +- kind: conda + name: ukkonen + version: 1.0.1 + build: py312h8572e83_4 + build_number: 4 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/ukkonen-1.0.1-py312h8572e83_4.conda + sha256: f9a4384d466f4d8b5b497d951329dd4407ebe02f8f93456434e9ab789d6e23ce + md5: 52c9e25ee0a32485a102eeecdb7eef52 + depends: + - cffi + - libgcc-ng >=12 + - libstdcxx-ng >=12 + - python >=3.12.0rc3,<3.13.0a0 + - python_abi 3.12.* *_cp312 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ukkonen + size: 14050 + timestamp: 1695549556745 +- kind: conda + name: urllib3 + version: 2.2.1 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.2.1-pyhd8ed1ab_0.conda + sha256: d4009dcc9327684d6409706ce17656afbeae690d8522d3c9bc4df57649a352cd + md5: 08807a87fa7af10754d46f63b368e016 + depends: + - brotli-python >=1.0.9 + - pysocks >=1.5.6,<2.0,!=1.5.7 + - python >=3.7 + license: MIT + license_family: MIT + purls: + - pkg:pypi/urllib3 + size: 94669 + timestamp: 1708239595549 +- kind: conda + name: userpath + version: 1.7.0 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/userpath-1.7.0-pyhd8ed1ab_0.tar.bz2 + sha256: c8cbddd625340e1b00b53bafabc764526ee85f7ddb91018424bab0eea057796d + md5: 5bf074c9253a3bf914becfc50757406f + depends: + - click + - python >=3.6 + license: MIT + license_family: MIT + purls: + - pkg:pypi/userpath + size: 17423 + timestamp: 1632758637093 +- kind: conda + name: uv + version: 0.1.40 + build: h0ea3d13_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/uv-0.1.40-h0ea3d13_0.conda + sha256: 7630f6081a3bc13701abad871a6674c0e9ae7fb2d84b1acbdc2fb668b251ca8a + md5: 0c6621213b37f2498edea3fecb7ffff6 + depends: + - libgcc-ng >=12 + - libstdcxx-ng >=12 + license: Apache-2.0 OR MIT + size: 12269217 + timestamp: 1715117771117 +- kind: conda + name: uv + version: 0.1.40 + build: hc069d6b_0 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/uv-0.1.40-hc069d6b_0.conda + sha256: a152aa43d7a073ced6bf3bb4b0d44aa9794e564961f8a69756faef13b6804790 + md5: f10b76fc6c560f8b37ff0f1d1b371109 + depends: + - __osx >=11.0 + - libcxx >=16 + constrains: + - __osx >=11.0 + license: Apache-2.0 OR MIT + size: 9069883 + timestamp: 1715119085373 +- kind: conda + name: versioningit + version: 3.1.1 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/versioningit-3.1.1-pyhd8ed1ab_0.conda + sha256: 9f90b1e10aae23761464407f2535de9b905df92a2d2c564a7f7fe3c64735dcbf + md5: d471782c9969774528f6d62ebc8a06d8 + depends: + - importlib-metadata >=3.6 + - packaging >=17.1 + - python >=3.7 + - tomli >=1.2,<3.0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/versioningit + size: 161217 + timestamp: 1714400685966 +- kind: conda + name: virtualenv + version: 20.26.1 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/virtualenv-20.26.1-pyhd8ed1ab_0.conda + sha256: d603f8608f353a7aaa794c00bd3df71aafd5b56bf53af3e9c3dfe135203a4f33 + md5: 4e1cd2faf006a6e62c148f95cef0cac2 + depends: + - distlib <1,>=0.3.7 + - filelock <4,>=3.12.2 + - platformdirs <5,>=3.9.1 + - python >=3.8 + license: MIT + license_family: MIT + purls: + - pkg:pypi/virtualenv + size: 3459994 + timestamp: 1714439521015 +- kind: conda + name: wmctrl + version: '0.5' + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/wmctrl-0.5-pyhd8ed1ab_0.conda + sha256: b7526024b323b43ab8af687adeb6ee8f40aba70a9ee5939317d1b6b50e050061 + md5: eee592c2bd3901849b3732ff1da58049 + depends: + - attrs + - python >=3 + license: MIT + license_family: MIT + purls: + - pkg:pypi/wmctrl + size: 10415 + timestamp: 1695590958853 +- kind: conda + name: xz + version: 5.2.6 + build: h166bdaf_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2 + sha256: 03a6d28ded42af8a347345f82f3eebdd6807a08526d47899a42d62d319609162 + md5: 2161070d867d1b1204ea749c8eec4ef0 + depends: + - libgcc-ng >=12 + license: LGPL-2.1 and GPL-2.0 + size: 418368 + timestamp: 1660346797927 +- kind: conda + name: xz + version: 5.2.6 + build: h57fd34a_0 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/xz-5.2.6-h57fd34a_0.tar.bz2 + sha256: 59d78af0c3e071021cfe82dc40134c19dab8cdf804324b62940f5c8cd71803ec + md5: 39c6b54e94014701dd157f4f576ed211 + license: LGPL-2.1 and GPL-2.0 + size: 235693 + timestamp: 1660346961024 +- kind: conda + name: yaml + version: 0.2.5 + build: h3422bc3_2 + build_number: 2 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/yaml-0.2.5-h3422bc3_2.tar.bz2 + sha256: 93181a04ba8cfecfdfb162fc958436d868cc37db504c58078eab4c1a3e57fbb7 + md5: 4bb3f014845110883a3c5ee811fd84b4 + license: MIT + license_family: MIT + size: 88016 + timestamp: 1641347076660 +- kind: conda + name: yaml + version: 0.2.5 + build: h7f98852_2 + build_number: 2 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h7f98852_2.tar.bz2 + sha256: a4e34c710eeb26945bdbdaba82d3d74f60a78f54a874ec10d373811a5d217535 + md5: 4cb3ad778ec2d5a7acbdf254eb1c42ae + depends: + - libgcc-ng >=9.4.0 + license: MIT + license_family: MIT + size: 89141 + timestamp: 1641346969816 +- kind: conda + name: zipp + version: 3.17.0 + build: pyhd8ed1ab_0 + subdir: noarch + noarch: python + url: https://conda.anaconda.org/conda-forge/noarch/zipp-3.17.0-pyhd8ed1ab_0.conda + sha256: bced1423fdbf77bca0a735187d05d9b9812d2163f60ab426fc10f11f92ecbe26 + md5: 2e4d6bc0b14e10f895fc6791a7d9b26a + depends: + - python >=3.8 + license: MIT + license_family: MIT + purls: + - pkg:pypi/zipp + size: 18954 + timestamp: 1695255262261 +- kind: conda + name: zstandard + version: 0.22.0 + build: py312h7975427_0 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/zstandard-0.22.0-py312h7975427_0.conda + sha256: af2e7339e65d85c02c0097e16961bf8aa6d2eb0705644ddd82f722583bd6b134 + md5: 10c282af2c570a5a52173fd571693ec6 + depends: + - cffi >=1.11 + - python >=3.12,<3.13.0a0 + - python >=3.12,<3.13.0a0 *_cpython + - python_abi 3.12.* *_cp312 + - zstd >=1.5.5,<1.5.6.0a0 + - zstd >=1.5.5,<1.6.0a0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/zstandard + size: 331245 + timestamp: 1698830496330 +- kind: conda + name: zstandard + version: 0.22.0 + build: py312hd58854c_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.22.0-py312hd58854c_0.conda + sha256: da76216a4868d7f1a777c726e090a1acb0225a30905170ce042870016b874fe8 + md5: 6532ce0d6b7b6c77081ba102d3540a81 + depends: + - cffi >=1.11 + - libgcc-ng >=12 + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + - zstd >=1.5.5,<1.5.6.0a0 + - zstd >=1.5.5,<1.6.0a0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/zstandard + size: 415099 + timestamp: 1698830281446 +- kind: conda + name: zstd + version: 1.5.5 + build: h4f39d0f_0 + subdir: osx-arm64 + url: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.5-h4f39d0f_0.conda + sha256: 7e1fe6057628bbb56849a6741455bbb88705bae6d6646257e57904ac5ee5a481 + md5: 5b212cfb7f9d71d603ad891879dc7933 + depends: + - libzlib >=1.2.13,<1.3.0a0 + license: BSD-3-Clause + license_family: BSD + size: 400508 + timestamp: 1693151393180 +- kind: conda + name: zstd + version: 1.5.5 + build: hfc55251_0 + subdir: linux-64 + url: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.5-hfc55251_0.conda + sha256: 607cbeb1a533be98ba96cf5cdf0ddbb101c78019f1fda063261871dad6248609 + md5: 04b88013080254850d6c01ed54810589 + depends: + - libgcc-ng >=12 + - libstdcxx-ng >=12 + - libzlib >=1.2.13,<1.3.0a0 + license: BSD-3-Clause + license_family: BSD + size: 545199 + timestamp: 1693151163452 diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..e5574d1 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,169 @@ +# SPDX-FileCopyrightText: Copyright © 2022 Idiap Research Institute +# +# SPDX-License-Identifier: BSD-3-Clause + +[build-system] +requires = ["hatchling", "versioningit"] +build-backend = "hatchling.build" + +[project] +name = "auto-intersphinx" +dynamic = ["version"] +requires-python = ">=3.10" +description = "Automatic links direct project dependencies to the intersphinx catalog" +readme = "README.md" +license = "BSD-3-Clause" +authors = [{ name = "Andre Anjos", email = "andre.anjos@idiap.ch" }] +classifiers = [ + "Framework :: Sphinx :: Extension", + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Natural Language :: English", + "Programming Language :: Python :: 3", + "Topic :: Software Development :: Libraries :: Python Modules", +] +dependencies = ["sphinx", "packaging", "requests", "lxml"] + +[project.urls] +documentation = "https://auto-intersphinx.readthedocs.io/en/latest/" +homepage = "https://pypi.org/project/auto-intersphinx" +repository = "https://gitlab.idiap.ch/software/auto-intersphinx" +changelog = "https://gitlab.idiap.ch/software/auto-intersphinx/-/releases" + +[project.optional-dependencies] +qa = ["pre-commit"] +doc = [ + "furo", + "sphinx-autodoc-typehints", + "sphinx-copybutton", + "sphinx-inline-tabs", + "sphinx-argparse", +] +test = ["pytest", "pytest-cov"] + +[project.scripts] +auto-intersphinx = "auto_intersphinx.cli:main" + +[tool.pixi.project] +channels = ["conda-forge"] +platforms = ["linux-64", "osx-arm64"] + +[tool.pixi.system-requirements] +linux = "4.19.0" + +[tool.pixi.dependencies] +sphinx = "*" +packaging = "*" +requests = "*" +lxml = "*" + +[tool.pixi.feature.self.pypi-dependencies] +auto-intersphinx = { path = ".", editable = true } + +[tool.pixi.feature.py311.dependencies] +python = "~=3.11.0" + +[tool.pixi.feature.py312.dependencies] +python = "~=3.12.0" + +[tool.pixi.feature.qa.dependencies] +pre-commit = "*" +ruff = "*" +reuse = "*" + +[tool.pixi.feature.qa.tasks] +qa-install = "pre-commit install" +qa = "pre-commit run --all-files" +qa-ci = "pre-commit run --all-files --show-diff-on-failure --verbose" + +[tool.pixi.feature.doc.dependencies] +furo = "*" +sphinx-autodoc-typehints = "*" +sphinx-copybutton = "*" +sphinx-inline-tabs = "*" +sphinx-argparse = "*" + +[tool.pixi.feature.doc.tasks] +doc-clean = "rm -rf doc/api && rm -rf html" +doc = "sphinx-build -aEW doc html" +doctest = "sphinx-build -aEb doctest doc html/doctest" + +[tool.pixi.feature.test.dependencies] +pytest = "*" +pytest-cov = "*" + +[tool.pixi.feature.test.tasks] +test = "pytest -sv tests/" +test-ci = "pytest -sv --cov-report 'html:html/coverage' --cov-report 'xml:coverage.xml' --junitxml 'junit-coverage.xml' --ignore '.profile' tests/" + +[tool.pixi.feature.build.dependencies] +hatch = "*" +versioningit = "*" +twine = "*" + +[tool.pixi.feature.build.tasks] +build = "hatch build" +check = "twine check dist/*" +upload = "twine upload dist/*" + +[tool.pixi.feature.dev.dependencies] +pdbpp = "*" +uv = "*" + +[tool.pixi.feature.dev.tasks] +update-catalog = "auto-intersphinx update-catalog -vvv --self -o src/auto_intersphinx/catalog.json" + +[tool.pixi.environments] +default = { features = ["qa", "build", "doc", "test", "dev", "py312", "self"] } +qa-ci = { features = ["qa", "py312"] } +build-ci = { features = ["build", "py312"] } +test-ci-alternative = { features = ["test", "py311", "self"] } + +[tool.hatch.version] +source = "versioningit" + +[tool.versioningit.next-version] +method = "smallest" + +[tool.versioningit.format] +# Example formatted version: 1.2.4.dev42+ge174a1f +distance = "{next_version}.dev{distance}+{vcs}{rev}" +# Example formatted version: 1.2.4.dev42+ge174a1f.d20230922 +distance-dirty = "{next_version}.dev{distance}+{vcs}{rev}.d{build_date:%Y%m%d}" + +[tool.hatch.build.targets.sdist] +include = [ + "src/**/*.py", + "src/**/*.json", + "tests/**/*.py", + "tests/**/*.json", + "tests/**/*.txt", + "doc/**/*.rst", + "doc/**/*.py", + "LICENSES/*.txt", +] + +[tool.hatch.build.targets.wheel] +packages = ["src/auto_intersphinx"] + +[tool.isort] +profile = "black" +line_length = 88 +order_by_type = true +lines_between_types = 1 + +[tool.black] +line-length = 88 + +[tool.coverage.run] +relative_files = true + +[tool.pytest.ini_options] +addopts = [ + "--cov=auto_intersphinx", + "--cov-report=term-missing", + "--import-mode=append", +] +junit_logging = "all" +junit_log_passing_tests = false diff --git a/src/auto_intersphinx/__init__.py b/src/auto_intersphinx/__init__.py new file mode 100644 index 0000000..53c9133 --- /dev/null +++ b/src/auto_intersphinx/__init__.py @@ -0,0 +1,323 @@ +# SPDX-FileCopyrightText: Copyright © 2022 Idiap Research Institute +# +# SPDX-License-Identifier: BSD-3-Clause +"""Sphinx extension to automatically link package documentation from their +names. + +This package contains a Sphinx plugin that can fill intersphinx mappings +based on package names. It simplifies the use of that plugin by +removing the need of knowing URLs for various API catologs you may want +to cross-reference. +""" + +from __future__ import annotations # not required for Python >= 3.10 + +import importlib.metadata +import inspect +import pathlib +import textwrap +import typing + +from sphinx.application import Sphinx +from sphinx.config import Config +from sphinx.util import logging + +from .catalog import BUILTIN_CATALOG, Catalog, LookupCatalog + +logger = logging.getLogger(__name__) + + +def oneliner(s: str) -> str: + """Transforms a multiline docstring into a single line of text. + + This method converts the multi-line string into a single line, while also + dedenting the text. + + + Arguments: + + s: The input multiline string + + + Returns: + + A single line with all text. + """ + return inspect.cleandoc(s).replace("\n", " ") + + +def rewrap(s: str) -> str: + """Re-wrap a multiline docstring into a 80-character format. + + This method first converts the multi-line string into a single line. It + then wraps the single line into 80-characters width. + + + Arguments: + + s: The input multiline string + + + Returns: + + An 80-column wrapped multiline string + """ + return "\n".join(textwrap.wrap(oneliner(s), width=80)) + + +def _add_index( + mapping: dict[str, tuple[str, str | None]], + name: str, + addr: str, + objects_inv: str | None = None, +) -> None: + """Helper to add a new doc index to the intersphinx mapping catalog. + + This function will also verify if repeated entries are being inserted, and + if will issue a warning or error in case it must ignore overrides. + + + Arguments: + + mapping: A pointer to the currently used ``intersphinx_mapping`` + variable + name: Name of the new package to add + addr: The URL that contains the ``object.inv`` file, to load for + mapping objects from that package + objects_inv: The name of the file to use with the catalog to load on + the remote address (if different than ``objects.inv``.) + """ + + if name not in mapping: + mapping[name] = (addr, objects_inv) + + elif mapping[name][0] == addr and mapping[name][1] == objects_inv: + logger.info(f"Ignoring repeated setting of `{name}' intersphinx_mapping") + + else: + curr = mapping[name][0] + curr += "/" if not curr.endswith("/") else "" + curr += mapping[name][1] if mapping[name][1] else "objects.inv" + + newval = addr + newval += "/" if not newval.endswith("/") else "" + newval += objects_inv if objects_inv else "objects.inv" + + logger.error( + rewrap( + f""" + Ignoring reset of `{name}' intersphinx_mapping, because it + currently already points to `{curr}', and that is different + from the new value `{newval}' + """ + ) + ) + + +def populate_intersphinx_mapping(app: Sphinx, config: Config) -> None: + """Main extension method. + + This function is called by Sphinx once it is :py:func:`setup`. It executes + the lookup procedure for all packages listed on the configuration parameter + ``auto_intersphinx_packages``. If a catalog name is provided at + ``auto_intersphinx_catalog``, and package information is not found on the + catalogs, but discovered elsewhere (environment, readthedocs.org, or + pypi.org), then it is saved on that file, so that the next lookup is + faster. + + It follows the following search protocol for each package (first match + found stops the search procedure): + + 1. User catalog (if available) + 2. Built-in catalog distributed with the package + 3. The current Python environment + 4. https://readthedocs.org + 5. https://pypi.org + + + Arguments: + + app: Sphinx application + + config: Sphinx configuration + """ + m = config.intersphinx_mapping + + builtin_catalog = Catalog() + builtin_catalog.loads(BUILTIN_CATALOG.read_text()) + builtin_lookup = LookupCatalog(builtin_catalog) + + user_catalog = Catalog() + + if config.auto_intersphinx_catalog: + user_catalog_file = pathlib.Path(config.auto_intersphinx_catalog) + if not user_catalog_file.is_absolute(): + user_catalog_file = ( + pathlib.Path(app.confdir) / config.auto_intersphinx_catalog + ) + if user_catalog_file.exists(): + user_catalog.loads(user_catalog_file.read_text()) + user_lookup = LookupCatalog(user_catalog) + + for k in config.auto_intersphinx_packages: + p, v = k if isinstance(k, (tuple, list)) else (k, "stable") + + addr = user_lookup.get(p, v) + if addr is not None: + _add_index(m, p, addr, None) + continue # got an URL, continue to next package + elif p in user_catalog: + # The user receiving the message has access to their own catalog. + # Warn because it may trigger a voluntary update action. + logger.warning( + rewrap( + f""" + Package {p} is available in user catalog, however version + {v} is not. You may want to fix or update the catalog? + """ + ) + ) + + addr = builtin_lookup.get(p, v) + if addr is not None: + _add_index(m, p, addr, None) + continue # got an URL, continue to next package + elif p in builtin_catalog: + # The user receiving the message may not have access to the + # built-in catalog. Downgrade message importance to INFO + logger.info( + rewrap( + f""" + Package {p} is available in builtin catalog, however + version {v} is not. You may want to fix or update that + catalog? + """ + ) + ) + + # try to see if the package is installed using the user catalog + user_catalog.update_versions_from_environment(p, None) + user_lookup.reset() + addr = user_lookup.get(p, v) + if addr is not None: + _add_index(m, p, addr, None) + continue # got an URL, continue to next package + else: + logger.info( + rewrap( + f""" + Package {p} is not available at your currently installed + environment. If the name of the installed package differs + from that you specified, you may tweak your catalog using + ['{p}']['sources']['environment'] = so that the + package can be properly found. + """ + ) + ) + + # try to see if the package is available on readthedocs.org + user_catalog.update_versions_from_rtd(p, None) + user_lookup.reset() + addr = user_lookup.get(p, v) + if addr is not None: + _add_index(m, p, addr, None) + continue # got an URL, continue to next package + else: + logger.info( + rewrap( + f""" + Package {p} is not available at readthedocs.org. If the + name of the installed package differs from that you + specify, you may patch your catalog using + ['{p}']['sources']['environment'] = so that the + package can be properly found. + """ + ) + ) + + # try to see if the package is available on readthedocs.org + user_catalog.update_versions_from_pypi(p, None, max_entries=0) + user_lookup.reset() + addr = user_lookup.get(p, v) + if addr is not None: + _add_index(m, p, addr, None) + continue # got an URL, continue to next package + else: + logger.info( + rewrap( + f""" + Package {p} is not available at your currently installed + environment. If the name of the installed package differs + from that you specify, you may patch your catalog using + ['{p}']['sources']['environment'] = so that the + package can be properly found. + """ + ) + ) + + # if you get to this point, then the package name was not + # resolved - emit an error and continue + if v is not None: + name = f"{p}@{v}" + else: + name = p + + logger.error( + rewrap( + f""" + Cannot find suitable catalog entry for `{name}'. I searched + both internally and online without access. To remedy this, + provide the links on your own catalog, be less selective with + the version to bind documentation to, or simply remove this + entry from the auto-intersphinx package list. May be this + package has no Sphinx documentation at all? + """ + ) + ) + + # by the end of the processing, save the user catalog file if a path was + # given, so that the user does not have to do this again on the next + # rebuild, making it work like a cache. + if config.auto_intersphinx_catalog and user_catalog: + user_catalog_file = pathlib.Path(config.auto_intersphinx_catalog) + if not user_catalog_file.is_absolute(): + user_catalog_file = ( + pathlib.Path(app.confdir) / config.auto_intersphinx_catalog + ) + current_contents: str = "" + if user_catalog_file.exists(): + current_contents = user_catalog_file.read_text() + if current_contents != user_catalog.dumps(): + logger.info( + f"Recording {len(user_catalog)} entries to {str(user_catalog_file)}..." + ) + user_catalog.dump(user_catalog_file) + + +def setup(app: Sphinx) -> dict[str, typing.Any]: + """Sphinx extension configuration entry-point. + + This function defines the main function to be executed, other + extensions to be loaded, the loading relative order of this + extension, and configuration options with their own defaults. + """ + # we need intersphinx + app.setup_extension("sphinx.ext.intersphinx") + + # List of packages to link, in the format: str | tuple[str, str|None] + # that indicate either the package name, or a tuple with (package, + # version), for pointing to a specific version number user guide. + app.add_config_value("auto_intersphinx_packages", [], "html") + + # Where the user catalog file will be placed, if any. If a value is set, + # then it is updated if we discover resources remotely. It works like a + # local cache, you can edit to complement the internal catalog. A relative + # path is taken w.r.t. the sphinx documentation configuration. + app.add_config_value("auto_intersphinx_catalog", None, "html") + + app.connect("config-inited", populate_intersphinx_mapping, priority=700) + + return { + "version": importlib.metadata.version(__package__), + "parallel_read_safe": True, + } diff --git a/src/auto_intersphinx/catalog.json b/src/auto_intersphinx/catalog.json new file mode 100644 index 0000000..91cc4ff --- /dev/null +++ b/src/auto_intersphinx/catalog.json @@ -0,0 +1,931 @@ +{ + "click": { + "versions": { + "latest": "https://click.palletsprojects.com/en/latest/", + "8.1.x": "https://click.palletsprojects.com/en/8.1.x/", + "8.0.x": "https://click.palletsprojects.com/en/8.0.x/", + "7.x": "https://click.palletsprojects.com/en/7.x/", + "6.x": "https://click.palletsprojects.com/en/6.x/", + "5.x": "https://click.palletsprojects.com/en/5.x/", + "4.x": "https://click.palletsprojects.com/en/4.x/", + "3.x": "https://click.palletsprojects.com/en/3.x/", + "2.x": "https://click.palletsprojects.com/en/2.x/", + "1.x": "https://click.palletsprojects.com/en/1.x/" + }, + "sources": {} + }, + "click-plugins": { + "versions": {}, + "sources": {} + }, + "coverage": { + "versions": { + "latest": "https://coverage.readthedocs.io/en/latest/", + "stable": "https://coverage.readthedocs.io/en/stable/", + "7.5.1": "https://coverage.readthedocs.io/en/7.5.1/", + "7.5.0": "https://coverage.readthedocs.io/en/7.5.0/", + "7.4.4": "https://coverage.readthedocs.io/en/7.4.4/", + "7.4.3": "https://coverage.readthedocs.io/en/7.4.3/", + "7.4.2": "https://coverage.readthedocs.io/en/7.4.2/", + "7.4.1": "https://coverage.readthedocs.io/en/7.4.1/", + "7.4.0": "https://coverage.readthedocs.io/en/7.4.0/", + "7.3.4": "https://coverage.readthedocs.io/en/7.3.4/", + "7.3.3": "https://coverage.readthedocs.io/en/7.3.3/", + "7.3.2": "https://coverage.readthedocs.io/en/7.3.2/", + "7.3.1": "https://coverage.readthedocs.io/en/7.3.1/", + "7.3.0": "https://coverage.readthedocs.io/en/7.3.0/", + "7.2.7": "https://coverage.readthedocs.io/en/7.2.7/", + "7.2.6": "https://coverage.readthedocs.io/en/7.2.6/", + "7.2.5": "https://coverage.readthedocs.io/en/7.2.5/", + "7.2.4": "https://coverage.readthedocs.io/en/7.2.4/", + "7.2.3": "https://coverage.readthedocs.io/en/7.2.3/", + "7.2.2": "https://coverage.readthedocs.io/en/7.2.2/", + "7.2.1": "https://coverage.readthedocs.io/en/7.2.1/", + "7.2.0": "https://coverage.readthedocs.io/en/7.2.0/", + "7.1.0": "https://coverage.readthedocs.io/en/7.1.0/", + "7.0.5": "https://coverage.readthedocs.io/en/7.0.5/", + "7.0.4": "https://coverage.readthedocs.io/en/7.0.4/", + "7.0.3": "https://coverage.readthedocs.io/en/7.0.3/", + "7.0.2": "https://coverage.readthedocs.io/en/7.0.2/", + "7.0.1": "https://coverage.readthedocs.io/en/7.0.1/", + "7.0.0": "https://coverage.readthedocs.io/en/7.0.0/", + "7.0.0b1": "https://coverage.readthedocs.io/en/7.0.0b1/", + "6.6.0b1": "https://coverage.readthedocs.io/en/6.6.0b1/", + "6.5.0": "https://coverage.readthedocs.io/en/6.5.0/", + "6.4.4": "https://coverage.readthedocs.io/en/6.4.4/", + "6.4.3": "https://coverage.readthedocs.io/en/6.4.3/", + "6.4.2": "https://coverage.readthedocs.io/en/6.4.2/", + "6.4.1": "https://coverage.readthedocs.io/en/6.4.1/", + "6.4": "https://coverage.readthedocs.io/en/6.4/", + "6.3.3": "https://coverage.readthedocs.io/en/6.3.3/", + "6.3.2": "https://coverage.readthedocs.io/en/6.3.2/", + "6.3.1": "https://coverage.readthedocs.io/en/6.3.1/", + "6.3": "https://coverage.readthedocs.io/en/6.3/", + "6.2": "https://coverage.readthedocs.io/en/6.2/", + "6.1.2": "https://coverage.readthedocs.io/en/6.1.2/", + "6.1.1": "https://coverage.readthedocs.io/en/6.1.1/", + "6.1": "https://coverage.readthedocs.io/en/6.1/", + "6.0.2": "https://coverage.readthedocs.io/en/6.0.2/", + "6.0.1": "https://coverage.readthedocs.io/en/6.0.1/", + "6.0": "https://coverage.readthedocs.io/en/6.0/", + "6.0b1": "https://coverage.readthedocs.io/en/6.0b1/", + "5.5": "https://coverage.readthedocs.io/en/5.5/", + "4.5.4": "https://coverage.readthedocs.io/en/4.5.4/", + "coverage-5.5": "https://coverage.readthedocs.io/en/coverage-5.5/", + "coverage-5.4": "https://coverage.readthedocs.io/en/coverage-5.4/", + "coverage-5.3.1": "https://coverage.readthedocs.io/en/coverage-5.3.1/", + "coverage-5.3": "https://coverage.readthedocs.io/en/coverage-5.3/", + "coverage-5.2.1": "https://coverage.readthedocs.io/en/coverage-5.2.1/", + "coverage-5.2": "https://coverage.readthedocs.io/en/coverage-5.2/", + "coverage-5.1": "https://coverage.readthedocs.io/en/coverage-5.1/", + "coverage-5.0.4": "https://coverage.readthedocs.io/en/coverage-5.0.4/", + "coverage-5.0.3": "https://coverage.readthedocs.io/en/coverage-5.0.3/", + "coverage-5.0.2": "https://coverage.readthedocs.io/en/coverage-5.0.2/", + "coverage-5.0.1": "https://coverage.readthedocs.io/en/coverage-5.0.1/", + "coverage-5.0": "https://coverage.readthedocs.io/en/coverage-5.0/", + "coverage-4.5.4": "https://coverage.readthedocs.io/en/coverage-4.5.4/" + }, + "sources": { + "readthedocs": "coverage" + } + }, + "dask": { + "versions": { + "latest": "https://docs.dask.org/en/latest/", + "stable": "https://docs.dask.org/en/stable/" + }, + "sources": { + "readthedocs": "dask" + } + }, + "dask-jobqueue": { + "versions": { + "latest": "https://jobqueue.dask.org/en/latest/", + "stable": "https://jobqueue.dask.org/en/stable/" + }, + "sources": { + "readthedocs": "dask-jobqueue" + } + }, + "dask-ml": { + "versions": { + "latest": "https://ml.dask.org" + }, + "sources": {} + }, + "ddt": { + "versions": { + "latest": "https://ddt.readthedocs.io/en/latest/", + "stable": "https://ddt.readthedocs.io/en/stable/" + }, + "sources": { + "readthedocs": "ddt" + } + }, + "distributed": { + "versions": { + "latest": "https://distributed.dask.org/en/latest/", + "stable": "https://distributed.dask.org/en/stable/" + }, + "sources": { + "readthedocs": "distributed" + } + }, + "docker": { + "versions": { + "latest": "https://docker-py.readthedocs.io/en/latest/", + "stable": "https://docker-py.readthedocs.io/en/stable/", + "7.0.0": "https://docker-py.readthedocs.io/en/7.0.0/", + "6.1.3": "https://docker-py.readthedocs.io/en/6.1.3/", + "6.1.2": "https://docker-py.readthedocs.io/en/6.1.2/", + "6.1.1": "https://docker-py.readthedocs.io/en/6.1.1/", + "6.1.0": "https://docker-py.readthedocs.io/en/6.1.0/", + "6.0.1": "https://docker-py.readthedocs.io/en/6.0.1/", + "6.0.0": "https://readthedocs.org/dashboard/docker-py/version/6.0.0/edit/", + "5.0.3": "https://docker-py.readthedocs.io/en/5.0.3/", + "5.0.2": "https://docker-py.readthedocs.io/en/5.0.2/", + "5.0.1": "https://docker-py.readthedocs.io/en/5.0.1/", + "5.0.0": "https://docker-py.readthedocs.io/en/5.0.0/", + "4.4.4": "https://docker-py.readthedocs.io/en/4.4.4/", + "4.4.3": "https://docker-py.readthedocs.io/en/4.4.3/", + "4.4.2": "https://docker-py.readthedocs.io/en/4.4.2/", + "4.4.1": "https://docker-py.readthedocs.io/en/4.4.1/", + "4.4.0": "https://docker-py.readthedocs.io/en/4.4.0/", + "4.3.1": "https://docker-py.readthedocs.io/en/4.3.1/", + "4.3.0": "https://docker-py.readthedocs.io/en/4.3.0/", + "4.2.2": "https://docker-py.readthedocs.io/en/4.2.2/", + "4.2.1": "https://docker-py.readthedocs.io/en/4.2.1/", + "4.2.0": "https://docker-py.readthedocs.io/en/4.2.0/", + "4.1.0": "https://docker-py.readthedocs.io/en/4.1.0/", + "4.0.2": "https://docker-py.readthedocs.io/en/4.0.2/", + "4.0.1": "https://docker-py.readthedocs.io/en/4.0.1/", + "3.7.0": "https://docker-py.readthedocs.io/en/3.7.0/", + "3.6.0": "https://docker-py.readthedocs.io/en/3.6.0/", + "3.5.1": "https://docker-py.readthedocs.io/en/3.5.1/", + "3.5.0": "https://docker-py.readthedocs.io/en/3.5.0/", + "3.4.0": "https://docker-py.readthedocs.io/en/3.4.0/", + "3.3.0": "https://docker-py.readthedocs.io/en/3.3.0/", + "3.2.1": "https://docker-py.readthedocs.io/en/3.2.1/", + "3.2.0": "https://docker-py.readthedocs.io/en/3.2.0/", + "3.1.1": "https://docker-py.readthedocs.io/en/3.1.1/", + "3.1.0": "https://docker-py.readthedocs.io/en/3.1.0/", + "3.0.1": "https://docker-py.readthedocs.io/en/3.0.1/", + "3.0.0": "https://docker-py.readthedocs.io/en/3.0.0/", + "2.7.0": "https://docker-py.readthedocs.io/en/2.7.0/", + "2.6.1": "https://docker-py.readthedocs.io/en/2.6.1/", + "2.6.0": "https://docker-py.readthedocs.io/en/2.6.0/", + "2.5.1": "https://docker-py.readthedocs.io/en/2.5.1/", + "2.5.0": "https://docker-py.readthedocs.io/en/2.5.0/", + "2.4.2": "https://docker-py.readthedocs.io/en/2.4.2/", + "2.3.0": "https://docker-py.readthedocs.io/en/2.3.0/", + "2.2.1": "https://docker-py.readthedocs.io/en/2.2.1/", + "2.2.0": "https://docker-py.readthedocs.io/en/2.2.0/", + "2.1.0": "https://docker-py.readthedocs.io/en/2.1.0/", + "2.0.2": "https://docker-py.readthedocs.io/en/2.0.2/", + "2.0.1": "https://docker-py.readthedocs.io/en/2.0.1/", + "1.10.6": "https://docker-py.readthedocs.io/en/1.10.6/", + "1.10.4": "https://docker-py.readthedocs.io/en/1.10.4/", + "1.10.3": "https://docker-py.readthedocs.io/en/1.10.3/", + "1.10.2": "https://docker-py.readthedocs.io/en/1.10.2/", + "1.10.0": "https://docker-py.readthedocs.io/en/1.10.0/", + "1.9.0": "https://docker-py.readthedocs.io/en/1.9.0/", + "1.8.1": "https://docker-py.readthedocs.io/en/1.8.1/", + "1.8.0": "https://docker-py.readthedocs.io/en/1.8.0/", + "1.7.2": "https://docker-py.readthedocs.io/en/1.7.2/", + "1.7.1": "https://docker-py.readthedocs.io/en/1.7.1/", + "1.7.0": "https://docker-py.readthedocs.io/en/1.7.0/", + "1.6.0": "https://docker-py.readthedocs.io/en/1.6.0/", + "1.5.0": "https://docker-py.readthedocs.io/en/1.5.0/", + "1.4.0": "https://docker-py.readthedocs.io/en/1.4.0/", + "1.3.1": "https://docker-py.readthedocs.io/en/1.3.1/", + "1.3.0": "https://docker-py.readthedocs.io/en/1.3.0/", + "1.2.3": "https://docker-py.readthedocs.io/en/1.2.3/", + "1.2.2": "https://docker-py.readthedocs.io/en/1.2.2/", + "1.2.1": "https://docker-py.readthedocs.io/en/1.2.1/", + "1.2.0": "https://docker-py.readthedocs.io/en/1.2.0/", + "1.1.0": "https://docker-py.readthedocs.io/en/1.1.0/" + }, + "sources": { + "readthedocs": "docker-py" + } + }, + "docopt": { + "versions": {}, + "sources": {} + }, + "flaky": { + "versions": {}, + "sources": {} + }, + "graphviz": { + "versions": { + "latest": "https://graphviz.readthedocs.io/en/latest/", + "stable": "https://graphviz.readthedocs.io/en/stable/" + }, + "sources": { + "readthedocs": "graphviz" + } + }, + "h5py": { + "versions": { + "latest": "https://docs.h5py.org/en/latest/", + "stable": "https://docs.h5py.org/en/stable/", + "3.11.0": "https://docs.h5py.org/en/3.11.0/", + "3.10.0": "https://docs.h5py.org/en/3.10.0/", + "3.9.0": "https://docs.h5py.org/en/3.9.0/", + "3.8.0": "https://docs.h5py.org/en/3.8.0/", + "3.7.0": "https://docs.h5py.org/en/3.7.0/", + "3.6.0": "https://docs.h5py.org/en/3.6.0/", + "3.5.0": "https://docs.h5py.org/en/3.5.0/", + "3.4.0": "https://docs.h5py.org/en/3.4.0/", + "3.3.0": "https://docs.h5py.org/en/3.3.0/", + "3.2.1": "https://docs.h5py.org/en/3.2.1/", + "3.2.0": "https://docs.h5py.org/en/3.2.0/", + "3.1.0": "https://docs.h5py.org/en/3.1.0/", + "3.0.0": "https://docs.h5py.org/en/3.0.0/", + "2.10.0": "https://docs.h5py.org/en/2.10.0/", + "2.9.0": "https://docs.h5py.org/en/2.9.0/", + "2.8.0": "https://docs.h5py.org/en/2.8.0/", + "2.7.1": "https://docs.h5py.org/en/2.7.1/", + "2.6.0": "https://docs.h5py.org/en/2.6.0/", + "2.5.0": "https://docs.h5py.org/en/2.5.0/" + }, + "sources": { + "readthedocs": "h5py" + } + }, + "imageio": { + "versions": { + "latest": "https://imageio.readthedocs.io/en/latest/", + "stable": "https://imageio.readthedocs.io/en/stable/", + "v2.34.1": "https://imageio.readthedocs.io/en/v2.34.1/", + "v2.34.0": "https://imageio.readthedocs.io/en/v2.34.0/", + "v2.33.1": "https://imageio.readthedocs.io/en/v2.33.1/", + "v2.33.0": "https://imageio.readthedocs.io/en/v2.33.0/", + "v2.32.0": "https://imageio.readthedocs.io/en/v2.32.0/", + "v2.31.6": "https://imageio.readthedocs.io/en/v2.31.6/", + "v2.31.5": "https://imageio.readthedocs.io/en/v2.31.5/", + "v2.31.4": "https://imageio.readthedocs.io/en/v2.31.4/", + "v2.31.3": "https://imageio.readthedocs.io/en/v2.31.3/", + "v2.31.2": "https://imageio.readthedocs.io/en/v2.31.2/", + "v2.31.1": "https://imageio.readthedocs.io/en/v2.31.1/", + "v2.31.0": "https://imageio.readthedocs.io/en/v2.31.0/", + "v2.30.0": "https://imageio.readthedocs.io/en/v2.30.0/", + "v2.29.0": "https://imageio.readthedocs.io/en/v2.29.0/", + "v2.28.1": "https://imageio.readthedocs.io/en/v2.28.1/", + "v2.28.0": "https://imageio.readthedocs.io/en/v2.28.0/", + "v2.27.0": "https://imageio.readthedocs.io/en/v2.27.0/", + "v2.26.1": "https://imageio.readthedocs.io/en/v2.26.1/", + "v2.26.0": "https://imageio.readthedocs.io/en/v2.26.0/", + "v2.25.1": "https://imageio.readthedocs.io/en/v2.25.1/", + "v2.25.0": "https://imageio.readthedocs.io/en/v2.25.0/", + "v2.24.0": "https://imageio.readthedocs.io/en/v2.24.0/", + "v2.23.0": "https://imageio.readthedocs.io/en/v2.23.0/", + "v2.22.4": "https://imageio.readthedocs.io/en/v2.22.4/", + "v2.22.3": "https://imageio.readthedocs.io/en/v2.22.3/", + "v2.22.2": "https://imageio.readthedocs.io/en/v2.22.2/", + "v2.22.1": "https://imageio.readthedocs.io/en/v2.22.1/", + "v2.22.0": "https://imageio.readthedocs.io/en/v2.22.0/", + "v2.21.3": "https://imageio.readthedocs.io/en/v2.21.3/", + "v2.21.2": "https://imageio.readthedocs.io/en/v2.21.2/", + "v2.21.1": "https://imageio.readthedocs.io/en/v2.21.1/", + "v2.21.0": "https://imageio.readthedocs.io/en/v2.21.0/", + "v2.20.0": "https://imageio.readthedocs.io/en/v2.20.0/", + "v2.19.5": "https://imageio.readthedocs.io/en/v2.19.5/", + "v2.19.4": "https://imageio.readthedocs.io/en/v2.19.4/", + "v2.19.3": "https://imageio.readthedocs.io/en/v2.19.3/", + "v2.19.2": "https://imageio.readthedocs.io/en/v2.19.2/", + "v2.19.1": "https://imageio.readthedocs.io/en/v2.19.1/", + "v2.19.0": "https://imageio.readthedocs.io/en/v2.19.0/", + "v2.18.0": "https://imageio.readthedocs.io/en/v2.18.0/", + "v2.17.0": "https://imageio.readthedocs.io/en/v2.17.0/", + "v2.16.2": "https://imageio.readthedocs.io/en/v2.16.2/", + "v2.16.1": "https://imageio.readthedocs.io/en/v2.16.1/", + "v2.16.0": "https://imageio.readthedocs.io/en/v2.16.0/", + "v2.15.0": "https://imageio.readthedocs.io/en/v2.15.0/", + "v2.14.1": "https://imageio.readthedocs.io/en/v2.14.1/", + "v2.14.0": "https://imageio.readthedocs.io/en/v2.14.0/", + "v2.13.5": "https://imageio.readthedocs.io/en/v2.13.5/", + "v2.13.4": "https://imageio.readthedocs.io/en/v2.13.4/", + "v2.13.3": "https://imageio.readthedocs.io/en/v2.13.3/", + "v2.13.2": "https://imageio.readthedocs.io/en/v2.13.2/", + "v2.13.1": "https://imageio.readthedocs.io/en/v2.13.1/", + "v2.13.0": "https://imageio.readthedocs.io/en/v2.13.0/", + "v2.12.0": "https://imageio.readthedocs.io/en/v2.12.0/", + "v2.11.1": "https://imageio.readthedocs.io/en/v2.11.1/", + "v2.11.0": "https://imageio.readthedocs.io/en/v2.11.0/", + "v2.10.5": "https://imageio.readthedocs.io/en/v2.10.5/", + "v2.10.4": "https://imageio.readthedocs.io/en/v2.10.4/", + "v2.10.3": "https://imageio.readthedocs.io/en/v2.10.3/", + "v2.10.2": "https://imageio.readthedocs.io/en/v2.10.2/", + "v2.10.1": "https://imageio.readthedocs.io/en/v2.10.1/", + "v2.10.0": "https://imageio.readthedocs.io/en/v2.10.0/", + "v2.9.0": "https://imageio.readthedocs.io/en/v2.9.0/", + "v2.8.0": "https://imageio.readthedocs.io/en/v2.8.0/", + "v2.6.1": "https://imageio.readthedocs.io/en/v2.6.1/", + "v2.5.0": "https://imageio.readthedocs.io/en/v2.5.0/", + "v2.4.1": "https://imageio.readthedocs.io/en/v2.4.1/" + }, + "sources": { + "readthedocs": "imageio" + } + }, + "imageio-ffmpeg": { + "versions": {}, + "sources": {} + }, + "jinja2": { + "versions": { + "latest": "https://jinja.palletsprojects.com/en/latest/", + "3.1.x": "https://jinja.palletsprojects.com/en/3.1.x/", + "3.0.x": "https://jinja.palletsprojects.com/en/3.0.x/", + "2.11.x": "https://jinja.palletsprojects.com/en/2.11.x/", + "2.10.x": "https://jinja.palletsprojects.com/en/2.10.x/", + "2.9.x": "https://jinja.palletsprojects.com/en/2.9.x/" + }, + "sources": {} + }, + "lightning": { + "versions": { + "latest": "https://lightning.ai/docs/pytorch/latest/", + "stable": "https://lightning.ai/docs/pytorch/stable/" + }, + "sources": {} + }, + "matplotlib": { + "versions": { + "stable": "https://matplotlib.org/stable/" + }, + "sources": {} + }, + "mne": { + "versions": { + "latest": "https://mne.tools/dev/", + "stable": "https://mne.tools/stable/", + "1.0.x": "https://mne.tools/1.0/", + "0.24.x": "https://mne.tools/0.24/", + "0.23.x": "https://mne.tools/0.23/", + "0.22.x": "https://mne.tools/0.22/", + "0.21.x": "https://mne.tools/0.21/", + "0.20.x": "https://mne.tools/0.20/", + "0.19.x": "https://mne.tools/0.19/", + "0.18.x": "https://mne.tools/0.18/", + "0.17.x": "https://mne.tools/0.17/", + "0.16.x": "https://mne.tools/0.16/", + "0.15.x": "https://mne.tools/0.15/", + "0.14.x": "https://mne.tools/0.14/", + "0.13.x": "https://mne.tools/0.13/", + "0.12.x": "https://mne.tools/0.12/", + "0.11.x": "https://mne.tools/0.11/" + }, + "sources": {} + }, + "nose": { + "versions": { + "latest": "https://nose.readthedocs.io/en/latest/" + }, + "sources": { + "readthedocs": "nose" + } + }, + "numba": { + "versions": { + "latest": "https://numba.readthedocs.io/en/latest/", + "stable": "https://numba.readthedocs.io/en/stable/", + "0.59.1": "https://numba.readthedocs.io/en/0.59.1/", + "0.59.0": "https://numba.readthedocs.io/en/0.59.0/", + "0.59.0rc1": "https://numba.readthedocs.io/en/0.59.0rc1/", + "0.58.1": "https://numba.readthedocs.io/en/0.58.1/", + "0.58.0": "https://numba.readthedocs.io/en/0.58.0/", + "0.58.0rc2": "https://numba.readthedocs.io/en/0.58.0rc2/", + "0.58.0rc1": "https://numba.readthedocs.io/en/0.58.0rc1/", + "0.57.1": "https://numba.readthedocs.io/en/0.57.1/", + "0.57.1rc1": "https://numba.readthedocs.io/en/0.57.1rc1/", + "0.57.0": "https://numba.readthedocs.io/en/0.57.0/", + "0.57.0rc1": "https://numba.readthedocs.io/en/0.57.0rc1/", + "0.56.4": "https://numba.readthedocs.io/en/0.56.4/", + "0.56.3": "https://numba.readthedocs.io/en/0.56.3/", + "0.56.2": "https://numba.readthedocs.io/en/0.56.2/", + "0.56.1": "https://numba.readthedocs.io/en/0.56.1/", + "0.56.0": "https://numba.readthedocs.io/en/0.56.0/", + "0.56.0rc1": "https://numba.readthedocs.io/en/0.56.0rc1/", + "0.55.2": "https://numba.readthedocs.io/en/0.55.2/", + "0.55.1": "https://numba.readthedocs.io/en/0.55.1/", + "0.55.0": "https://numba.readthedocs.io/en/0.55.0/", + "0.55.0rc1": "https://numba.readthedocs.io/en/0.55.0rc1/", + "0.54.1": "https://numba.readthedocs.io/en/0.54.1/", + "0.54.0": "https://numba.readthedocs.io/en/0.54.0/", + "0.53.1": "https://numba.readthedocs.io/en/0.53.1/", + "0.53.0": "https://numba.readthedocs.io/en/0.53.0/", + "0.52.0": "https://numba.readthedocs.io/en/0.52.0/", + "0.51.2": "https://numba.readthedocs.io/en/0.51.2/", + "0.51.1": "https://numba.readthedocs.io/en/0.51.1/", + "0.51.0": "https://numba.readthedocs.io/en/0.51.0/" + }, + "sources": { + "readthedocs": "numba" + } + }, + "numpy": { + "versions": { + "latest": "https://numpy.org/devdocs/", + "stable": "https://numpy.org/doc/stable/", + "1.24.2": "https://numpy.org/doc/1.24/", + "1.23.4": "https://numpy.org/doc/1.23/", + "1.23.x": "https://numpy.org/doc/1.23/", + "1.22.x": "https://numpy.org/doc/1.22/", + "1.21.x": "https://numpy.org/doc/1.21/", + "1.20.x": "https://numpy.org/doc/1.20/", + "1.19.x": "https://numpy.org/doc/1.19/", + "1.18.x": "https://numpy.org/doc/1.18/", + "1.17.x": "https://numpy.org/doc/1.17/", + "1.16.x": "https://numpy.org/doc/1.16/", + "1.15.x": "https://numpy.org/doc/1.15/", + "1.14.x": "https://numpy.org/doc/1.14/", + "1.13.x": "https://numpy.org/doc/1.13/" + }, + "sources": { + "pypi": "numpy" + } + }, + "packaging": { + "versions": { + "latest": "https://packaging.pypa.io/en/latest/", + "stable": "https://packaging.pypa.io/en/stable/" + }, + "sources": { + "readthedocs": "packaging" + } + }, + "pandas": { + "versions": { + "latest": "https://pandas.pydata.org/docs/dev/", + "stable": "https://pandas.pydata.org/docs/", + "1.4.x": "https://pandas.pydata.org/pandas-docs/version/1.4/", + "1.3.x": "https://pandas.pydata.org/pandas-docs/version/1.3/", + "1.2.x": "https://pandas.pydata.org/pandas-docs/version/1.2/", + "1.1.x": "https://pandas.pydata.org/pandas-docs/version/1.1/", + "1.0.x": "https://pandas.pydata.org/pandas-docs/version/1.0/" + }, + "sources": {} + }, + "pillow": { + "versions": { + "latest": "https://pillow.readthedocs.io/en/latest/", + "stable": "https://pillow.readthedocs.io/en/stable/" + }, + "sources": { + "readthedocs": "pillow" + } + }, + "pip": { + "versions": { + "latest": "https://pip.pypa.io/en/latest/", + "stable": "https://pip.pypa.io/en/stable/" + }, + "sources": { + "readthedocs": "pip" + } + }, + "psutil": { + "versions": { + "latest": "https://psutil.readthedocs.io/en/latest/", + "stable": "https://psutil.readthedocs.io/en/stable/", + "release-5.3.0": "https://readthedocs.org/dashboard/psutil/version/release-5.3.0/edit/", + "release-5.2.2": "https://readthedocs.org/dashboard/psutil/version/release-5.2.2/edit/", + "release-5.1.3": "https://readthedocs.org/dashboard/psutil/version/release-5.1.3/edit/", + "release-5.0.1": "https://readthedocs.org/dashboard/psutil/version/release-5.0.1/edit/", + "release-4.4.2": "https://readthedocs.org/dashboard/psutil/version/release-4.4.2/edit/", + "release-4.3.1": "https://readthedocs.org/dashboard/psutil/version/release-4.3.1/edit/", + "release-4.2.0": "https://readthedocs.org/dashboard/psutil/version/release-4.2.0/edit/", + "release-3.4.2": "https://readthedocs.org/dashboard/psutil/version/release-3.4.2/edit/", + "release-3.2.2": "https://readthedocs.org/dashboard/psutil/version/release-3.2.2/edit/", + "release-3.1.1": "https://readthedocs.org/dashboard/psutil/version/release-3.1.1/edit/", + "release-3.0.1": "https://readthedocs.org/dashboard/psutil/version/release-3.0.1/edit/", + "release-2.2.1": "https://readthedocs.org/dashboard/psutil/version/release-2.2.1/edit/" + }, + "sources": { + "readthedocs": "psutil" + } + }, + "pybind11": { + "versions": { + "latest": "https://pybind11.readthedocs.io/en/latest/", + "stable": "https://pybind11.readthedocs.io/en/stable/" + }, + "sources": { + "readthedocs": "pybind11" + } + }, + "pytest": { + "versions": { + "latest": "https://docs.pytest.org/en/latest/", + "stable": "https://docs.pytest.org/en/stable/", + "7.2.x": "https://docs.pytest.org/en/7.2.x/", + "7.1.x": "https://docs.pytest.org/en/7.1.x/", + "7.0.x": "https://docs.pytest.org/en/7.0.x/", + "6.2.x": "https://docs.pytest.org/en/6.2.x/", + "4.6.x": "https://docs.pytest.org/en/4.6.x/", + "7.4.x": "https://docs.pytest.org/en/7.4.x/", + "7.3.x": "https://docs.pytest.org/en/7.3.x/", + "8.2.x": "https://docs.pytest.org/en/8.2.x/", + "8.1.x": "https://docs.pytest.org/en/8.1.x/", + "8.0.x": "https://docs.pytest.org/en/8.0.x/" + }, + "sources": { + "readthedocs": "pytest" + } + }, + "pytest-cov": { + "versions": { + "latest": "https://pytest-cov.readthedocs.io/en/latest/", + "stable": "https://pytest-cov.readthedocs.io/en/stable/", + "v2.10.1_a": "https://pytest-cov.readthedocs.io/en/v2.10.1_a/", + "v2.10.0": "https://pytest-cov.readthedocs.io/en/v2.10.0/", + "v2.9.0": "https://pytest-cov.readthedocs.io/en/v2.9.0/", + "v2.8.1": "https://pytest-cov.readthedocs.io/en/v2.8.1/", + "v2.8.0": "https://pytest-cov.readthedocs.io/en/v2.8.0/", + "v2.7.1": "https://pytest-cov.readthedocs.io/en/v2.7.1/", + "v2.7.0": "https://pytest-cov.readthedocs.io/en/v2.7.0/", + "v2.6.1": "https://pytest-cov.readthedocs.io/en/v2.6.1/", + "v2.6.0": "https://pytest-cov.readthedocs.io/en/v2.6.0/" + }, + "sources": { + "readthedocs": "pytest-cov" + } + }, + "python": { + "versions": { + "stable": "https://docs.python.org/", + "3": "https://docs.python.org/3/", + "3.x.x": "https://docs.python.org/3/", + "3.12.x": "https://docs.python.org/3.12/", + "3.11.x": "https://docs.python.org/3.11/", + "3.10.x": "https://docs.python.org/3.10/", + "3.9.x": "https://docs.python.org/3.9/", + "3.8.x": "https://docs.python.org/3.8/", + "3.7.x": "https://docs.python.org/3.7/", + "3.6.x": "https://docs.python.org/3.6/", + "3.5.x": "https://docs.python.org/3.5/", + "2": "https://docs.python.org/2/", + "2.7.x": "https://docs.python.org/2.7/" + }, + "sources": {} + }, + "pytorch-lightning": { + "versions": { + "latest": "https://pytorch-lightning.readthedocs.io/en/latest/", + "stable": "https://pytorch-lightning.readthedocs.io/en/stable/" + }, + "sources": {} + }, + "pyyaml": { + "versions": {}, + "sources": {} + }, + "pyzmq": { + "versions": { + "latest": "https://pyzmq.readthedocs.io/en/latest/", + "stable": "https://pyzmq.readthedocs.io/en/stable/", + "v26.0.3": "https://pyzmq.readthedocs.io/en/v26.0.3/", + "v26.0.2": "https://pyzmq.readthedocs.io/en/v26.0.2/", + "v26.0.1": "https://pyzmq.readthedocs.io/en/v26.0.1/", + "v26.0.0": "https://pyzmq.readthedocs.io/en/v26.0.0/", + "v25.1.2": "https://pyzmq.readthedocs.io/en/v25.1.2/", + "v25.1.1": "https://pyzmq.readthedocs.io/en/v25.1.1/", + "v25.1.0": "https://pyzmq.readthedocs.io/en/v25.1.0/", + "v25.0.2": "https://pyzmq.readthedocs.io/en/v25.0.2/", + "v25.0.1": "https://pyzmq.readthedocs.io/en/v25.0.1/", + "v25.0.0": "https://pyzmq.readthedocs.io/en/v25.0.0/", + "v24.0.1": "https://pyzmq.readthedocs.io/en/v24.0.1/", + "v24.0.0": "https://pyzmq.readthedocs.io/en/v24.0.0/", + "v23.2.1": "https://pyzmq.readthedocs.io/en/v23.2.1/", + "v23.2.0": "https://pyzmq.readthedocs.io/en/v23.2.0/", + "v23.1.0": "https://pyzmq.readthedocs.io/en/v23.1.0/", + "v23.0.0": "https://pyzmq.readthedocs.io/en/v23.0.0/", + "v22.3.0": "https://pyzmq.readthedocs.io/en/v22.3.0/", + "v22.2.1": "https://pyzmq.readthedocs.io/en/v22.2.1/", + "v22.2.0": "https://pyzmq.readthedocs.io/en/v22.2.0/", + "v22.1.0": "https://pyzmq.readthedocs.io/en/v22.1.0/", + "v22.0.3": "https://pyzmq.readthedocs.io/en/v22.0.3/", + "v22.0.2": "https://pyzmq.readthedocs.io/en/v22.0.2/", + "v20.0.0": "https://pyzmq.readthedocs.io/en/v20.0.0/", + "v19.0.2": "https://pyzmq.readthedocs.io/en/v19.0.2/", + "v19.0.0": "https://pyzmq.readthedocs.io/en/v19.0.0/", + "v18.1.1": "https://pyzmq.readthedocs.io/en/v18.1.1/", + "v18.0.2": "https://pyzmq.readthedocs.io/en/v18.0.2/", + "v17.1.3": "https://pyzmq.readthedocs.io/en/v17.1.3/", + "v17.1.2": "https://pyzmq.readthedocs.io/en/v17.1.2/", + "v17.1.1": "https://pyzmq.readthedocs.io/en/v17.1.1/", + "v17.1.0": "https://pyzmq.readthedocs.io/en/v17.1.0/", + "v17.0.0": "https://pyzmq.readthedocs.io/en/v17.0.0/", + "v16.0.4": "https://readthedocs.org/dashboard/pyzmq/version/v16.0.4/edit/", + "v16.0.3": "https://pyzmq.readthedocs.io/en/v16.0.3/", + "v16.0.2": "https://pyzmq.readthedocs.io/en/v16.0.2/", + "v16.0.1": "https://pyzmq.readthedocs.io/en/v16.0.1/", + "v16.0.0": "https://pyzmq.readthedocs.io/en/v16.0.0/", + "v15.4.0": "https://pyzmq.readthedocs.io/en/v15.4.0/", + "v15.3.0": "https://pyzmq.readthedocs.io/en/v15.3.0/", + "v15.2.0": "https://pyzmq.readthedocs.io/en/v15.2.0/", + "v15.1.0": "https://pyzmq.readthedocs.io/en/v15.1.0/", + "v15.0.0": "https://pyzmq.readthedocs.io/en/v15.0.0/", + "v14.7.0": "https://pyzmq.readthedocs.io/en/v14.7.0/", + "v14.6.0": "https://pyzmq.readthedocs.io/en/v14.6.0/" + }, + "sources": { + "readthedocs": "pyzmq" + } + }, + "requests": { + "versions": { + "latest": "https://requests.readthedocs.io/en/latest/", + "stable": "https://requests.readthedocs.io/en/stable/", + "v3.0.0": "https://requests.readthedocs.io/en/v3.0.0/", + "v2.9.1": "https://requests.readthedocs.io/en/v2.9.1/", + "v2.8.1": "https://requests.readthedocs.io/en/v2.8.1/", + "v2.7.0": "https://requests.readthedocs.io/en/v2.7.0/", + "v2.6.2": "https://requests.readthedocs.io/en/v2.6.2/", + "v2.5.3": "https://requests.readthedocs.io/en/v2.5.3/", + "v2.4.3": "https://requests.readthedocs.io/en/v2.4.3/", + "v2.3.0": "https://requests.readthedocs.io/en/v2.3.0/", + "v2.2.1": "https://requests.readthedocs.io/en/v2.2.1/", + "v2.1.0": "https://requests.readthedocs.io/en/v2.1.0/", + "v2.0.0": "https://requests.readthedocs.io/en/v2.0.0/", + "v1.2.3": "https://requests.readthedocs.io/en/v1.2.3/", + "v1.1.0": "https://requests.readthedocs.io/en/v1.1.0/", + "v1.0.4": "https://requests.readthedocs.io/en/v1.0.4/" + }, + "sources": { + "readthedocs": "requests" + } + }, + "schema": { + "versions": {}, + "sources": {} + }, + "scikit-image": { + "versions": { + "latest": "https://scikit-image.org/docs/dev/", + "stable": "https://scikit-image.org/docs/stable/", + "0.19.x": "https://scikit-image.org/docs/0.19.x/", + "0.18.x": "https://scikit-image.org/docs/0.18.x/", + "0.17.x": "https://scikit-image.org/docs/0.17.x/", + "0.16.x": "https://scikit-image.org/docs/0.16.x/", + "0.15.x": "https://scikit-image.org/docs/0.15.x/", + "0.14.x": "https://scikit-image.org/docs/0.14.x/", + "0.13.x": "https://scikit-image.org/docs/0.13.x/", + "0.12.x": "https://scikit-image.org/docs/0.12.x/", + "0.11.x": "https://scikit-image.org/docs/0.11.x/", + "0.10.x": "https://scikit-image.org/docs/0.10.x/", + "0.9.x": "https://scikit-image.org/docs/0.9.x/", + "0.8.0": "https://scikit-image.org/docs/0.8.0/", + "0.7.0": "https://scikit-image.org/docs/0.7.0/", + "0.6": "https://scikit-image.org/docs/0.6/", + "0.5": "https://scikit-image.org/docs/0.5/", + "0.4": "https://scikit-image.org/docs/0.4/", + "0.3": "https://scikit-image.org/docs/0.3/" + }, + "sources": {} + }, + "scikit-learn": { + "versions": { + "latest": "https://scikit-learn.org/dev/", + "stable": "https://scikit-learn.org/stable/", + "1.0.x": "https://scikit-learn.org/1.0/", + "0.24.x": "https://scikit-learn.org/0.24/", + "0.23.x": "https://scikit-learn.org/0.23/", + "0.22.x": "https://scikit-learn.org/0.22/", + "0.21.x": "https://scikit-learn.org/0.21/", + "0.20.x": "https://scikit-learn.org/0.20/", + "0.19.x": "https://scikit-learn.org/0.19/", + "0.18.x": "https://scikit-learn.org/0.18/", + "0.17.x": "https://scikit-learn.org/0.17/", + "0.16.x": "https://scikit-learn.org/0.16/" + }, + "sources": {} + }, + "scipy": { + "versions": { + "latest": "https://scipy.github.io/devdocs/", + "stable": "https://docs.scipy.org/doc/scipy/", + "1.9.0": "https://docs.scipy.org/doc/scipy-1.9.0/", + "1.8.1": "https://docs.scipy.org/doc/scipy-1.8.1/", + "1.8.0": "https://docs.scipy.org/doc/scipy-1.8.0/", + "1.7.1": "https://docs.scipy.org/doc/scipy-1.7.1/", + "1.7.0": "https://docs.scipy.org/doc/scipy-1.7.0/", + "1.6.3": "https://docs.scipy.org/doc/scipy-1.6.3/", + "1.6.2": "https://docs.scipy.org/doc/scipy-1.6.2/", + "1.6.1": "https://docs.scipy.org/doc/scipy-1.6.1/", + "1.6.0": "https://docs.scipy.org/doc/scipy-1.6.0/", + "1.5.4": "https://docs.scipy.org/doc/scipy-1.5.4/", + "1.5.3": "https://docs.scipy.org/doc/scipy-1.5.3/", + "1.5.2": "https://docs.scipy.org/doc/scipy-1.5.2/", + "1.5.1": "https://docs.scipy.org/doc/scipy-1.5.1/", + "1.5.0": "https://docs.scipy.org/doc/scipy-1.5.0/", + "1.4.1": "https://docs.scipy.org/doc/scipy-1.4.1/", + "1.4.0": "https://docs.scipy.org/doc/scipy-1.4.0/", + "1.3.3": "https://docs.scipy.org/doc/scipy-1.3.3/", + "1.3.2": "https://docs.scipy.org/doc/scipy-1.3.2/", + "1.3.1": "https://docs.scipy.org/doc/scipy-1.3.1/", + "1.3.0": "https://docs.scipy.org/doc/scipy-1.3.0/", + "1.2.3": "https://docs.scipy.org/doc/scipy-1.2.3/", + "1.2.1": "https://docs.scipy.org/doc/scipy-1.2.1/", + "1.2.0": "https://docs.scipy.org/doc/scipy-1.2.0/" + }, + "sources": {} + }, + "setuptools": { + "versions": { + "latest": "https://setuptools.pypa.io/en/latest/", + "stable": "https://setuptools.pypa.io/en/stable/" + }, + "sources": { + "readthedocs": "setuptools" + } + }, + "simplejson": { + "versions": { + "latest": "https://simplejson.readthedocs.io/en/latest/", + "stable": "https://simplejson.readthedocs.io/en/stable/", + "v3.19.2": "https://readthedocs.org/dashboard/simplejson/version/v3.19.2/edit/", + "v3.19.1": "https://simplejson.readthedocs.io/en/v3.19.1/", + "v3.19.0": "https://simplejson.readthedocs.io/en/v3.19.0/", + "v3.18.4": "https://simplejson.readthedocs.io/en/v3.18.4/", + "v3.18.3": "https://simplejson.readthedocs.io/en/v3.18.3/", + "v3.18.2": "https://simplejson.readthedocs.io/en/v3.18.2/", + "v3.18.1": "https://simplejson.readthedocs.io/en/v3.18.1/", + "v3.18.0": "https://simplejson.readthedocs.io/en/v3.18.0/", + "v3.17.6": "https://readthedocs.org/dashboard/simplejson/version/v3.17.6/edit/", + "v3.17.5": "https://simplejson.readthedocs.io/en/v3.17.5/", + "v3.17.4": "https://simplejson.readthedocs.io/en/v3.17.4/", + "v3.17.3": "https://simplejson.readthedocs.io/en/v3.17.3/", + "v3.17.2": "https://simplejson.readthedocs.io/en/v3.17.2/", + "v3.17.1": "https://simplejson.readthedocs.io/en/v3.17.1/", + "v3.17.0": "https://simplejson.readthedocs.io/en/v3.17.0/", + "v3.16.1": "https://simplejson.readthedocs.io/en/v3.16.1/" + }, + "sources": { + "readthedocs": "simplejson" + } + }, + "six": { + "versions": { + "latest": "https://six.readthedocs.io/", + "stable": "https://six.readthedocs.io/" + }, + "sources": { + "readthedocs": "six" + } + }, + "soundfile": { + "versions": {}, + "sources": {} + }, + "sphinx": { + "versions": { + "master": "https://www.sphinx-doc.org/en/master/" + }, + "sources": { + "readthedocs": "sphinx" + } + }, + "sphinx-autodoc-typehints": { + "versions": {}, + "sources": {} + }, + "sphinx-click": { + "versions": { + "latest": "https://sphinx-click.readthedocs.io/en/latest/", + "stable": "https://sphinx-click.readthedocs.io/en/stable/" + }, + "sources": { + "readthedocs": "sphinx-click" + } + }, + "sphinx_rtd_theme": { + "versions": { + "latest": "https://sphinx-rtd-theme.readthedocs.io/en/latest/", + "stable": "https://sphinx-rtd-theme.readthedocs.io/en/stable/", + "2.0.0": "https://sphinx-rtd-theme.readthedocs.io/en/2.0.0/", + "1.3.0": "https://sphinx-rtd-theme.readthedocs.io/en/1.3.0/", + "1.2.2": "https://sphinx-rtd-theme.readthedocs.io/en/1.2.2/", + "1.2.1": "https://sphinx-rtd-theme.readthedocs.io/en/1.2.1/", + "1.2.0": "https://sphinx-rtd-theme.readthedocs.io/en/1.2.0/", + "1.1.1": "https://sphinx-rtd-theme.readthedocs.io/en/1.1.1/", + "1.1.0": "https://sphinx-rtd-theme.readthedocs.io/en/1.1.0/", + "1.0.0": "https://sphinx-rtd-theme.readthedocs.io/en/1.0.0/", + "1.0.0rc1": "https://sphinx-rtd-theme.readthedocs.io/en/1.0.0rc1/", + "0.5.2": "https://sphinx-rtd-theme.readthedocs.io/en/0.5.2/", + "0.5.1": "https://sphinx-rtd-theme.readthedocs.io/en/0.5.1/", + "0.5.0": "https://sphinx-rtd-theme.readthedocs.io/en/0.5.0/", + "0.4.3": "https://readthedocs.org/dashboard/sphinx-rtd-theme/version/0.4.3/edit/", + "test-pelson-fix-sphinx-version-not-three-ints": "https://sphinx-rtd-theme.readthedocs.io/en/test-pelson-fix-sphinx-version-not-three-ints/" + }, + "sources": { + "readthedocs": "sphinx_rtd_theme" + } + }, + "sphinxcontrib-programoutput": { + "versions": { + "latest": "https://sphinxcontrib-programoutput.readthedocs.io/en/latest/", + "stable": "https://sphinxcontrib-programoutput.readthedocs.io/en/stable/" + }, + "sources": { + "readthedocs": "sphinxcontrib-programoutput" + } + }, + "sqlalchemy": { + "versions": { + "latest": "https://sqlalchemy.readthedocs.io/en/latest/", + "stable": "https://sqlalchemy.readthedocs.io/en/stable/" + }, + "sources": { + "readthedocs": "sqlalchemy" + } + }, + "tabulate": { + "versions": {}, + "sources": {} + }, + "tensorboard": { + "versions": {}, + "sources": {} + }, + "tensorflow": { + "versions": {}, + "sources": {} + }, + "termcolor": { + "versions": { + "latest": "https://termcolor.readthedocs.io/", + "stable": "https://termcolor.readthedocs.io/" + }, + "sources": { + "readthedocs": "termcolor" + } + }, + "tomli": { + "versions": {}, + "sources": {} + }, + "tomli-w": { + "versions": {}, + "sources": {} + }, + "tomlkit": { + "versions": { + "latest": "https://tomlkit.readthedocs.io/en/latest/" + }, + "sources": {} + }, + "torch": { + "versions": { + "stable": "https://pytorch.org/docs/stable/" + }, + "sources": {} + }, + "torchmetrics": { + "versions": { + "stable": "https://lightning.ai/docs/torchmetrics/stable/", + "latest": "https://lightning.ai/docs/torchmetrics/latest/" + }, + "sources": {} + }, + "torchvision": { + "versions": { + "stable": "https://pytorch.org/vision/stable/" + }, + "sources": {} + }, + "tqdm": { + "versions": {}, + "sources": {} + }, + "xarray": { + "versions": { + "latest": "https://docs.xarray.dev/en/latest/", + "stable": "https://docs.xarray.dev/en/stable/", + "v2022.10.0": "https://docs.xarray.dev/en/v2022.10.0/", + "v2022.09.0": "https://docs.xarray.dev/en/v2022.09.0/", + "v2022.06.0": "https://docs.xarray.dev/en/v2022.06.0/", + "v2022.03.0": "https://docs.xarray.dev/en/v2022.03.0/", + "v0.21.1": "https://docs.xarray.dev/en/v0.21.1/", + "v0.21.0": "https://docs.xarray.dev/en/v0.21.0/", + "v0.20.1": "https://docs.xarray.dev/en/v0.20.1/", + "v0.20.0": "https://docs.xarray.dev/en/v0.20.0/", + "v0.19.0": "https://docs.xarray.dev/en/v0.19.0/", + "v0.18.2": "https://docs.xarray.dev/en/v0.18.2/", + "v0.18.1": "https://docs.xarray.dev/en/v0.18.1/", + "v0.18.0": "https://docs.xarray.dev/en/v0.18.0/", + "v0.17.0": "https://docs.xarray.dev/en/v0.17.0/", + "v0.16.2": "https://docs.xarray.dev/en/v0.16.2/", + "v0.16.1": "https://docs.xarray.dev/en/v0.16.1/", + "v0.16.0": "https://docs.xarray.dev/en/v0.16.0/", + "v0.15.1": "https://docs.xarray.dev/en/v0.15.1/", + "v0.14.1": "https://docs.xarray.dev/en/v0.14.1/", + "v0.14.0": "https://docs.xarray.dev/en/v0.14.0/", + "v0.13.0": "https://docs.xarray.dev/en/v0.13.0/" + }, + "sources": {} + } +} diff --git a/src/auto_intersphinx/catalog.py b/src/auto_intersphinx/catalog.py new file mode 100644 index 0000000..29214a7 --- /dev/null +++ b/src/auto_intersphinx/catalog.py @@ -0,0 +1,686 @@ +# SPDX-FileCopyrightText: Copyright © 2022 Idiap Research Institute +# +# SPDX-License-Identifier: BSD-3-Clause +"""This module contains instructions for documentation lookup.""" + +from __future__ import annotations # not required for Python >= 3.10 + +import collections.abc +import importlib.metadata +import importlib.resources +import json +import pathlib +import re +import shutil +import typing + +import lxml.html +import packaging.version +import requests + +from sphinx.util import logging + +logger = logging.getLogger(__name__) + + +PackageDictionaryType = dict[str, dict[str, str]] +"""Type for the internal values of :py:class:`Catalog`""" + + +BUILTIN_CATALOG = importlib.resources.files(__package__).joinpath("catalog.json") +"""Base name for the catalog file distributed with this package.""" + + +PEP440_RE = re.compile( + r"^\s*" + packaging.version.VERSION_PATTERN + r"\s*$", + re.VERBOSE | re.IGNORECASE, +) +"""Regular expression for matching PEP-440 version numbers.""" + + +def _ensure_webdir(addr: str) -> str: + """Ensures the web-address ends in a /, and contains ``objects.inv``""" + if addr.endswith(".html"): + addr = addr[: addr.rfind("/")] + if not addr.endswith("/"): + addr += "/" + + # objects = addr + "/" + "objects.inv" + # if requests.head(objects).ok: + # logger.error("Cannot find {objects}...") + # return None + + return addr + + +def _reorder_versions(vdict: dict[str, str]) -> dict[str, str]: + """Re-orders version dictionary by decreasing version.""" + # nota bene: new dicts preserve insertion order + retval: dict[str, str] = {} + + # these keys come always first, if available + protected = ("latest", "main", "master", "stable") + for key in protected: + if key in vdict: + retval[key] = vdict[key] + + # next, are releases in reverse order + version_map = { + packaging.version.Version(k): k + for k in vdict.keys() + if (k not in protected) and PEP440_RE.match(k) + } + for version in sorted(version_map.keys(), reverse=True): + retval[version_map[version]] = vdict[version_map[version]] + + # now, everything else + retval.update({k: v for k, v in vdict.items() if k not in retval}) + + return retval + + +def docurls_from_environment(package: str) -> dict[str, str]: + """Checks installed package metadata for documentation URLs. + + Arguments: + + package: Name of the package you want to check + + version: A version such as "stable", "latest" or a formal version + number parsed by :py:class:`packaging.version.Version`. + + + Returns: + + A dictionary, that maps the version of the documentation found on PyPI + to the URL. + """ + try: + md = importlib.metadata.metadata(package) + if md.get_all("Project-URL") is None: + return {} + for k in md.get_all("Project-URL"): + if k.startswith(("documentation, ", "Documentation, ")): + addr = _ensure_webdir(k.split(",", 1)[1].strip()) + if requests.head(addr + "/objects.inv").ok: + try: + return {md["version"]: addr} + except KeyError: + return {"latest": addr} + + except importlib.metadata.PackageNotFoundError: + pass + + return {} + + +def docurls_from_rtd(package: str) -> dict[str, str]: + """Checks readthedocs.org for documentation pointers for the package. + + Arguments: + + package: Name of the package to check on rtd.org - this must be the + name it is know at rtd.org and not necessarily the package name. + Some packages do have different names on rtd.org. + + + Returns: + + A dictionary, which contains all versions of documentation available + for the given package on RTD. If the package's documentation is not + available on RTD, returns an empty dictionary. + """ + try: + url = f"https://readthedocs.org/projects/{package}/versions/" + logger.debug(f"Reaching for `{url}'...") + r = requests.get(f"https://readthedocs.org/projects/{package}/versions/") + if r.ok: + tree = lxml.html.fromstring(r.text) + return { + k.text: _ensure_webdir(k.attrib["href"]) + for k in tree.xpath("//a[contains(@class, 'module-item-title')]") + if k.attrib["href"].startswith("http") + } + + except requests.exceptions.RequestException: + pass + + return {} + + +def _get_json(url: str) -> dict | None: + try: + logger.debug(f"Reaching for `{url}'...") + r = requests.get(url) + if r.ok: + return r.json() + + except requests.exceptions.RequestException: + pass + + return None + + +def docurls_from_pypi(package: str, max_entries: int) -> dict[str, str]: + """Checks PyPI for documentation pointers for a given package. + + This procedure first looks up the main repo JSON entry, and then figures + out all available versions of the package. In a second step, and depending + on the value of ``max_entries``, this function will retrieve the latest + ``max_entries`` available on that particular package. + + + Arguments: + + package: Name of the PyPI package you want to check + + max_entries: The maximum number of entries to lookup in PyPI. A value + of zero will download only the main package information and will + hit PyPI only once. A value bigger than zero will download at most + the information from the last ``max_entries`` releases. Finally, a + negative value will imply the download of all available releases. + + + Returns: + + A dictionary, that maps the version of the documentation found on PyPI + to the URL. + """ + versions: dict[str, str] = {} + data = _get_json(f"https://pypi.org/pypi/{package}/json") + if data is None: + return versions + + urls = data["info"]["project_urls"] + addr = urls.get("Documentation") or urls.get("documentation") + if addr is not None: + addr = _ensure_webdir(addr) + if requests.head(addr + "/objects.inv").ok: + versions[data["info"]["version"]] = addr + + # download further versions, if requested by user + version_map = { + packaging.version.Version(k): k + for k in data["releases"].keys() + if PEP440_RE.match(k) + } + versions_to_probe = sorted(list(version_map.keys()), reverse=True) + + if max_entries >= 0: + versions_to_probe = versions_to_probe[:max_entries] + + for k in versions_to_probe: + data = _get_json(f"https://pypi.org/pypi/{package}/{version_map[k]}/json") + if data is None: + continue + + urls = data["info"]["project_urls"] + addr = urls.get("Documentation") or urls.get("documentation") + if addr is not None: + addr = _ensure_webdir(addr) + if requests.head(addr + "/objects.inv").ok: + versions[data["info"]["version"]] = addr + + return versions + + +class Catalog(collections.abc.MutableMapping): + """A type that can lookup and store information about Sphinx documents. + + The object is organised as a dictionary (mutable mapping type) with extra + methods to handle information update from various sources. Information is + organised as dictionary mapping Python package names to another dictionary + containing the following entries: + + * ``versions``: A dictionary mapping version numbers to URLs. The keys + have free form, albeit are mostly PEP440 version numbers. Keywords such + as ``stable``, ``latest``, ``master``, or ``main`` are typically found as + well. + * ``sources``: A dictionary mapping information sources for this particular + entry. Keys are one of ``pypi``, ``readthedocs`` or ``environment``. + Values correspond to specific names used for the lookup of the + information on those sources. + + + Attributes: + + _data: Internal dictionary containing the mapping between package names + the user can refer to, versions and eventual sources of such + information. + """ + + _data: dict[str, PackageDictionaryType] + + def __init__(self) -> None: + self.reset() + + def load(self, path: pathlib.Path) -> None: + """Loads and replaces contents with those from the file.""" + with path.open("rt") as f: + logger.debug(f"Loading package catalog from {str(path)}...") + self._data = json.load(f) + logger.debug(f"Loaded {len(self)} entries from {str(path)}") + + def loads(self, contents: str) -> None: + """Loads and replaces contents with those from the string.""" + self._data = json.loads(contents) + logger.debug(f"Loaded {len(self)} entries from string") + + def dump(self, path: pathlib.Path) -> None: + """Loads and replaces contents with those from the file.""" + if path.exists(): + backup = path.with_suffix(path.suffix + "~") + logger.debug(f"Backing up: {str(path)} -> {str(backup)}...") + shutil.copy(path, backup) # backup + + with path.open("wt") as f: + logger.debug( + f"Saving package catalog with {len(self)} entries at {str(path)}..." + ) + json.dump(self._data, f, indent=2) + f.write("\n") # avoids pre-commit/self-update conflicting changes + + def dumps(self) -> str: + """Loads and replaces contents with those from the string.""" + return json.dumps(self._data, indent=2) + + def reset(self) -> None: + """Full resets internal catalog.""" + self._data = {} + + # mutable mapping operations, so this looks like a dictionary + def __getitem__(self, key: str) -> PackageDictionaryType: + return self._data[key] + + def __setitem__(self, key: str, value: PackageDictionaryType) -> None: + self._data[key] = value + + def __delitem__(self, key: str) -> None: + del self._data[key] + + def __len__(self) -> int: + return len(self._data) + + def __iter__(self) -> typing.Iterator[str]: + return iter(self._data) + + def __repr__(self) -> str: + return repr(self._data) + + def _ensure_defaults(self, pkg: str) -> None: + """Ensures a standardised setup for a package entry.""" + self.setdefault(pkg, {"versions": {}, "sources": {}}) + self[pkg].setdefault("versions", {}) + self[pkg].setdefault("sources", {}) + + def update_versions_from_environment(self, pkg: str, name: str | None) -> bool: + """Replaces package documentation URLs using information from current + Python environment. + + Arguments: + + pkg: Name of the package as one would find in pypi.org. This + name can be different then that of the Python package + itself. + + name: This is the name of the package as installed on the current + environment. Sometimes, this name can be different then that of + the Python package itself. If this value is set to ``None``, + then we just use ``pkg`` as the name to lookup. + + + Returns: + + ``True``, if the update was successful (found versions), or + ``False``, otherwise. + """ + + self._ensure_defaults(pkg) + + name = name or pkg + + logger.debug(f"{pkg}: checking current Python environment for {name}...") + + versions = docurls_from_environment(name) + logger.debug( + f"{pkg}: Found {len(versions)} doc URL(s) at current Python environment" + ) + + if versions: + self[pkg]["versions"].update(versions) + self[pkg]["versions"] = _reorder_versions(self[pkg]["versions"]) + self[pkg]["sources"]["environment"] = name + + return len(versions) > 0 + + def update_versions_from_rtd(self, pkg: str, name: str | None) -> bool: + """Replaces package documentation URLs using information from + readthedocs.org. + + Arguments: + + pkg: Name of the Python package to update versions for. + + name: This is the name of the package on readthedocs.org. Often, + this name is different then that of the Python package itself. + If this value is set to ``None``, then we just use ``pkg`` as + the name to lookup. + + + Returns: + + The dictionary of values for the current package, as obtained from + readthedocs.org, and potentially merged with the existing one. + """ + self._ensure_defaults(pkg) + + name = name or pkg + + logger.debug(f"{pkg}: checking readthedocs.org for {name}...") + + versions = docurls_from_rtd(name) + logger.debug(f"{pkg}: Found {len(versions)} doc URL(s) at readthedocs.org") + + if versions: + self[pkg]["versions"].update(versions) + self[pkg]["versions"] = _reorder_versions(self[pkg]["versions"]) + self[pkg]["sources"]["readthedocs"] = name + + return len(versions) > 0 + + def update_versions_from_pypi( + self, pkg: str, name: str | None, max_entries: int + ) -> bool: + """Replaces package documentation URLs using information from pypi.org. + + Arguments: + + pkg: Name of the package as one would find in pypi.org. This + name can be different then that of the Python package + itself. + + name: This is the name of the package on pypi.org. Sometimes, this + name can be different then that of the Python package itself. + If this value is set to ``None``, then we just use ``pkg`` as + the name to lookup. + + max_entries: The maximum number of entries to lookup in PyPI. A + value of zero will download only the main package information + and will hit PyPI only once. A value bigger than zero will + download at most the information from the last ``max_entries`` + releases. Finally, a negative value will imply the download of + all available releases. + + + Returns: + + The dictionary of values for the current package, as obtained from + pypi.org, and potentially merged with the existing one. + """ + + self._ensure_defaults(pkg) + + name = name or pkg + + logger.debug(f"{pkg}: checking pypi.org for {name}...") + + versions = docurls_from_pypi(name, max_entries) + logger.debug(f"{pkg}: Found {len(versions)} doc URL(s) at pypi.org") + + if versions: + self[pkg]["versions"].update(versions) + self[pkg]["versions"] = _reorder_versions(self[pkg]["versions"]) + self[pkg]["sources"]["pypi"] = name + + return len(versions) > 0 + + def update_versions( + self, + pkgs: typing.Iterable[str], + order: typing.Iterable[str] = ["environment", "readthedocs", "pypi"], + names: dict[str, dict[str, str]] = {}, + pypi_max_entries: int = 0, + keep_going: bool = False, + ) -> None: + """Updates versions for a list of packages in this catalog. + + This method will add a list of packages defined by ``pkgs`` (list of + names) into its own catalog. The order of look-ups by default is set + by the ``order``, and it is the following: + + 1. Current Python environment (``environment``) + 2. readthedocs.org (``readthedocs``) + 3. PyPI (``pypi``) + + + Arguments: + + pkgs: List of packages that will have their versions updated + + order: A list, containing the order in which lookup will happen. + There are only 3 possible keys that can be used here: + ``environment``, which stands for finding package metadata from + the currently installed Python environment, ``readthedocs``, + which will trigger readthedocs.org lookups, and ``pypi``, which + will trigger pypi.org lookups from uploaded packages. + + names: A dictionary, that eventually maps source names (as in + ``order``) to another dictionary that maps package names to to + their supposed names on readthedocs.org, pypi.org or the current + environment. If keys for various packages are not available, then + their package names are used. If the keys exist, but are set + to ``None``, then lookup for that particular source is skipped. + + pypi_max_entries: The maximum number of entries to lookup in PyPI. + A value of zero will download only the main package information + and will hit PyPI only once. A value bigger than zero will + download at most the information from the last ``max_entries`` + releases. Finally, a negative value will imply the download of + all available releases. + + keep_going: By default, the method stops adding a package when a + hit is found (in either of these sources of information). If + the flag ``keep_going`` is set to ``True`` (defaults to + ``False``), then it merges information from all sources. Note + that some of this information may be repetitive. + """ + + for pkg in pkgs: + for action in order: + if action == "environment": + name = names.get(action, {}).get(pkg, pkg) + if name is not None: + ok = self.update_versions_from_environment(pkg, name) + if ok and not keep_going: + break + + elif action == "readthedocs": + name = names.get(action, {}).get(pkg, pkg) + if name is not None: + ok = self.update_versions_from_rtd(pkg, name) + if ok and not keep_going: + break + + elif action == "pypi": + name = names.get(action, {}).get(pkg, pkg) + if name is not None: + ok = self.update_versions_from_pypi(pkg, name, pypi_max_entries) + if ok and not keep_going: + break + + else: + raise RuntimeError(f"Unrecognized source: {action}") + + def self_update(self) -> None: + """Runs a self-update procedure, by re-looking up known sources.""" + # organises the names as expected by update_versions() + names: dict[str, dict[str, str]] = dict(environment={}, readthedocs={}, pypi={}) + for pkg, info in self.items(): + for src in ("environment", "readthedocs", "pypi"): + names[src][pkg] = info["sources"].get(src) + + self.update_versions(pkgs=self.keys(), names=names) + + +def _string2version(v: str) -> packaging.version.Version | None: + """Converts a string into a version number. + + This method covers various specific use-cases: + + * ``1.2.3`` -> specific version + * ``1.2.x``, ``1.2`` -> anything in the ``[1.2.0, 1.3.0)`` range + * ``1.x.x``, ``1`` -> anything in the ``[1.0.0, 2.0.0)`` range + * anything else: discarded + + Arguments: + + v: a string containing the version number to be parsed, like the ones + in the catalog + + + Returns: + + Either ``None``, or the version object with the parsed version. + """ + v = v.replace(".x", "") + try: + return packaging.version.Version(v) + except packaging.version.InvalidVersion: + return None + + +def _prepare_versions(versions: dict[str, str]) -> dict[str, str]: + """Prepares a dictionary of versions for structured lookups. + + This procedure: + + 1. Ensures there is one ``latest`` and ``stable`` entries in the input + dictionary + 2. Augment the version dictionary with PEP-440 version numbers (e.g. + annotates ``v2.2.0`` -> ``2.2.0``, or ``1.x`` -> ``1``) + + + Arguments: + + versions: A dictionary that maps release version (and aliases such as + ``stable`` or ``latest`` to URLs that contain Sphinx-generated + documentation. + + + Returns: + + A dictionary with keys that correspond to parsed versions and aliases. + """ + if not versions: + return versions + + # see what each valid number means + version_map = {_string2version(k): k for k in versions.keys()} + sorted_versions = sorted([k for k in version_map.keys() if k is not None]) + + retval: dict[str, str] = {} + if sorted_versions: + # there is at least 1 (valid) version number + latest = sorted_versions[-1] + retval["latest"] = versions.get("latest", versions[version_map[latest]]) + + stable_versions = [ + k for k in sorted_versions if not (k.is_prerelease or k.is_devrelease) + ] + if stable_versions: + stable = stable_versions[-1] + else: + stable = latest + retval["stable"] = versions.get("stable", versions[version_map[stable]]) + + # fill-in the remainder of the versions, leave latest on top + for k in reversed(sorted_versions): + retval[version_map[k]] = versions[version_map[k]] + if ".x" in version_map[k]: + # copy to a shortened version number as well + retval[version_map[k].replace(".x", "")] = versions[version_map[k]] + elif k.public != version_map[k]: + # copy a standardised version number as well + retval[k.public] = versions[version_map[k]] + + else: + # there is either nothing, or just aliases such as stable/latest + retval["latest"] = ( + versions.get("latest") + or versions.get("stable") + or versions.get("master") + or versions.get("main") + or "" + ) + retval["stable"] = ( + versions.get("stable") + or versions.get("latest") + or versions.get("master") + or versions.get("main") + or "" + ) + + return retval + + +class LookupCatalog: + """A catalog that guarantees standardised version lookups. + + Arguments: + + catalog: The catalog to use as base for the lookup. + """ + + def __init__(self, catalog: Catalog): + self._catalog = catalog + self.reset() + + def reset(self): + """Internally creates all possible aliases for package names and + versions. + + This method will expand the catalog package names and version + numbers so that the user can refer to these using environment, + readthedocs.org or pypi.org names for packages, and PEP-440 + compatible strings for version names during the lookup. + + The catalog associated to this lookup is not modified in this + process. All augmentations are built-into the object instance. + """ + self._version_map: dict[str, dict[str, str]] = {} + self._package_map: dict[str, str] = {} + for pkg in self._catalog.keys(): + self._version_map[pkg] = _prepare_versions(self._catalog[pkg]["versions"]) + + # translations from Python, rtd.org or pypi.org names + self._package_map[pkg] = pkg + self._package_map.update( + {v: pkg for v in self._catalog[pkg]["sources"].values()} + ) + + def get(self, pkg: str, version: str | None, default: typing.Any = None): + """Accesses one single ``pkg/version`` documentation URL. + + Arguments: + + pkg: The package name, as available on the catalog or through one + of its environment, readthedocs.org or pypi.org names. + + version: The version of the package to search for. This must be + either an identifier from readthedocs.org or pypi.org, or a valid + PEP-440 version number as a string. + + default: The default value to return in case we do not find a + match. + + + Returns: + + If a match is found, returns the URL for the documentation. + Otherwise, returns the ``default`` value. + """ + if pkg not in self._package_map: + return default + if version not in self._version_map[pkg]: + return default + return self._version_map[self._package_map[pkg]][version] diff --git a/src/auto_intersphinx/check_packages.py b/src/auto_intersphinx/check_packages.py new file mode 100644 index 0000000..3bec08b --- /dev/null +++ b/src/auto_intersphinx/check_packages.py @@ -0,0 +1,213 @@ +# SPDX-FileCopyrightText: Copyright © 2022 Idiap Research Institute +# +# SPDX-License-Identifier: BSD-3-Clause + +from __future__ import annotations # not required for Python >= 3.10 + +import argparse +import importlib.resources +import json +import pathlib +import textwrap + +from . import oneliner +from .catalog import ( + Catalog, + docurls_from_environment, + docurls_from_pypi, + docurls_from_rtd, +) +from .update_catalog import setup_verbosity + + +def _main(args) -> None: + """Main function, that actually executes the check-package command.""" + setup_verbosity(args.verbose) + + builtin_catalog = Catalog() + if not args.no_builtin: + catalog_file = importlib.resources.files(__name__.split(".", 1)[0]).joinpath( + "catalog.json" + ) + builtin_catalog.loads(catalog_file.read_text()) + + user_catalog = Catalog() + if args.user: + user_catalog.load(args.user) + + for p in args.packages: + if p in user_catalog: + print(f"Found {p} in user catalog:") + print( + textwrap.indent( + json.dumps(user_catalog[p]["versions"], indent=2), " | " + ) + ) + if not args.keep_going: + continue + + if p in builtin_catalog: + print(f"Found {p} in builtin catalog:") + print( + textwrap.indent( + json.dumps(builtin_catalog[p]["versions"], indent=2), " | " + ) + ) + if not args.keep_going: + continue + + if not args.no_environment: + versions = docurls_from_environment(p) + if versions: + print(f"Found {p} documentation in installed Python environment:") + print(textwrap.indent(json.dumps(versions, indent=2), " | ")) + if not args.keep_going: + continue + + if not args.no_rtd: + versions = docurls_from_rtd(p) + if versions: + print(f"Found {p} documentation in readthedocs.org:") + print(textwrap.indent(json.dumps(versions, indent=2), " | ")) + if not args.keep_going: + continue + + if not args.no_pypi: + print(f"Looking up all PyPI versions of {p} - this may be long...") + versions = docurls_from_pypi(p, args.pypi_max_entries) + if versions: + print(f"Found {p} documentation in PyPI:") + print(textwrap.indent(json.dumps(versions, indent=2), " | ")) + if not args.keep_going: + continue + + +def add_parser(subparsers) -> argparse.ArgumentParser: + """Just sets up the parser for this CLI.""" + prog = "auto-intersphinx check-packages" + + parser = subparsers.add_parser( + prog.split()[1], + help="Discover documentation cross-references for packages", + description="Discover documentation cross-references for packages", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=textwrap.dedent( + f""" + examples: + + 1. Checks internal catalog, Python environment, readthedocs.org and + PyPI for package "requests": + + .. code:: sh + + {prog} requests + + 2. Checks internal and user catalog, Python environment, + readthedocs.org and PyPI for package "requests": + + .. code:: sh + + {prog} --user=doc/catalog.json requests + + 3. Skip internal catalog checks when running for package "requests" + (checks readthedocs.org and PyPI only): + + .. code:: sh + + {prog} --no-builtin requests + + 4. Keep looking for references in all available places (do not stop + when first finds a documentation link, such as the extension does): + + .. code:: sh + + {prog} --keep-going requests + """ + ), + ) + + parser.add_argument( + "-v", + "--verbose", + action="count", + default=0, + help="Can be set multiple times to increase console verbosity", + ) + + parser.add_argument( + "packages", + nargs="+", + help="Names of packages to check - specify one or more", + ) + + parser.add_argument( + "-S", + "--no-builtin", + action="store_true", + default=False, + help="If set, then do not check own catalog", + ) + + parser.add_argument( + "-E", + "--no-environment", + action="store_true", + default=False, + help="If set, then do not check the current environment package documentation", + ) + + parser.add_argument( + "-R", + "--no-rtd", + action="store_true", + default=False, + help="If set, then do not check readthedocs.org for package documentation", + ) + + parser.add_argument( + "-P", + "--no-pypi", + action="store_true", + default=False, + help="If set, then do not check PyPI for package documentation", + ) + + parser.add_argument( + "-M", + "--pypi-max-entries", + default=0, + help=oneliner( + """ + The maximum number of entries to lookup in PyPI. A value of zero + will download only the main package information and will hit PyPI + only once. A value bigger than zero will download at most the + information from the last ``max_entries`` releases. Finally, a + negative value will imply the download of all available releases. + """ + ), + ) + + parser.add_argument( + "-k", + "--keep-going", + action="store_true", + default=False, + help=oneliner( + """ + If set, then do not stop at first found reference (such as + auto-intersphinx would do), but rather keep searching for all + references. + """ + ), + ) + + parser.add_argument( + "-u", + "--user", + type=pathlib.Path, + help="If set, then also checks the local user-catalog at the specified path", + ) + + parser.set_defaults(func=_main) + + return parser diff --git a/src/auto_intersphinx/cli.py b/src/auto_intersphinx/cli.py new file mode 100644 index 0000000..2cc96c1 --- /dev/null +++ b/src/auto_intersphinx/cli.py @@ -0,0 +1,38 @@ +# SPDX-FileCopyrightText: Copyright © 2022 Idiap Research Institute +# +# SPDX-License-Identifier: BSD-3-Clause + +from __future__ import annotations # not required for Python >= 3.10 + +import argparse +import sys + + +def make_parser() -> argparse.ArgumentParser: + """Creates the main parser.""" + parser = argparse.ArgumentParser( + prog=sys.argv[0], + description="Commands to handle sphinx catalogs.", + ) + subparsers = parser.add_subparsers(help="commands") + + from . import check_packages + + check_packages.add_parser(subparsers) + + from . import dump_objects + + dump_objects.add_parser(subparsers) + + from . import update_catalog + + update_catalog.add_parser(subparsers) + + return parser + + +def main(argv: list[str] | None = None) -> None: + # parse and execute + parser = make_parser() + args = parser.parse_args(argv) + args.func(args) diff --git a/src/auto_intersphinx/dump_objects.py b/src/auto_intersphinx/dump_objects.py new file mode 100644 index 0000000..2c0e844 --- /dev/null +++ b/src/auto_intersphinx/dump_objects.py @@ -0,0 +1,81 @@ +# Copyright © 2022 Idiap Research Institute +# +# SPDX-License-Identifier: BSD-3-Clause + +from __future__ import annotations + +import argparse +import textwrap + +from sphinx.util import logging + +from .update_catalog import setup_verbosity + +logger = logging.getLogger(__name__) + + +def _main(args) -> None: + """Main function, that actually executes the dump-objects command.""" + setup_verbosity(args.verbose) + + from sphinx.ext import intersphinx + + for k in args.url: + logger.info(f"Dumping {k}...") + intersphinx.inspect_main([k]) + + +def add_parser(subparsers) -> argparse.ArgumentParser: + """Just sets up the parser for this CLI.""" + prog = "auto-intersphinx dump-objects" + + parser = subparsers.add_parser( + prog.split()[1], + help="Dumps objects documented in a Sphinx inventory URL", + description="Dumps objects documented in a Sphinx inventory URL", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=textwrap.dedent( + f""" + examples: + + 1. Dumps objects documented in a local Sphinx build: + + .. code:: sh + + {prog} html/objects.inv + + + 2. Dumps objects documented in python 3.x: + + .. code:: sh + + {prog} https://docs.python.org/3/objects.inv + + + 3. Dumps objects documented in numpy: + + .. code:: sh + + {prog} https://docs.scipy.org/doc/numpy/objects.inv + """ + ), + ) + + parser.add_argument( + "-v", + "--verbose", + action="count", + default=0, + help="Can be set multiple times to increase console verbosity", + ) + + parser.add_argument( + "url", + nargs="*", + default=[], + help="``objects.inv`` URL to parse and dump (can refer to a local file)", + ) + + parser.set_defaults(func=_main) + + return parser diff --git a/src/auto_intersphinx/update_catalog.py b/src/auto_intersphinx/update_catalog.py new file mode 100644 index 0000000..3aff90b --- /dev/null +++ b/src/auto_intersphinx/update_catalog.py @@ -0,0 +1,226 @@ +# SPDX-FileCopyrightText: Copyright © 2022 Idiap Research Institute +# +# SPDX-License-Identifier: BSD-3-Clause + +from __future__ import annotations # not required for Python >= 3.10 + +import argparse +import importlib.abc +import os +import pathlib +import re +import sys +import textwrap + +import requests + +from sphinx.util import logging + +from . import oneliner +from .catalog import BUILTIN_CATALOG, Catalog + +logger = logging.getLogger(__name__) + + +def _parse_requirements(contents: str) -> list[str]: + """Parses a pip-requirements file and extracts package lists.""" + lines = contents.split() + lines = [k.strip() for k in lines if not k.strip().startswith("#")] + split_re = re.compile(r"[=\s]+") + return [split_re.split(k)[0] for k in lines] + + +def setup_verbosity(verbose: int) -> None: + """Sets up logger verbosity.""" + import logging as builtin_logging + + package_logger = builtin_logging.getLogger("sphinx." + __package__) + + handler = builtin_logging.StreamHandler(sys.stdout) + formatter = builtin_logging.Formatter("[%(levelname)s] %(message)s") + handler.setFormatter(formatter) + handler.setLevel(builtin_logging.DEBUG) + + package_logger.addHandler(handler) + if verbose == 0: + package_logger.setLevel(builtin_logging.ERROR) + elif verbose == 1: + package_logger.setLevel(builtin_logging.WARNING) + elif verbose == 2: + package_logger.setLevel(builtin_logging.INFO) + else: + package_logger.setLevel(builtin_logging.DEBUG) + + +def _main(args) -> None: + """Main function, that actually executes the update-catalog command.""" + setup_verbosity(args.verbose) + + catalog = Catalog() + + if isinstance(args.catalog, str): + catalog_path = pathlib.Path(args.catalog) + if catalog_path.exists(): + catalog.load(catalog_path) + else: + logger.info( + f"Input catalog file `{str(args.catalog)}' does not " + f"exist. Skipping..." + ) + elif isinstance(args.catalog, importlib.abc.Traversable): + catalog.loads(args.catalog.read_text()) + + if args.self: + catalog.self_update() + + package_list = [] + for pkg in args.packages: + if pkg.startswith("http"): + logger.info(f"Retrieving package list from `{pkg}'...") + r = requests.get(pkg) + if r.ok: + package_list += _parse_requirements(r.text) + else: + logger.error(f"Could not retrieve `{pkg}'") + sys.exit(1) + + elif os.path.exists(pkg): + with open(pkg) as f: + package_list += _parse_requirements(f.read()) + + else: + package_list.append(pkg) + + if package_list: + catalog.update_versions( + pkgs=package_list, + pypi_max_entries=args.pypi_max_entries, + keep_going=args.keep_going, + ) + + if args.output: + catalog.dump(args.output) + + if (args.self or package_list) and args.output is None: + # an update was run, dump results + print(catalog.dumps()) + + +def add_parser(subparsers) -> argparse.ArgumentParser: + """Just sets up the parser for this CLI.""" + prog = "auto-intersphinx update-catalog" + + parser = subparsers.add_parser( + prog.split()[1], + help="Updates catalog of intersphinx cross-references", + description="Updates catalog of intersphinx cross-references", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=textwrap.dedent( + f""" + examples: + + 1. Updates numpy and scipy from the internal catalog, dumps new + catalog to stdout + + .. code:: sh + + {prog} numpy scipy + + 2. Self-update internal catalog: + + .. code:: sh + + {prog} --self + + 3. Refresh internal catalog from a remote pip-constraints.txt file: + + .. code:: sh + + {prog} https://gitlab.idiap.ch/software/idiap-citools/-/raw/main/src/citools/data/pip-constraints.txt + + 4. Run local tests without modifying the package catalog: + + .. code:: sh + + {prog} --output=testout.json + """ + ), + ) + + parser.add_argument( + "-v", + "--verbose", + action="count", + default=0, + help="Can be set multiple times to increase console verbosity", + ) + + parser.add_argument( + "--self", + action="store_true", + default=False, + help="If set, then self-updates catalog entries", + ) + + parser.add_argument( + "-o", + "--output", + type=pathlib.Path, + help="If set, then dump the existing catalog to an output file", + ) + + parser.add_argument( + "-c", + "--catalog", + default=BUILTIN_CATALOG, + help="Location of the catalog to update [default: %(default)s]", + ) + + parser.add_argument( + "-M", + "--pypi-max-entries", + default=0, + type=int, + help=oneliner( + """ + The maximum number of entries to lookup in PyPI. A value of zero + will download only the main package information and will hit PyPI + only once. A value bigger than zero will download at most the + information from the last ``max_entries`` releases. Finally, a + negative value will imply the download of all available releases. + """ + ), + ) + + parser.add_argument( + "-k", + "--keep-going", + action="store_true", + default=False, + help=oneliner( + """ + If set, then do not stop at first found reference (such as + auto-intersphinx would do), but rather keep searching for all + references. + """ + ), + ) + + parser.add_argument( + "packages", + nargs="*", + default=[], + help=oneliner( + """ + Location of the reference package list to load to populate catalog. + If not specified, then does not update anything (unless --self is + set, of course). This argument may take multiple inputs. Each + input may be a filename, which contains package lists, a remote + http/https file, or a package name. + """ + ), + ) + + parser.set_defaults(func=_main) + + return parser diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..ba675dc --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,13 @@ +# SPDX-FileCopyrightText: Copyright © 2022 Idiap Research Institute +# +# SPDX-License-Identifier: BSD-3-Clause + +import pathlib + +from pytest import fixture + + +@fixture +def datadir(request) -> pathlib.Path: + """Returns the directory in which the test is sitting.""" + return pathlib.Path(request.module.__file__).parents[0] / "data" diff --git a/tests/data/catalog.json b/tests/data/catalog.json new file mode 100644 index 0000000..aedbdf1 --- /dev/null +++ b/tests/data/catalog.json @@ -0,0 +1,39 @@ +{ + "click": { + "versions": { + "latest": "https://click.palletsprojects.com/en/latest/", + "8.1.x": "https://click.palletsprojects.com/en/8.1.x/", + "8.0.x": "https://click.palletsprojects.com/en/8.0.x/", + "7.x": "https://click.palletsprojects.com/en/7.x/", + "6.x": "https://click.palletsprojects.com/en/6.x/", + "5.x": "https://click.palletsprojects.com/en/5.x/", + "4.x": "https://click.palletsprojects.com/en/4.x/", + "3.x": "https://click.palletsprojects.com/en/3.x/", + "2.x": "https://click.palletsprojects.com/en/2.x/", + "1.x": "https://click.palletsprojects.com/en/1.x/" + }, + "sources": {} + }, + "numpy": { + "versions": { + "latest": "https://numpy.org/devdocs/", + "stable": "https://numpy.org/doc/stable/", + "1.23.4": "https://numpy.org/doc/1.23/", + "1.23.x": "https://numpy.org/doc/1.23/", + "1.22.x": "https://numpy.org/doc/1.22/", + "1.21.x": "https://numpy.org/doc/1.21/" + }, + "sources": { + "pypi": "numpy" + } + }, + "packaging": { + "versions": { + "latest": "https://packaging.pypa.io/en/latest/", + "stable": "https://packaging.pypa.io/en/stable/" + }, + "sources": { + "readthedocs": "packaging" + } + } +} diff --git a/tests/data/requirements.txt b/tests/data/requirements.txt new file mode 100644 index 0000000..9e551c9 --- /dev/null +++ b/tests/data/requirements.txt @@ -0,0 +1,7 @@ +# SPDX-FileCopyrightText: Copyright © 2022 Idiap Research Institute +# +# SPDX-License-Identifier: BSD-3-Clause + +numpy==1.22.4 +click==8.0.1 +requests diff --git a/tests/test_auto_intersphinx.py b/tests/test_auto_intersphinx.py new file mode 100644 index 0000000..3760a5b --- /dev/null +++ b/tests/test_auto_intersphinx.py @@ -0,0 +1,314 @@ +# SPDX-FileCopyrightText: Copyright © 2022 Idiap Research Institute +# +# SPDX-License-Identifier: BSD-3-Clause + +import os +import pathlib +import subprocess +import sys +import typing + +# this import avoids a pytest warning +import auto_intersphinx # noqa: F401 + + +def _sphinx_build_html( + dir: pathlib.Path, + rst: typing.Iterable[str], + conf: typing.Iterable[str], +) -> tuple[int, str, str, pathlib.Path, pathlib.Path]: + """Runs ``sphinx-build -b html`` over input data and return results. + + This function will create a temporary directory containing the test + documents composed of a single RST file and a Sphinx configuration file. It + will then call the command-line program ``sphinx-build``, to build the + documentation. It returns the program exit status, the stdout, stderr + streams, and a path leading to the root of the document tree. + + Arguments: + + dir: Path to a (temporary) directory to be used to create the ``doc`` + and resulting ``html`` directories for this build. You must manage + the creation and eventual destruction of this directory. This + function will **NOT** do it. + + rst: Strings corresponding to the RST file to use for testing. Each + entry in the iterable corresponds to a new line in test RST file. + + A string corresponding to the contents of the single file that + will be created on the documentation tree. + + conf: Strings corresponding to the configuration to test. The + configuration has a Python syntax, each string corresponds to one + new line to be added to the configuration file. + + + Returns: + + A tuple, that contains the exit code of running ``sphinx-build``, its + stdout and stderr outputs, and finally the paths leading to the + source "doc" and resulting "html" build directories. + """ + + # prepares the "doc" directory + srcdir = dir / "doc" + os.makedirs(srcdir, exist_ok=False) + with open(srcdir / "index.rst", "w") as f: + f.write("\n".join(rst)) + + pre_conf = [ + "master_doc='index'", + "source_suffix='.rst'", + "extensions=['auto_intersphinx']", + ] + + with open(srcdir / "conf.py", "w") as f: + f.write("\n".join(pre_conf + list(conf))) + + # runs sphinx + htmldir = dir / "html" + proc = subprocess.run( + f"sphinx-build -aE -b html {srcdir} {htmldir}".split(), + capture_output=True, + text=True, + ) + + return proc.returncode, proc.stdout, proc.stderr, srcdir, htmldir + + +def test_basic_functionality(tmp_path) -> None: + python_version = "%d.%d" % sys.version_info[:2] + conf = [ + f"auto_intersphinx_packages=[('python', '{python_version}'), 'numpy']", + ] + + index_rst = [ + "* Python: :class:`list`, :func:`os.path.basename`", + "* Numpy: :class:`numpy.ndarray`", + ] + + status, stdout, stderr, _, htmldir = _sphinx_build_html( + tmp_path, + index_rst, + conf, + ) + + assert status == 0 + + assert ( + f"loading intersphinx inventory from " + f"https://docs.python.org/{sys.version_info[0]}.{sys.version_info[1]}" in stdout + ) + + assert ( + "loading intersphinx inventory from https://numpy.org/doc/stable/objects.inv" + in stdout + ) + + assert (htmldir / "index.html").exists() + + assert len(stderr) == 0 + + +def test_warnings_dev_and_base(tmp_path) -> None: + conf = [ + "auto_intersphinx_packages=[('numpy', 'latest'), 'numpy']", + ] + + index_rst = [ + "* Python: :class:`list`, :func:`os.path.basename`", + "* Numpy: :class:`numpy.ndarray`", + ] + + status, stdout, stderr, _, htmldir = _sphinx_build_html( + tmp_path, + index_rst, + conf, + ) + + assert status == 0 + + assert ( + "loading intersphinx inventory from https://numpy.org/devdocs/objects.inv" + in stdout + ) + + assert "Ignoring reset of `numpy' intersphinx_mapping" in stderr + + assert (htmldir / "index.html").exists() + + +def test_can_remove_duplicates_without_warning(tmp_path) -> None: + conf = [ + "auto_intersphinx_packages=['numpy', 'numpy']", + ] + + index_rst = [ + "* Python: :class:`list`, :func:`os.path.basename`", + "* Numpy: :class:`numpy.ndarray`", + ] + + status, stdout, _, _, htmldir = _sphinx_build_html( + tmp_path, + index_rst, + conf, + ) + + assert status == 0 + + assert "loading intersphinx inventory from https://numpy.org/doc/stable/" in stdout + + assert "Ignoring repeated setting of `numpy' intersphinx_mapping" in stdout + + assert (htmldir / "index.html").exists() + + +def test_conflict_from_intersphinx_mapping(tmp_path) -> None: + conf = [ + "intersphinx_mapping={'numpy': ('https://numpy.org/doc/stable/', None)}", + "auto_intersphinx_packages=['numpy']", + ] + + index_rst = [ + "* Python: :class:`list`, :func:`os.path.basename`", + "* Numpy: :class:`numpy.ndarray`", + ] + + status, stdout, _, _, htmldir = _sphinx_build_html( + tmp_path, + index_rst, + conf, + ) + + assert status == 0 + + assert "loading intersphinx inventory from https://numpy.org/doc/stable/" in stdout + + assert "Ignoring repeated setting of `numpy' intersphinx_mapping" in stdout + + assert (htmldir / "index.html").exists() + + +def test_discover_from_internal_catalog(tmp_path) -> None: + conf = [ + "auto_intersphinx_packages=['setuptools']", + ] + + index_rst = [ + "* Python: :class:`list`, :func:`os.path.basename`", + "* Numpy: :class:`numpy.ndarray`", + ] + + status, stdout, _, _, htmldir = _sphinx_build_html( + tmp_path, + index_rst, + conf, + ) + + assert status == 0 + + assert "loading intersphinx inventory from https://setuptools" in stdout + + assert (htmldir / "index.html").exists() + + +def test_warning_with_internal_catalog(tmp_path) -> None: + conf = [ + "auto_intersphinx_packages=[('setuptools', '61.0.0')]", + ] + + index_rst = [ + "* Python: :class:`list`, :func:`os.path.basename`", + "* Numpy: :class:`numpy.ndarray`", + ] + + status, stdout, stderr, _, htmldir = _sphinx_build_html( + tmp_path, + index_rst, + conf, + ) + + assert status == 0 + + assert "Cannot find suitable catalog entry for `setuptools@61.0.0'" in stderr + + assert (htmldir / "index.html").exists() + + +def test_error_unknown_package(tmp_path) -> None: + conf = [ + "auto_intersphinx_packages=[('setuptoolx', '61.0.0'), ('dead-beef-xyz')]", + ] + + index_rst = [ + "* Python: :class:`list`, :func:`os.path.basename`", + "* Numpy: :class:`numpy.ndarray`", + ] + + status, stdout, stderr, _, htmldir = _sphinx_build_html( + tmp_path, + index_rst, + conf, + ) + + assert status == 0 + + assert "Cannot find suitable catalog entry for `setuptoolx@61.0.0'" in stderr + + assert "Cannot find suitable catalog entry for `dead-beef-xyz@stable'" in stderr + + assert (htmldir / "index.html").exists() + + +def test_discover_from_metadata(tmp_path) -> None: + conf = [ + "auto_intersphinx_packages=['jinja2']", + ] + + index_rst = [ + "* Python: :class:`list`, :func:`os.path.basename`", + "* Numpy: :class:`numpy.ndarray`", + ] + + status, stdout, _, _, htmldir = _sphinx_build_html( + tmp_path, + index_rst, + conf, + ) + + assert status == 0 + + assert ( + "loading intersphinx inventory from https://jinja.palletsprojects.com/" + in stdout + ) + + assert (htmldir / "index.html").exists() + + +def test_create_user_catalog(tmp_path) -> None: + conf = [ + "auto_intersphinx_packages=['flask']", + "auto_intersphinx_catalog='catalog.json'", + ] + + index_rst = [ + "* Flask: :mod:`flask`", + ] + + status, stdout, _, srcdir, htmldir = _sphinx_build_html( + tmp_path, + index_rst, + conf, + ) + + assert status == 0 + + assert ( + "loading intersphinx inventory from https://flask.palletsprojects.com/" + in stdout + ) + + assert (srcdir / "catalog.json").exists() + + assert (htmldir / "index.html").exists() diff --git a/tests/test_check_packages.py b/tests/test_check_packages.py new file mode 100644 index 0000000..06d896b --- /dev/null +++ b/tests/test_check_packages.py @@ -0,0 +1,143 @@ +# SPDX-FileCopyrightText: Copyright © 2022 Idiap Research Institute +# +# SPDX-License-Identifier: BSD-3-Clause + +import pytest + +from auto_intersphinx.cli import main + + +@pytest.mark.parametrize("option", ("-h", "--help")) +def test_help(capsys, option): + try: + main(["check-packages"] + [option]) + except SystemExit: + pass + + output = capsys.readouterr().out + assert "Discover documentation cross-references for packages" in output + + +def test_keep_going(capsys): + try: + main(["check-packages", "-vvv", "--keep-going", "requests"]) + except SystemExit: + pass + + output = capsys.readouterr().out + assert "Found requests in builtin catalog" in output + assert "Found requests documentation in installed Python environment" in output + assert "Found requests documentation in readthedocs.org" in output + assert "Found requests documentation in PyPI" in output + + +def test_user_catalog(capsys, datadir): + user_catalog = datadir / "catalog.json" + + try: + main( + [ + "check-packages", + "-vvv", + f"--user={str(user_catalog)}", + "--keep-going", + "click", + ] + ) + except SystemExit: + pass + + output = capsys.readouterr().out + assert "Found click in user catalog" in output + assert "Found click in builtin catalog" in output + assert "Found click documentation in readthedocs.org" in output + assert "Found click documentation in PyPI" in output + + +def test_stop_at_user_catalog(capsys, datadir): + user_catalog = datadir / "catalog.json" + + try: + main(["check-packages", "-vvv", f"--user={str(user_catalog)}", "click"]) + except SystemExit: + pass + + output = capsys.readouterr().out + assert "Found click in user catalog" in output + assert "Found click in builtin catalog" not in output + assert "Found click documentation in installed Python environment" not in output + assert "Found click documentation in readthedocs.org" not in output + assert "Found click documentation in PyPI" not in output + + +def test_stop_at_builtin_catalog(capsys): + try: + main(["check-packages", "-vvv", "requests"]) + except SystemExit: + pass + + output = capsys.readouterr().out + assert "Found requests in user catalog" not in output + assert "Found requests in builtin catalog" in output + assert "Found requests documentation in installed Python environment" not in output + assert "Found requests documentation in readthedocs.org" not in output + assert "Found requests documentation in PyPI" not in output + + +def test_stop_at_environment(capsys): + try: + main(["check-packages", "-vvv", "--no-builtin", "requests"]) + except SystemExit: + pass + + output = capsys.readouterr().out + assert "Found requests in user catalog" not in output + assert "Found requests in builtin catalog" not in output + assert "Found requests documentation in installed Python environment" in output + assert "Found requests documentation in readthedocs.org" not in output + assert "Found requests documentation in PyPI" not in output + + +def test_stop_at_readthedocs(capsys): + try: + main( + [ + "check-packages", + "-vvv", + "--no-builtin", + "--no-environment", + "requests", + ] + ) + except SystemExit: + pass + + output = capsys.readouterr().out + assert "Found requests in user catalog" not in output + assert "Found requests in builtin catalog" not in output + assert "Found requests documentation in installed Python environment" not in output + assert "Found requests documentation in readthedocs.org" in output + assert "Found requests documentation in PyPI" not in output + + +def test_stop_at_pypi(capsys): + try: + main( + [ + "check-packages", + "-vvv", + "--no-builtin", + "--no-environment", + "--no-rtd", + "requests", + ] + ) + except SystemExit: + pass + + output = capsys.readouterr().out + assert "Found requests in user catalog" not in output + assert "Found requests in builtin catalog" not in output + assert "Found requests documentation in installed Python environment" not in output + assert "Found requests documentation in readthedocs.org" not in output + assert "Found requests documentation in PyPI" in output diff --git a/tests/test_dump_objects.py b/tests/test_dump_objects.py new file mode 100644 index 0000000..b151049 --- /dev/null +++ b/tests/test_dump_objects.py @@ -0,0 +1,30 @@ +# SPDX-FileCopyrightText: Copyright © 2022 Idiap Research Institute +# +# SPDX-License-Identifier: BSD-3-Clause + +import pytest + +from auto_intersphinx.cli import main + + +@pytest.mark.parametrize("option", ("-h", "--help")) +def test_help(capsys, option): + try: + main(["dump-objects"] + [option]) + except SystemExit: + pass + + output = capsys.readouterr().out + assert "Dumps objects documented in a Sphinx inventory URL" in output + + +def test_python_3_dump(capsys): + try: + main(["dump-objects", "-vvv", "https://docs.python.org/3/objects.inv"]) + except SystemExit: + pass + + output = capsys.readouterr().out + assert "" in output + assert "Dumping https://docs.python.org/3/objects.inv" in output + assert "library/os" in output diff --git a/tests/test_update_catalog.py b/tests/test_update_catalog.py new file mode 100644 index 0000000..e59814b --- /dev/null +++ b/tests/test_update_catalog.py @@ -0,0 +1,283 @@ +# SPDX-FileCopyrightText: Copyright © 2022 Idiap Research Institute +# +# SPDX-License-Identifier: BSD-3-Clause + +import pytest + +from auto_intersphinx.catalog import BUILTIN_CATALOG +from auto_intersphinx.cli import main + + +@pytest.mark.parametrize("option", ("-h", "--help")) +def test_help(capsys, option): + try: + main(["update-catalog"] + [option]) + except SystemExit: + pass + + output = capsys.readouterr().out + assert "Updates catalog of intersphinx cross-references" in output + + +def test_dump(capsys, tmp_path): + output_catalog = tmp_path / "catalog.json" + + try: + main( + [ + "update-catalog", + "-vvv", + f"--output={str(output_catalog)}", + ] + ) + except SystemExit: + pass + + assert output_catalog.exists() + assert BUILTIN_CATALOG.read_text() == output_catalog.read_text() + + output = capsys.readouterr().out + assert "click" not in output + assert "https://pypi.org/pypi/numpy/json" not in output + assert "https://readthedocs.org/projects/packaging/versions/" not in output + + +def test_dump2(capsys, datadir, tmp_path): + input_catalog = datadir / "catalog.json" + output_catalog = tmp_path / "catalog.json" + + try: + main( + [ + "update-catalog", + "-vvv", + f"--catalog={str(input_catalog)}", + f"--output={str(output_catalog)}", + ] + ) + except SystemExit: + pass + + assert output_catalog.exists() + assert input_catalog.read_text() == output_catalog.read_text() + + output = capsys.readouterr().out + assert "click" not in output + assert "https://pypi.org/pypi/numpy/json" not in output + assert "https://readthedocs.org/projects/packaging/versions/" not in output + + +def test_verbose_0(capsys, datadir, tmp_path): + input_catalog = datadir / "catalog.json" + output_catalog = tmp_path / "catalog.json" + + try: + main( + [ + "update-catalog", + f"--catalog={str(input_catalog)}", + f"--output={str(output_catalog)}", + ] + ) + except SystemExit: + pass + + assert output_catalog.exists() + assert input_catalog.read_text() == output_catalog.read_text() + + output = capsys.readouterr().out + assert output == "" + + +def test_verbose_1(capsys, datadir, tmp_path): + input_catalog = datadir / "catalog.json" + output_catalog = tmp_path / "catalog.json" + + try: + main( + [ + "update-catalog", + "-v", + f"--catalog={str(input_catalog)}", + f"--output={str(output_catalog)}", + ] + ) + except SystemExit: + pass + + assert output_catalog.exists() + assert input_catalog.read_text() == output_catalog.read_text() + + output = capsys.readouterr().out + assert output == "" + + +def test_verbose_2(capsys, datadir, tmp_path): + input_catalog = datadir / "catalog.json" + output_catalog = tmp_path / "catalog.json" + + try: + main( + [ + "update-catalog", + "-vv", + f"--catalog={str(input_catalog)}", + f"--output={str(output_catalog)}", + ] + ) + except SystemExit: + pass + + assert output_catalog.exists() + assert input_catalog.read_text() == output_catalog.read_text() + + output = capsys.readouterr().out + assert output == "" + + +def test_self_update(capsys, datadir, tmp_path): + input_catalog = datadir / "catalog.json" + output_catalog = tmp_path / "catalog.json" + + try: + main( + [ + "update-catalog", + "-vvv", + "--self", + f"--catalog={str(input_catalog)}", + f"--output={str(output_catalog)}", + ] + ) + except SystemExit: + pass + + assert output_catalog.exists() + + output = capsys.readouterr().out + assert "click" not in output + assert "https://pypi.org/pypi/numpy/json" in output + assert "https://readthedocs.org/projects/packaging/versions/" in output + + +def test_boostrap_from_package_list(capsys, tmp_path): + catalog = tmp_path / "catalog.json" + + try: + main( + [ + "update-catalog", + "-vvv", + "--keep-going", + "--pypi-max-entries=2", + f"--catalog={str(catalog)}", + f"--output={str(catalog)}", + "numpy", + "requests", + "click", + ] + ) + except SystemExit: + pass + + assert catalog.exists() + + output = capsys.readouterr().out + assert "click" in output + assert "numpy" in output + assert "requests" in output + assert "https://readthedocs.org/projects/click/versions/" in output + assert "https://pypi.org/pypi/click/json" in output + assert "https://pypi.org/pypi/numpy/json" in output + assert "https://pypi.org/pypi/requests/json" in output + assert "Saving package catalog with 3 entries at" in output + + +def test_boostrap_from_package_list_to_stdout(capsys, tmp_path): + catalog = tmp_path / "catalog.json" + + try: + main( + [ + "update-catalog", + "-vvv", + "--keep-going", + "--pypi-max-entries=2", + f"--catalog={str(catalog)}", + "numpy", + "requests", + "click", + ] + ) + except SystemExit: + pass + + assert not catalog.exists() + + output = capsys.readouterr().out + assert "click" in output + assert "numpy" in output + assert "requests" in output + assert "https://readthedocs.org/projects/click/versions/" in output + assert "https://pypi.org/pypi/click/json" in output + assert "https://pypi.org/pypi/numpy/json" in output + assert "https://pypi.org/pypi/requests/json" in output + assert '"readthedocs": "numpy"' in output + assert '"readthedocs": "click"' in output + assert '"readthedocs": "requests"' in output + + +def test_boostrap_from_file(capsys, datadir, tmp_path): + requirements = datadir / "requirements.txt" + catalog = tmp_path / "catalog.json" + + try: + main( + [ + "update-catalog", + "-vvv", + "--keep-going", + "--pypi-max-entries=0", + f"--catalog={str(catalog)}", + f"--output={str(catalog)}", + f"{str(requirements)}", + ] + ) + except SystemExit: + pass + + assert catalog.exists() + + output = capsys.readouterr().out + assert "click" in output + assert "numpy" in output + assert "requests" in output + assert "https://readthedocs.org/projects/click/versions/" in output + assert "https://pypi.org/pypi/click/json" in output + assert "https://pypi.org/pypi/numpy/json" in output + assert "https://pypi.org/pypi/requests/json" in output + assert "Saving package catalog with 13 entries at" in output + + +def test_remote_list_does_not_exist(capsys, tmp_path): + address = "https://example.com/does/not/exist/requirements.txt" + catalog = tmp_path / "catalog.json" + + try: + main( + [ + "update-catalog", + "--keep-going", + "--pypi-max-entries=0", + f"--catalog={str(catalog)}", + f"--output={str(catalog)}", + address, + ] + ) + except SystemExit: + pass + + assert not catalog.exists() + + output = capsys.readouterr().out + assert f"[ERROR] Could not retrieve `{address}'" == output.strip()