diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ba58ac5ca2..beb076dfba 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-22.04, macos-13, windows-latest] - python: ["3.9", "3.10", "3.11", "3.12"] + python: ["3.9", "3.10", "3.11", "3.12", "3.13"] steps: - name: Checkout the repository @@ -31,7 +31,7 @@ jobs: - name: Install Poetry run: | - pipx install "poetry==1.7.*" + pipx install "poetry==1.8.*" poetry config virtualenvs.prefer-active-python true - name: Setup Python ${{ matrix.python }} @@ -142,10 +142,7 @@ jobs: Expand-Archive -LiteralPath "$($env:TMP)\TinyTex.zip" -DestinationPath "$($PWD)\ManimCache\LatexWindows" $env:Path = "$($PWD)\ManimCache\LatexWindows\TinyTeX\bin\windows;$($env:PATH)" tlmgr update --self - foreach ($c in $tinyTexPackages){ - $c=$c.Trim() - tlmgr install $c - } + tlmgr install $tinyTexPackages $env:PATH=$OriPath echo "Completed Latex" @@ -156,10 +153,9 @@ jobs: $env:Path = "$env:USERPROFILE\.poetry\bin;$($env:PATH)" echo "$env:Path" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - - name: Install manim + - name: Install dependencies and manim run: | - poetry config installer.modern-installation false - poetry install + poetry install --all-extras - name: Run tests run: | diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index c9c7c2cbb2..4dd14f281a 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -25,7 +25,7 @@ jobs: password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: platforms: linux/arm64,linux/amd64 push: true @@ -61,7 +61,7 @@ jobs: print(f"tag_name={ref_tag}", file=f) - name: Build and push - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: platforms: linux/arm64,linux/amd64 push: true diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8977518d43..50b4217aa9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,9 +1,9 @@ -default_stages: [commit, push] +default_stages: [pre-commit, pre-push] fail_fast: false exclude: ^(manim/grpc/gen/|docs/i18n/) repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.6.0 + rev: v5.0.0 hooks: - id: check-ast name: Validate Python @@ -12,13 +12,8 @@ repos: - id: end-of-file-fixer - id: check-toml name: Validate Poetry - - repo: https://github.com/pre-commit/pygrep-hooks - rev: v1.10.0 - hooks: - - id: python-check-blanket-noqa - name: Precision flake ignores - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.4.10 + rev: v0.8.0 hooks: - id: ruff name: ruff lint @@ -26,22 +21,8 @@ repos: args: [--exit-non-zero-on-fix] - id: ruff-format types: [python] - - repo: https://github.com/PyCQA/flake8 - rev: 7.1.0 - hooks: - - id: flake8 - additional_dependencies: - [ - flake8-bugbear==21.4.3, - flake8-builtins==1.5.3, - flake8-comprehensions>=3.6.1, - flake8-docstrings==1.6.0, - flake8-pytest-style==1.5.0, - flake8-rst-docstrings==0.2.3, - flake8-simplify==0.14.1, - ] - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.10.0 + rev: v1.13.0 hooks: - id: mypy additional_dependencies: diff --git a/README.md b/README.md index cc394142d2..a909e5a1df 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,8 @@ Manim is an animation engine for explanatory math videos. It's used to create precise animations programmatically, as demonstrated in the videos of [3Blue1Brown](https://www.3blue1brown.com/). -> NOTE: This repository is maintained by the Manim Community and is not associated with Grant Sanderson or 3Blue1Brown in any way (although we are definitely indebted to him for providing his work to the world). If you would like to study how Grant makes his videos, head over to his repository ([3b1b/manim](https://github.com/3b1b/manim)). This fork is updated more frequently than his, and it's recommended to use this fork if you'd like to use Manim for your own projects. +> [!NOTE] +> This repository is maintained by the Manim Community and is not associated with Grant Sanderson or 3Blue1Brown in any way (although we are definitely indebted to him for providing his work to the world). If you would like to study how Grant makes his videos, head over to his repository ([3b1b/manim](https://github.com/3b1b/manim)). This fork is updated more frequently than his, and it's recommended to use this fork if you'd like to use Manim for your own projects. ## Table of Contents: @@ -35,7 +36,8 @@ Manim is an animation engine for explanatory math videos. It's used to create pr ## Installation -> **WARNING:** These instructions are for the community version _only_. Trying to use these instructions to install [3b1b/manim](https://github.com/3b1b/manim) or instructions there to install this version will cause problems. Read [this](https://docs.manim.community/en/stable/faq/installation.html#why-are-there-different-versions-of-manim) and decide which version you wish to install, then only follow the instructions for your desired version. +> [!CAUTION] +> These instructions are for the community version _only_. Trying to use these instructions to install [3b1b/manim](https://github.com/3b1b/manim) or instructions there to install this version will cause problems. Read [this](https://docs.manim.community/en/stable/faq/installation.html#why-are-there-different-versions-of-manim) and decide which version you wish to install, then only follow the instructions for your desired version. Manim requires a few dependencies that must be installed prior to using it. If you want to try it out first before installing it locally, you can do so diff --git a/conftest.py b/conftest.py deleted file mode 100644 index 683bd2bc05..0000000000 --- a/conftest.py +++ /dev/null @@ -1,43 +0,0 @@ -# This file is automatically picked by pytest -# while running tests. So, that each test is -# run on difference temporary directories and avoiding -# errors. - -from __future__ import annotations - -import cairo -import moderngl - -# If it is running Doctest the current directory -# is changed because it also tests the config module -# itself. If it's a normal test then it uses the -# tempconfig to change directories. -import pytest -from _pytest.doctest import DoctestItem - -from manim import config, tempconfig - - -@pytest.fixture(autouse=True) -def temp_media_dir(tmpdir, monkeypatch, request): - if isinstance(request.node, DoctestItem): - monkeypatch.chdir(tmpdir) - yield tmpdir - else: - with tempconfig({"media_dir": str(tmpdir)}): - assert config.media_dir == str(tmpdir) - yield tmpdir - - -def pytest_report_header(config): - ctx = moderngl.create_standalone_context() - info = ctx.info - ctx.release() - return ( - f"\nCairo Version: {cairo.cairo_version()}", - "\nOpenGL information", - "------------------", - f"vendor: {info['GL_VENDOR'].strip()}", - f"renderer: {info['GL_RENDERER'].strip()}", - f"version: {info['GL_VERSION'].strip()}\n", - ) diff --git a/docker/Dockerfile b/docker/Dockerfile index b41647e4e8..83696e335a 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -22,9 +22,9 @@ RUN wget -O /tmp/install-tl-unx.tar.gz http://mirror.ctan.org/systems/texlive/tl tar -xzf /tmp/install-tl-unx.tar.gz -C /tmp/install-tl --strip-components=1 && \ /tmp/install-tl/install-tl --profile=/tmp/texlive-profile.txt \ && tlmgr install \ - amsmath babel-english cbfonts-fd cm-super ctex doublestroke dvisvgm everysel \ + amsmath babel-english cbfonts-fd cm-super count1to ctex doublestroke dvisvgm everysel \ fontspec frcursive fundus-calligra gnu-freefont jknapltx latex-bin \ - mathastext microtype ms physics preview ragged2e relsize rsfs \ + mathastext microtype multitoc physics prelim2e preview ragged2e relsize rsfs \ setspace standalone tipa wasy wasysym xcolor xetex xkeyval # clone and build manim @@ -36,9 +36,9 @@ RUN pip install -r docs/requirements.txt ARG NB_USER=manimuser ARG NB_UID=1000 -ENV USER ${NB_USER} -ENV NB_UID ${NB_UID} -ENV HOME /manim +ENV USER=${NB_USER} +ENV NB_UID=${NB_UID} +ENV HOME=/manim RUN adduser --disabled-password \ --gecos "Default user" \ diff --git a/docs/requirements.txt b/docs/requirements.txt index 807fb0d3c4..5b607e9c8b 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -3,3 +3,5 @@ myst-parser sphinx>=7.3 sphinx-copybutton sphinxext-opengraph +sphinx-design +sphinx-reredirects diff --git a/docs/source/conf.py b/docs/source/conf.py index 3910fd7ed1..a4a092441d 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -26,7 +26,7 @@ # -- Project information ----------------------------------------------------- project = "Manim" -copyright = f"2020-{datetime.now().year}, The Manim Community Dev Team" +copyright = f"2020-{datetime.now().year}, The Manim Community Dev Team" # noqa: A001 author = "The Manim Community Dev Team" @@ -51,11 +51,22 @@ "sphinx.ext.inheritance_diagram", "sphinxcontrib.programoutput", "myst_parser", + "sphinx_design", + "sphinx_reredirects", ] # Automatically generate stub pages when using the .. autosummary directive autosummary_generate = True +myst_enable_extensions = ["colon_fence", "amsmath"] + +# redirects (for moved / deleted pages) +redirects = { + "installation/linux": "uv.html", + "installation/macos": "uv.html", + "installation/windows": "uv.html", +} + # generate documentation from type hints ALIAS_DOCS_DICT = parse_module_attributes()[0] autodoc_typehints = "description" @@ -63,7 +74,7 @@ alias_name: f"~manim.{module}.{alias_name}" for module, module_dict in ALIAS_DOCS_DICT.items() for category_dict in module_dict.values() - for alias_name in category_dict.keys() + for alias_name in category_dict } autoclass_content = "both" diff --git a/docs/source/contributing/docs/types.rst b/docs/source/contributing/docs/types.rst index fb6f06732b..63e5083579 100644 --- a/docs/source/contributing/docs/types.rst +++ b/docs/source/contributing/docs/types.rst @@ -57,7 +57,8 @@ consider this slightly contrived function: .. code-block:: python - def shift_mobject(mob: Mobject, direction: Vector3D, scale_factor: float = 1) -> mob: + M = TypeVar("M", bound=Mobject) # allow any mobject + def shift_mobject(mob: M, direction: Vector3D, scale_factor: float = 1) -> M: return mob.shift(direction * scale_factor) Here we see an important example of the difference. ``direction`` can not, and @@ -129,6 +130,6 @@ There are several representations of images in Manim. The most common is the representation as a NumPy array of floats representing the pixels of an image. This is especially common when it comes to the OpenGL renderer. -This is the use case of the :class:`~.typing.Image` type hint. Sometimes, Manim may use ``PIL.Image``, -in which case one should use that type hint instead. +This is the use case of the :class:`~.typing.PixelArray` type hint. Sometimes, Manim may use ``PIL.Image.Image``, +which is not the same as :class:`~.typing.PixelArray`. In this case, use the ``PIL.Image.Image`` typehint. Of course, if a more specific type of image is needed, it can be annotated as such. diff --git a/docs/source/examples.rst b/docs/source/examples.rst index 6d39027bfc..3213c35160 100644 --- a/docs/source/examples.rst +++ b/docs/source/examples.rst @@ -90,7 +90,7 @@ Basic Concepts [[i * 256 / n for i in range(0, n)] for _ in range(0, n)] ) image = ImageMobject(imageArray).scale(2) - image.background_rectangle = SurroundingRectangle(image, GREEN) + image.background_rectangle = SurroundingRectangle(image, color=GREEN) self.add(image, image.background_rectangle) .. manim:: BooleanOperations diff --git a/docs/source/faq/installation.md b/docs/source/faq/installation.md index c60044b66a..25db9cbad5 100644 --- a/docs/source/faq/installation.md +++ b/docs/source/faq/installation.md @@ -120,19 +120,24 @@ of [ManimPango's README](https://github.com/ManimCommunity/ManimPango). --- +(not-on-path)= ## I am using Windows and get the error `X is not recognized as an internal or external command, operable program or batch file` -Regardless of whether `X` says `python` or `manim`, this means that the executable you -are trying to run is not located in one of the directories your system is looking -for them (specified by the `PATH` variable). Take a look at the instructions -{doc}`in the installation guide for Windows `, or -[this StackExchange answer](https://superuser.com/questions/143119/how-do-i-add-python-to-the-windows-path/143121#143121) -to get help with editing the `PATH` variable manually. +If you have followed {doc}`our local installation instructions ` and +have not activated the corresponding virtual environment, make sure to use `uv run manim ...` +instead of just `manim` (or activate the virtual environment by following the instructions +printed when running `uv venv`). -If `python` is recognized but not `manim` or `pip`, you can try running +Otherwise there is a problem with the directories where your system is looking for +executables (the `PATH` variable). +If `python` is recognized, you can try running commands by prepending `python -m`. That is, `manim` becomes `python -m manim`, and `pip` becomes `python -m pip`. +Otherwise see +[this StackExchange answer](https://superuser.com/questions/143119/how-do-i-add-python-to-the-windows-path/143121#143121) +to get help with editing the `PATH` variable manually. + --- ## I have tried using Chocolatey (`choco install manimce`) to install Manim, but it failed! diff --git a/docs/source/installation.rst b/docs/source/installation.rst index fbc65a7cc6..3c2b4e4c09 100644 --- a/docs/source/installation.rst +++ b/docs/source/installation.rst @@ -8,8 +8,8 @@ require no local installation. Head over to https://try.manim.community to give our interactive tutorial a try. Otherwise, if you intend to use Manim to work on an animation project, -we recommend installing the library locally (either to a conda environment, -your system's Python, or via Docker). +we recommend installing the library locally (preferably to some isolated +virtual Python environment, or a conda-like environment, or via Docker). .. warning:: @@ -19,13 +19,31 @@ your system's Python, or via Docker). versions ` if you are unsure which version you should install. +#. :ref:`(Recommended) Installing Manim via Python's package manager pip + ` #. :ref:`Installing Manim to a conda environment ` -#. :ref:`Installing Manim to your system's Python ` #. :ref:`Using Manim via Docker ` #. :ref:`Interactive Jupyter notebooks via Binder / Google Colab ` +.. _local-installation: + +Installing Manim locally via pip +******************************** + +The recommended way of installing Manim is by using Python's package manager +pip. If you already have a Python environment set up, you can simply run +``pip install manim`` to install the library. + +Our :doc:`local installation guide ` provides more detailed +instructions, including best practices for setting up a suitable local environment. + +.. toctree:: + :hidden: + + installation/uv + .. _conda-installation: Installing Manim via Conda and related environment managers @@ -55,48 +73,6 @@ The following pages show how to install Manim in a conda environment: installation/conda - -.. _local-installation: - -Installing Manim locally -************************ - -Manim is a Python library, and it can be -installed via `pip `__ -or `conda `__. However, -in order for Manim to work properly, some additional system -dependencies need to be installed first. The following pages have -operating system specific instructions for you to follow. - -Manim requires Python version ``3.9`` or above to run. - -.. hint:: - - Depending on your particular setup, the installation process - might be slightly different. Make sure that you have tried to - follow the steps on the following pages carefully, but in case - you hit a wall we are happy to help: either `join our Discord - `__, or start a new - Discussion `directly on GitHub - `__. - -.. toctree:: - :maxdepth: 2 - - installation/windows - installation/macos - installation/linux - -Once Manim is installed locally, you can proceed to our -:doc:`quickstart guide ` which walks you -through rendering a first simple scene. - -As mentioned above, do not worry if there are errors or other -problems: consult our :doc:`FAQ section ` for help -(including instructions for how to ask Manim's community for help). - - - .. _docker-installation: Using Manim via Docker @@ -140,6 +116,11 @@ If you're using Visual Studio Code you can install an extension called of the animation inside the editor. The extension can be installed through the `marketplace of VS Code `__. +.. caution:: + + This extension is not officially maintained by the Manim Community. + If you run into issues, please report them to the extension's author. + Installation for developers *************************** diff --git a/docs/source/installation/conda.rst b/docs/source/installation/conda.rst index b69c8d6de6..8350bfaeea 100644 --- a/docs/source/installation/conda.rst +++ b/docs/source/installation/conda.rst @@ -10,15 +10,25 @@ namely `conda `, -:ref:`Linux ` or -:ref:`macOS `. - +Recommendations on how to install LaTeX on different operating systems +can be found :doc:`in our local installation guide `. Working with Manim diff --git a/docs/source/installation/linux.rst b/docs/source/installation/linux.rst deleted file mode 100644 index 6c154d8eed..0000000000 --- a/docs/source/installation/linux.rst +++ /dev/null @@ -1,162 +0,0 @@ -Linux -===== - -The installation instructions depend on your particular operating -system and package manager. If you happen to know exactly what you are doing, -you can also simply ensure that your system has: - -- a reasonably recent version of Python 3 (3.9 or above), -- with working Cairo bindings in the form of - `pycairo `__, -- and `Pango `__ headers. - -Then, installing Manim is just a matter of running: - -.. code-block:: bash - - pip3 install manim - -.. note:: - - In light of the current efforts of migrating to rendering via OpenGL, - this list might be incomplete. Please `let us know - ` if you - ran into missing dependencies while installing. - -In any case, we have also compiled instructions for several common -combinations of operating systems and package managers below. - -Required Dependencies ---------------------- - -apt – Ubuntu / Mint / Debian -**************************** - -To first update your sources, and then install Cairo and Pango -simply run: - -.. code-block:: bash - - sudo apt update - sudo apt install build-essential python3-dev libcairo2-dev libpango1.0-dev - -If you don't have python3-pip installed, install it via: - -.. code-block:: bash - - sudo apt install python3-pip - -Then, to install Manim, run: - -.. code-block:: bash - - pip3 install manim - -Continue by reading the :ref:`optional dependencies ` -section. - -dnf – Fedora / CentOS / RHEL -**************************** - -To install Cairo and Pango: - -.. code-block:: bash - - sudo dnf install cairo-devel pango-devel - -In order to successfully build the ``pycairo`` wheel, you will also -need the Python development headers: - -.. code-block:: bash - - sudo dnf install python3-devel - -At this point you have all required dependencies and can install -Manim by running: - -.. code-block:: bash - - pip3 install manim - -Continue by reading the :ref:`optional dependencies ` -section. - -pacman – Arch / Manjaro -*********************** - -.. tip:: - - Thanks to *groctel*, there is a `dedicated Manim package - on the AUR! ` - -If you don't want to use the packaged version from AUR, here is what -you need to do manually: Update your package sources, then install -Cairo and Pango: - -.. code-block:: bash - - sudo pacman -Syu - sudo pacman -S cairo pango - -If you don't have ``python-pip`` installed, get it by running: - -.. code-block:: bash - - sudo pacman -S python-pip - -then simply install Manim via: - -.. code-block:: bash - - pip3 install manim - - -Continue by reading the :ref:`optional dependencies ` -section. - - -.. _linux-optional-dependencies: - -Optional Dependencies ---------------------- - -In order to make use of Manim's interface to LaTeX for, e.g., rendering -equations, LaTeX has to be installed as well. Note that this is an optional -dependency: if you don't intend to use LaTeX, you don't have to install it. - -You can use whichever LaTeX distribution you like or whichever is easiest -to install with your package manager. Usually, -`TeX Live `__ is a good candidate if you don't -care too much about disk space. - -For Debian-based systems (like Ubuntu), sufficient LaTeX dependencies can be -installed by running: - -.. code-block:: bash - - sudo apt install texlive texlive-latex-extra - -For Fedora (see `docs `__): - -.. code-block:: bash - - sudo dnf install texlive-scheme-full - -Should you choose to work with some smaller TeX distribution like -`TinyTeX `__ , the full list -of LaTeX packages which Manim interacts with in some way (a subset might -be sufficient for your particular application) is:: - - collection-basic amsmath babel-english cbfonts-fd cm-super ctex doublestroke - dvisvgm everysel fontspec frcursive fundus-calligra gnu-freefont jknapltx - latex-bin mathastext microtype ms physics preview ragged2e relsize rsfs - setspace standalone tipa wasy wasysym xcolor xetex xkeyval - - - -Working with Manim ------------------- - -At this point, you should have a working installation of Manim, head -over to our :doc:`Quickstart Tutorial <../tutorials/quickstart>` to learn -how to make your own *Manimations*! diff --git a/docs/source/installation/macos.rst b/docs/source/installation/macos.rst deleted file mode 100644 index 8a0d2b817a..0000000000 --- a/docs/source/installation/macos.rst +++ /dev/null @@ -1,101 +0,0 @@ -macOS -===== - -For the sake of simplicity, the following instructions assume that you have -the popular `package manager Homebrew `__ installed. While -you can certainly also install all dependencies without it, using Homebrew -makes the process much easier. - -If you want to use Homebrew but do not have it installed yet, please -follow `Homebrew's installation instructions `__. - -.. note:: - - For a while after Apple released its new ARM-based processors (the Apple Silicon chips like the *"M1 chip"*), - the recommended way of installing Manim relied on *Rosetta*, Apple's compatibility - layer between Intel and ARM architectures. This is no longer necessary, Manim can - (and is recommended to) be installed natively. - - -Required Dependencies ---------------------- - -To install all required dependencies for installing Manim (namely: Python, -and some required Python packages), run: - -.. code-block:: bash - - brew install py3cairo - -On *Apple Silicon* based machines (i.e., devices with the M1 chip or similar; if -you are unsure which processor you have check by opening the Apple menu, select -*About This Mac* and check the entry next to *Chip*), some additional dependencies -are required, namely: - -.. code-block:: bash - - brew install pango pkg-config scipy - -After all required dependencies are installed, simply run: - -.. code-block:: bash - - pip3 install manim - -to install Manim. - -.. note:: - - A frequent source for installation problems is if ``pip3`` - does not point to the correct Python installation on your system. - To check this, run ``pip3 -V``: for macOS Intel, the path should - start with ``/usr/local``, and for Apple Silicon with - ``/opt/homebrew``. If this is not the case, you either forgot - to modify your shell profile (``.zprofile``) during the installation - of Homebrew, or did not reload your shell (e.g., by opening a new - terminal) after doing so. It is also possible that some other - software (like Pycharm) changed the ``PATH`` variable – to fix this, - make sure that the Homebrew-related lines in your ``.zprofile`` are - at the very end of the file. - -.. _macos-optional-dependencies: - -Optional Dependencies ---------------------- - -In order to make use of Manim's interface to LaTeX for, e.g., rendering -equations, LaTeX has to be installed as well. Note that this is an optional -dependency: if you don't intend to use LaTeX, you don't have to install it. - -For macOS, the recommended LaTeX distribution is -`MacTeX `__. You can install it by following -the instructions from the link, or alternatively also via Homebrew by -running: - -.. code-block:: bash - - brew install --cask mactex-no-gui - -.. warning:: - - MacTeX is a *full* LaTeX distribution and will require more than 4GB of - disk space. If this is an issue for you, consider installing a smaller - distribution like - `BasicTeX `__. - -Should you choose to work with some partial TeX distribution, the full list -of LaTeX packages which Manim interacts with in some way (a subset might -be sufficient for your particular application) is:: - - amsmath babel-english cbfonts-fd cm-super ctex doublestroke dvisvgm everysel - fontspec frcursive fundus-calligra gnu-freefont jknapltx latex-bin - mathastext microtype ms physics preview ragged2e relsize rsfs - setspace standalone tipa wasy wasysym xcolor xetex xkeyval - - -Working with Manim ------------------- - -At this point, you should have a working installation of Manim. Head -over to our :doc:`Quickstart Tutorial <../tutorials/quickstart>` to learn -how to make your own *Manimations*! diff --git a/docs/source/installation/uv.md b/docs/source/installation/uv.md new file mode 100644 index 0000000000..45e805a51e --- /dev/null +++ b/docs/source/installation/uv.md @@ -0,0 +1,284 @@ +# Installing Manim locally + +The standard way of installing Manim is by using +Python's package manager `pip` to install the latest +release from [PyPI](https://pypi.org/project/manim/). + +To make it easier for you to follow best practices when it +comes to setting up a Python project for your Manim animations, +we strongly recommend using a tool for managing Python environments +and dependencies. In particular, +[we strongly recommend using `uv`](https://docs.astral.sh/uv/#getting-started). + +For the two main ways of installing Manim described below, we assume +that `uv` is available; we think it is particularly helpful if you are +new to Python or programming in general. It is not a hard requirement +whatsoever; if you know what you are doing you can just use `pip` to +install Manim directly. + +:::::{admonition} Installing the Python management tool `uv` +:class: seealso + +One way to install `uv` is via the dedicated console installer supporting +all large operating systems. Simply paste the following snippet into +your terminal / PowerShell -- or +[consult `uv`'s documentation](https://docs.astral.sh/uv/#getting-started) +for alternative ways to install the tool. + +::::{tab-set} +:::{tab-item} MacOS and Linux +```bash +curl -LsSf https://astral.sh/uv/install.sh | sh +``` +::: +:::{tab-item} Windows +```powershell +powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" +``` +::: +:::: + +::::: + +Of course, if you know what you are doing and prefer to setup a virtual +environment yourself, feel free to do so! + +:::{important} +If you run into issues when following our instructions below, do +not worry: check our [installation FAQs]() to +see whether the problem is already addressed there -- and otherwise go and +check [how to contact our community]() to get help. +::: + + + +## Installation + +### Step 1: Installing Python + +We first need to check that an appropriate version of Python is available +on your machine. Open a terminal to run +```bash +uv python install +``` +to install the latest version of Python. If this is successful, continue +to the next step. + +(installation-optional-latex)= +### Step 2 (optional): Installing LaTeX + +[LaTeX](https://en.wikibooks.org/wiki/LaTeX/Mathematics) is a very well-known +and widely used typesetting system allowing you to write formulas like + +\begin{equation*} +\frac{1}{2\pi i} \oint_{\gamma} \frac{f(z)}{(z - z_0)^{n+1}}~dz += \frac{f^{(n)}(z_0)}{n!}. +\end{equation*} + +If rendering plain text is sufficient for your needs and you don't want +to render any typeset formulas, you can technically skip this step. Otherwise +select your operating system from the tab list below and follow the instructions. + +:::::{tab-set} + +::::{tab-item} Windows +For Windows we recommend installing LaTeX via the +[MiKTeX distribution](https://miktex.org). Simply grab +the Windows installer available from their download page, + and run it. +:::: + +::::{tab-item} MacOS +If you are running MacOS, we recommend installing the +[MacTeX distribution](https://www.tug.org/mactex/). The latest +available PKG file can be downloaded from +. +Get it and follow the standard installation procedure. +:::: + +::::{tab-item} Linux +Given the large number of Linux distributions with different ways +of installing packages, we cannot give detailed instructions for +all package managers. + +In general we recommend to install a *TeX Live* distribution +(). For most Linux distributions, +TeX Live has already been packaged such that it can be installed +easily with your system package manager. Search the internet and +your usual OS resources for detailed instructions. + +For example, on Debian-based systems with the package manager `apt`, +a full TeX Live distribution can be installed by running +```bash +sudo apt install texlive-full +``` +For Fedora (managed via `dnf`), the corresponding command is +```bash +sudo dnf install texlive-scheme-full +``` +As soon as LaTeX is installed, continue with actually installing Manim +itself. + +:::: + +::::: + +:::{dropdown} I know what I am doing and I would like to setup a minimal LaTeX installation +You are welcome to use a smaller, more customizable LaTeX distribution like +[TinyTeX](https://yihui.org/tinytex/). Manim overall requires the following +LaTeX packages to be installed in your distribution: +```text +amsmath babel-english cbfonts-fd cm-super count1to ctex doublestroke dvisvgm everysel +fontspec frcursive fundus-calligra gnu-freefont jknapltx latex-bin +mathastext microtype multitoc physics preview prelim2e ragged2e relsize rsfs +setspace standalone tipa wasy wasysym xcolor xetex xkeyval +``` +::: + +### Step 3: Installing Manim + +These steps again differ slightly between different operating systems. Make +sure you select the correct one from the tab list below, then follow +the instructions below. + +::::::{tab-set} + +:::::{tab-item} MacOS & Windows +The following commands will + +- create a new directory for a Python project, +- and add Manim as a dependency, which installs it into the corresponding + local Python environment. + +The name for the Python project is *manimations*, which you can change +to anything you like. + +```bash +uv init manimations +cd manimations +uv add manim +``` + +Manim is now installed in your local project environment! + +::::: + +:::::{tab-item} Linux +Practically, the instructions given in the *MacOS & Windows* tab +also apply for Linux -- however, some additional dependencies are +required as Linux users need to build +[ManimPango](https://github.com/ManimCommunity/ManimPango) +(and potentially [pycairo](https://pycairo.readthedocs.io/en/latest/)) +from source. More specifically, this includes: + +- A C compiler, +- Python's development headers, +- the `pkg-config` tool, +- Pango and its development headers, +- and Cairo and its development headers. + +Instructions for popular systems / package managers are given below. + +::::{tab-set} + +:::{tab-item} Debian-based / apt +```bash +sudo apt update +sudo apt install build-essential python3-dev libcairo2-dev libpango1.0-dev +``` +::: + +:::{tab-item} Fedora / dnf +```bash +sudo dnf install python3-devel pkg-config cairo-devel pango-devel +``` +::: + +:::{tab-item} Arch Linux / pacman +```bash +sudo pacman -Syu base-devel cairo pango +``` +::: + +:::: + +As soon as the required dependencies are installed, you can create +a Python project (feel free to change the name *manimations* used below +to some other name) with a local environment containing Manim by running +```bash +uv init manimations +cd manimations +uv add manim +``` + +::::: + +:::::: + +To verify that your local Python project is setup correctly +and that Manim is available, simply run +```bash +uv run manim checkhealth +``` + +At this point, you can also open your project folder with the +IDE of your choice. All modern Python IDEs (for example VS Code +with the Python extension, or PyCharm) should automatically detect +the local environment created by `uv` such that if you put +```py +import manim +``` +into a new file `my-first-animation.py`, the import is resolved +correctly and autocompletion is available. + +*Happy Manimating!* + + +:::{dropdown} Alternative: Installing Manim as a global `uv`-managed tool +If you have Manim projects in many different directories and you do not +want to setup a local project environment for each of them, you could +also install Manim as a `uv`-managed tool. + +See [`uv`'s documentation for more information](https://docs.astral.sh/uv/concepts/tools/) +on their tool mechanism. + +To install Manim as a global `uv` tool, simply run +```bash +uv tool install manim +``` +after which the `manim` executable will be available on your +global system path, without the need to activate any virtual +environment or prefixing your commands with `uv run`. + +Note that when using this approach, setting up your code editor +to properly resolve `import manim` requires additional work, as +the global tool environment is not automatically detected: the +base path of all tool environments can be determined by running +``` +uv tool dir +``` +which should now contain a directory `manim` in which the appropriate +virtual environment is located. Set the Python interpreter of your IDE +to this environment to make imports properly resolve themselves. +::: + +:::{dropdown} Installing Manim for a different version of Python +In case you would like to use a different version of Python +(for example, due to compatibility issues with other packages), +then `uv` allows you to do so in a fairly straightforward way. + +When initializing the local Python project, simply pass the Python +version you want to use as an argument to the `init` command: +``` +uv init --python 3.12 manimations +cd manimations +uv add manim +``` +To change the version for an existing package, you will need to +edit the `pyproject.toml` file. If you are downgrading the python version, the +`requires-python` entry needs to be updated such that your chosen +version satisfies the requirement. Change the line to, for example +`requires-python = ">=3.12"`. After that, run `uv python pin 3.12` +to pin the python version to `3.12`. Finally, run `uv sync`, and your +environment is updated! +::: diff --git a/docs/source/installation/windows.rst b/docs/source/installation/windows.rst deleted file mode 100644 index 04fe2b735a..0000000000 --- a/docs/source/installation/windows.rst +++ /dev/null @@ -1,108 +0,0 @@ -Windows -======= - -The easiest way of installing Manim and its dependencies is by using a -package manager like `Chocolatey `__ -or `Scoop `__, especially if you need optional dependencies -like LaTeX support. - -If you choose to use one of the package managers, please follow -their installation instructions -(`for Chocolatey `__, -`for Scoop `__) -to make one of them available on your system. - - -Required Dependencies ---------------------- - -Manim requires a recent version of Python (3.9 or above) -in order to work. - -Chocolatey -********** - -Manim can be installed via Chocolatey simply by running: - -.. code-block:: powershell - - choco install manimce - -That's it, no further steps required. You can continue with installing -the :ref:`optional dependencies ` below. - -Pip -*** - -As mentioned above, Manim needs a reasonably recent version of -Python 3 (3.9 or above). - -**Python:** Head over to https://www.python.org, download an installer -for a recent version of Python, and follow its instructions to get Python -installed on your system. - -.. note:: - - We have received reports of problems caused by using the version of - Python that can be installed from the Windows Store. At this point, - we recommend staying away from the Windows Store version. Instead, - install Python directly from the - `official website `__. - -Then, Manim can be installed via Pip simply by running: - -.. code-block:: powershell - - python -m pip install manim - -Manim should now be installed on your system. Continue reading -the :ref:`optional dependencies ` section -below. - - -.. _win-optional-dependencies: - -Optional Dependencies ---------------------- - -In order to make use of Manim's interface to LaTeX to, for example, render -equations, LaTeX has to be installed as well. Note that this is an optional -dependency: if you don't intend to use LaTeX, you don't have to install it. - -For Windows, the recommended LaTeX distribution is -`MiKTeX `__. You can install it by using the -installer from the linked MiKTeX site, or by using the package manager -of your choice (Chocolatey: ``choco install miktex.install``, -Scoop: ``scoop install latex``, Winget: ``winget install MiKTeX.MiKTeX``). - -If you are concerned about disk space, there are some alternative, -smaller distributions of LaTeX. - -**Using Chocolatey:** If you used Chocolatey to install manim or are already -a chocolatey user, then you can simply run ``choco install manim-latex``. It -is a dedicated package for Manim based on TinyTeX which contains all the -required packages that Manim interacts with. - -**Manual Installation:** -You can also use `TinyTeX `__ (Chocolatey: ``choco install tinytex``, -Scoop: first ``scoop bucket add r-bucket https://github.com/cderv/r-bucket.git``, -then ``scoop install tinytex``) alternative installation instructions can be found at their website. -Keep in mind that you will have to manage the LaTeX packages installed on your system yourself via ``tlmgr``. -Therefore we only recommend this option if you know what you are doing. - -The full list of LaTeX packages which Manim interacts with in some way -(a subset might be sufficient for your particular application) are:: - - amsmath babel-english cbfonts-fd cm-super ctex doublestroke dvisvgm everysel - fontspec frcursive fundus-calligra gnu-freefont jknapltx latex-bin - mathastext microtype ms physics preview ragged2e relsize rsfs - setspace standalone tipa wasy wasysym xcolor xetex xkeyval - - - -Working with Manim ------------------- - -At this point, you should have a working installation of Manim, head -over to our :doc:`Quickstart Tutorial <../tutorials/quickstart>` to learn -how to make your own *Manimations*! diff --git a/docs/source/plugins.rst b/docs/source/plugins.rst index c4c631b655..7bd8c0061c 100644 --- a/docs/source/plugins.rst +++ b/docs/source/plugins.rst @@ -106,7 +106,7 @@ specified in Poetry as: [tool.poetry.plugins."manim.plugins"] "name" = "object_reference" -.. versionremoved:: 0.19.0 +.. versionremoved:: 0.18.1 Plugins should be imported explicitly to be usable in user code. The plugin system will probably be refactored in the future to provide a more structured diff --git a/docs/source/reference_index/utilities_misc.rst b/docs/source/reference_index/utilities_misc.rst index 1fe9962079..874a20ef86 100644 --- a/docs/source/reference_index/utilities_misc.rst +++ b/docs/source/reference_index/utilities_misc.rst @@ -10,6 +10,7 @@ Module Index :toctree: ../reference ~utils.bezier + cli ~utils.color ~utils.commands ~utils.config_ops diff --git a/docs/source/tutorials/quickstart.rst b/docs/source/tutorials/quickstart.rst index 84df97b8af..6f419aa029 100644 --- a/docs/source/tutorials/quickstart.rst +++ b/docs/source/tutorials/quickstart.rst @@ -3,12 +3,22 @@ Quickstart ========== .. note:: - Before proceeding, install Manim and make sure it's running properly by - following the steps in :doc:`../installation`. For - information on using Manim with Jupyterlab or Jupyter notebook, go to the - documentation for the - :meth:`IPython magic command `, - ``%%manim``. + + Before proceeding, install Manim and make sure it is running properly by + following the steps in :doc:`../installation`. For + information on using Manim with Jupyterlab or Jupyter notebook, go to the + documentation for the + :meth:`IPython magic command `, + ``%%manim``. + + +.. important:: + + If you installed Manim in the recommended way, using the + Python management tool ``uv``, then you either need to make sure the corresponding + virtual environment is activated (follow the instructions printed on running ``uv venv``), + or you need to remember to prefix the ``manim`` command in the console with ``uv run``; + that is, ``uv run manim ...``. Overview ******** @@ -28,45 +38,38 @@ use to modify ``Mobject``\s. Starting a new project ********************** -Start by creating a new folder. For the purposes of this guide, name the folder ``project``: +Start by creating a new folder:: -.. code-block:: bash + manim init project my-project --default - project/ - -This folder is the root folder for your project. It contains all the files that Manim needs to function, +The ``my-project`` folder is the root folder for your project. It contains all the files that Manim needs to function, as well as any output that your project produces. Animating a circle ****************** -1. Open a text editor, such as Notepad. Copy the following code snippet into the window: +1. Open a text editor, such as Notepad. Open the file ``main.py`` in the ``my-project`` folder. + It should look something like this: -.. code-block:: python + .. code-block:: python - from manim import * + from manim import * - class CreateCircle(Scene): - def construct(self): - circle = Circle() # create a circle - circle.set_fill(PINK, opacity=0.5) # set the color and transparency - self.play(Create(circle)) # show the circle on screen + class CreateCircle(Scene): + def construct(self): + circle = Circle() # create a circle + circle.set_fill(PINK, opacity=0.5) # set the color and transparency + self.play(Create(circle)) # show the circle on screen -2. Save the code snippet into your project folder with the name ``scene.py``. -.. code-block:: bash - - project/ - └─scene.py +2. Open the command line, navigate to your project folder, and execute + the following command: -3. Open the command line, navigate to your project folder, and execute -the following command: - -.. code-block:: bash + .. code-block:: bash - manim -pql scene.py CreateCircle + manim -pql main.py CreateCircle Manim will output rendering information, then create an MP4 file. Your default movie player will play the MP4 file, displaying the following animation. diff --git a/example_scenes/advanced_tex_fonts.py b/example_scenes/advanced_tex_fonts.py index 63edb06039..d8d7486ff9 100644 --- a/example_scenes/advanced_tex_fonts.py +++ b/example_scenes/advanced_tex_fonts.py @@ -23,7 +23,8 @@ def FrenchCursive(*tex_strings, **kwargs): class TexFontTemplateManual(Scene): """An example scene that uses a manually defined TexTemplate() object to create - LaTeX output in French Cursive font""" + LaTeX output in French Cursive font + """ def construct(self): self.add(Tex("Tex Font Example").to_edge(UL)) diff --git a/example_scenes/opengl.py b/example_scenes/opengl.py index 27f579a6e4..baa59899cf 100644 --- a/example_scenes/opengl.py +++ b/example_scenes/opengl.py @@ -2,7 +2,7 @@ import manim.utils.opengl as opengl from manim import * -from manim.opengl import * # type: ignore +from manim.opengl import * # Copied from https://3b1b.github.io/manim/getting_started/example_scenes.html#surfaceexample. # Lines that do not yet work with the Community Version are commented. diff --git a/manim/__main__.py b/manim/__main__.py index f05f4c2971..572053bf08 100644 --- a/manim/__main__.py +++ b/manim/__main__.py @@ -3,22 +3,49 @@ import click import cloup -from . import __version__, cli_ctx_settings, console -from .cli.cfg.group import cfg -from .cli.checkhealth.commands import checkhealth -from .cli.default_group import DefaultGroup -from .cli.init.commands import init -from .cli.plugins.commands import plugins -from .cli.render.commands import render -from .constants import EPILOG +from manim import __version__ +from manim._config import cli_ctx_settings, console +from manim.cli.cfg.group import cfg +from manim.cli.checkhealth.commands import checkhealth +from manim.cli.default_group import DefaultGroup +from manim.cli.init.commands import init +from manim.cli.plugins.commands import plugins +from manim.cli.render.commands import render +from manim.constants import EPILOG -def show_splash(ctx, param, value): +def show_splash(ctx: click.Context, param: click.Option, value: str | None) -> None: + """When giving a value by console, show an initial message with the Manim + version before executing any other command: ``Manim Community vA.B.C``. + + Parameters + ---------- + ctx + The Click context. + param + A Click option. + value + A string value given by console, or None. + """ if value: console.print(f"Manim Community [green]v{__version__}[/green]\n") -def print_version_and_exit(ctx, param, value): +def print_version_and_exit( + ctx: click.Context, param: click.Option, value: str | None +) -> None: + """Same as :func:`show_splash`, but also exit when giving a value by + console. + + Parameters + ---------- + ctx + The Click context. + param + A Click option. + value + A string value given by console, or None. + """ show_splash(ctx, param, value) if value: ctx.exit() @@ -53,8 +80,14 @@ def print_version_and_exit(ctx, param, value): expose_value=False, ) @cloup.pass_context -def main(ctx): - """The entry point for manim.""" +def main(ctx: click.Context) -> None: + """The entry point for Manim. + + Parameters + ---------- + ctx + The Click context. + """ pass diff --git a/manim/_config/cli_colors.py b/manim/_config/cli_colors.py index c39f24d716..5b1d151bdb 100644 --- a/manim/_config/cli_colors.py +++ b/manim/_config/cli_colors.py @@ -1,13 +1,14 @@ from __future__ import annotations import configparser +from typing import Any from cloup import Context, HelpFormatter, HelpTheme, Style __all__ = ["parse_cli_ctx"] -def parse_cli_ctx(parser: configparser.SectionProxy) -> Context: +def parse_cli_ctx(parser: configparser.SectionProxy) -> dict[str, Any]: formatter_settings: dict[str, str | int] = { "indent_increment": int(parser["indent_increment"]), "width": int(parser["width"]), diff --git a/manim/_config/logger_utils.py b/manim/_config/logger_utils.py index f3b43f8f78..9205635eef 100644 --- a/manim/_config/logger_utils.py +++ b/manim/_config/logger_utils.py @@ -99,6 +99,7 @@ def make_logger( logger = logging.getLogger("manim") logger.addHandler(rich_handler) logger.setLevel(verbosity) + logger.propagate = False if not (libav_logger := logging.getLogger()).hasHandlers(): libav_logger.addHandler(rich_handler) diff --git a/manim/_config/utils.py b/manim/_config/utils.py index 0316311778..b453b290e2 100644 --- a/manim/_config/utils.py +++ b/manim/_config/utils.py @@ -40,6 +40,8 @@ __all__ = ["config_file_paths", "make_config_parser", "ManimConfig", "ManimFrame"] +logger = logging.getLogger("manim") + def config_file_paths() -> list[Path]: """The paths where ``.cfg`` files will be searched for. @@ -321,7 +323,7 @@ class MyScene(Scene): ... } def __init__(self) -> None: - self._d: dict[str, Any | None] = {k: None for k in self._OPTS} + self._d: dict[str, Any | None] = dict.fromkeys(self._OPTS) # behave like a dict def __iter__(self) -> Iterator[str]: @@ -370,7 +372,6 @@ def update(self, obj: ManimConfig | dict[str, Any]) -> None: # type: ignore[ove :meth:`~ManimConfig.digest_parser` """ - if isinstance(obj, ManimConfig): self._d.update(obj._d) if obj.tex_template: @@ -641,21 +642,18 @@ def digest_parser(self, parser: configparser.ConfigParser) -> Self: gui_location = tuple( map(int, re.split(r"[;,\-]", parser["CLI"]["gui_location"])), ) - setattr(self, "gui_location", gui_location) + self.gui_location = gui_location window_size = parser["CLI"][ "window_size" ] # if not "default", get a tuple of the position if window_size != "default": window_size = tuple(map(int, re.split(r"[;,\-]", window_size))) - setattr(self, "window_size", window_size) + self.window_size = window_size # plugins plugins = parser["CLI"].get("plugins", fallback="", raw=True) - if plugins == "": - plugins = [] - else: - plugins = plugins.split(",") + plugins = [] if plugins == "" else plugins.split(",") self.plugins = plugins # the next two must be set AFTER digesting pixel_width and pixel_height self["frame_height"] = parser["CLI"].getfloat("frame_height", 8.0) @@ -672,7 +670,7 @@ def digest_parser(self, parser: configparser.ConfigParser) -> Self: val = parser["CLI"].get("progress_bar") if val: - setattr(self, "progress_bar", val) + self.progress_bar = val val = parser["ffmpeg"].get("loglevel") if val: @@ -682,11 +680,11 @@ def digest_parser(self, parser: configparser.ConfigParser) -> Self: val = parser["jupyter"].getboolean("media_embed") except ValueError: val = None - setattr(self, "media_embed", val) + self.media_embed = val val = parser["jupyter"].get("media_width") if val: - setattr(self, "media_width", val) + self.media_width = val val = parser["CLI"].get("quality", fallback="", raw=True) if val: @@ -799,7 +797,7 @@ def digest_args(self, args: argparse.Namespace) -> Self: try: self.upto_animation_number = nflag[1] except Exception: - logging.getLogger("manim").info( + logger.info( f"No end scene number specified in -n option. Rendering from {nflag[0]} onwards...", ) @@ -837,15 +835,12 @@ def digest_args(self, args: argparse.Namespace) -> Self: if args.tex_template: self.tex_template = TexTemplate.from_file(args.tex_template) - if ( - self.renderer == RendererType.OPENGL - and getattr(args, "write_to_movie") is None - ): + if self.renderer == RendererType.OPENGL and args.write_to_movie is None: # --write_to_movie was not passed on the command line, so don't generate video. self["write_to_movie"] = False # Handle --gui_location flag. - if getattr(args, "gui_location") is not None: + if args.gui_location is not None: self.gui_location = args.gui_location return self @@ -1038,7 +1033,7 @@ def verbosity(self, val: str) -> None: val, ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"], ) - logging.getLogger("manim").setLevel(val) + logger.setLevel(val) @property def format(self) -> str: @@ -1052,8 +1047,9 @@ def format(self, val: str) -> None: val, [None, "png", "gif", "mp4", "mov", "webm"], ) + self.resolve_movie_file_extension(self.transparent) if self.format == "webm": - logging.getLogger("manim").warning( + logger.warning( "Output format set as webm, this can be slower than other formats", ) @@ -1271,6 +1267,8 @@ def background_opacity(self) -> float: @background_opacity.setter def background_opacity(self, value: float) -> None: self._set_between("background_opacity", value, 0, 1) + if self.background_opacity < 1: + self.resolve_movie_file_extension(is_transparent=True) @property def frame_size(self) -> tuple[int, int]: @@ -1305,8 +1303,8 @@ def quality(self, value: str | None) -> None: @property def transparent(self) -> bool: - """Whether the background opacity is 0.0 (-t).""" - return self._d["background_opacity"] == 0.0 + """Whether the background opacity is less than 1.0 (-t).""" + return self._d["background_opacity"] < 1.0 @transparent.setter def transparent(self, value: bool) -> None: @@ -1424,6 +1422,7 @@ def window_size(self, value: str) -> None: self._d.__setitem__("window_size", value) def resolve_movie_file_extension(self, is_transparent: bool) -> None: + prev_file_extension = self.movie_file_extension if is_transparent: self.movie_file_extension = ".webm" if self.format == "webm" else ".mov" elif self.format == "webm": @@ -1432,6 +1431,11 @@ def resolve_movie_file_extension(self, is_transparent: bool) -> None: self.movie_file_extension = ".mov" else: self.movie_file_extension = ".mp4" + if self.movie_file_extension != prev_file_extension: + logger.warning( + f"Output format changed to '{self.movie_file_extension}' " + "to support transparency", + ) @property def enable_gui(self) -> bool: @@ -1777,7 +1781,7 @@ def tex_template_file(self) -> Path: def tex_template_file(self, val: str) -> None: if val: if not os.access(val, os.R_OK): - logging.getLogger("manim").warning( + logger.warning( f"Custom TeX template {val} not found or not readable.", ) else: diff --git a/manim/animation/animation.py b/manim/animation/animation.py index 042054b7ba..491d573740 100644 --- a/manim/animation/animation.py +++ b/manim/animation/animation.py @@ -7,16 +7,17 @@ from .. import config, logger from ..constants import RendererType from ..mobject import mobject -from ..mobject.mobject import Mobject +from ..mobject.mobject import Group, Mobject from ..mobject.opengl import opengl_mobject from ..utils.rate_functions import linear, smooth -__all__ = ["Animation", "Wait", "override_animation"] +__all__ = ["Animation", "Wait", "Add", "override_animation"] from collections.abc import Iterable, Sequence from copy import deepcopy -from typing import TYPE_CHECKING, Callable +from functools import partialmethod +from typing import TYPE_CHECKING, Any, Callable from typing_extensions import Self @@ -171,6 +172,19 @@ def __init__( ), ) + @property + def run_time(self) -> float: + return self._run_time + + @run_time.setter + def run_time(self, value: float) -> None: + if value < 0: + raise ValueError( + f"The run_time of {self.__class__.__name__} cannot be " + f"negative. The given value was {value}." + ) + self._run_time = value + def _typecheck_input(self, mobject: Mobject | None) -> None: if mobject is None: logger.debug("Animation with empty mobject") @@ -479,6 +493,52 @@ def is_introducer(self) -> bool: """ return self.introducer + @classmethod + def __init_subclass__(cls, **kwargs) -> None: + super().__init_subclass__(**kwargs) + + cls._original__init__ = cls.__init__ + + @classmethod + def set_default(cls, **kwargs) -> None: + """Sets the default values of keyword arguments. + + If this method is called without any additional keyword + arguments, the original default values of the initialization + method of this class are restored. + + Parameters + ---------- + + kwargs + Passing any keyword argument will update the default + values of the keyword arguments of the initialization + function of this class. + + Examples + -------- + + .. manim:: ChangeDefaultAnimation + + class ChangeDefaultAnimation(Scene): + def construct(self): + Rotate.set_default(run_time=2, rate_func=rate_functions.linear) + Indicate.set_default(color=None) + + S = Square(color=BLUE, fill_color=BLUE, fill_opacity=0.25) + self.add(S) + self.play(Rotate(S, PI)) + self.play(Indicate(S)) + + Rotate.set_default() + Indicate.set_default() + + """ + if kwargs: + cls.__init__ = partialmethod(cls.__init__, **kwargs) + else: + cls.__init__ = cls._original__init__ + def prepare_animation( anim: Animation | mobject._AnimationBuilder, @@ -578,6 +638,90 @@ def interpolate(self, alpha: float) -> None: pass +class Add(Animation): + """Add Mobjects to a scene, without animating them in any other way. This + is similar to the :meth:`.Scene.add` method, but :class:`Add` is an + animation which can be grouped into other animations. + + Parameters + ---------- + mobjects + One :class:`~.Mobject` or more to add to a scene. + run_time + The duration of the animation after adding the ``mobjects``. Defaults + to 0, which means this is an instant animation without extra wait time + after adding them. + **kwargs + Additional arguments to pass to the parent :class:`Animation` class. + + Examples + -------- + + .. manim:: DefaultAddScene + + class DefaultAddScene(Scene): + def construct(self): + text_1 = Text("I was added with Add!") + text_2 = Text("Me too!") + text_3 = Text("And me!") + texts = VGroup(text_1, text_2, text_3).arrange(DOWN) + rect = SurroundingRectangle(texts, buff=0.5) + + self.play( + Create(rect, run_time=3.0), + Succession( + Wait(1.0), + # You can Add a Mobject in the middle of an animation... + Add(text_1), + Wait(1.0), + # ...or multiple Mobjects at once! + Add(text_2, text_3), + ), + ) + self.wait() + + .. manim:: AddWithRunTimeScene + + class AddWithRunTimeScene(Scene): + def construct(self): + # A 5x5 grid of circles + circles = VGroup( + *[Circle(radius=0.5) for _ in range(25)] + ).arrange_in_grid(5, 5) + + self.play( + Succession( + # Add a run_time of 0.2 to wait for 0.2 seconds after + # adding the circle, instead of using Wait(0.2) after Add! + *[Add(circle, run_time=0.2) for circle in circles], + rate_func=smooth, + ) + ) + self.wait() + """ + + def __init__( + self, *mobjects: Mobject, run_time: float = 0.0, **kwargs: Any + ) -> None: + mobject = mobjects[0] if len(mobjects) == 1 else Group(*mobjects) + super().__init__(mobject, run_time=run_time, introducer=True, **kwargs) + + def begin(self) -> None: + pass + + def finish(self) -> None: + pass + + def clean_up_from_scene(self, scene: Scene) -> None: + pass + + def update_mobjects(self, dt: float) -> None: + pass + + def interpolate(self, alpha: float) -> None: + pass + + def override_animation( animation_class: type[Animation], ) -> Callable[[Callable], Callable]: diff --git a/manim/animation/composition.py b/manim/animation/composition.py index c5a756502f..1391dbfd1b 100644 --- a/manim/animation/composition.py +++ b/manim/animation/composition.py @@ -87,7 +87,6 @@ def begin(self) -> None: f"Trying to play {self} without animations, this is not supported. " "Please add at least one subanimation." ) - self.anim_group_time = 0.0 if self.suspend_mobject_updating: self.group.suspend_updating() @@ -175,11 +174,13 @@ def interpolate(self, alpha: float) -> None: ] run_times = to_update["end"] - to_update["start"] + with_zero_run_time = run_times == 0 + run_times[with_zero_run_time] = 1 sub_alphas = (anim_group_time - to_update["start"]) / run_times if time_goes_back: - sub_alphas[sub_alphas < 0] = 0 + sub_alphas[(sub_alphas < 0) | with_zero_run_time] = 0 else: - sub_alphas[sub_alphas > 1] = 1 + sub_alphas[(sub_alphas > 1) | with_zero_run_time] = 1 for anim_to_update, sub_alpha in zip(to_update["anim"], sub_alphas): anim_to_update.interpolate(sub_alpha) diff --git a/manim/animation/creation.py b/manim/animation/creation.py index e6f7199bf2..dc3ec69527 100644 --- a/manim/animation/creation.py +++ b/manim/animation/creation.py @@ -250,7 +250,9 @@ def __init__( def _typecheck_input(self, vmobject: VMobject | OpenGLVMobject) -> None: if not isinstance(vmobject, (VMobject, OpenGLVMobject)): - raise TypeError("DrawBorderThenFill only works for vectorized Mobjects") + raise TypeError( + f"{self.__class__.__name__} only works for vectorized Mobjects" + ) def begin(self) -> None: self.outline = self.get_outline() @@ -281,7 +283,7 @@ def interpolate_submobject( alpha: float, ) -> None: # Fixme: not matching the parent class? What is outline doing here? index: int - subalpha: int + subalpha: float index, subalpha = integer_interpolate(0, 2, alpha) if index == 0: submobject.pointwise_become_partial(outline, 0, subalpha) @@ -351,10 +353,7 @@ def _set_default_config_from_length( ) -> tuple[float, float]: length = len(vmobject.family_members_with_points()) if run_time is None: - if length < 15: - run_time = 1 - else: - run_time = 2 + run_time = 1 if length < 15 else 2 if lag_ratio is None: lag_ratio = min(4.0 / max(1.0, length), 0.2) return run_time, lag_ratio diff --git a/manim/animation/fading.py b/manim/animation/fading.py index 1e98b2c295..f99eebe4cf 100644 --- a/manim/animation/fading.py +++ b/manim/animation/fading.py @@ -57,10 +57,7 @@ def __init__( ) -> None: if not mobjects: raise ValueError("At least one mobject must be passed.") - if len(mobjects) == 1: - mobject = mobjects[0] - else: - mobject = Group(*mobjects) + mobject = mobjects[0] if len(mobjects) == 1 else Group(*mobjects) self.point_target = False if shift is None: @@ -97,7 +94,7 @@ def _create_faded_mobject(self, fadeIn: bool) -> Mobject: class FadeIn(_Fade): - """Fade in :class:`~.Mobject` s. + r"""Fade in :class:`~.Mobject` s. Parameters ---------- @@ -122,7 +119,7 @@ def construct(self): dot = Dot(UP * 2 + LEFT) self.add(dot) tex = Tex( - "FadeIn with ", "shift ", " or target\\_position", " and scale" + "FadeIn with ", "shift ", r" or target\_position", " and scale" ).scale(1) animations = [ FadeIn(tex[0]), @@ -145,7 +142,7 @@ def create_starting_mobject(self): class FadeOut(_Fade): - """Fade out :class:`~.Mobject` s. + r"""Fade out :class:`~.Mobject` s. Parameters ---------- diff --git a/manim/animation/indication.py b/manim/animation/indication.py index 89bf506ebe..f931491b37 100644 --- a/manim/animation/indication.py +++ b/manim/animation/indication.py @@ -270,7 +270,7 @@ def create_line_anims(self) -> Iterable[ShowPassingFlash]: class ShowPassingFlash(ShowPartial): - """Show only a sliver of the VMobject each frame. + r"""Show only a sliver of the VMobject each frame. Parameters ---------- @@ -290,7 +290,7 @@ def construct(self): self.add(p, lbl) p = p.copy().set_color(BLUE) for time_width in [0.2, 0.5, 1, 2]: - lbl.become(Tex(r"\\texttt{time\\_width={{%.1f}}}"%time_width)) + lbl.become(Tex(r"\texttt{time\_width={{%.1f}}}"%time_width)) self.play(ShowPassingFlash( p.copy().set_color(BLUE), run_time=2, @@ -551,7 +551,7 @@ def interpolate_submobject( class Circumscribe(Succession): - """Draw a temporary line surrounding the mobject. + r"""Draw a temporary line surrounding the mobject. Parameters ---------- @@ -582,7 +582,7 @@ class Circumscribe(Succession): class UsingCircumscribe(Scene): def construct(self): - lbl = Tex(r"Circum-\\\\scribe").scale(2) + lbl = Tex(r"Circum-\\scribe").scale(2) self.add(lbl) self.play(Circumscribe(lbl)) self.play(Circumscribe(lbl, Circle)) @@ -608,8 +608,8 @@ def __init__( if shape is Rectangle: frame = SurroundingRectangle( mobject, - color, - buff, + color=color, + buff=buff, stroke_width=stroke_width, ) elif shape is Circle: diff --git a/manim/animation/movement.py b/manim/animation/movement.py index 4533eeeb70..0be7e01c15 100644 --- a/manim/animation/movement.py +++ b/manim/animation/movement.py @@ -90,9 +90,7 @@ class ComplexHomotopy(Homotopy): def __init__( self, complex_homotopy: Callable[[complex], float], mobject: Mobject, **kwargs ) -> None: - """ - Complex Homotopy a function Cx[0, 1] to C - """ + """Complex Homotopy a function Cx[0, 1] to C""" def homotopy( x: float, diff --git a/manim/animation/specialized.py b/manim/animation/specialized.py index 99320f36d9..e5f9e96d96 100644 --- a/manim/animation/specialized.py +++ b/manim/animation/specialized.py @@ -70,10 +70,7 @@ def __init__( anims = [] # Works by saving the mob that is passed into the animation, scaling it to 0 (or the initial_width) and then restoring the original mob. - if mobject.fill_opacity: - fill_o = True - else: - fill_o = False + fill_o = bool(mobject.fill_opacity) for _ in range(self.n_mobs): mob = mobject.copy() diff --git a/manim/animation/transform.py b/manim/animation/transform.py index d4b9941399..a7c62a9e6a 100644 --- a/manim/animation/transform.py +++ b/manim/animation/transform.py @@ -298,9 +298,7 @@ def __init__(self, mobject: Mobject, target_mobject: Mobject, **kwargs) -> None: class TransformFromCopy(Transform): - """ - Performs a reversed Transform - """ + """Performs a reversed Transform""" def __init__(self, mobject: Mobject, target_mobject: Mobject, **kwargs) -> None: super().__init__(target_mobject, mobject, **kwargs) diff --git a/manim/animation/updaters/mobject_update_utils.py b/manim/animation/updaters/mobject_update_utils.py index dee27ff398..213180f3bd 100644 --- a/manim/animation/updaters/mobject_update_utils.py +++ b/manim/animation/updaters/mobject_update_utils.py @@ -178,7 +178,7 @@ def construct(self): def turn_animation_into_updater( - animation: Animation, cycle: bool = False, **kwargs + animation: Animation, cycle: bool = False, delay: float = 0, **kwargs ) -> Mobject: """ Add an updater to the animation's mobject which applies @@ -187,6 +187,8 @@ def turn_animation_into_updater( If cycle is True, this repeats over and over. Otherwise, the updater will be popped upon completion + The ``delay`` parameter is the delay (in seconds) before the animation starts.. + Examples -------- @@ -206,21 +208,22 @@ def construct(self): mobject = animation.mobject animation.suspend_mobject_updating = False animation.begin() - animation.total_time = 0 + animation.total_time = -delay def update(m: Mobject, dt: float): - run_time = animation.get_run_time() - time_ratio = animation.total_time / run_time - if cycle: - alpha = time_ratio % 1 - else: - alpha = np.clip(time_ratio, 0, 1) - if alpha >= 1: - animation.finish() - m.remove_updater(update) - return - animation.interpolate(alpha) - animation.update_mobjects(dt) + if animation.total_time >= 0: + run_time = animation.get_run_time() + time_ratio = animation.total_time / run_time + if cycle: + alpha = time_ratio % 1 + else: + alpha = np.clip(time_ratio, 0, 1) + if alpha >= 1: + animation.finish() + m.remove_updater(update) + return + animation.interpolate(alpha) + animation.update_mobjects(dt) animation.total_time += dt mobject.add_updater(update) diff --git a/manim/camera/camera.py b/manim/camera/camera.py index bf917b7e9e..af5899c5c5 100644 --- a/manim/camera/camera.py +++ b/manim/camera/camera.py @@ -377,7 +377,6 @@ def make_background_from_func( np.array The pixel array which can then be passed to set_background. """ - logger.info("Starting set_background") coords = self.get_coords_of_all_pixels() new_background = np.apply_along_axis(coords_to_colors_func, 2, coords) diff --git a/manim/cli/__init__.py b/manim/cli/__init__.py index e69de29bb2..f1aa512e02 100644 --- a/manim/cli/__init__.py +++ b/manim/cli/__init__.py @@ -0,0 +1,17 @@ +"""The Manim CLI, and the available commands for ``manim``. + +This page is a work in progress. Please run ``manim`` or ``manim --help`` in +your terminal to find more information on the following commands. + +Available commands +------------------ + +.. autosummary:: + :toctree: ../reference + + cfg + checkhealth + init + plugins + render +""" diff --git a/manim/cli/cfg/group.py b/manim/cli/cfg/group.py index 346205d89f..13834311ab 100644 --- a/manim/cli/cfg/group.py +++ b/manim/cli/cfg/group.py @@ -8,24 +8,26 @@ from __future__ import annotations +import contextlib from ast import literal_eval from pathlib import Path +from typing import Any, cast import cloup from rich.errors import StyleSyntaxError from rich.style import Style -from ... import cli_ctx_settings, console -from ..._config.utils import config_file_paths, make_config_parser -from ...constants import EPILOG -from ...utils.file_ops import guarantee_existence, open_file +from manim._config import cli_ctx_settings, console +from manim._config.utils import config_file_paths, make_config_parser +from manim.constants import EPILOG +from manim.utils.file_ops import guarantee_existence, open_file RICH_COLOUR_INSTRUCTIONS: str = """ [red]The default colour is used by the input statement. If left empty, the default colour will be used.[/red] [magenta] For a full list of styles, visit[/magenta] [green]https://rich.readthedocs.io/en/latest/style.html[/green] """ -RICH_NON_STYLE_ENTRIES: str = ["log.width", "log.height", "log.timestamps"] +RICH_NON_STYLE_ENTRIES: list[str] = ["log.width", "log.height", "log.timestamps"] __all__ = [ "value_from_string", @@ -40,7 +42,8 @@ def value_from_string(value: str) -> str | int | bool: - """Extracts the literal of proper datatype from a string. + """Extract the literal of proper datatype from a ``value`` string. + Parameters ---------- value @@ -48,51 +51,60 @@ def value_from_string(value: str) -> str | int | bool: Returns ------- - Union[:class:`str`, :class:`int`, :class:`bool`] - Returns the literal of appropriate datatype. + :class:`str` | :class:`int` | :class:`bool` + The literal of appropriate datatype. """ - try: + with contextlib.suppress(SyntaxError, ValueError): value = literal_eval(value) - except (SyntaxError, ValueError): - pass return value -def _is_expected_datatype(value: str, expected: str, style: bool = False) -> bool: - """Checks whether `value` is the same datatype as `expected`, - and checks if it is a valid `style` if `style` is true. +def _is_expected_datatype( + value: str, expected: str, validate_style: bool = False +) -> bool: + """Check whether the literal from ``value`` is the same datatype as the + literal from ``expected``. If ``validate_style`` is ``True``, also check if + the style given by ``value`` is valid, according to ``rich``. Parameters ---------- value - The string of the value to check (obtained from reading the user input). + The string of the value to check, obtained from reading the user input. expected - The string of the literal datatype must be matched by `value`. Obtained from - reading the cfg file. - style - Whether or not to confirm if `value` is a style, by default False + The string of the literal datatype which must be matched by ``value``. + This is obtained from reading the ``cfg`` file. + validate_style + Whether or not to confirm if ``value`` is a valid style, according to + ``rich``. Default is ``False``. Returns ------- :class:`bool` - Whether or not `value` matches the datatype of `expected`. + Whether or not the literal from ``value`` matches the datatype of the + literal from ``expected``. """ - value = value_from_string(value) - expected = type(value_from_string(expected)) + value_literal = value_from_string(value) + ExpectedLiteralType = type(value_from_string(expected)) - return isinstance(value, expected) and (is_valid_style(value) if style else True) + return isinstance(value_literal, ExpectedLiteralType) and ( + (isinstance(value_literal, str) and is_valid_style(value_literal)) + if validate_style + else True + ) def is_valid_style(style: str) -> bool: - """Checks whether the entered color is a valid color according to rich + """Checks whether the entered color style is valid, according to ``rich``. + Parameters ---------- style The style to check whether it is valid. + Returns ------- - Boolean - Returns whether it is valid style or not according to rich. + :class:`bool` + Whether the color style is valid or not, according to ``rich``. """ try: Style.parse(style) @@ -101,16 +113,20 @@ def is_valid_style(style: str) -> bool: return False -def replace_keys(default: dict) -> dict: - """Replaces _ to . and vice versa in a dictionary for rich +def replace_keys(default: dict[str, Any]) -> dict[str, Any]: + """Replace ``_`` with ``.`` and vice versa in a dictionary's keys for + ``rich``. + Parameters ---------- default - The dictionary to check and replace + The dictionary whose keys will be checked and replaced. + Returns ------- :class:`dict` - The dictionary which is modified by replacing _ with . and vice versa + The dictionary whose keys are modified by replacing ``_`` with ``.`` + and vice versa. """ for key in default: if "_" in key: @@ -134,7 +150,7 @@ def replace_keys(default: dict) -> dict: help="Manages Manim configuration files.", ) @cloup.pass_context -def cfg(ctx): +def cfg(ctx: cloup.Context) -> None: """Responsible for the cfg subcommand.""" pass @@ -148,7 +164,7 @@ def cfg(ctx): help="Specify if this config is for user or the working directory.", ) @cloup.option("-o", "--open", "openfile", is_flag=True) -def write(level: str = None, openfile: bool = False) -> None: +def write(level: str | None = None, openfile: bool = False) -> None: config_paths = config_file_paths() console.print( "[yellow bold]Manim Configuration File Writer[/yellow bold]", @@ -167,7 +183,7 @@ def write(level: str = None, openfile: bool = False) -> None: action = "save this as" for category in parser: console.print(f"{category}", style="bold green underline") - default = parser[category] + default = cast(dict[str, Any], parser[category]) if category == "logger": console.print(RICH_COLOUR_INSTRUCTIONS) default = replace_keys(default) @@ -197,7 +213,7 @@ def write(level: str = None, openfile: bool = False) -> None: """Not enough values in input. You may have added a new entry to default.cfg, in which case you will have to modify write_cfg_subcmd_input to account for it.""", - ) + ) from None if temp: while temp and not _is_expected_datatype( temp, @@ -250,7 +266,7 @@ def write(level: str = None, openfile: bool = False) -> None: @cfg.command(context_settings=cli_ctx_settings) -def show(): +def show() -> None: parser = make_config_parser() rich_non_style_entries = [a.replace(".", "_") for a in RICH_NON_STYLE_ENTRIES] for category in parser: @@ -270,7 +286,7 @@ def show(): @cfg.command(context_settings=cli_ctx_settings) @cloup.option("-d", "--directory", default=Path.cwd()) @cloup.pass_context -def export(ctx, directory): +def export(ctx: cloup.Context, directory: str) -> None: directory_path = Path(directory) if directory_path.absolute == Path.cwd().absolute: console.print( diff --git a/manim/cli/checkhealth/checks.py b/manim/cli/checkhealth/checks.py index dfc5f231a4..ec9c07dec7 100644 --- a/manim/cli/checkhealth/checks.py +++ b/manim/cli/checkhealth/checks.py @@ -1,62 +1,79 @@ """Auxiliary module for the checkhealth subcommand, contains -the actual check implementations.""" +the actual check implementations. +""" from __future__ import annotations import os import shutil -from typing import Callable +from typing import Callable, Protocol, cast __all__ = ["HEALTH_CHECKS"] -HEALTH_CHECKS = [] + +class HealthCheckFunction(Protocol): + description: str + recommendation: str + skip_on_failed: list[str] + post_fail_fix_hook: Callable[..., object] | None + __name__: str + + def __call__(self) -> bool: ... + + +HEALTH_CHECKS: list[HealthCheckFunction] = [] def healthcheck( description: str, recommendation: str, - skip_on_failed: list[Callable | str] | None = None, - post_fail_fix_hook: Callable | None = None, -): + skip_on_failed: list[HealthCheckFunction | str] | None = None, + post_fail_fix_hook: Callable[..., object] | None = None, +) -> Callable[[Callable[[], bool]], HealthCheckFunction]: """Decorator used for declaring health checks. - This decorator attaches some data to a function, - which is then added to a list containing all checks. + This decorator attaches some data to a function, which is then added to a + a list containing all checks. Parameters ---------- description - A brief description of this check, displayed when - the checkhealth subcommand is run. + A brief description of this check, displayed when the ``checkhealth`` + subcommand is run. recommendation Help text which is displayed in case the check fails. skip_on_failed - A list of check functions which, if they fail, cause - the current check to be skipped. + A list of check functions which, if they fail, cause the current check + to be skipped. post_fail_fix_hook - A function that is supposed to (interactively) help - to fix the detected problem, if possible. This is - only called upon explicit confirmation of the user. + A function that is meant to (interactively) help to fix the detected + problem, if possible. This is only called upon explicit confirmation of + the user. Returns ------- - A check function, as required by the checkhealth subcommand. + Callable[Callable[[], bool], :class:`HealthCheckFunction`] + A decorator which converts a function into a health check function, as + required by the ``checkhealth`` subcommand. """ + new_skip_on_failed: list[str] if skip_on_failed is None: - skip_on_failed = [] - skip_on_failed = [ - skip.__name__ if callable(skip) else skip for skip in skip_on_failed - ] + new_skip_on_failed = [] + else: + new_skip_on_failed = [ + skip.__name__ if callable(skip) else skip for skip in skip_on_failed + ] - def decorator(func): - func.description = description - func.recommendation = recommendation - func.skip_on_failed = skip_on_failed - func.post_fail_fix_hook = post_fail_fix_hook - HEALTH_CHECKS.append(func) - return func + def wrapper(func: Callable[[], bool]) -> HealthCheckFunction: + health_func = cast(HealthCheckFunction, func) + health_func.description = description + health_func.recommendation = recommendation + health_func.skip_on_failed = new_skip_on_failed + health_func.post_fail_fix_hook = post_fail_fix_hook + HEALTH_CHECKS.append(health_func) + return health_func - return decorator + return wrapper @healthcheck( @@ -74,7 +91,14 @@ def decorator(func): "PATH variable." ), ) -def is_manim_on_path(): +def is_manim_on_path() -> bool: + """Check whether ``manim`` is in ``PATH``. + + Returns + ------- + :class:`bool` + Whether ``manim`` is in ``PATH`` or not. + """ path_to_manim = shutil.which("manim") return path_to_manim is not None @@ -90,10 +114,30 @@ def is_manim_on_path(): ), skip_on_failed=[is_manim_on_path], ) -def is_manim_executable_associated_to_this_library(): +def is_manim_executable_associated_to_this_library() -> bool: + """Check whether the ``manim`` executable in ``PATH`` is associated to this + library. To verify this, the executable should look like this: + + .. code-block:: python + + #!/.../python + import sys + from manim.__main__ import main + + if __name__ == "__main__": + sys.exit(main()) + + + Returns + ------- + :class:`bool` + Whether the ``manim`` executable in ``PATH`` is associated to this + library or not. + """ path_to_manim = shutil.which("manim") - with open(path_to_manim, "rb") as f: - manim_exec = f.read() + assert path_to_manim is not None + with open(path_to_manim, "rb") as manim_binary: + manim_exec = manim_binary.read() # first condition below corresponds to the executable being # some sort of python script. second condition happens when @@ -113,7 +157,14 @@ def is_manim_executable_associated_to_this_library(): "LaTeX distribution on your operating system." ), ) -def is_latex_available(): +def is_latex_available() -> bool: + """Check whether ``latex`` is in ``PATH`` and can be executed. + + Returns + ------- + :class:`bool` + Whether ``latex`` is in ``PATH`` and can be executed or not. + """ path_to_latex = shutil.which("latex") return path_to_latex is not None and os.access(path_to_latex, os.X_OK) @@ -128,6 +179,13 @@ def is_latex_available(): ), skip_on_failed=[is_latex_available], ) -def is_dvisvgm_available(): +def is_dvisvgm_available() -> bool: + """Check whether ``dvisvgm`` is in ``PATH`` and can be executed. + + Returns + ------- + :class:`bool` + Whether ``dvisvgm`` is in ``PATH`` and can be executed or not. + """ path_to_dvisvgm = shutil.which("dvisvgm") return path_to_dvisvgm is not None and os.access(path_to_dvisvgm, os.X_OK) diff --git a/manim/cli/checkhealth/commands.py b/manim/cli/checkhealth/commands.py index d6873755f2..3750f63d4f 100644 --- a/manim/cli/checkhealth/commands.py +++ b/manim/cli/checkhealth/commands.py @@ -6,11 +6,12 @@ from __future__ import annotations import sys +import timeit import click import cloup -from .checks import HEALTH_CHECKS +from manim.cli.checkhealth.checks import HEALTH_CHECKS, HealthCheckFunction __all__ = ["checkhealth"] @@ -18,13 +19,13 @@ @cloup.command( context_settings=None, ) -def checkhealth(): +def checkhealth() -> None: """This subcommand checks whether Manim is installed correctly and has access to its required (and optional) system dependencies. """ click.echo(f"Python executable: {sys.executable}\n") click.echo("Checking whether your installation of Manim Community is healthy...") - failed_checks = [] + failed_checks: list[HealthCheckFunction] = [] for check in HEALTH_CHECKS: click.echo(f"- {check.description} ... ", nl=False) @@ -62,7 +63,7 @@ def checkhealth(): import manim as mn class CheckHealthDemo(mn.Scene): - def construct(self): + def _inner_construct(self) -> None: banner = mn.ManimBanner().shift(mn.UP * 0.5) self.play(banner.create()) self.wait(0.5) @@ -79,5 +80,11 @@ def construct(self): mn.FadeOut(text_tex_group, shift=mn.DOWN), ) + def construct(self) -> None: + self.execution_time = timeit.timeit(self._inner_construct, number=1) + with mn.tempconfig({"preview": True, "disable_caching": True}): - CheckHealthDemo().render() + scene = CheckHealthDemo() + scene.render() + + click.echo(f"Scene rendered in {scene.execution_time:.2f} seconds.") diff --git a/manim/cli/default_group.py b/manim/cli/default_group.py index f4c8c33dbb..579a3e3a05 100644 --- a/manim/cli/default_group.py +++ b/manim/cli/default_group.py @@ -6,70 +6,192 @@ This is a vendored version of https://github.com/click-contrib/click-default-group/ under the BSD 3-Clause "New" or "Revised" License. - This library isn't used as a dependency as we need to inherit from ``cloup.Group`` instead - of ``click.Group``. + This library isn't used as a dependency, as we need to inherit from + :class:`cloup.Group` instead of :class:`click.Group`. """ from __future__ import annotations import warnings +from typing import TYPE_CHECKING, Any, Callable import cloup +from manim.utils.deprecation import deprecated + __all__ = ["DefaultGroup"] +if TYPE_CHECKING: + from click import Command, Context + class DefaultGroup(cloup.Group): - """Invokes a subcommand marked with ``default=True`` if any subcommand not + """Invokes a subcommand marked with ``default=True`` if any subcommand is not chosen. + + Parameters + ---------- + *args + Positional arguments to forward to :class:`cloup.Group`. + **kwargs + Keyword arguments to forward to :class:`cloup.Group`. The keyword + ``ignore_unknown_options`` must be set to ``False``. + + Attributes + ---------- + default_cmd_name : str | None + The name of the default command, if specified through the ``default`` + keyword argument. Otherwise, this is set to ``None``. + default_if_no_args : bool + Whether to include or not the default command, if no command arguments + are supplied. This can be specified through the ``default_if_no_args`` + keyword argument. Default is ``False``. """ - def __init__(self, *args, **kwargs): + def __init__(self, *args: Any, **kwargs: Any): # To resolve as the default command. if not kwargs.get("ignore_unknown_options", True): raise ValueError("Default group accepts unknown options") self.ignore_unknown_options = True - self.default_cmd_name = kwargs.pop("default", None) - self.default_if_no_args = kwargs.pop("default_if_no_args", False) + self.default_cmd_name: str | None = kwargs.pop("default", None) + self.default_if_no_args: bool = kwargs.pop("default_if_no_args", False) super().__init__(*args, **kwargs) - def set_default_command(self, command): - """Sets a command function as the default command.""" + def set_default_command(self, command: Command) -> None: + """Sets a command function as the default command. + + Parameters + ---------- + command + The command to set as default. + """ cmd_name = command.name self.add_command(command) self.default_cmd_name = cmd_name - def parse_args(self, ctx, args): - if not args and self.default_if_no_args: + def parse_args(self, ctx: Context, args: list[str]) -> list[str]: + """Parses the list of ``args`` by forwarding it to + :meth:`cloup.Group.parse_args`. Before doing so, if + :attr:`default_if_no_args` is set to ``True`` and ``args`` is empty, + this function appends to it the name of the default command specified + by :attr:`default_cmd_name`. + + Parameters + ---------- + ctx + The Click context. + args + A list of arguments. If it's empty and :attr:`default_if_no_args` + is ``True``, append the name of the default command to it. + + Returns + ------- + list[str] + The parsed arguments. + """ + if not args and self.default_if_no_args and self.default_cmd_name: args.insert(0, self.default_cmd_name) - return super().parse_args(ctx, args) - - def get_command(self, ctx, cmd_name): - if cmd_name not in self.commands: + parsed_args: list[str] = super().parse_args(ctx, args) + return parsed_args + + def get_command(self, ctx: Context, cmd_name: str) -> Command | None: + """Get a command function by its name, by forwarding the arguments to + :meth:`cloup.Group.get_command`. If ``cmd_name`` does not match any of + the command names in :attr:`commands`, attempt to get the default command + instead. + + Parameters + ---------- + ctx + The Click context. + cmd_name + The name of the command to get. + + Returns + ------- + :class:`click.Command` | None + The command, if found. Otherwise, ``None``. + """ + if cmd_name not in self.commands and self.default_cmd_name: # No command name matched. - ctx.arg0 = cmd_name + ctx.meta["arg0"] = cmd_name cmd_name = self.default_cmd_name return super().get_command(ctx, cmd_name) - def resolve_command(self, ctx, args): - base = super() - cmd_name, cmd, args = base.resolve_command(ctx, args) - if hasattr(ctx, "arg0"): - args.insert(0, ctx.arg0) - cmd_name = cmd.name + def resolve_command( + self, ctx: Context, args: list[str] + ) -> tuple[str | None, Command | None, list[str]]: + """Given a list of ``args`` given by a CLI, find a command which + matches the first element, and return its name (``cmd_name``), the + command function itself (``cmd``) and the rest of the arguments which + shall be passed to the function (``cmd_args``). If not found, return + ``None``, ``None`` and the rest of the arguments. + + After resolving the command, if the Click context given by ``ctx`` + contains an ``arg0`` attribute in its :attr:`click.Context.meta` + dictionary, insert it as the first element of the returned + ``cmd_args``. + + Parameters + ---------- + ctx + The Click context. + cmd_name + The name of the command to get. + + Returns + ------- + cmd_name : str | None + The command name, if found. Otherwise, ``None``. + cmd : :class:`click.Command` | None + The command, if found. Otherwise, ``None``. + cmd_args : list[str] + The rest of the arguments to be passed to ``cmd``. + """ + cmd_name, cmd, args = super().resolve_command(ctx, args) + if "arg0" in ctx.meta: + args.insert(0, ctx.meta["arg0"]) + if cmd is not None: + cmd_name = cmd.name return cmd_name, cmd, args - def command(self, *args, **kwargs): + @deprecated + def command( + self, *args: Any, **kwargs: Any + ) -> Callable[[Callable[..., object]], Command]: + """Return a decorator which converts any function into the default + subcommand for this :class:`DefaultGroup`. + + .. warning:: + This method is deprecated. Use the ``default`` parameter of + :class:`DefaultGroup` or :meth:`set_default_command` instead. + + Parameters + ---------- + *args + Positional arguments to pass to :meth:`cloup.Group.command`. + **kwargs + Keyword arguments to pass to :meth:`cloup.Group.command`. + + Returns + ------- + Callable[[Callable[..., object]], click.Command] + A decorator which transforms its input into this + :class:`DefaultGroup`'s default subcommand. + """ default = kwargs.pop("default", False) - decorator = super().command(*args, **kwargs) + decorator: Callable[[Callable[..., object]], Command] = super().command( + *args, **kwargs + ) if not default: return decorator warnings.warn( "Use default param of DefaultGroup or set_default_command() instead", DeprecationWarning, + stacklevel=1, ) - def _decorator(f): + def _decorator(f: Callable) -> Command: cmd = decorator(f) self.set_default_command(cmd) return cmd diff --git a/manim/cli/init/commands.py b/manim/cli/init/commands.py index 1ca5b9c05c..dd9d64837f 100644 --- a/manim/cli/init/commands.py +++ b/manim/cli/init/commands.py @@ -10,13 +10,14 @@ import configparser from pathlib import Path +from typing import Any import click import cloup -from ... import console -from ...constants import CONTEXT_SETTINGS, EPILOG, QUALITIES -from ...utils.file_ops import ( +from manim._config import console +from manim.constants import CONTEXT_SETTINGS, EPILOG, QUALITIES +from manim.utils.file_ops import ( add_import_statement, copy_template_files, get_template_names, @@ -34,15 +35,15 @@ __all__ = ["select_resolution", "update_cfg", "project", "scene"] -def select_resolution(): +def select_resolution() -> tuple[int, int]: """Prompts input of type click.Choice from user. Presents options from QUALITIES constant. Returns ------- - :class:`tuple` - Tuple containing height and width. + tuple[int, int] + Tuple containing height and width. """ - resolution_options = [] + resolution_options: list[tuple[int, int]] = [] for quality in QUALITIES.items(): resolution_options.append( (quality[1]["pixel_height"], quality[1]["pixel_width"]), @@ -54,18 +55,21 @@ def select_resolution(): show_default=False, default="480p", ) - return [res for res in resolution_options if f"{res[0]}p" == choice][0] + matches = [res for res in resolution_options if f"{res[0]}p" == choice] + return matches[0] -def update_cfg(cfg_dict: dict, project_cfg_path: Path): - """Updates the manim.cfg file after reading it from the project_cfg_path. +def update_cfg(cfg_dict: dict[str, Any], project_cfg_path: Path) -> None: + """Update the ``manim.cfg`` file after reading it from the specified + ``project_cfg_path``. Parameters ---------- cfg_dict - values used to update manim.cfg found project_cfg_path. + Values used to update ``manim.cfg`` which is found in + ``project_cfg_path``. project_cfg_path - Path of manim.cfg file. + Path of the ``manim.cfg`` file. """ config = configparser.ConfigParser() config.read(project_cfg_path) @@ -85,7 +89,7 @@ def update_cfg(cfg_dict: dict, project_cfg_path: Path): context_settings=CONTEXT_SETTINGS, epilog=EPILOG, ) -@cloup.argument("project_name", type=Path, required=False) +@cloup.argument("project_name", type=cloup.Path(path_type=Path), required=False) @cloup.option( "-d", "--default", @@ -94,13 +98,14 @@ def update_cfg(cfg_dict: dict, project_cfg_path: Path): help="Default settings for project creation.", nargs=1, ) -def project(default_settings, **args): +def project(default_settings: bool, **kwargs: Any) -> None: """Creates a new project. PROJECT_NAME is the name of the folder in which the new project will be initialized. """ - if args["project_name"]: - project_name = args["project_name"] + project_name: Path + if kwargs["project_name"]: + project_name = kwargs["project_name"] else: project_name = click.prompt("Project Name", type=Path) @@ -117,7 +122,7 @@ def project(default_settings, **args): ) else: project_name.mkdir() - new_cfg = {} + new_cfg: dict[str, Any] = {} new_cfg_path = Path.resolve(project_name / "manim.cfg") if not default_settings: @@ -145,23 +150,23 @@ def project(default_settings, **args): ) @cloup.argument("scene_name", type=str, required=True) @cloup.argument("file_name", type=str, required=False) -def scene(**args): +def scene(**kwargs: Any) -> None: """Inserts a SCENE to an existing FILE or creates a new FILE. SCENE is the name of the scene that will be inserted. FILE is the name of file in which the SCENE will be inserted. """ - template_name = click.prompt( + template_name: str = click.prompt( "template", type=click.Choice(get_template_names(), False), default="Default", ) scene = (get_template_path() / f"{template_name}.mtp").resolve().read_text() - scene = scene.replace(template_name + "Template", args["scene_name"], 1) + scene = scene.replace(template_name + "Template", kwargs["scene_name"], 1) - if args["file_name"]: - file_name = Path(args["file_name"]) + if kwargs["file_name"]: + file_name = Path(kwargs["file_name"]) if file_name.suffix != ".py": file_name = file_name.with_suffix(file_name.suffix + ".py") @@ -190,7 +195,7 @@ def scene(**args): help="Create a new project or insert a new scene.", ) @cloup.pass_context -def init(ctx): +def init(ctx: cloup.Context) -> None: pass diff --git a/manim/cli/plugins/commands.py b/manim/cli/plugins/commands.py index d47325cd03..994e074242 100644 --- a/manim/cli/plugins/commands.py +++ b/manim/cli/plugins/commands.py @@ -10,8 +10,8 @@ import cloup -from ...constants import CONTEXT_SETTINGS, EPILOG -from ...plugins.plugins_flags import list_plugins +from manim.constants import CONTEXT_SETTINGS, EPILOG +from manim.plugins.plugins_flags import list_plugins __all__ = ["plugins"] @@ -29,6 +29,16 @@ is_flag=True, help="List available plugins.", ) -def plugins(list_available): +def plugins(list_available: bool) -> None: + """Print a list of all available plugins when calling ``manim plugins -l`` + or ``manim plugins --list``. + + Parameters + ---------- + list_available + If the ``-l`` or ``-list`` option is passed to ``manim plugins``, this + parameter will be set to ``True``, which will print a list of all + available plugins. + """ if list_available: list_plugins() diff --git a/manim/cli/render/commands.py b/manim/cli/render/commands.py index 5b23ba8fb7..fde82f4970 100644 --- a/manim/cli/render/commands.py +++ b/manim/cli/render/commands.py @@ -13,78 +13,83 @@ import sys import urllib.error import urllib.request +from argparse import Namespace from pathlib import Path -from typing import cast +from typing import Any, cast import cloup -from ... import __version__, config, console, error_console, logger -from ..._config import tempconfig -from ...constants import EPILOG, RendererType -from ...utils.module_ops import scene_classes_from_file -from .ease_of_access_options import ease_of_access_options -from .global_options import global_options -from .output_options import output_options -from .render_options import render_options +from manim import __version__ +from manim._config import ( + config, + console, + error_console, + logger, + tempconfig, +) +from manim.cli.render.ease_of_access_options import ease_of_access_options +from manim.cli.render.global_options import global_options +from manim.cli.render.output_options import output_options +from manim.cli.render.render_options import render_options +from manim.constants import EPILOG, RendererType +from manim.utils.module_ops import scene_classes_from_file __all__ = ["render"] +class ClickArgs(Namespace): + def __init__(self, args: dict[str, Any]) -> None: + for name in args: + setattr(self, name, args[name]) + + def _get_kwargs(self) -> list[tuple[str, Any]]: + return list(self.__dict__.items()) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, ClickArgs): + return NotImplemented + return vars(self) == vars(other) + + def __contains__(self, key: str) -> bool: + return key in self.__dict__ + + def __repr__(self) -> str: + return str(self.__dict__) + + @cloup.command( context_settings=None, no_args_is_help=True, epilog=EPILOG, ) -@cloup.argument("file", type=Path, required=True) +@cloup.argument("file", type=cloup.Path(path_type=Path), required=True) @cloup.argument("scene_names", required=False, nargs=-1) @global_options @output_options -@render_options # type: ignore +@render_options @ease_of_access_options -def render( - **args, -): +def render(**kwargs: Any) -> ClickArgs | dict[str, Any]: """Render SCENE(S) from the input FILE. FILE is the file path of the script or a config file. SCENES is an optional list of scenes in the file. """ - - if args["save_as_gif"]: + if kwargs["save_as_gif"]: logger.warning("--save_as_gif is deprecated, please use --format=gif instead!") - args["format"] = "gif" + kwargs["format"] = "gif" - if args["save_pngs"]: + if kwargs["save_pngs"]: logger.warning("--save_pngs is deprecated, please use --format=png instead!") - args["format"] = "png" + kwargs["format"] = "png" - if args["show_in_file_browser"]: + if kwargs["show_in_file_browser"]: logger.warning( "The short form of show_in_file_browser is deprecated and will be moved to support --format.", ) - class ClickArgs: - def __init__(self, args): - for name in args: - setattr(self, name, args[name]) - - def _get_kwargs(self): - return list(self.__dict__.items()) - - def __eq__(self, other): - if not isinstance(other, ClickArgs): - return NotImplemented - return vars(self) == vars(other) - - def __contains__(self, key): - return key in self.__dict__ - - def __repr__(self): - return str(self.__dict__) - - click_args = ClickArgs(args) - if args["jupyter"]: + click_args = ClickArgs(kwargs) + if kwargs["jupyter"]: return click_args config.digest_args(click_args) @@ -153,4 +158,4 @@ def __repr__(self): "You should consider upgrading via [yellow]pip install -U manim[/yellow]", ) - return args + return kwargs diff --git a/manim/cli/render/global_options.py b/manim/cli/render/global_options.py index d7424dd1ee..32f9547b0c 100644 --- a/manim/cli/render/global_options.py +++ b/manim/cli/render/global_options.py @@ -1,22 +1,56 @@ from __future__ import annotations +import logging import re +import sys +from typing import TYPE_CHECKING from cloup import Choice, option, option_group -from ... import logger +if TYPE_CHECKING: + from click import Context, Option __all__ = ["global_options"] +logger = logging.getLogger("manim") -def validate_gui_location(ctx, param, value): - if value: - try: - x_offset, y_offset = map(int, re.split(r"[;,\-]", value)) - return (x_offset, y_offset) - except Exception: - logger.error("GUI location option is invalid.") - exit() + +def validate_gui_location( + ctx: Context, param: Option, value: str | None +) -> tuple[int, int] | None: + """If the ``value`` string is given, extract from it the GUI location, + which should be in any of these formats: 'x;y', 'x,y' or 'x-y'. + + Parameters + ---------- + ctx + The Click context. + param + A Click option. + value + The optional string which will be parsed. + + Returns + ------- + tuple[int, int] | None + If ``value`` is ``None``, the return value is ``None``. Otherwise, it's + the ``(x, y)`` location for the GUI. + + Raises + ------ + ValueError + If ``value`` has an invalid format. + """ + if value is None: + return None + + try: + x_offset, y_offset = map(int, re.split(r"[;,\-]", value)) + except Exception: + logger.error("GUI location option is invalid.") + sys.exit() + + return (x_offset, y_offset) global_options = option_group( diff --git a/manim/cli/render/render_options.py b/manim/cli/render/render_options.py index 5a2d992db8..0f069c04e0 100644 --- a/manim/cli/render/render_options.py +++ b/manim/cli/render/render_options.py @@ -1,40 +1,105 @@ from __future__ import annotations +import logging import re +import sys +from typing import TYPE_CHECKING from cloup import Choice, option, option_group from manim.constants import QUALITIES, RendererType -from ... import logger +if TYPE_CHECKING: + from click import Context, Option __all__ = ["render_options"] +logger = logging.getLogger("manim") + + +def validate_scene_range( + ctx: Context, param: Option, value: str | None +) -> tuple[int] | tuple[int, int] | None: + """If the ``value`` string is given, extract from it the scene range, which + should be in any of these formats: 'start', 'start;end', 'start,end' or + 'start-end'. Otherwise, return ``None``. + + Parameters + ---------- + ctx + The Click context. + param + A Click option. + value + The optional string which will be parsed. + + Returns + ------- + tuple[int] | tuple[int, int] | None + If ``value`` is ``None``, the return value is ``None``. Otherwise, it's + the scene range, given by a tuple which may contain a single value + ``start`` or two values ``start`` and ``end``. + + Raises + ------ + ValueError + If ``value`` has an invalid format. + """ + if value is None: + return None -def validate_scene_range(ctx, param, value): try: start = int(value) return (start,) except Exception: pass - if value: - try: - start, end = map(int, re.split(r"[;,\-]", value)) - return start, end - except Exception: - logger.error("Couldn't determine a range for -n option.") - exit() + try: + start, end = map(int, re.split(r"[;,\-]", value)) + except Exception: + logger.error("Couldn't determine a range for -n option.") + sys.exit() + + return start, end -def validate_resolution(ctx, param, value): - if value: - try: - start, end = map(int, re.split(r"[;,\-]", value)) - return (start, end) - except Exception: - logger.error("Resolution option is invalid.") - exit() +def validate_resolution( + ctx: Context, param: Option, value: str | None +) -> tuple[int, int] | None: + """If the ``value`` string is given, extract from it the resolution, which + should be in any of these formats: 'W;H', 'W,H' or 'W-H'. Otherwise, return + ``None``. + + Parameters + ---------- + ctx + The Click context. + param + A Click option. + value + The optional string which will be parsed. + + Returns + ------- + tuple[int, int] | None + If ``value`` is ``None``, the return value is ``None``. Otherwise, it's + the resolution as a ``(W, H)`` tuple. + + Raises + ------ + ValueError + If ``value`` has an invalid format. + """ + if value is None: + return None + + try: + width, height = map(int, re.split(r"[;,\-]", value)) + except Exception: + logger.error("Resolution option is invalid.") + sys.exit() + + return width, height render_options = option_group( @@ -71,7 +136,7 @@ def validate_resolution(ctx, param, value): "--quality", default=None, type=Choice( - list(reversed([q["flag"] for q in QUALITIES.values() if q["flag"]])), # type: ignore + list(reversed([q["flag"] for q in QUALITIES.values() if q["flag"]])), case_sensitive=False, ), help="Render quality at the follow resolution framerates, respectively: " diff --git a/manim/constants.py b/manim/constants.py index 3f3fae19de..0a3e00da85 100644 --- a/manim/constants.py +++ b/manim/constants.py @@ -1,10 +1,9 @@ -""" -Constant definitions. -""" +"""Constant definitions.""" from __future__ import annotations from enum import Enum +from typing import TypedDict import numpy as np from cloup import Context @@ -199,8 +198,16 @@ DEGREES = TAU / 360 """The exchange rate between radians and degrees.""" + +class QualityDict(TypedDict): + flag: str | None + pixel_height: int + pixel_width: int + frame_rate: int + + # Video qualities -QUALITIES: dict[str, dict[str, str | int | None]] = { +QUALITIES: dict[str, QualityDict] = { "fourk_quality": { "flag": "k", "pixel_height": 2160, diff --git a/manim/mobject/frame.py b/manim/mobject/frame.py index b854643911..639e8c384e 100644 --- a/manim/mobject/frame.py +++ b/manim/mobject/frame.py @@ -24,7 +24,6 @@ def aspect_ratio(self): When set, the width is stretched to accommodate the new aspect ratio. """ - return self.width / self.height @aspect_ratio.setter diff --git a/manim/mobject/geometry/arc.py b/manim/mobject/geometry/arc.py index dd532b07b6..c211deae01 100644 --- a/manim/mobject/geometry/arc.py +++ b/manim/mobject/geometry/arc.py @@ -44,7 +44,7 @@ def construct(self): import itertools import warnings -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, cast import numpy as np from typing_extensions import Self @@ -63,11 +63,20 @@ def construct(self): ) if TYPE_CHECKING: + from collections.abc import Iterable + from typing import Any + import manim.mobject.geometry.tips as tips from manim.mobject.mobject import Mobject from manim.mobject.text.tex_mobject import SingleStringMathTex, Tex from manim.mobject.text.text_mobject import Text - from manim.typing import CubicBezierPoints, Point3D, QuadraticBezierPoints, Vector3D + from manim.typing import ( + CubicBezierPoints, + InternalPoint3D, + Point3D, + QuadraticBezierPoints, + Vector3D, + ) class TipableVMobject(VMobject, metaclass=ConvertToOpenGL): @@ -93,7 +102,7 @@ def __init__( tip_length: float = DEFAULT_ARROW_TIP_LENGTH, normal_vector: Vector3D = OUT, tip_style: dict = {}, - **kwargs, + **kwargs: Any, ) -> None: self.tip_length: float = tip_length self.normal_vector: Vector3D = normal_vector @@ -126,10 +135,10 @@ def add_tip( def create_tip( self, tip_shape: type[tips.ArrowTip] | None = None, - tip_length: float = None, - tip_width: float = None, + tip_length: float | None = None, + tip_width: float | None = None, at_start: bool = False, - ): + ) -> tips.ArrowTip: """Stylises the tip, positions it spatially, and returns the newly instantiated tip to the caller. """ @@ -142,13 +151,13 @@ def get_unpositioned_tip( tip_shape: type[tips.ArrowTip] | None = None, tip_length: float | None = None, tip_width: float | None = None, - ): + ) -> tips.ArrowTip | tips.ArrowTriangleFilledTip: """Returns a tip that has been stylistically configured, but has not yet been given a position in space. """ from manim.mobject.geometry.tips import ArrowTriangleFilledTip - style = {} + style: dict[str, Any] = {} if tip_shape is None: tip_shape = ArrowTriangleFilledTip @@ -166,7 +175,7 @@ def get_unpositioned_tip( tip = tip_shape(length=tip_length, **style) return tip - def position_tip(self, tip: tips.ArrowTip, at_start: bool = False): + def position_tip(self, tip: tips.ArrowTip, at_start: bool = False) -> tips.ArrowTip: # Last two control points, defining both # the end, and the tangency direction if at_start: @@ -175,16 +184,18 @@ def position_tip(self, tip: tips.ArrowTip, at_start: bool = False): else: handle = self.get_last_handle() anchor = self.get_end() - angles = cartesian_to_spherical(handle - anchor) + angles = cartesian_to_spherical((handle - anchor).tolist()) tip.rotate( angles[1] - PI - tip.tip_angle, ) # Rotates the tip along the azimuthal if not hasattr(self, "_init_positioning_axis"): - axis = [ - np.sin(angles[1]), - -np.cos(angles[1]), - 0, - ] # Obtains the perpendicular of the tip + axis = np.array( + [ + np.sin(angles[1]), + -np.cos(angles[1]), + 0, + ] + ) # Obtains the perpendicular of the tip tip.rotate( -angles[2] + PI / 2, axis=axis, @@ -244,39 +255,44 @@ def get_tips(self) -> VGroup: result.add(self.start_tip) return result - def get_tip(self): + def get_tip(self) -> VMobject: """Returns the TipableVMobject instance's (first) tip, - otherwise throws an exception.""" + otherwise throws an exception. + """ tips = self.get_tips() if len(tips) == 0: raise Exception("tip not found") else: - return tips[0] + tip: VMobject = tips[0] + return tip def get_default_tip_length(self) -> float: return self.tip_length - def get_first_handle(self) -> Point3D: + def get_first_handle(self) -> InternalPoint3D: + # Type inference of extracting an element from a list, is not + # supported by numpy, see this numpy issue + # https://github.com/numpy/numpy/issues/16544 return self.points[1] - def get_last_handle(self) -> Point3D: + def get_last_handle(self) -> InternalPoint3D: return self.points[-2] - def get_end(self) -> Point3D: + def get_end(self) -> InternalPoint3D: if self.has_tip(): return self.tip.get_start() else: return super().get_end() - def get_start(self) -> Point3D: + def get_start(self) -> InternalPoint3D: if self.has_start_tip(): return self.start_tip.get_start() else: return super().get_start() - def get_length(self) -> np.floating: + def get_length(self) -> float: start, end = self.get_start_and_end() - return np.linalg.norm(start - end) + return float(np.linalg.norm(start - end)) class Arc(TipableVMobject): @@ -296,20 +312,20 @@ def construct(self): def __init__( self, - radius: float = 1.0, + radius: float | None = 1.0, start_angle: float = 0, angle: float = TAU / 4, num_components: int = 9, - arc_center: Point3D = ORIGIN, - **kwargs, + arc_center: InternalPoint3D = ORIGIN, + **kwargs: Any, ): if radius is None: # apparently None is passed by ArcBetweenPoints radius = 1.0 self.radius = radius - self.num_components: int = num_components - self.arc_center: Point3D = arc_center - self.start_angle: float = start_angle - self.angle: float = angle + self.num_components = num_components + self.arc_center = arc_center + self.start_angle = start_angle + self.angle = angle self._failed_to_get_center: bool = False super().__init__(**kwargs) @@ -378,7 +394,7 @@ def _set_pre_positioned_points(self) -> None: handles2 = anchors[1:] - (d_theta / 3) * tangent_vectors[1:] self.set_anchors_and_handles(anchors[:-1], handles1, handles2, anchors[1:]) - def get_arc_center(self, warning: bool = True) -> Point3D: + def get_arc_center(self, warning: bool = True) -> InternalPoint3D: """Looks at the normals to the first two anchors, and finds their intersection points """ @@ -400,16 +416,21 @@ def get_arc_center(self, warning: bool = True) -> Point3D: return line_intersection(line1=(a1, a1 + n1), line2=(a2, a2 + n2)) except Exception: if warning: - warnings.warn("Can't find Arc center, using ORIGIN instead") + warnings.warn( + "Can't find Arc center, using ORIGIN instead", stacklevel=1 + ) self._failed_to_get_center = True return np.array(ORIGIN) - def move_arc_center_to(self, point: Point3D) -> Self: + def move_arc_center_to(self, point: InternalPoint3D) -> Self: self.shift(point - self.get_arc_center()) return self def stop_angle(self) -> float: - return angle_of_vector(self.points[-1] - self.get_arc_center()) % TAU + return cast( + float, + angle_of_vector(self.points[-1] - self.get_arc_center()) % TAU, + ) class ArcBetweenPoints(Arc): @@ -436,8 +457,8 @@ def __init__( start: Point3D, end: Point3D, angle: float = TAU / 4, - radius: float = None, - **kwargs, + radius: float | None = None, + **kwargs: Any, ) -> None: if radius is not None: self.radius = radius @@ -457,19 +478,20 @@ def __init__( super().__init__(radius=radius, angle=angle, **kwargs) if angle == 0: - self.set_points_as_corners([LEFT, RIGHT]) + self.set_points_as_corners(np.array([LEFT, RIGHT])) self.put_start_and_end_on(start, end) if radius is None: center = self.get_arc_center(warning=False) if not self._failed_to_get_center: - self.radius = np.linalg.norm(np.array(start) - np.array(center)) + temp_radius: float = np.linalg.norm(np.array(start) - np.array(center)) + self.radius = temp_radius else: self.radius = np.inf class CurvedArrow(ArcBetweenPoints): - def __init__(self, start_point: Point3D, end_point: Point3D, **kwargs) -> None: + def __init__(self, start_point: Point3D, end_point: Point3D, **kwargs: Any) -> None: from manim.mobject.geometry.tips import ArrowTriangleFilledTip tip_shape = kwargs.pop("tip_shape", ArrowTriangleFilledTip) @@ -478,7 +500,7 @@ def __init__(self, start_point: Point3D, end_point: Point3D, **kwargs) -> None: class CurvedDoubleArrow(CurvedArrow): - def __init__(self, start_point: Point3D, end_point: Point3D, **kwargs) -> None: + def __init__(self, start_point: Point3D, end_point: Point3D, **kwargs: Any) -> None: if "tip_shape_end" in kwargs: kwargs["tip_shape"] = kwargs.pop("tip_shape_end") from manim.mobject.geometry.tips import ArrowTriangleFilledTip @@ -517,7 +539,7 @@ def __init__( self, radius: float | None = None, color: ParsableManimColor = RED, - **kwargs, + **kwargs: Any, ) -> None: super().__init__( radius=radius, @@ -569,7 +591,6 @@ def construct(self): group = Group(group1, group2, group3).arrange(buff=1) self.add(group) """ - # Ignores dim_to_match and stretch; result will always be a circle # TODO: Perhaps create an ellipse class to handle single-dimension stretching @@ -609,14 +630,15 @@ def construct(self): self.add(circle, s1, s2) """ - start_angle = angle_of_vector(self.points[0] - self.get_center()) proportion = (angle - start_angle) / TAU proportion -= np.floor(proportion) return self.point_from_proportion(proportion) @staticmethod - def from_three_points(p1: Point3D, p2: Point3D, p3: Point3D, **kwargs) -> Self: + def from_three_points( + p1: Point3D, p2: Point3D, p3: Point3D, **kwargs: Any + ) -> Circle: """Returns a circle passing through the specified three points. @@ -636,10 +658,10 @@ def construct(self): self.add(NumberPlane(), circle, dots) """ center = line_intersection( - perpendicular_bisector([p1, p2]), - perpendicular_bisector([p2, p3]), + perpendicular_bisector([np.asarray(p1), np.asarray(p2)]), + perpendicular_bisector([np.asarray(p2), np.asarray(p3)]), ) - radius = np.linalg.norm(p1 - center) + radius: float = np.linalg.norm(p1 - center) return Circle(radius=radius, **kwargs).shift(center) @@ -681,7 +703,7 @@ def __init__( stroke_width: float = 0, fill_opacity: float = 1.0, color: ParsableManimColor = WHITE, - **kwargs, + **kwargs: Any, ) -> None: super().__init__( arc_center=point, @@ -702,7 +724,7 @@ def __init__( stroke_width: float = 5, stroke_color: ParsableManimColor = WHITE, fill_color: ParsableManimColor = BLUE, - **kwargs, + **kwargs: Any, ) -> None: super().__init__( radius=radius, @@ -751,12 +773,12 @@ def __init__( self, label: str | SingleStringMathTex | Text | Tex, radius: float | None = None, - **kwargs, + **kwargs: Any, ) -> None: if isinstance(label, str): from manim import MathTex - rendered_label = MathTex(label, color=BLACK) + rendered_label: VMobject = MathTex(label, color=BLACK) else: rendered_label = label @@ -792,7 +814,7 @@ def construct(self): self.add(ellipse_group) """ - def __init__(self, width: float = 2, height: float = 1, **kwargs) -> None: + def __init__(self, width: float = 2, height: float = 1, **kwargs: Any) -> None: super().__init__(**kwargs) self.stretch_to_fit_width(width) self.stretch_to_fit_height(height) @@ -853,7 +875,7 @@ def __init__( fill_opacity: float = 1, stroke_width: float = 0, color: ParsableManimColor = WHITE, - **kwargs, + **kwargs: Any, ) -> None: self.inner_radius = inner_radius self.outer_radius = outer_radius @@ -895,17 +917,15 @@ class Sector(AnnularSector): class ExampleSector(Scene): def construct(self): - sector = Sector(outer_radius=2, inner_radius=1) - sector2 = Sector(outer_radius=2.5, inner_radius=0.8).move_to([-3, 0, 0]) + sector = Sector(radius=2) + sector2 = Sector(radius=2.5, angle=60*DEGREES).move_to([-3, 0, 0]) sector.set_color(RED) sector2.set_color(PINK) self.add(sector, sector2) """ - def __init__( - self, outer_radius: float = 1, inner_radius: float = 0, **kwargs - ) -> None: - super().__init__(inner_radius=inner_radius, outer_radius=outer_radius, **kwargs) + def __init__(self, radius: float = 1, **kwargs: Any) -> None: + super().__init__(inner_radius=0, outer_radius=radius, **kwargs) class Annulus(Circle): @@ -934,13 +954,13 @@ def construct(self): def __init__( self, - inner_radius: float | None = 1, - outer_radius: float | None = 2, + inner_radius: float = 1, + outer_radius: float = 2, fill_opacity: float = 1, stroke_width: float = 0, color: ParsableManimColor = WHITE, mark_paths_closed: bool = False, - **kwargs, + **kwargs: Any, ) -> None: self.mark_paths_closed = mark_paths_closed # is this even used? self.inner_radius = inner_radius @@ -990,7 +1010,7 @@ def __init__( start_handle: CubicBezierPoints, end_handle: CubicBezierPoints, end_anchor: CubicBezierPoints, - **kwargs, + **kwargs: Any, ) -> None: super().__init__(**kwargs) self.add_cubic_bezier_curve(start_anchor, start_handle, end_handle, end_anchor) @@ -1081,14 +1101,16 @@ def __init__( angle: float = PI / 4, radius: float | None = None, arc_config: list[dict] | None = None, - **kwargs, + **kwargs: Any, ) -> None: n = len(vertices) point_pairs = [(vertices[k], vertices[(k + 1) % n]) for k in range(n)] if not arc_config: if radius: - all_arc_configs = itertools.repeat({"radius": radius}, len(point_pairs)) + all_arc_configs: Iterable[dict] = itertools.repeat( + {"radius": radius}, len(point_pairs) + ) else: all_arc_configs = itertools.repeat({"angle": angle}, len(point_pairs)) elif isinstance(arc_config, dict): @@ -1220,7 +1242,7 @@ def construct(self): self.wait(2) """ - def __init__(self, *arcs: Arc | ArcBetweenPoints, **kwargs) -> None: + def __init__(self, *arcs: Arc | ArcBetweenPoints, **kwargs: Any) -> None: if not all(isinstance(m, (Arc, ArcBetweenPoints)) for m in arcs): raise ValueError( "All ArcPolygon submobjects must be of type Arc/ArcBetweenPoints", diff --git a/manim/mobject/geometry/boolean_ops.py b/manim/mobject/geometry/boolean_ops.py index ef5bd4fa58..a34d6fc7c4 100644 --- a/manim/mobject/geometry/boolean_ops.py +++ b/manim/mobject/geometry/boolean_ops.py @@ -13,7 +13,9 @@ from manim.mobject.types.vectorized_mobject import VMobject if TYPE_CHECKING: - from manim.typing import Point2D_Array, Point3D_Array + from typing import Any + + from manim.typing import InternalPoint3D_Array, Point2D_Array from ...constants import RendererType @@ -30,7 +32,7 @@ def _convert_2d_to_3d_array( self, points: Point2D_Array, z_dim: float = 0.0, - ) -> Point3D_Array: + ) -> InternalPoint3D_Array: """Converts an iterable with coordinates in 2D to 3D by adding :attr:`z_dim` as the Z coordinate. @@ -51,13 +53,14 @@ def _convert_2d_to_3d_array( >>> a = _BooleanOps() >>> p = [(1, 2), (3, 4)] >>> a._convert_2d_to_3d_array(p) - [array([1., 2., 0.]), array([3., 4., 0.])] + array([[1., 2., 0.], + [3., 4., 0.]]) """ - points = list(points) - for i, point in enumerate(points): + list_of_points = list(points) + for i, point in enumerate(list_of_points): if len(point) == 2: - points[i] = np.array(list(point) + [z_dim]) - return points + list_of_points[i] = np.array(list(point) + [z_dim]) + return np.asarray(list_of_points) def _convert_vmobject_to_skia_path(self, vmobject: VMobject) -> SkiaPath: """Converts a :class:`~.VMobject` to SkiaPath. This method only works for @@ -90,17 +93,17 @@ def _convert_vmobject_to_skia_path(self, vmobject: VMobject) -> SkiaPath: quads = vmobject.get_bezier_tuples_from_points(subpath) start = subpath[0] path.moveTo(*start[:2]) - for p0, p1, p2 in quads: + for _p0, p1, p2 in quads: path.quadTo(*p1[:2], *p2[:2]) if vmobject.consider_points_equals(subpath[0], subpath[-1]): path.close() elif config.renderer == RendererType.CAIRO: - subpaths = vmobject.gen_subpaths_from_points_2d(points) + subpaths = vmobject.gen_subpaths_from_points_2d(points) # type: ignore[assignment] for subpath in subpaths: quads = vmobject.gen_cubic_bezier_tuples_from_points(subpath) start = subpath[0] path.moveTo(*start[:2]) - for p0, p1, p2, p3 in quads: + for _p0, p1, p2, p3 in quads: path.cubicTo(*p1[:2], *p2[:2], *p3[:2]) if vmobject.consider_points_equals_2d(subpath[0], subpath[-1]): @@ -177,7 +180,7 @@ def construct(self): """ - def __init__(self, *vmobjects: VMobject, **kwargs) -> None: + def __init__(self, *vmobjects: VMobject, **kwargs: Any) -> None: if len(vmobjects) < 2: raise ValueError("At least 2 mobjects needed for Union.") super().__init__(**kwargs) @@ -216,7 +219,7 @@ def construct(self): """ - def __init__(self, subject: VMobject, clip: VMobject, **kwargs) -> None: + def __init__(self, subject: VMobject, clip: VMobject, **kwargs: Any) -> None: super().__init__(**kwargs) outpen = SkiaPath() difference( @@ -258,7 +261,7 @@ def construct(self): """ - def __init__(self, *vmobjects: VMobject, **kwargs) -> None: + def __init__(self, *vmobjects: VMobject, **kwargs: Any) -> None: if len(vmobjects) < 2: raise ValueError("At least 2 mobjects needed for Intersection.") @@ -311,7 +314,7 @@ def construct(self): """ - def __init__(self, subject: VMobject, clip: VMobject, **kwargs) -> None: + def __init__(self, subject: VMobject, clip: VMobject, **kwargs: Any) -> None: super().__init__(**kwargs) outpen = SkiaPath() xor( diff --git a/manim/mobject/geometry/labeled.py b/manim/mobject/geometry/labeled.py index 1a39ee2771..3c6ef335e2 100644 --- a/manim/mobject/geometry/labeled.py +++ b/manim/mobject/geometry/labeled.py @@ -2,17 +2,116 @@ from __future__ import annotations -__all__ = ["LabeledLine", "LabeledArrow"] +__all__ = ["Label", "LabeledLine", "LabeledArrow", "LabeledPolygram"] + +from typing import TYPE_CHECKING + +import numpy as np from manim.constants import * from manim.mobject.geometry.line import Arrow, Line +from manim.mobject.geometry.polygram import Polygram from manim.mobject.geometry.shape_matchers import ( BackgroundRectangle, SurroundingRectangle, ) from manim.mobject.text.tex_mobject import MathTex, Tex from manim.mobject.text.text_mobject import Text -from manim.utils.color import WHITE, ManimColor, ParsableManimColor +from manim.mobject.types.vectorized_mobject import VGroup +from manim.utils.color import WHITE +from manim.utils.polylabel import polylabel + +if TYPE_CHECKING: + from typing import Any + + from manim.typing import Point3D_Array + + +class Label(VGroup): + """A Label consisting of text surrounded by a frame. + + Parameters + ---------- + label + Label that will be displayed. + label_config + A dictionary containing the configuration for the label. + This is only applied if ``label`` is of type ``str``. + box_config + A dictionary containing the configuration for the background box. + frame_config + A dictionary containing the configuration for the frame. + + Examples + -------- + .. manim:: LabelExample + :save_last_frame: + :quality: high + + class LabelExample(Scene): + def construct(self): + label = Label( + label=Text('Label Text', font='sans-serif'), + box_config = { + "color" : BLUE, + "fill_opacity" : 0.75 + } + ) + label.scale(3) + self.add(label) + """ + + def __init__( + self, + label: str | Tex | MathTex | Text, + label_config: dict[str, Any] | None = None, + box_config: dict[str, Any] | None = None, + frame_config: dict[str, Any] | None = None, + **kwargs: Any, + ) -> None: + super().__init__(**kwargs) + + # Setup Defaults + default_label_config: dict[str, Any] = { + "color": WHITE, + "font_size": DEFAULT_FONT_SIZE, + } + + default_box_config: dict[str, Any] = { + "color": None, + "buff": 0.05, + "fill_opacity": 1, + "stroke_width": 0.5, + } + + default_frame_config: dict[str, Any] = { + "color": WHITE, + "buff": 0.05, + "stroke_width": 0.5, + } + + # Merge Defaults + label_config = default_label_config | (label_config or {}) + box_config = default_box_config | (box_config or {}) + frame_config = default_frame_config | (frame_config or {}) + + # Determine the type of label and instantiate the appropriate object + self.rendered_label: MathTex | Tex | Text + if isinstance(label, str): + self.rendered_label = MathTex(label, **label_config) + elif isinstance(label, (MathTex, Tex, Text)): + self.rendered_label = label + else: + raise TypeError("Unsupported label type. Must be MathTex, Tex, or Text.") + + # Add a background box + self.background_rect = BackgroundRectangle(self.rendered_label, **box_config) + + # Add a frame around the label + self.frame = SurroundingRectangle(self.rendered_label, **frame_config) + + # Add components to the VGroup + self.add(self.background_rect, self.rendered_label, self.frame) class LabeledLine(Line): @@ -20,42 +119,38 @@ class LabeledLine(Line): Parameters ---------- - label : str | Tex | MathTex | Text + label Label that will be displayed on the line. - label_position : float | optional + label_position A ratio in the range [0-1] to indicate the position of the label with respect to the length of the line. Default value is 0.5. - font_size : float | optional - Control font size for the label. This parameter is only used when `label` is of type `str`. - label_color: ParsableManimColor | optional - The color of the label's text. This parameter is only used when `label` is of type `str`. - label_frame : Bool | optional - Add a `SurroundingRectangle` frame to the label box. - frame_fill_color : ParsableManimColor | optional - Background color to fill the label box. If no value is provided, the background color of the canvas will be used. - frame_fill_opacity : float | optional - Determine the opacity of the label box by passing a value in the range [0-1], where 0 indicates complete transparency and 1 means full opacity. - - .. seealso:: - :class:`LabeledArrow` + label_config + A dictionary containing the configuration for the label. + This is only applied if ``label`` is of type ``str``. + box_config + A dictionary containing the configuration for the background box. + frame_config + A dictionary containing the configuration for the frame. + + .. seealso:: + :class:`LabeledArrow` Examples -------- .. manim:: LabeledLineExample :save_last_frame: + :quality: high class LabeledLineExample(Scene): def construct(self): line = LabeledLine( label = '0.5', label_position = 0.8, - font_size = 20, - label_color = WHITE, - label_frame = True, - + label_config = { + "font_size" : 20 + }, start=LEFT+DOWN, end=RIGHT+UP) - line.set_length(line.get_length() * 2) self.add(line) """ @@ -64,50 +159,29 @@ def __init__( self, label: str | Tex | MathTex | Text, label_position: float = 0.5, - font_size: float = DEFAULT_FONT_SIZE, - label_color: ParsableManimColor = WHITE, - label_frame: bool = True, - frame_fill_color: ParsableManimColor = None, - frame_fill_opacity: float = 1, - *args, - **kwargs, + label_config: dict[str, Any] | None = None, + box_config: dict[str, Any] | None = None, + frame_config: dict[str, Any] | None = None, + *args: Any, + **kwargs: Any, ) -> None: - label_color = ManimColor(label_color) - frame_fill_color = ManimColor(frame_fill_color) - if isinstance(label, str): - from manim import MathTex - - rendered_label = MathTex(label, color=label_color, font_size=font_size) - else: - rendered_label = label - super().__init__(*args, **kwargs) - # calculating the vector for the label position + # Create Label + self.label = Label( + label=label, + label_config=label_config, + box_config=box_config, + frame_config=frame_config, + ) + + # Compute Label Position line_start, line_end = self.get_start_and_end() new_vec = (line_end - line_start) * label_position label_coords = line_start + new_vec - # rendered_label.move_to(self.get_vector() * label_position) - rendered_label.move_to(label_coords) - - box = BackgroundRectangle( - rendered_label, - buff=0.05, - color=frame_fill_color, - fill_opacity=frame_fill_opacity, - stroke_width=0.5, - ) - self.add(box) - - if label_frame: - box_frame = SurroundingRectangle( - rendered_label, buff=0.05, color=label_color, stroke_width=0.5 - ) - - self.add(box_frame) - - self.add(rendered_label) + self.label.move_to(label_coords) + self.add(self.label) class LabeledArrow(LabeledLine, Arrow): @@ -116,29 +190,26 @@ class LabeledArrow(LabeledLine, Arrow): Parameters ---------- - label : str | Tex | MathTex | Text - Label that will be displayed on the line. - label_position : float | optional + label + Label that will be displayed on the Arrow. + label_position A ratio in the range [0-1] to indicate the position of the label with respect to the length of the line. Default value is 0.5. - font_size : float | optional - Control font size for the label. This parameter is only used when `label` is of type `str`. - label_color: ParsableManimColor | optional - The color of the label's text. This parameter is only used when `label` is of type `str`. - label_frame : Bool | optional - Add a `SurroundingRectangle` frame to the label box. - frame_fill_color : ParsableManimColor | optional - Background color to fill the label box. If no value is provided, the background color of the canvas will be used. - frame_fill_opacity : float | optional - Determine the opacity of the label box by passing a value in the range [0-1], where 0 indicates complete transparency and 1 means full opacity. + label_config + A dictionary containing the configuration for the label. + This is only applied if ``label`` is of type ``str``. + box_config + A dictionary containing the configuration for the background box. + frame_config + A dictionary containing the configuration for the frame. - - .. seealso:: - :class:`LabeledLine` + .. seealso:: + :class:`LabeledLine` Examples -------- .. manim:: LabeledArrowExample :save_last_frame: + :quality: high class LabeledArrowExample(Scene): def construct(self): @@ -149,7 +220,159 @@ def construct(self): def __init__( self, - *args, - **kwargs, + *args: Any, + **kwargs: Any, ) -> None: super().__init__(*args, **kwargs) + + +class LabeledPolygram(Polygram): + """Constructs a polygram containing a label box at its pole of inaccessibility. + + Parameters + ---------- + vertex_groups + Vertices passed to the :class:`~.Polygram` constructor. + label + Label that will be displayed on the Polygram. + precision + The precision used by the PolyLabel algorithm. + label_config + A dictionary containing the configuration for the label. + This is only applied if ``label`` is of type ``str``. + box_config + A dictionary containing the configuration for the background box. + frame_config + A dictionary containing the configuration for the frame. + + .. note:: + The PolyLabel Algorithm expects each vertex group to form a closed ring. + If the input is open, :class:`LabeledPolygram` will attempt to close it. + This may cause the polygon to intersect itself leading to unexpected results. + + .. tip:: + Make sure the precision corresponds to the scale of your inputs! + For instance, if the bounding box of your polygon stretches from 0 to 10,000, a precision of 1.0 or 10.0 should be sufficient. + + Examples + -------- + .. manim:: LabeledPolygramExample + :save_last_frame: + :quality: high + + class LabeledPolygramExample(Scene): + def construct(self): + # Define Rings + ring1 = [ + [-3.8, -2.4, 0], [-2.4, -2.5, 0], [-1.3, -1.6, 0], [-0.2, -1.7, 0], + [1.7, -2.5, 0], [2.9, -2.6, 0], [3.5, -1.5, 0], [4.9, -1.4, 0], + [4.5, 0.2, 0], [4.7, 1.6, 0], [3.5, 2.4, 0], [1.1, 2.5, 0], + [-0.1, 0.9, 0], [-1.2, 0.5, 0], [-1.6, 0.7, 0], [-1.4, 1.9, 0], + [-2.6, 2.6, 0], [-4.4, 1.2, 0], [-4.9, -0.8, 0], [-3.8, -2.4, 0] + ] + ring2 = [ + [0.2, -1.2, 0], [0.9, -1.2, 0], [1.4, -2.0, 0], [2.1, -1.6, 0], + [2.2, -0.5, 0], [1.4, 0.0, 0], [0.4, -0.2, 0], [0.2, -1.2, 0] + ] + ring3 = [[-2.7, 1.4, 0], [-2.3, 1.7, 0], [-2.8, 1.9, 0], [-2.7, 1.4, 0]] + + # Create Polygons (for reference) + p1 = Polygon(*ring1, fill_opacity=0.75) + p2 = Polygon(*ring2, fill_color=BLACK, fill_opacity=1) + p3 = Polygon(*ring3, fill_color=BLACK, fill_opacity=1) + + # Create Labeled Polygram + polygram = LabeledPolygram( + *[ring1, ring2, ring3], + label=Text('Pole', font='sans-serif'), + precision=0.01, + ) + + # Display Circle (for reference) + circle = Circle(radius=polygram.radius, color=WHITE).move_to(polygram.pole) + + self.add(p1, p2, p3) + self.add(polygram) + self.add(circle) + + .. manim:: LabeledCountryExample + :save_last_frame: + :quality: high + + import requests + import json + + class LabeledCountryExample(Scene): + def construct(self): + # Fetch JSON data and process arcs + data = requests.get('https://cdn.jsdelivr.net/npm/us-atlas@3/nation-10m.json').json() + arcs, transform = data['arcs'], data['transform'] + sarcs = [np.cumsum(arc, axis=0) * transform['scale'] + transform['translate'] for arc in arcs] + ssarcs = sorted(sarcs, key=len, reverse=True)[:1] + + # Compute Bounding Box + points = np.concatenate(ssarcs) + mins, maxs = np.min(points, axis=0), np.max(points, axis=0) + + # Build Axes + ax = Axes( + x_range=[mins[0], maxs[0], maxs[0] - mins[0]], x_length=10, + y_range=[mins[1], maxs[1], maxs[1] - mins[1]], y_length=7, + tips=False + ) + + # Adjust Coordinates + array = [[ax.c2p(*point) for point in sarc] for sarc in ssarcs] + + # Add Polygram + polygram = LabeledPolygram( + *array, + label=Text('USA', font='sans-serif'), + precision=0.01, + fill_color=BLUE, + stroke_width=0, + fill_opacity=0.75 + ) + + # Display Circle (for reference) + circle = Circle(radius=polygram.radius, color=WHITE).move_to(polygram.pole) + + self.add(ax) + self.add(polygram) + self.add(circle) + """ + + def __init__( + self, + *vertex_groups: Point3D_Array, + label: str | Tex | MathTex | Text, + precision: float = 0.01, + label_config: dict[str, Any] | None = None, + box_config: dict[str, Any] | None = None, + frame_config: dict[str, Any] | None = None, + **kwargs: Any, + ) -> None: + # Initialize the Polygram with the vertex groups + super().__init__(*vertex_groups, **kwargs) + + # Create Label + self.label = Label( + label=label, + label_config=label_config, + box_config=box_config, + frame_config=frame_config, + ) + + # Close Vertex Groups + rings = [ + group if np.array_equal(group[0], group[-1]) else list(group) + [group[0]] + for group in vertex_groups + ] + + # Compute the Pole of Inaccessibility + cell = polylabel(rings, precision=precision) + self.pole, self.radius = np.pad(cell.c, (0, 1), "constant"), cell.d + + # Position the label at the pole + self.label.move_to(self.pole) + self.add(self.label) diff --git a/manim/mobject/geometry/line.py b/manim/mobject/geometry/line.py index 50d63c1190..ef0e4aa1ff 100644 --- a/manim/mobject/geometry/line.py +++ b/manim/mobject/geometry/line.py @@ -30,9 +30,11 @@ from manim.utils.space_ops import angle_of_vector, line_intersection, normalize if TYPE_CHECKING: + from typing import Any + from typing_extensions import Self - from manim.typing import Point2D, Point3D, Vector3D + from manim.typing import InternalPoint3D, Point2D, Point3D, Vector3D from manim.utils.color import ParsableManimColor from ..matrix import Matrix # Avoid circular import @@ -45,20 +47,21 @@ def __init__( end: Point3D | Mobject = RIGHT, buff: float = 0, path_arc: float | None = None, - **kwargs, + **kwargs: Any, ) -> None: self.dim = 3 self.buff = buff self.path_arc = path_arc self._set_start_and_end_attrs(start, end) super().__init__(**kwargs) + # TODO: Deal with the situation where path_arc is None def generate_points(self) -> None: self.set_points_by_ends( start=self.start, end=self.end, buff=self.buff, - path_arc=self.path_arc, + path_arc=self.path_arc, # type: ignore[arg-type] ) def set_points_by_ends( @@ -85,29 +88,29 @@ def set_points_by_ends( """ self._set_start_and_end_attrs(start, end) if path_arc: + # self.path_arc could potentially be None, which is not accepted + # as parameter. + assert self.path_arc is not None arc = ArcBetweenPoints(self.start, self.end, angle=self.path_arc) self.set_points(arc.points) else: - self.set_points_as_corners([self.start, self.end]) + self.set_points_as_corners(np.asarray([self.start, self.end])) self._account_for_buff(buff) init_points = generate_points - def _account_for_buff(self, buff: float) -> Self: + def _account_for_buff(self, buff: float) -> None: if buff == 0: return # - if self.path_arc == 0: - length = self.get_length() - else: - length = self.get_arc_length() + length = self.get_length() if self.path_arc == 0 else self.get_arc_length() # if length < 2 * buff: return buff_proportion = buff / length self.pointwise_become_partial(self, buff_proportion, 1 - buff_proportion) - return self + return def _set_start_and_end_attrs( self, start: Point3D | Mobject, end: Point3D | Mobject @@ -127,7 +130,7 @@ def _pointify( self, mob_or_point: Mobject | Point3D, direction: Vector3D | None = None, - ) -> Point3D: + ) -> InternalPoint3D: """Transforms a mobject into its corresponding point. Does nothing if a point is passed. ``direction`` determines the location of the point along its bounding box in that direction. @@ -151,7 +154,11 @@ def set_path_arc(self, new_value: float) -> None: self.path_arc = new_value self.init_points() - def put_start_and_end_on(self, start: Point3D, end: Point3D) -> Self: + def put_start_and_end_on( + self, + start: InternalPoint3D, + end: InternalPoint3D, + ) -> Self: """Sets starts and end coordinates of a line. Examples @@ -191,7 +198,7 @@ def get_unit_vector(self) -> Vector3D: def get_angle(self) -> float: return angle_of_vector(self.get_vector()) - def get_projection(self, point: Point3D) -> Vector3D: + def get_projection(self, point: InternalPoint3D) -> Vector3D: """Returns the projection of a point onto a line. Parameters @@ -199,14 +206,13 @@ def get_projection(self, point: Point3D) -> Vector3D: point The point to which the line is projected. """ - start = self.get_start() end = self.get_end() unit_vect = normalize(end - start) - return start + np.dot(point - start, unit_vect) * unit_vect + return start + float(np.dot(point - start, unit_vect)) * unit_vect def get_slope(self) -> float: - return np.tan(self.get_angle()) + return float(np.tan(self.get_angle())) def set_angle(self, angle: float, about_point: Point3D | None = None) -> Self: if about_point is None: @@ -220,7 +226,8 @@ def set_angle(self, angle: float, about_point: Point3D | None = None) -> Self: return self def set_length(self, length: float) -> Self: - return self.scale(length / self.get_length()) + scale_factor: float = length / self.get_length() + return self.scale(scale_factor) class DashedLine(Line): @@ -259,10 +266,10 @@ def construct(self): def __init__( self, - *args, + *args: Any, dash_length: float = DEFAULT_DASH_LENGTH, dashed_ratio: float = 0.5, - **kwargs, + **kwargs: Any, ) -> None: self.dash_length = dash_length self.dashed_ratio = dashed_ratio @@ -285,14 +292,13 @@ def _calculate_num_dashes(self) -> int: >>> DashedLine()._calculate_num_dashes() 20 """ - # Minimum number of dashes has to be 2 return max( 2, int(np.ceil((self.get_length() / self.dash_length) * self.dashed_ratio)), ) - def get_start(self) -> Point3D: + def get_start(self) -> InternalPoint3D: """Returns the start point of the line. Examples @@ -302,13 +308,12 @@ def get_start(self) -> Point3D: >>> DashedLine().get_start() array([-1., 0., 0.]) """ - if len(self.submobjects) > 0: return self.submobjects[0].get_start() else: return super().get_start() - def get_end(self) -> Point3D: + def get_end(self) -> InternalPoint3D: """Returns the end point of the line. Examples @@ -318,13 +323,12 @@ def get_end(self) -> Point3D: >>> DashedLine().get_end() array([1., 0., 0.]) """ - if len(self.submobjects) > 0: return self.submobjects[-1].get_end() else: return super().get_end() - def get_first_handle(self) -> Point3D: + def get_first_handle(self) -> InternalPoint3D: """Returns the point of the first handle. Examples @@ -334,10 +338,12 @@ def get_first_handle(self) -> Point3D: >>> DashedLine().get_first_handle() array([-0.98333333, 0. , 0. ]) """ - + # Type inference of extracting an element from a list, is not + # supported by numpy, see this numpy issue + # https://github.com/numpy/numpy/issues/16544 return self.submobjects[0].points[1] - def get_last_handle(self) -> Point3D: + def get_last_handle(self) -> InternalPoint3D: """Returns the point of the last handle. Examples @@ -347,7 +353,9 @@ def get_last_handle(self) -> Point3D: >>> DashedLine().get_last_handle() array([0.98333333, 0. , 0. ]) """ - + # Type inference of extracting an element from a list, is not + # supported by numpy, see this numpy issue + # https://github.com/numpy/numpy/issues/16544 return self.submobjects[-1].points[-2] @@ -390,7 +398,7 @@ def __init__( alpha: float, length: float = 1, d_alpha: float = 1e-6, - **kwargs, + **kwargs: Any, ) -> None: self.length = length self.d_alpha = d_alpha @@ -433,10 +441,10 @@ def construct(self): self.add(elbow_group) """ - def __init__(self, width: float = 0.2, angle: float = 0, **kwargs) -> None: + def __init__(self, width: float = 0.2, angle: float = 0, **kwargs: Any) -> None: self.angle = angle super().__init__(**kwargs) - self.set_points_as_corners([UP, UP + RIGHT, RIGHT]) + self.set_points_as_corners(np.array([UP, UP + RIGHT, RIGHT])) self.scale_to_fit_width(width, about_point=ORIGIN) self.rotate(self.angle, about_point=ORIGIN) @@ -531,24 +539,24 @@ def construct(self): def __init__( self, - *args, + *args: Any, stroke_width: float = 6, buff: float = MED_SMALL_BUFF, max_tip_length_to_length_ratio: float = 0.25, max_stroke_width_to_length_ratio: float = 5, - **kwargs, + **kwargs: Any, ) -> None: self.max_tip_length_to_length_ratio = max_tip_length_to_length_ratio self.max_stroke_width_to_length_ratio = max_stroke_width_to_length_ratio tip_shape = kwargs.pop("tip_shape", ArrowTriangleFilledTip) - super().__init__(*args, buff=buff, stroke_width=stroke_width, **kwargs) + super().__init__(*args, buff=buff, stroke_width=stroke_width, **kwargs) # type: ignore[misc] # TODO, should this be affected when # Arrow.set_stroke is called? self.initial_stroke_width = self.stroke_width self.add_tip(tip_shape=tip_shape) self._set_stroke_width_from_length() - def scale(self, factor: float, scale_tips: bool = False, **kwargs) -> Self: + def scale(self, factor: float, scale_tips: bool = False, **kwargs: Any) -> Self: # type: ignore[override] r"""Scale an arrow, but keep stroke width and arrow tip size fixed. @@ -608,7 +616,6 @@ def get_normal_vector(self) -> Vector3D: >>> np.round(Arrow().get_normal_vector()) + 0. # add 0. to avoid negative 0 in output array([ 0., 0., -1.]) """ - p0, p1, p2 = self.tip.get_start_anchors()[:3] return normalize(np.cross(p2 - p1, p1 - p0)) @@ -628,7 +635,6 @@ def get_default_tip_length(self) -> float: >>> Arrow().get_default_tip_length() 0.35 """ - max_ratio = self.max_tip_length_to_length_ratio return min(self.tip_length, max_ratio * self.get_length()) @@ -636,7 +642,11 @@ def _set_stroke_width_from_length(self) -> Self: """Sets stroke width based on length.""" max_ratio = self.max_stroke_width_to_length_ratio if config.renderer == RendererType.OPENGL: - self.set_stroke( + # Mypy does not recognize that the self object in this case + # is a OpenGLVMobject and that the set_stroke method is + # defined here: + # mobject/opengl/opengl_vectorized_mobject.py#L248 + self.set_stroke( # type: ignore[call-arg] width=min(self.initial_stroke_width, max_ratio * self.get_length()), recurse=False, ) @@ -679,7 +689,10 @@ def construct(self): """ def __init__( - self, direction: Point2D | Point3D = RIGHT, buff: float = 0, **kwargs + self, + direction: Point2D | Point3D = RIGHT, + buff: float = 0, + **kwargs: Any, ) -> None: self.buff = buff if len(direction) == 2: @@ -692,7 +705,7 @@ def coordinate_label( integer_labels: bool = True, n_dim: int = 2, color: ParsableManimColor | None = None, - **kwargs, + **kwargs: Any, ) -> Matrix: """Creates a label based on the coordinates of the vector. @@ -728,7 +741,6 @@ def construct(self): self.add(plane, vec_1, vec_2, label_1, label_2) """ - # avoiding circular imports from ..matrix import Matrix @@ -796,7 +808,7 @@ def construct(self): self.add(box, d1, d2, d3) """ - def __init__(self, *args, **kwargs) -> None: + def __init__(self, *args: Any, **kwargs: Any) -> None: if "tip_shape_end" in kwargs: kwargs["tip_shape"] = kwargs.pop("tip_shape_end") tip_shape_start = kwargs.pop("tip_shape_start", ArrowTriangleFilledTip) @@ -925,7 +937,7 @@ def __init__( dot_distance: float = 0.55, dot_color: ParsableManimColor = WHITE, elbow: bool = False, - **kwargs, + **kwargs: Any, ) -> None: super().__init__(**kwargs) self.lines = (line1, line2) @@ -962,9 +974,9 @@ def __init__( + quadrant[0] * radius * line1.get_unit_vector() + quadrant[1] * radius * line2.get_unit_vector() ) - angle_mobject = Elbow(**kwargs) + angle_mobject: VMobject = Elbow(**kwargs) angle_mobject.set_points_as_corners( - [anchor_angle_1, anchor_middle, anchor_angle_2], + np.array([anchor_angle_1, anchor_middle, anchor_angle_2]), ) else: angle_1 = angle_of_vector(anchor_angle_1 - inter) @@ -1028,11 +1040,10 @@ def get_lines(self) -> VGroup: >>> angle.get_lines() VGroup(Line, Line) """ - return VGroup(*self.lines) def get_value(self, degrees: bool = False) -> float: - """Get the value of an angle of the :class:`Angle` class. + r"""Get the value of an angle of the :class:`Angle` class. Parameters ---------- @@ -1062,12 +1073,11 @@ def construct(self): self.add(line1, line2, angle, value) """ - return self.angle_value / DEGREES if degrees else self.angle_value @staticmethod - def from_three_points(A: Point3D, B: Point3D, C: Point3D, **kwargs) -> Angle: - """The angle between the lines AB and BC. + def from_three_points(A: Point3D, B: Point3D, C: Point3D, **kwargs: Any) -> Angle: + r"""The angle between the lines AB and BC. This constructs the angle :math:`\\angle ABC`. @@ -1142,6 +1152,10 @@ def construct(self): """ def __init__( - self, line1: Line, line2: Line, length: float | None = None, **kwargs + self, + line1: Line, + line2: Line, + length: float | None = None, + **kwargs: Any, ) -> None: super().__init__(line1, line2, radius=length, elbow=True, **kwargs) diff --git a/manim/mobject/geometry/polygram.py b/manim/mobject/geometry/polygram.py index de48c28998..482581df12 100644 --- a/manim/mobject/geometry/polygram.py +++ b/manim/mobject/geometry/polygram.py @@ -13,6 +13,7 @@ "Square", "RoundedRectangle", "Cutout", + "ConvexHull", ] @@ -27,12 +28,21 @@ from manim.mobject.types.vectorized_mobject import VGroup, VMobject from manim.utils.color import BLUE, WHITE, ParsableManimColor from manim.utils.iterables import adjacent_n_tuples, adjacent_pairs +from manim.utils.qhull import QuickHull from manim.utils.space_ops import angle_between_vectors, normalize, regular_vertices if TYPE_CHECKING: + from typing import Any, Literal + + import numpy.typing as npt from typing_extensions import Self - from manim.typing import Point3D, Point3D_Array + from manim.typing import ( + InternalPoint3D, + InternalPoint3D_Array, + Point3D, + Point3D_Array, + ) from manim.utils.color import ParsableManimColor @@ -72,11 +82,16 @@ def construct(self): """ def __init__( - self, *vertex_groups: Point3D, color: ParsableManimColor = BLUE, **kwargs + self, + *vertex_groups: Point3D_Array, + color: ParsableManimColor = BLUE, + **kwargs: Any, ): super().__init__(color=color, **kwargs) for vertices in vertex_groups: + # The inferred type for *vertices is Any, but it should be + # InternalPoint3D_Array first_vertex, *vertices = vertices first_vertex = np.array(first_vertex) @@ -85,7 +100,7 @@ def __init__( [*(np.array(vertex) for vertex in vertices), first_vertex], ) - def get_vertices(self) -> Point3D_Array: + def get_vertices(self) -> InternalPoint3D_Array: """Gets the vertices of the :class:`Polygram`. Returns @@ -104,10 +119,9 @@ def get_vertices(self) -> Point3D_Array: [-1., -1., 0.], [ 1., -1., 0.]]) """ - return self.get_start_anchors() - def get_vertex_groups(self) -> np.ndarray[Point3D_Array]: + def get_vertex_groups(self) -> InternalPoint3D_Array: """Gets the vertex groups of the :class:`Polygram`. Returns @@ -129,7 +143,6 @@ def get_vertex_groups(self) -> np.ndarray[Point3D_Array]: [-1., 1., 0.], [-2., 0., 0.]]]) """ - vertex_groups = [] group = [] @@ -204,11 +217,10 @@ def construct(self): shapes.arrange(RIGHT) self.add(shapes) """ - if radius == 0: return self - new_points = [] + new_points: list[InternalPoint3D] = [] for vertices in self.get_vertex_groups(): arcs = [] @@ -277,7 +289,7 @@ def construct(self): new_points.extend(line.points) - self.set_points(new_points) + self.set_points(np.array(new_points)) return self @@ -312,7 +324,7 @@ def construct(self): self.add(isosceles, square_and_triangles) """ - def __init__(self, *vertices: Point3D, **kwargs) -> None: + def __init__(self, *vertices: InternalPoint3D, **kwargs: Any) -> None: super().__init__(vertices, **kwargs) @@ -355,7 +367,7 @@ def __init__( density: int = 2, radius: float = 1, start_angle: float | None = None, - **kwargs, + **kwargs: Any, ) -> None: # Regular polygrams can be expressed by the number of their vertices # and their density. This relation can be expressed as its Schläfli @@ -376,7 +388,7 @@ def __init__( # Utility function for generating the individual # polygon vertices. - def gen_polygon_vertices(start_angle): + def gen_polygon_vertices(start_angle: float | None) -> tuple[list[Any], float]: reg_vertices, start_angle = regular_vertices( num_vertices, radius=radius, @@ -432,7 +444,7 @@ def construct(self): self.add(poly_group) """ - def __init__(self, n: int = 6, **kwargs) -> None: + def __init__(self, n: int = 6, **kwargs: Any) -> None: super().__init__(n, density=1, **kwargs) @@ -502,7 +514,7 @@ def __init__( inner_radius: float | None = None, density: int = 2, start_angle: float | None = TAU / 4, - **kwargs, + **kwargs: Any, ) -> None: inner_angle = TAU / (2 * n) @@ -534,7 +546,7 @@ def __init__( start_angle=self.start_angle + inner_angle, ) - vertices = [] + vertices: list[npt.NDArray] = [] for pair in zip(outer_vertices, inner_vertices): vertices.extend(pair) @@ -562,7 +574,7 @@ def construct(self): self.add(tri_group) """ - def __init__(self, **kwargs) -> None: + def __init__(self, **kwargs: Any) -> None: super().__init__(n=3, **kwargs) @@ -613,7 +625,7 @@ def __init__( grid_ystep: float | None = None, mark_paths_closed: bool = True, close_new_points: bool = True, - **kwargs, + **kwargs: Any, ): super().__init__(UR, UL, DL, DR, color=color, **kwargs) self.stretch_to_fit_width(width) @@ -684,10 +696,17 @@ def construct(self): self.add(square_1, square_2, square_3) """ - def __init__(self, side_length: float = 2.0, **kwargs) -> None: - self.side_length = side_length + def __init__(self, side_length: float = 2.0, **kwargs: Any) -> None: super().__init__(height=side_length, width=side_length, **kwargs) + @property + def side_length(self) -> float: + return float(np.linalg.norm(self.get_vertices()[0] - self.get_vertices()[1])) + + @side_length.setter + def side_length(self, value: float) -> None: + self.scale(value / self.side_length) + class RoundedRectangle(Rectangle): """A rectangle with rounded corners. @@ -713,7 +732,7 @@ def construct(self): self.add(rect_group) """ - def __init__(self, corner_radius: float | list[float] = 0.5, **kwargs): + def __init__(self, corner_radius: float | list[float] = 0.5, **kwargs: Any): super().__init__(**kwargs) self.corner_radius = corner_radius self.round_corners(self.corner_radius) @@ -754,12 +773,77 @@ def construct(self): self.wait() """ - def __init__(self, main_shape: VMobject, *mobjects: VMobject, **kwargs) -> None: + def __init__( + self, main_shape: VMobject, *mobjects: VMobject, **kwargs: Any + ) -> None: super().__init__(**kwargs) self.append_points(main_shape.points) - if main_shape.get_direction() == "CW": - sub_direction = "CCW" - else: - sub_direction = "CW" + sub_direction: Literal["CCW", "CW"] = ( + "CCW" if main_shape.get_direction() == "CW" else "CW" + ) for mobject in mobjects: self.append_points(mobject.force_direction(sub_direction).points) + + +class ConvexHull(Polygram): + """Constructs a convex hull for a set of points in no particular order. + + Parameters + ---------- + points + The points to consider. + tolerance + The tolerance used by quickhull. + kwargs + Forwarded to the parent constructor. + + Examples + -------- + .. manim:: ConvexHullExample + :save_last_frame: + :quality: high + + class ConvexHullExample(Scene): + def construct(self): + points = [ + [-2.35, -2.25, 0], + [1.65, -2.25, 0], + [2.65, -0.25, 0], + [1.65, 1.75, 0], + [-0.35, 2.75, 0], + [-2.35, 0.75, 0], + [-0.35, -1.25, 0], + [0.65, -0.25, 0], + [-1.35, 0.25, 0], + [0.15, 0.75, 0] + ] + hull = ConvexHull(*points, color=BLUE) + dots = VGroup(*[Dot(point) for point in points]) + self.add(hull) + self.add(dots) + """ + + def __init__( + self, *points: Point3D, tolerance: float = 1e-5, **kwargs: Any + ) -> None: + # Build Convex Hull + array = np.array(points)[:, :2] + hull = QuickHull(tolerance) + hull.build(array) + + # Extract Vertices + facets = set(hull.facets) - hull.removed + facet = facets.pop() + subfacets = list(facet.subfacets) + while len(subfacets) <= len(facets): + sf = subfacets[-1] + (facet,) = hull.neighbors[sf] - {facet} + (sf,) = facet.subfacets - {sf} + subfacets.append(sf) + + # Setup Vertices as Point3D + coordinates = np.vstack([sf.coordinates for sf in subfacets]) + vertices = np.hstack((coordinates, np.zeros((len(coordinates), 1)))) + + # Call Polygram + super().__init__(vertices, **kwargs) diff --git a/manim/mobject/geometry/shape_matchers.py b/manim/mobject/geometry/shape_matchers.py index 76c0d86ec6..b6148824f9 100644 --- a/manim/mobject/geometry/shape_matchers.py +++ b/manim/mobject/geometry/shape_matchers.py @@ -6,8 +6,15 @@ from typing import TYPE_CHECKING, Any -from manim import config, logger -from manim.constants import * +from manim import logger +from manim._config import config +from manim.constants import ( + DOWN, + LEFT, + RIGHT, + SMALL_BUFF, + UP, +) from manim.mobject.geometry.line import Line from manim.mobject.geometry.polygram import RoundedRectangle from manim.mobject.mobject import Mobject @@ -44,21 +51,29 @@ def construct(self): def __init__( self, - mobject: Mobject, + *mobjects: Mobject, color: ParsableManimColor = YELLOW, buff: float = SMALL_BUFF, corner_radius: float = 0.0, - **kwargs, + **kwargs: Any, ) -> None: + from manim.mobject.mobject import Group + + if not all(isinstance(mob, Mobject) for mob in mobjects): + raise TypeError( + "Expected all inputs for parameter mobjects to be a Mobjects" + ) + + group = Group(*mobjects) super().__init__( color=color, - width=mobject.width + 2 * buff, - height=mobject.height + 2 * buff, + width=group.width + 2 * buff, + height=group.height + 2 * buff, corner_radius=corner_radius, **kwargs, ) self.buff = buff - self.move_to(mobject) + self.move_to(group) class BackgroundRectangle(SurroundingRectangle): @@ -88,19 +103,19 @@ def construct(self): def __init__( self, - mobject: Mobject, + *mobjects: Mobject, color: ParsableManimColor | None = None, stroke_width: float = 0, stroke_opacity: float = 0, fill_opacity: float = 0.75, buff: float = 0, - **kwargs, - ): + **kwargs: Any, + ) -> None: if color is None: color = config.background_color super().__init__( - mobject, + *mobjects, color=color, stroke_width=stroke_width, stroke_opacity=stroke_opacity, @@ -114,7 +129,7 @@ def pointwise_become_partial(self, mobject: Mobject, a: Any, b: float) -> Self: self.set_fill(opacity=b * self.original_fill_opacity) return self - def set_style(self, fill_opacity: float, **kwargs) -> Self: + def set_style(self, fill_opacity: float, **kwargs: Any) -> Self: # type: ignore[override] # Unchangeable style, except for fill_opacity # All other style arguments are ignored super().set_style( @@ -131,7 +146,10 @@ def set_style(self, fill_opacity: float, **kwargs) -> Self: return self def get_fill_color(self) -> ManimColor: - return self.color + # The type of the color property is set to Any using the property decorator + # vectorized_mobject.py#L571 + temp_color: ManimColor = self.color + return temp_color class Cross(VGroup[Line]): @@ -165,7 +183,7 @@ def __init__( stroke_color: ParsableManimColor = RED, stroke_width: float = 6.0, scale_factor: float = 1.0, - **kwargs, + **kwargs: Any, ) -> None: super().__init__(Line(UL, DR), Line(UR, DL), **kwargs) if mobject is not None: @@ -189,7 +207,9 @@ def construct(self): self.add(man, ul) """ - def __init__(self, mobject: Mobject, buff: float = SMALL_BUFF, **kwargs) -> None: + def __init__( + self, mobject: Mobject, buff: float = SMALL_BUFF, **kwargs: Any + ) -> None: super().__init__(LEFT, RIGHT, buff=buff, **kwargs) self.match_width(mobject) self.next_to(mobject, DOWN, buff=self.buff) diff --git a/manim/mobject/geometry/tips.py b/manim/mobject/geometry/tips.py index a7f116d3bf..5479f768e8 100644 --- a/manim/mobject/geometry/tips.py +++ b/manim/mobject/geometry/tips.py @@ -25,7 +25,9 @@ from manim.utils.space_ops import angle_of_vector if TYPE_CHECKING: - from manim.typing import Point3D, Vector3D + from typing import Any + + from manim.typing import InternalPoint3D, Point3D, Vector3D class ArrowTip(VMobject, metaclass=ConvertToOpenGL): @@ -112,7 +114,7 @@ def construct(self): self.add(*big_arrows, *small_arrows, *labels) """ - def __init__(self, *args, **kwargs) -> None: + def __init__(self, *args: Any, **kwargs: Any) -> None: raise NotImplementedError("Has to be implemented in inheriting subclasses.") @property @@ -134,7 +136,7 @@ def base(self) -> Point3D: return self.point_from_proportion(0.5) @property - def tip_point(self) -> Point3D: + def tip_point(self) -> InternalPoint3D: r"""The tip point of the arrow tip. Examples @@ -147,6 +149,9 @@ def tip_point(self) -> Point3D: array([2., 0., 0.]) """ + # Type inference of extracting an element from a list, is not + # supported by numpy, see this numpy issue + # https://github.com/numpy/numpy/issues/16544 return self.points[0] @property @@ -175,14 +180,14 @@ def tip_angle(self) -> float: >>> from manim import Arrow >>> arrow = Arrow(np.array([0, 0, 0]), np.array([1, 1, 0]), buff=0) - >>> round(arrow.tip.tip_angle, 5) == round(PI/4, 5) + >>> bool(round(arrow.tip.tip_angle, 5) == round(PI/4, 5)) True """ return angle_of_vector(self.vector) @property - def length(self) -> np.floating: + def length(self) -> float: r"""The length of the arrow tip. Examples @@ -195,7 +200,7 @@ def length(self) -> np.floating: 0.35 """ - return np.linalg.norm(self.vector) + return float(np.linalg.norm(self.vector)) class StealthTip(ArrowTip): @@ -207,36 +212,38 @@ class StealthTip(ArrowTip): def __init__( self, - fill_opacity=1, - stroke_width=3, - length=DEFAULT_ARROW_TIP_LENGTH / 2, - start_angle=PI, - **kwargs, + fill_opacity: float = 1, + stroke_width: float = 3, + length: float = DEFAULT_ARROW_TIP_LENGTH / 2, + start_angle: float = PI, + **kwargs: Any, ): self.start_angle = start_angle VMobject.__init__( self, fill_opacity=fill_opacity, stroke_width=stroke_width, **kwargs ) self.set_points_as_corners( - [ - [2, 0, 0], # tip - [-1.2, 1.6, 0], - [0, 0, 0], # base - [-1.2, -1.6, 0], - [2, 0, 0], # close path, back to tip - ] + np.array( + [ + [2, 0, 0], # tip + [-1.2, 1.6, 0], + [0, 0, 0], # base + [-1.2, -1.6, 0], + [2, 0, 0], # close path, back to tip + ] + ) ) self.scale(length / self.length) @property - def length(self): + def length(self) -> float: """The length of the arrow tip. In this case, the length is computed as the height of the triangle encompassing the stealth tip (otherwise, the tip is scaled too large). """ - return np.linalg.norm(self.vector) * 1.6 + return float(np.linalg.norm(self.vector) * 1.6) class ArrowTriangleTip(ArrowTip, Triangle): @@ -249,7 +256,7 @@ def __init__( length: float = DEFAULT_ARROW_TIP_LENGTH, width: float = DEFAULT_ARROW_TIP_LENGTH, start_angle: float = PI, - **kwargs, + **kwargs: Any, ) -> None: Triangle.__init__( self, @@ -271,7 +278,7 @@ class ArrowTriangleFilledTip(ArrowTriangleTip): """ def __init__( - self, fill_opacity: float = 1, stroke_width: float = 0, **kwargs + self, fill_opacity: float = 1, stroke_width: float = 0, **kwargs: Any ) -> None: super().__init__(fill_opacity=fill_opacity, stroke_width=stroke_width, **kwargs) @@ -285,7 +292,7 @@ def __init__( stroke_width: float = 3, length: float = DEFAULT_ARROW_TIP_LENGTH, start_angle: float = PI, - **kwargs, + **kwargs: Any, ) -> None: self.start_angle = start_angle Circle.__init__( @@ -299,7 +306,7 @@ class ArrowCircleFilledTip(ArrowCircleTip): r"""Circular arrow tip with filled tip.""" def __init__( - self, fill_opacity: float = 1, stroke_width: float = 0, **kwargs + self, fill_opacity: float = 1, stroke_width: float = 0, **kwargs: Any ) -> None: super().__init__(fill_opacity=fill_opacity, stroke_width=stroke_width, **kwargs) @@ -313,7 +320,7 @@ def __init__( stroke_width: float = 3, length: float = DEFAULT_ARROW_TIP_LENGTH, start_angle: float = PI, - **kwargs, + **kwargs: Any, ) -> None: self.start_angle = start_angle Square.__init__( @@ -331,6 +338,6 @@ class ArrowSquareFilledTip(ArrowSquareTip): r"""Square arrow tip with filled tip.""" def __init__( - self, fill_opacity: float = 1, stroke_width: float = 0, **kwargs + self, fill_opacity: float = 1, stroke_width: float = 0, **kwargs: Any ) -> None: super().__init__(fill_opacity=fill_opacity, stroke_width=stroke_width, **kwargs) diff --git a/manim/mobject/graph.py b/manim/mobject/graph.py index 72a26d27db..9cca91f03e 100644 --- a/manim/mobject/graph.py +++ b/manim/mobject/graph.py @@ -338,10 +338,7 @@ def _tree_layout( parent = {u: root_vertex for u in children[root_vertex]} pos = {} obstruction = [0.0] * len(T) - if orientation == "down": - o = -1 - else: - o = 1 + o = -1 if orientation == "down" else 1 def slide(v, dx): """ @@ -404,15 +401,9 @@ def slide(v, dx): if isinstance(scale, (float, int)) and (width > 0 or height > 0): sf = 2 * scale / max(width, height) elif isinstance(scale, tuple): - if scale[0] is not None and width > 0: - sw = 2 * scale[0] / width - else: - sw = 1 + sw = 2 * scale[0] / width if scale[0] is not None and width > 0 else 1 - if scale[1] is not None and height > 0: - sh = 2 * scale[1] / height - else: - sh = 1 + sh = 2 * scale[1] / height if scale[1] is not None and height > 0 else 1 sf = np.array([sw, sh, 0]) else: @@ -478,11 +469,11 @@ def _determine_graph_layout( return cast(LayoutFunction, layout)( nx_graph, scale=layout_scale, **layout_config ) - except TypeError: + except TypeError as e: raise ValueError( f"The layout '{layout}' is neither a recognized layout, a layout function," "nor a vertex placement dictionary.", - ) + ) from e class GenericGraph(VMobject, metaclass=ConvertToOpenGL): @@ -826,7 +817,7 @@ def _create_vertices( labels = {v: labels for v in vertices} else: assert isinstance(labels, dict) - base_labels = {v: False for v in vertices} + base_labels = dict.fromkeys(vertices, False) base_labels.update(labels) labels = base_labels @@ -851,7 +842,7 @@ def _create_vertices( label_fill_color=label_fill_color, vertex_type=vertex_type, vertex_config=vertex_config[v], - vertex_mobject=vertex_mobjects[v] if v in vertex_mobjects else None, + vertex_mobject=vertex_mobjects.get(v), ) for v in vertices ] diff --git a/manim/mobject/graphing/coordinate_systems.py b/manim/mobject/graphing/coordinate_systems.py index 435d7aced8..fa07c7fd53 100644 --- a/manim/mobject/graphing/coordinate_systems.py +++ b/manim/mobject/graphing/coordinate_systems.py @@ -48,6 +48,7 @@ ManimColor, ParsableManimColor, color_gradient, + interpolate_color, invert_color, ) from manim.utils.config_ops import merge_dicts_recursively, update_dict_recursively @@ -333,7 +334,6 @@ def construct(self): ) self.add(ax, y_label) """ - return self._get_axis_label( label, self.get_y_axis(), edge, direction, buff=buff, **kwargs ) @@ -366,7 +366,6 @@ def _get_axis_label( :class:`~.Mobject` The positioned label along the given axis. """ - label = self.x_axis._create_label_tex(label) label.next_to(axis.get_edge_center(edge), direction=direction, buff=buff) label.shift_onto_screen(buff=MED_SMALL_BUFF) @@ -420,7 +419,6 @@ def add_coordinates( x_dict = dict(zip(x_pos, x_vals)) ax.add_coordinates(x_dict) """ - self.coordinate_labels = VGroup() # if nothing is passed to axes_numbers, produce axes with default labelling if not axes_numbers: @@ -501,7 +499,6 @@ def get_line_from_axis_to_point( # type: ignore[no-untyped-def] :meth:`~.CoordinateSystem.get_vertical_line` :meth:`~.CoordinateSystem.get_horizontal_line` """ - line_config = line_config if line_config is not None else {} if color is None: @@ -578,7 +575,6 @@ def construct(self): self.add(ax, line, dot) """ - return self.get_line_from_axis_to_point(1, point, **kwargs) def get_lines_to_point(self, point: Sequence[float], **kwargs) -> VGroup: @@ -615,7 +611,6 @@ def construct(self): lines_2 = ax.get_lines_to_point(circ.get_corner(DL), color=BLUE_B) self.add(ax, lines_1, lines_2, circ) """ - return VGroup( self.get_horizontal_line(point, **kwargs), self.get_vertical_line(point, **kwargs), @@ -628,6 +623,8 @@ def plot( function: Callable[[float], float], x_range: Sequence[float] | None = None, use_vectorized: bool = False, + colorscale: Union[Iterable[Color], Iterable[Color, float]] | None = None, + colorscale_axis: int = 1, **kwargs: Any, ) -> ParametricFunction: """Generates a curve based on a function. @@ -641,6 +638,12 @@ def plot( use_vectorized Whether to pass in the generated t value array to the function. Only use this if your function supports it. Output should be a numpy array of shape ``[y_0, y_1, ...]`` + colorscale + Colors of the function. Optional parameter used when coloring a function by values. Passing a list of colors + and a colorscale_axis will color the function by y-value. Passing a list of tuples in the form ``(color, pivot)`` + allows user-defined pivots where the color transitions. + colorscale_axis + Defines the axis on which the colorscale is applied (0 = x, 1 = y), default is y-axis (1). kwargs Additional parameters to be passed to :class:`~.ParametricFunction`. @@ -700,7 +703,6 @@ def log_func(x): self.add(axes, curves) """ - t_range = np.array(self.x_range, dtype=float) if x_range is not None: t_range[: len(x_range)] = x_range @@ -719,7 +721,57 @@ def log_func(x): use_vectorized=use_vectorized, **kwargs, ) + graph.underlying_function = function + + if colorscale: + if type(colorscale[0]) in (list, tuple): + new_colors, pivots = [ + [i for i, j in colorscale], + [j for i, j in colorscale], + ] + else: + new_colors = colorscale + + ranges = [self.x_range, self.y_range] + pivot_min = ranges[colorscale_axis][0] + pivot_max = ranges[colorscale_axis][1] + pivot_frequency = (pivot_max - pivot_min) / (len(new_colors) - 1) + pivots = np.arange( + start=pivot_min, + stop=pivot_max + pivot_frequency, + step=pivot_frequency, + ) + + resolution = 0.01 if len(x_range) == 2 else x_range[2] + sample_points = np.arange(x_range[0], x_range[1] + resolution, resolution) + color_list = [] + for samp_x in sample_points: + axis_value = (samp_x, function(samp_x))[colorscale_axis] + if axis_value <= pivots[0]: + color_list.append(new_colors[0]) + elif axis_value >= pivots[-1]: + color_list.append(new_colors[-1]) + else: + for i, pivot in enumerate(pivots): + if pivot > axis_value: + color_index = (axis_value - pivots[i - 1]) / ( + pivots[i] - pivots[i - 1] + ) + color_index = min(color_index, 1) + mob_color = interpolate_color( + new_colors[i - 1], + new_colors[i], + color_index, + ) + color_list.append(mob_color) + break + if config.renderer == RendererType.OPENGL: + graph.set_color(color_list) + else: + graph.set_stroke(color_list) + graph.set_sheen_direction(RIGHT) + return graph def plot_implicit_curve( @@ -987,7 +1039,6 @@ def construct(self): self.add(ax, curve, sq) """ - if hasattr(graph, "underlying_function"): return graph.function(x) else: @@ -1043,7 +1094,7 @@ def get_graph_label( dot: bool = False, dot_config: dict[str, Any] | None = None, ) -> Mobject: - """Creates a properly positioned label for the passed graph, with an optional dot. + r"""Creates a properly positioned label for the passed graph, with an optional dot. Parameters ---------- @@ -1080,7 +1131,7 @@ def construct(self): sin = ax.plot(lambda x: np.sin(x), color=PURPLE_B) label = ax.get_graph_label( graph=sin, - label= MathTex(r"\\frac{\\pi}{2}"), + label= MathTex(r"\frac{\pi}{2}"), x_val=PI / 2, dot=True, direction=UR, @@ -1088,7 +1139,6 @@ def construct(self): self.add(ax, sin, label) """ - if dot_config is None: dot_config = {} if color is None: @@ -1208,7 +1258,6 @@ def construct(self): ax, bounding_line, quadratic, rects_right, rects_left, bounded_rects ) """ - # setting up x_range, overwrite user's third input if x_range is None: if bounded_graph is None: @@ -1398,7 +1447,6 @@ def angle_of_tangent( ax.angle_of_tangent(x=3, graph=curve) # 1.4056476493802699 """ - p0 = np.array([*self.input_to_graph_coords(x, graph)]) p1 = np.array([*self.input_to_graph_coords(x + dx, graph)]) return angle_of_vector(p1 - p0) @@ -1430,7 +1478,6 @@ def slope_of_tangent( ax.slope_of_tangent(x=-2, graph=curve) # -3.5000000259052038 """ - return np.tan(self.angle_of_tangent(x, graph, **kwargs)) def plot_derivative_graph( @@ -1706,7 +1753,6 @@ def construct(self): self.add(ax, curve, lines) """ - x_range = x_range if x_range is not None else self.x_range return VGroup( @@ -1768,7 +1814,6 @@ def construct(self): t_label = axes.get_T_label(x_val=4, graph=func, label=Tex("x-value")) self.add(axes, func, t_label) """ - T_label_group = VGroup() triangle = RegularPolygon(n=3, start_angle=np.pi / 2, stroke_width=0).set_fill( color=triangle_color, @@ -1960,7 +2005,6 @@ def _update_default_configs( ) ) """ - for default_config, passed_config in zip(default_configs, passed_configs): if passed_config is not None: update_dict_recursively(default_config, passed_config) @@ -2205,7 +2249,6 @@ def construct(self): ) self.add(ax, labels) """ - self.axis_labels = VGroup( self.get_x_axis_label(x_label), self.get_y_axis_label(y_label), @@ -2492,7 +2535,6 @@ def construct(self): self.set_camera_orientation(phi=2*PI/5, theta=PI/5) self.add(ax, lab) """ - positioned_label = self._get_axis_label( label, self.get_y_axis(), edge, direction, buff=buff, **kwargs ) @@ -2543,7 +2585,6 @@ def construct(self): self.set_camera_orientation(phi=2*PI/5, theta=PI/5) self.add(ax, lab) """ - positioned_label = self._get_axis_label( label, self.get_z_axis(), edge, direction, buff=buff, **kwargs ) @@ -2597,7 +2638,6 @@ def construct(self): ) self.add(axes, labels) """ - self.axis_labels = VGroup( self.get_x_axis_label(x_label), self.get_y_axis_label(y_label), @@ -2821,7 +2861,6 @@ def _get_lines_parallel_to_axis( The first (i.e the non-faded lines parallel to `axis_parallel_to`) and second (i.e the faded lines parallel to `axis_parallel_to`) sets of lines, respectively. """ - line = Line(axis_parallel_to.get_start(), axis_parallel_to.get_end()) if ratio_faded_lines == 0: # don't show faded lines ratio_faded_lines = 1 # i.e. set ratio to 1 @@ -3333,7 +3372,6 @@ def number_to_point(self, number: float | complex) -> np.ndarray: np.ndarray The point on the plane. """ - number = complex(number) return self.coords_to_point(number.real, number.imag) @@ -3354,7 +3392,6 @@ def point_to_number(self, point: Point3D) -> complex: complex A complex number consisting of real and imaginary components. """ - x, y = self.point_to_coords(point) return complex(x, y) @@ -3392,7 +3429,6 @@ def get_coordinate_labels( :class:`~.VGroup` A :class:`~.VGroup` containing the positioned label mobjects. """ - # TODO: Make this work the same as coord_sys.add_coordinates() if len(numbers) == 0: numbers = self._get_default_coordinate_values() @@ -3423,6 +3459,5 @@ def add_coordinates( kwargs Additional arguments to be passed to :meth:`~.NumberLine.get_number_mobject`, i.e. :class:`~.DecimalNumber`. """ - self.add(self.get_coordinate_labels(*numbers, **kwargs)) return self diff --git a/manim/mobject/graphing/functions.py b/manim/mobject/graphing/functions.py index 8ed4b43c2e..1cd660b894 100644 --- a/manim/mobject/graphing/functions.py +++ b/manim/mobject/graphing/functions.py @@ -17,7 +17,9 @@ from manim.mobject.types.vectorized_mobject import VMobject if TYPE_CHECKING: - from manim.typing import Point2D, Point3D + from typing_extensions import Self + + from manim.typing import Point3D from manim.utils.color import YELLOW @@ -103,7 +105,7 @@ def construct(self): def __init__( self, function: Callable[[float], Point3D], - t_range: Point2D | Point3D = (0, 1), + t_range: tuple[float, float] | tuple[float, float, float] = (0, 1), scaling: _ScaleBase = LinearBase(), dt: float = 1e-8, discontinuities: Iterable[float] | None = None, @@ -112,9 +114,8 @@ def __init__( **kwargs, ): self.function = function - t_range = (0, 1, 0.01) if t_range is None else t_range if len(t_range) == 2: - t_range = np.array([*t_range, 0.01]) + t_range = (*t_range, 0.01) self.scaling = scaling @@ -126,13 +127,13 @@ def __init__( super().__init__(**kwargs) - def get_function(self): + def get_function(self) -> Callable[[float], Point3D]: return self.function - def get_point_from_function(self, t): + def get_point_from_function(self, t: float) -> Point3D: return self.function(t) - def generate_points(self): + def generate_points(self) -> Self: if self.discontinuities is not None: discontinuities = filter( lambda t: self.t_min <= t <= self.t_max, diff --git a/manim/mobject/graphing/number_line.py b/manim/mobject/graphing/number_line.py index 26df7df044..70c40e6bbc 100644 --- a/manim/mobject/graphing/number_line.py +++ b/manim/mobject/graphing/number_line.py @@ -277,7 +277,8 @@ def rotate_about_number( def add_ticks(self): """Adds ticks to the number line. Ticks can be accessed after creation - via ``self.ticks``.""" + via ``self.ticks``. + """ ticks = VGroup() elongated_tick_size = self.tick_size * self.longer_tick_multiple elongated_tick_offsets = self.numbers_with_elongated_ticks - self.x_min @@ -402,9 +403,9 @@ def point_to_number(self, point: Sequence[float]) -> float: >>> from manim import NumberLine >>> number_line = NumberLine() >>> number_line.point_to_number((0, 0, 0)) - 0.0 + np.float64(0.0) >>> number_line.point_to_number((1, 0, 0)) - 1.0 + np.float64(1.0) >>> number_line.point_to_number([[0.5, 0, 0], [1, 0, 0], [1.5, 0, 0]]) array([0.5, 1. , 1.5]) @@ -580,7 +581,6 @@ def add_labels( AttributeError If the label does not have a ``font_size`` attribute, an ``AttributeError`` is raised. """ - direction = self.label_direction if direction is None else direction buff = self.line_to_number_buff if buff is None else buff font_size = self.font_size if font_size is None else font_size diff --git a/manim/mobject/graphing/probability.py b/manim/mobject/graphing/probability.py index 0f98620dc3..24134c0a7a 100644 --- a/manim/mobject/graphing/probability.py +++ b/manim/mobject/graphing/probability.py @@ -319,7 +319,6 @@ def _update_colors(self): Primarily used when the bars are initialized with ``self._add_bars`` or updated via ``self.change_bar_values``. """ - self.bars.set_color_by_gradient(*self.bar_colors) def _add_x_axis_labels(self): @@ -329,7 +328,6 @@ def _add_x_axis_labels(self): UP for negative values and DOWN for positive values. """ - val_range = np.arange( 0.5, len(self.bar_names), 1 ) # 0.5 shifted so that labels are centered, not on ticks @@ -339,10 +337,7 @@ def _add_x_axis_labels(self): for i, (value, bar_name) in enumerate(zip(val_range, self.bar_names)): # to accommodate negative bars, the label may need to be # below or above the x_axis depending on the value of the bar - if self.values[i] < 0: - direction = UP - else: - direction = DOWN + direction = UP if self.values[i] < 0 else DOWN bar_name_label = self.x_axis.label_constructor(bar_name) bar_name_label.font_size = self.x_axis.font_size @@ -372,7 +367,6 @@ def _create_bar(self, bar_number: int, value: float) -> Rectangle: Rectangle A positioned rectangle representing a bar on the chart. """ - # bar measurements relative to the axis # distance from between the y-axis and the top of the bar @@ -435,7 +429,6 @@ def construct(self): self.add(chart, c_bar_lbls) """ - bar_labels = VGroup() for bar, value in zip(self.bars, self.values): bar_lbl = label_constructor(str(value)) @@ -483,7 +476,6 @@ def construct(self): chart.change_bar_values(list(reversed(values))) self.add(chart.get_bar_labels(font_size=24)) """ - for i, (bar, value) in enumerate(zip(self.bars, values)): chart_val = self.values[i] diff --git a/manim/mobject/graphing/scale.py b/manim/mobject/graphing/scale.py index 8ba8a7e63c..78ffa2308b 100644 --- a/manim/mobject/graphing/scale.py +++ b/manim/mobject/graphing/scale.py @@ -90,7 +90,6 @@ def __init__(self, scale_factor: float = 1.0): scale_factor The slope of the linear function, by default 1.0 """ - super().__init__() self.scale_factor = scale_factor @@ -177,7 +176,6 @@ def get_custom_labels( base_config Additional arguments to be passed to :class:`~.Integer`. """ - # uses `format` syntax to control the number of decimal places. tex_labels = [ Integer( diff --git a/manim/mobject/matrix.py b/manim/mobject/matrix.py index 0921416383..e506bc4528 100644 --- a/manim/mobject/matrix.py +++ b/manim/mobject/matrix.py @@ -72,7 +72,7 @@ def matrix_to_mobject(matrix): class Matrix(VMobject, metaclass=ConvertToOpenGL): - """A mobject that displays a matrix on the screen. + r"""A mobject that displays a matrix on the screen. Parameters ---------- @@ -118,22 +118,22 @@ class Matrix(VMobject, metaclass=ConvertToOpenGL): class MatrixExamples(Scene): def construct(self): - m0 = Matrix([[2, "\\pi"], [-1, 1]]) + m0 = Matrix([[2, r"\pi"], [-1, 1]]) m1 = Matrix([[2, 0, 4], [-1, 1, 5]], v_buff=1.3, h_buff=0.8, bracket_h_buff=SMALL_BUFF, bracket_v_buff=SMALL_BUFF, - left_bracket="\\{", - right_bracket="\\}") + left_bracket=r"\{", + right_bracket=r"\}") m1.add(SurroundingRectangle(m1.get_columns()[1])) m2 = Matrix([[2, 1], [-1, 3]], element_alignment_corner=UL, left_bracket="(", right_bracket=")") m3 = Matrix([[2, 1], [-1, 3]], - left_bracket="\\\\langle", - right_bracket="\\\\rangle") + left_bracket=r"\langle", + right_bracket=r"\rangle") m4 = Matrix([[2, 1], [-1, 3]], ).set_column_colors(RED, GREEN) m5 = Matrix([[2, 1], [-1, 3]], @@ -241,7 +241,6 @@ def _add_brackets(self, left: str = "[", right: str = "]", **kwargs): :class:`Matrix` The current matrix object (self). """ - # Height per row of LaTeX array with default settings BRACKET_HEIGHT = 0.5977 @@ -280,7 +279,7 @@ def _add_brackets(self, left: str = "[", right: str = "]", **kwargs): return self def get_columns(self): - """Return columns of the matrix as VGroups. + r"""Return columns of the matrix as VGroups. Returns -------- @@ -299,7 +298,6 @@ def construct(self): m0.add(SurroundingRectangle(m0.get_columns()[1])) self.add(m0) """ - return VGroup( *( VGroup(*(row[i] for row in self.mob_matrix)) @@ -308,7 +306,7 @@ def construct(self): ) def set_column_colors(self, *colors: str): - """Set individual colors for each columns of the matrix. + r"""Set individual colors for each columns of the matrix. Parameters ---------- @@ -338,7 +336,7 @@ def construct(self): return self def get_rows(self): - """Return rows of the matrix as VGroups. + r"""Return rows of the matrix as VGroups. Returns -------- @@ -360,7 +358,7 @@ def construct(self): return VGroup(*(VGroup(*row) for row in self.mob_matrix)) def set_row_colors(self, *colors: str): - """Set individual colors for each row of the matrix. + r"""Set individual colors for each row of the matrix. Parameters ---------- @@ -438,7 +436,7 @@ def construct(self): return self.elements def get_brackets(self): - """Return the bracket mobjects. + r"""Return the bracket mobjects. Returns -------- @@ -464,7 +462,7 @@ def construct(self): class DecimalMatrix(Matrix): - """A mobject that displays a matrix with decimal entries on the screen. + r"""A mobject that displays a matrix with decimal entries on the screen. Examples -------- @@ -544,7 +542,7 @@ def __init__( class MobjectMatrix(Matrix): - """A mobject that displays a matrix of mobject entries on the screen. + r"""A mobject that displays a matrix of mobject entries on the screen. Examples -------- diff --git a/manim/mobject/mobject.py b/manim/mobject/mobject.py index 6e405a18eb..d0b13adfc3 100644 --- a/manim/mobject/mobject.py +++ b/manim/mobject/mobject.py @@ -44,11 +44,12 @@ from manim.typing import ( FunctionOverride, - Image, + InternalPoint3D, ManimFloat, ManimInt, MappingFunction, PathFuncType, + PixelArray, Point3D, Point3D_Array, Vector3D, @@ -406,14 +407,14 @@ def reset_points(self) -> None: """Sets :attr:`points` to be an empty array.""" self.points = np.zeros((0, self.dim)) - def init_colors(self) -> None: + def init_colors(self) -> object: """Initializes the colors. Gets called upon creation. This is an empty method that can be implemented by subclasses. """ - def generate_points(self) -> None: + def generate_points(self) -> object: """Initializes :attr:`points` and therefore the shape. Gets called upon creation. This is an empty method that can be implemented by @@ -666,7 +667,6 @@ def set(self, **kwargs) -> Self: >>> mob.foo 0 """ - for attr, value in kwargs.items(): setattr(self, attr, value) @@ -748,7 +748,6 @@ def construct(self): :meth:`length_over_dim` """ - # Get the length across the X dimension return self.length_over_dim(0) @@ -785,7 +784,6 @@ def construct(self): :meth:`length_over_dim` """ - # Get the length across the Y dimension return self.length_over_dim(1) @@ -806,7 +804,6 @@ def depth(self) -> float: :meth:`length_over_dim` """ - # Get the length across the Z dimension return self.length_over_dim(2) @@ -825,7 +822,7 @@ def apply_over_attr_arrays(self, func: MappingFunction) -> Self: # Displaying - def get_image(self, camera=None) -> Image: + def get_image(self, camera=None) -> PixelArray: if camera is None: from ..camera.camera import Camera @@ -838,7 +835,8 @@ def show(self, camera=None) -> None: def save_image(self, name: str | None = None) -> None: """Saves an image of only this :class:`Mobject` at its position to a png - file.""" + file. + """ self.get_image().save( Path(config.get_dir("video_dir")).joinpath((name or str(self)) + ".png"), ) @@ -1029,7 +1027,6 @@ def construct(self): :meth:`remove_updater` :class:`~.UpdateFromFunc` """ - if index is None: self.updaters.append(update_function) else: @@ -1119,7 +1116,6 @@ def match_updaters(self, mobject: Mobject) -> Self: :meth:`clear_updaters` """ - self.clear_updaters() for updater in mobject.get_updaters(): self.add_updater(updater) @@ -1145,7 +1141,6 @@ def suspend_updating(self, recursive: bool = True) -> Self: :meth:`add_updater` """ - self.updating_suspended = True if recursive: for submob in self.submobjects: @@ -1220,7 +1215,6 @@ def shift(self, *vectors: Vector3D) -> Self: -------- :meth:`move_to` """ - total_vector = reduce(op.add, vectors) for mob in self.family_members_with_points(): mob.points = mob.points.astype("float") @@ -1505,7 +1499,7 @@ def construct(self): tex_top.to_edge(UP) tex_side = Tex("I am moving to the side!") c = Circle().shift(2*DOWN) - self.add(tex_top, tex_side) + self.add(tex_top, tex_side, c) tex_side.to_edge(LEFT) c.to_edge(RIGHT, buff=0) @@ -1579,9 +1573,7 @@ def is_off_screen(self): return True if self.get_bottom()[1] > config["frame_y_radius"]: return True - if self.get_top()[1] < -config["frame_y_radius"]: - return True - return False + return self.get_top()[1] < -config["frame_y_radius"] def stretch_about_point(self, factor: float, dim: int, point: Point3D) -> Self: return self.stretch(factor, dim, about_point=point) @@ -1613,15 +1605,14 @@ def scale_to_fit_width(self, width: float, **kwargs) -> Self: >>> from manim import * >>> sq = Square() >>> sq.height - 2.0 + np.float64(2.0) >>> sq.scale_to_fit_width(5) Square >>> sq.width - 5.0 + np.float64(5.0) >>> sq.height - 5.0 + np.float64(5.0) """ - return self.rescale_to_fit(width, 0, stretch=False, **kwargs) def stretch_to_fit_width(self, width: float, **kwargs) -> Self: @@ -1639,15 +1630,14 @@ def stretch_to_fit_width(self, width: float, **kwargs) -> Self: >>> from manim import * >>> sq = Square() >>> sq.height - 2.0 + np.float64(2.0) >>> sq.stretch_to_fit_width(5) Square >>> sq.width - 5.0 + np.float64(5.0) >>> sq.height - 2.0 + np.float64(2.0) """ - return self.rescale_to_fit(width, 0, stretch=True, **kwargs) def scale_to_fit_height(self, height: float, **kwargs) -> Self: @@ -1665,15 +1655,14 @@ def scale_to_fit_height(self, height: float, **kwargs) -> Self: >>> from manim import * >>> sq = Square() >>> sq.width - 2.0 + np.float64(2.0) >>> sq.scale_to_fit_height(5) Square >>> sq.height - 5.0 + np.float64(5.0) >>> sq.width - 5.0 + np.float64(5.0) """ - return self.rescale_to_fit(height, 1, stretch=False, **kwargs) def stretch_to_fit_height(self, height: float, **kwargs) -> Self: @@ -1691,25 +1680,22 @@ def stretch_to_fit_height(self, height: float, **kwargs) -> Self: >>> from manim import * >>> sq = Square() >>> sq.width - 2.0 + np.float64(2.0) >>> sq.stretch_to_fit_height(5) Square >>> sq.height - 5.0 + np.float64(5.0) >>> sq.width - 2.0 + np.float64(2.0) """ - return self.rescale_to_fit(height, 1, stretch=True, **kwargs) def scale_to_fit_depth(self, depth: float, **kwargs) -> Self: """Scales the :class:`~.Mobject` to fit a depth while keeping width/height proportional.""" - return self.rescale_to_fit(depth, 2, stretch=False, **kwargs) def stretch_to_fit_depth(self, depth: float, **kwargs) -> Self: """Stretches the :class:`~.Mobject` to fit a depth, not keeping width/height proportional.""" - return self.rescale_to_fit(depth, 2, stretch=True, **kwargs) def set_coord(self, value, dim: int, direction: Vector3D = ORIGIN) -> Self: @@ -1836,7 +1822,6 @@ def add_background_rectangle( :class:`~.BackgroundRectangle` """ - # TODO, this does not behave well when the mobject has points, # since it gets displayed on top from manim.mobject.geometry.shape_matchers import BackgroundRectangle @@ -1988,14 +1973,15 @@ def restore(self) -> Self: def reduce_across_dimension(self, reduce_func: Callable, dim: int): """Find the min or max value from a dimension across all points in this and submobjects.""" - assert dim >= 0 and dim <= 2 + assert dim >= 0 + assert dim <= 2 if len(self.submobjects) == 0 and len(self.points) == 0: # If we have no points and no submobjects, return 0 (e.g. center) return 0 # If we do not have points (but do have submobjects) # use only the points from those. - if len(self.points) == 0: + if len(self.points) == 0: # noqa: SIM108 rv = None else: # Otherwise, be sure to include our own points @@ -2004,10 +1990,7 @@ def reduce_across_dimension(self, reduce_func: Callable, dim: int): # smallest dimension they have and compare it to the return value. for mobj in self.submobjects: value = mobj.reduce_across_dimension(reduce_func, dim) - if rv is None: - rv = value - else: - rv = reduce_func([value, rv]) + rv = value if rv is None else reduce_func([value, rv]) return rv def nonempty_submobjects(self) -> list[Self]: @@ -2176,17 +2159,17 @@ def get_z(self, direction: Vector3D = ORIGIN) -> ManimFloat: """Returns z Point3D of the center of the :class:`~.Mobject` as ``float``""" return self.get_coord(2, direction) - def get_start(self) -> Point3D: + def get_start(self) -> InternalPoint3D: """Returns the point, where the stroke that surrounds the :class:`~.Mobject` starts.""" self.throw_error_if_no_points() return np.array(self.points[0]) - def get_end(self) -> Point3D: + def get_end(self) -> InternalPoint3D: """Returns the point, where the stroke that surrounds the :class:`~.Mobject` ends.""" self.throw_error_if_no_points() return np.array(self.points[-1]) - def get_start_and_end(self) -> tuple[Point3D, Point3D]: + def get_start_and_end(self) -> tuple[InternalPoint3D, InternalPoint3D]: """Returns starting and ending point of a stroke as a ``tuple``.""" return self.get_start(), self.get_end() @@ -2488,10 +2471,10 @@ def init_size(num, alignments, sizes): buff_x = buff_y = buff # Initialize alignments correctly - def init_alignments(alignments, num, mapping, name, dir): + def init_alignments(alignments, num, mapping, name, dir_): if alignments is None: # Use cell_alignment as fallback - return [cell_alignment * dir] * num + return [cell_alignment * dir_] * num if len(alignments) != num: raise ValueError(f"{name}_alignments has a mismatching size.") alignments = list(alignments) @@ -2886,7 +2869,7 @@ def construct(self): >>> result = rect.copy().become(circ, stretch=True) >>> result.height, result.width - (2.0, 4.0) + (np.float64(2.0), np.float64(4.0)) >>> ellipse_points = np.array(result.get_anchors()) >>> ellipse_eq = np.sum(ellipse_points**2 * [1/4, 1, 0], axis=1) >>> np.allclose(ellipse_eq, 1) @@ -2900,14 +2883,14 @@ def construct(self): >>> result = rect.copy().become(circ, match_height=True) >>> result.height, result.width - (2.0, 2.0) + (np.float64(2.0), np.float64(2.0)) >>> circle_points = np.array(result.get_anchors()) >>> circle_eq = np.sum(circle_points**2, axis=1) >>> np.allclose(circle_eq, 1) True >>> result = rect.copy().become(circ, match_width=True) >>> result.height, result.width - (4.0, 4.0) + (np.float64(4.0), np.float64(4.0)) >>> circle_points = np.array(result.get_anchors()) >>> circle_eq = np.sum(circle_points**2, axis=1) >>> np.allclose(circle_eq, 2**2) diff --git a/manim/mobject/opengl/opengl_geometry.py b/manim/mobject/opengl/opengl_geometry.py index 2ec0bbe4dd..dc9a3fc2c2 100644 --- a/manim/mobject/opengl/opengl_geometry.py +++ b/manim/mobject/opengl/opengl_geometry.py @@ -187,7 +187,8 @@ def get_tips(self): def get_tip(self): """Returns the TipableVMobject instance's (first) tip, - otherwise throws an exception.""" + otherwise throws an exception. + """ tips = self.get_tips() if len(tips) == 0: raise Exception("tip not found") @@ -463,10 +464,7 @@ def account_for_buff(self, buff): if buff == 0: return # - if self.path_arc == 0: - length = self.get_length() - else: - length = self.get_arc_length() + length = self.get_length() if self.path_arc == 0 else self.get_arc_length() # if length < 2 * buff: return @@ -519,9 +517,7 @@ def get_angle(self): return angle_of_vector(self.get_vector()) def get_projection(self, point): - """ - Return projection of a point onto the line - """ + """Return projection of a point onto the line""" unit_vect = self.get_unit_vector() start = self.get_start() return start + np.dot(point - start, unit_vect) * unit_vect diff --git a/manim/mobject/opengl/opengl_mobject.py b/manim/mobject/opengl/opengl_mobject.py index c907c4c2e0..1f7d44d6a3 100644 --- a/manim/mobject/opengl/opengl_mobject.py +++ b/manim/mobject/opengl/opengl_mobject.py @@ -321,22 +321,25 @@ def construct(self): def init_data(self) -> None: """Initializes the ``points``, ``bounding_box`` and ``rgbas`` attributes and groups them into self.data. - Subclasses can inherit and overwrite this method to extend `self.data`.""" + Subclasses can inherit and overwrite this method to extend `self.data`. + """ self.points = np.zeros((0, 3)) self.bounding_box = np.zeros((3, 3)) self.rgbas = np.zeros((1, 4)) - def init_colors(self) -> None: + def init_colors(self) -> object: """Initializes the colors. - Gets called upon creation""" + Gets called upon creation + """ self.set_color(self.color, self.opacity) - def init_points(self): + def init_points(self) -> object: """Initializes :attr:`points` and therefore the shape. Gets called upon creation. This is an empty method that can be implemented by - subclasses.""" + subclasses. + """ # Typically implemented in subclass, unless purposefully left blank pass @@ -368,7 +371,6 @@ def set(self, **kwargs) -> Self: """ - for attr, value in kwargs.items(): setattr(self, attr, value) @@ -501,7 +503,6 @@ def construct(self): :meth:`length_over_dim` """ - # Get the length across the X dimension return self.length_over_dim(0) @@ -539,7 +540,6 @@ def construct(self): :meth:`length_over_dim` """ - # Get the length across the Y dimension return self.length_over_dim(1) @@ -560,7 +560,6 @@ def depth(self) -> float: :meth:`length_over_dim` """ - # Get the length across the Z dimension return self.length_over_dim(2) @@ -875,7 +874,6 @@ def insert( update_parent Whether or not to set ``mobject.parent`` to ``self``. """ - if update_parent: mobject.parent = self @@ -1351,7 +1349,8 @@ def construct(self): for submob in self.submobjects: submob.invert(recursive=True) self.submobjects.reverse() - # Is there supposed to be an assemble_family here? + self.assemble_family() + return self # Copying @@ -1868,9 +1867,7 @@ def is_off_screen(self) -> bool: return True if self.get_bottom()[1] > config.frame_y_radius: return True - if self.get_top()[1] < -config.frame_y_radius: - return True - return False + return self.get_top()[1] < -config.frame_y_radius def stretch_about_point(self, factor: float, dim: int, point: Point3D) -> Self: return self.stretch(factor, dim, about_point=point) @@ -2569,10 +2566,7 @@ def construct(self): if key not in mobject1.data or key not in mobject2.data: continue - if key in ("points", "bounding_box"): - func = path_func - else: - func = interpolate + func = path_func if key in ("points", "bounding_box") else interpolate self.data[key][:] = func(mobject1.data[key], mobject2.data[key], alpha) @@ -2647,7 +2641,6 @@ def construct(self): circ.become(square) self.wait(0.5) """ - if stretch: mobject.stretch_to_fit_height(self.height) mobject.stretch_to_fit_width(self.width) diff --git a/manim/mobject/opengl/opengl_point_cloud_mobject.py b/manim/mobject/opengl/opengl_point_cloud_mobject.py index 0b5a940a7e..1725eccee8 100644 --- a/manim/mobject/opengl/opengl_point_cloud_mobject.py +++ b/manim/mobject/opengl/opengl_point_cloud_mobject.py @@ -65,13 +65,11 @@ def add_points(self, points, rgbas=None, color=None, opacity=None): return self def thin_out(self, factor=5): - """ - Removes all but every nth point for n = factor - """ + """Removes all but every nth point for n = factor""" for mob in self.family_members_with_points(): num_points = mob.get_num_points() - def thin_func(): + def thin_func(num_points=num_points): return np.arange(0, num_points, factor) if len(mob.points) == len(mob.rgbas): @@ -126,9 +124,7 @@ def filter_out(self, condition): return self def sort_points(self, function=lambda p: p[0]): - """ - function is any map from R^3 to R - """ + """function is any map from R^3 to R""" for mob in self.family_members_with_points(): indices = np.argsort(np.apply_along_axis(function, 1, mob.points)) for key in mob.data: diff --git a/manim/mobject/opengl/opengl_vectorized_mobject.py b/manim/mobject/opengl/opengl_vectorized_mobject.py index 8037760c4a..b31934e999 100644 --- a/manim/mobject/opengl/opengl_vectorized_mobject.py +++ b/manim/mobject/opengl/opengl_vectorized_mobject.py @@ -472,9 +472,7 @@ def add_cubic_bezier_curve(self, anchor1, handle1, handle2, anchor2): self.append_points(new_points) def add_cubic_bezier_curve_to(self, handle1, handle2, anchor): - """ - Add cubic bezier curve to the path. - """ + """Add cubic bezier curve to the path.""" self.throw_error_if_no_points() quadratic_approx = get_quadratic_approximation_of_cubic( self.get_last_point(), @@ -817,7 +815,6 @@ def get_nth_curve_function_with_length( length : :class:`float` The length of the nth curve. """ - if sample_points is None: sample_points = 10 @@ -857,7 +854,6 @@ def get_nth_curve_length( length : :class:`float` The length of the nth curve. """ - _, length = self.get_nth_curve_function_with_length(n, sample_points) return length @@ -872,7 +868,6 @@ def get_curve_functions( Iterable[Callable[[float], np.ndarray]] The functions for the curves. """ - num_curves = self.get_num_curves() for n in range(num_curves): @@ -922,7 +917,6 @@ def get_curve_functions_with_lengths( Iterable[Tuple[Callable[[float], np.ndarray], float]] The functions and lengths of the curves. """ - num_curves = self.get_num_curves() for n in range(num_curves): @@ -948,7 +942,6 @@ def point_from_proportion(self, alpha: float) -> np.ndarray: :exc:`Exception` If the :class:`OpenGLVMobject` has no points. """ - if alpha < 0 or alpha > 1: raise ValueError(f"Alpha {alpha} not between 0 and 1.") @@ -1103,7 +1096,6 @@ def get_arc_length(self, sample_points_per_curve: int | None = None) -> float: float The length of the :class:`OpenGLVMobject`. """ - return np.sum( length for _, length in self.get_curve_functions_with_lengths( @@ -1874,10 +1866,7 @@ def __init__( if num_dashes > 0: # Assuming total length is 1 dash_len = r / n - if vmobject.is_closed(): - void_len = (1 - r) / n - else: - void_len = (1 - r) / (n - 1) + void_len = (1 - r) / n if vmobject.is_closed() else (1 - r) / (n - 1) self.add( *( diff --git a/manim/mobject/svg/brace.py b/manim/mobject/svg/brace.py index 17429bb729..ae7ee6a2ac 100644 --- a/manim/mobject/svg/brace.py +++ b/manim/mobject/svg/brace.py @@ -5,6 +5,7 @@ __all__ = ["Brace", "BraceLabel", "ArcBrace", "BraceText", "BraceBetweenPoints"] from collections.abc import Sequence +from typing import TYPE_CHECKING import numpy as np import svgelements as se @@ -24,6 +25,10 @@ from ...utils.color import BLACK from ..svg.svg_mobject import VMobjectFromSVGPath +if TYPE_CHECKING: + from manim.typing import Point3D, Vector3D + from manim.utils.color.core import ParsableManimColor + __all__ = ["Brace", "BraceBetweenPoints", "BraceLabel", "ArcBrace"] @@ -65,13 +70,13 @@ def construct(self): def __init__( self, mobject: Mobject, - direction: Sequence[float] | None = DOWN, - buff=0.2, - sharpness=2, - stroke_width=0, - fill_opacity=1.0, - background_stroke_width=0, - background_stroke_color=BLACK, + direction: Vector3D | None = DOWN, + buff: float = 0.2, + sharpness: float = 2, + stroke_width: float = 0, + fill_opacity: float = 1.0, + background_stroke_width: float = 0, + background_stroke_color: ParsableManimColor = BLACK, **kwargs, ): path_string_template = ( @@ -125,7 +130,20 @@ def __init__( for mob in mobject, self: mob.rotate(angle, about_point=ORIGIN) - def put_at_tip(self, mob, use_next_to=True, **kwargs): + def put_at_tip(self, mob: Mobject, use_next_to: bool = True, **kwargs): + """Puts the given mobject at the brace tip. + + Parameters + ---------- + mob + The mobject to be placed at the tip. + use_next_to + If true, then :meth:`next_to` is used to place the mobject at the + tip. + kwargs + Any additional keyword arguments are passed to :meth:`next_to` which + is used to put the mobject next to the brace tip. + """ if use_next_to: mob.next_to(self.get_tip(), np.round(self.get_direction()), **kwargs) else: @@ -136,16 +154,45 @@ def put_at_tip(self, mob, use_next_to=True, **kwargs): return self def get_text(self, *text, **kwargs): + """Places the text at the brace tip. + + Parameters + ---------- + text + The text to be placed at the brace tip. + kwargs + Any additional keyword arguments are passed to :meth:`.put_at_tip` which + is used to position the text at the brace tip. + + Returns + ------- + :class:`~.Tex` + """ text_mob = Tex(*text) self.put_at_tip(text_mob, **kwargs) return text_mob def get_tex(self, *tex, **kwargs): + """Places the tex at the brace tip. + + Parameters + ---------- + tex + The tex to be placed at the brace tip. + kwargs + Any further keyword arguments are passed to :meth:`.put_at_tip` which + is used to position the tex at the brace tip. + + Returns + ------- + :class:`~.MathTex` + """ tex_mob = MathTex(*tex) self.put_at_tip(tex_mob, **kwargs) return tex_mob def get_tip(self): + """Returns the point at the brace tip.""" # Returns the position of the seventh point in the path, which is the tip. if config["renderer"] == "opengl": return self.points[34] @@ -153,6 +200,7 @@ def get_tip(self): return self.points[28] # = 7*4 def get_direction(self): + """Returns the direction from the center to the brace tip.""" vect = self.get_tip() - self.get_center() return vect / np.linalg.norm(vect) @@ -201,7 +249,7 @@ def __init__( self.brace = Brace(obj, brace_direction, buff, **brace_config) if isinstance(text, (tuple, list)): - self.label = self.label_constructor(font_size=font_size, *text, **kwargs) + self.label = self.label_constructor(*text, font_size=font_size, **kwargs) else: self.label = self.label_constructor(str(text), font_size=font_size) @@ -269,9 +317,9 @@ def construct(self): def __init__( self, - point_1: Sequence[float] | None, - point_2: Sequence[float] | None, - direction: Sequence[float] | None = ORIGIN, + point_1: Point3D | None, + point_2: Point3D | None, + direction: Vector3D | None = ORIGIN, **kwargs, ): if all(direction == ORIGIN): diff --git a/manim/mobject/svg/svg_mobject.py b/manim/mobject/svg/svg_mobject.py index c029daa942..82c121fce7 100644 --- a/manim/mobject/svg/svg_mobject.py +++ b/manim/mobject/svg/svg_mobject.py @@ -264,7 +264,8 @@ def get_mobjects_from(self, svg: se.SVG) -> list[VMobject]: """ result = [] for shape in svg.elements(): - if isinstance(shape, se.Group): + # can we combine the two continue cases into one? + if isinstance(shape, se.Group): # noqa: SIM114 continue elif isinstance(shape, se.Path): mob = self.path_to_mobject(shape) diff --git a/manim/mobject/table.py b/manim/mobject/table.py index 88f3f43b3e..aaed561996 100644 --- a/manim/mobject/table.py +++ b/manim/mobject/table.py @@ -85,7 +85,7 @@ def construct(self): class Table(VGroup[VMobjectT]): - """A mobject that displays a table on the screen. + r"""A mobject that displays a table on the screen. Parameters ---------- @@ -683,7 +683,6 @@ def construct(self): item.set_color(random_bright_color()) self.add(table) """ - return VGroup(*self.row_labels) def get_col_labels(self) -> VGroup: @@ -712,7 +711,6 @@ def construct(self): item.set_color(random_bright_color()) self.add(table) """ - return VGroup(*self.col_labels) def get_labels(self) -> VGroup: @@ -1067,7 +1065,7 @@ def __init__( class IntegerTable(Table): - """A specialized :class:`~.Table` mobject for use with :class:`~.Integer`. + r"""A specialized :class:`~.Table` mobject for use with :class:`~.Integer`. Examples -------- @@ -1081,14 +1079,14 @@ def construct(self): [[0,30,45,60,90], [90,60,45,30,0]], col_labels=[ - MathTex("\\\\frac{\\sqrt{0}}{2}"), - MathTex("\\\\frac{\\sqrt{1}}{2}"), - MathTex("\\\\frac{\\sqrt{2}}{2}"), - MathTex("\\\\frac{\\sqrt{3}}{2}"), - MathTex("\\\\frac{\\sqrt{4}}{2}")], - row_labels=[MathTex("\\sin"), MathTex("\\cos")], + MathTex(r"\frac{\sqrt{0}}{2}"), + MathTex(r"\frac{\sqrt{1}}{2}"), + MathTex(r"\frac{\sqrt{2}}{2}"), + MathTex(r"\frac{\sqrt{3}}{2}"), + MathTex(r"\frac{\sqrt{4}}{2}")], + row_labels=[MathTex(r"\sin"), MathTex(r"\cos")], h_buff=1, - element_to_mobject_config={"unit": "^{\\circ}"}) + element_to_mobject_config={"unit": r"^{\circ}"}) self.add(t0) """ diff --git a/manim/mobject/text/numbers.py b/manim/mobject/text/numbers.py index 6a0eb45a82..5283c24a20 100644 --- a/manim/mobject/text/numbers.py +++ b/manim/mobject/text/numbers.py @@ -22,7 +22,7 @@ class DecimalNumber(VMobject, metaclass=ConvertToOpenGL): - """An mobject representing a decimal number. + r"""An mobject representing a decimal number. Parameters ---------- @@ -210,10 +210,7 @@ def _get_num_string(self, number): rounded_num = np.round(number, self.num_decimal_places) if num_string.startswith("-") and rounded_num == 0: - if self.include_sign: - num_string = "+" + num_string[1:] - else: - num_string = num_string[1:] + num_string = "+" + num_string[1:] if self.include_sign else num_string[1:] return num_string diff --git a/manim/mobject/text/tex_mobject.py b/manim/mobject/text/tex_mobject.py index c6810d8f65..26334a60d9 100644 --- a/manim/mobject/text/tex_mobject.py +++ b/manim/mobject/text/tex_mobject.py @@ -12,7 +12,7 @@ from __future__ import annotations -from manim.utils.color import ManimColor +from manim.utils.color import BLACK, ManimColor, ParsableManimColor __all__ = [ "SingleStringMathTex", @@ -62,12 +62,11 @@ def __init__( tex_environment: str = "align*", tex_template: TexTemplate | None = None, font_size: float = DEFAULT_FONT_SIZE, + color: ParsableManimColor | None = None, **kwargs, ): - if kwargs.get("color") is None: - # makes it so that color isn't explicitly passed for these mobs, - # and can instead inherit from the parent - kwargs["color"] = VMobject().color + if color is None: + color = VMobject().color self._font_size = font_size self.organize_left_to_right = organize_left_to_right @@ -88,6 +87,7 @@ def __init__( should_center=should_center, stroke_width=stroke_width, height=height, + color=color, path_string_config={ "should_subdivide_sharp_curves": True, "should_remove_null_curves": True, @@ -191,7 +191,6 @@ def _remove_stray_braces(self, tex): This is important when the braces in the TeX code are spread over multiple arguments as in, e.g., ``MathTex(r"e^{i", r"\tau} = 1")``. """ - # "\{" does not count (it's a brace literal), but "\\{" counts (it's a new line and then brace) num_lefts = tex.count("{") - tex.count("\\{") + tex.count("\\\\{") num_rights = tex.count("}") - tex.count("\\}") + tex.count("\\\\}") @@ -211,10 +210,16 @@ def get_tex_string(self): return self.tex_string def init_colors(self, propagate_colors=True): - if config.renderer == RendererType.OPENGL: - super().init_colors() - elif config.renderer == RendererType.CAIRO: - super().init_colors(propagate_colors=propagate_colors) + for submobject in self.submobjects: + # needed to preserve original (non-black) + # TeX colors of individual submobjects + if submobject.color != BLACK: + continue + submobject.color = self.color + if config.renderer == RendererType.OPENGL: + submobject.init_colors() + elif config.renderer == RendererType.CAIRO: + submobject.init_colors(propagate_colors=propagate_colors) class MathTex(SingleStringMathTex): @@ -427,6 +432,10 @@ def sort_alphabetically(self): class Tex(MathTex): r"""A string compiled with LaTeX in normal mode. + The color can be set using + the ``color`` argument. Any parts of the ``tex_string`` that are colored by the + TeX commands ``\color`` or ``\textcolor`` will retain their original color. + Tests ----- diff --git a/manim/mobject/text/text_mobject.py b/manim/mobject/text/text_mobject.py index 346425bbbf..e8841a68dd 100644 --- a/manim/mobject/text/text_mobject.py +++ b/manim/mobject/text/text_mobject.py @@ -663,7 +663,8 @@ def _set_color_by_t2c(self, t2c=None): ) def _set_color_by_t2g(self, t2g=None): """Sets gradient colors for specified - strings. Behaves similarly to ``set_color_by_t2c``.""" + strings. Behaves similarly to ``set_color_by_t2c``. + """ t2g = t2g if t2g else self.t2g for word, gradient in list(t2g.items()): for start, end in self._find_indexes(word, self.text): @@ -1410,7 +1411,8 @@ def _count_real_chars(self, s): """Counts characters that will be displayed. This is needed for partial coloring or gradients, because space - counts to the text's `len`, but has no corresponding character.""" + counts to the text's `len`, but has no corresponding character. + """ count = 0 level = 0 # temporarily replace HTML entities by single char @@ -1453,7 +1455,9 @@ def _extract_gradient_tags(self): "end_offset": end_offset, }, ) - self.text = re.sub("]+>(.+?)", r"\1", self.text, 0, re.S) + self.text = re.sub( + "]+>(.+?)", r"\1", self.text, count=0, flags=re.S + ) return gradientmap def _parse_color(self, col): @@ -1495,7 +1499,9 @@ def _extract_color_tags(self): "end_offset": end_offset, }, ) - self.text = re.sub("]+>(.+?)", r"\1", self.text, 0, re.S) + self.text = re.sub( + "]+>(.+?)", r"\1", self.text, count=0, flags=re.S + ) return colormap def __repr__(self): @@ -1541,7 +1547,6 @@ def register_font(font_file: str | Path): This method is available for macOS for ``ManimPango>=v0.2.3``. Using this method with previous releases will raise an :class:`AttributeError` on macOS. """ - input_folder = Path(config.input_file).parent.resolve() possible_paths = [ Path(font_file), diff --git a/manim/mobject/three_d/polyhedra.py b/manim/mobject/three_d/polyhedra.py index 768b3e6377..d1d4718818 100644 --- a/manim/mobject/three_d/polyhedra.py +++ b/manim/mobject/three_d/polyhedra.py @@ -10,11 +10,20 @@ from manim.mobject.graph import Graph from manim.mobject.three_d.three_dimensions import Dot3D from manim.mobject.types.vectorized_mobject import VGroup, VMobjectT +from manim.utils.qhull import QuickHull if TYPE_CHECKING: from manim.mobject.mobject import Mobject + from manim.typing import Point3D -__all__ = ["Polyhedron", "Tetrahedron", "Octahedron", "Icosahedron", "Dodecahedron"] +__all__ = [ + "Polyhedron", + "Tetrahedron", + "Octahedron", + "Icosahedron", + "Dodecahedron", + "ConvexHull3D", +] class Polyhedron(VGroup[VMobjectT]): @@ -361,3 +370,91 @@ def __init__(self, edge_length: float = 1, **kwargs): ], **kwargs, ) + + +class ConvexHull3D(Polyhedron): + """A convex hull for a set of points + + Parameters + ---------- + points + The points to consider. + tolerance + The tolerance used for quickhull. + kwargs + Forwarded to the parent constructor. + + Examples + -------- + .. manim:: ConvexHull3DExample + :save_last_frame: + :quality: high + + class ConvexHull3DExample(ThreeDScene): + def construct(self): + self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES) + points = [ + [ 1.93192757, 0.44134585, -1.52407061], + [-0.93302521, 1.23206983, 0.64117067], + [-0.44350918, -0.61043677, 0.21723705], + [-0.42640268, -1.05260843, 1.61266094], + [-1.84449637, 0.91238739, -1.85172623], + [ 1.72068132, -0.11880457, 0.51881751], + [ 0.41904805, 0.44938012, -1.86440686], + [ 0.83864666, 1.66653337, 1.88960123], + [ 0.22240514, -0.80986286, 1.34249326], + [-1.29585759, 1.01516189, 0.46187522], + [ 1.7776499, -1.59550796, -1.70240747], + [ 0.80065226, -0.12530398, 1.70063977], + [ 1.28960948, -1.44158255, 1.39938582], + [-0.93538943, 1.33617705, -0.24852643], + [-1.54868271, 1.7444399, -0.46170734] + ] + hull = ConvexHull3D( + *points, + faces_config = {"stroke_opacity": 0}, + graph_config = { + "vertex_type": Dot3D, + "edge_config": { + "stroke_color": BLUE, + "stroke_width": 2, + "stroke_opacity": 0.05, + } + } + ) + dots = VGroup(*[Dot3D(point) for point in points]) + self.add(hull) + self.add(dots) + """ + + def __init__(self, *points: Point3D, tolerance: float = 1e-5, **kwargs): + # Build Convex Hull + array = np.array(points) + hull = QuickHull(tolerance) + hull.build(array) + + # Setup Lists + vertices = [] + faces = [] + + # Extract Faces + c = 0 + d = {} + facets = set(hull.facets) - hull.removed + for facet in facets: + tmp = set() + for subfacet in facet.subfacets: + for point in subfacet.points: + if point not in d: + vertices.append(point.coordinates) + d[point] = c + c += 1 + tmp.add(point) + faces.append([d[point] for point in tmp]) + + # Call Polyhedron + super().__init__( + vertex_coords=vertices, + faces_list=faces, + **kwargs, + ) diff --git a/manim/mobject/three_d/three_dimensions.py b/manim/mobject/three_d/three_dimensions.py index bd1afdc391..62945496cb 100644 --- a/manim/mobject/three_d/three_dimensions.py +++ b/manim/mobject/three_d/three_dimensions.py @@ -672,10 +672,7 @@ def _rotate_to_direction(self) -> None: x, y, z = self.direction r = np.sqrt(x**2 + y**2 + z**2) - if r > 0: - theta = np.arccos(z / r) - else: - theta = 0 + theta = np.arccos(z / r) if r > 0 else 0 if x == 0: if y == 0: # along the z axis @@ -840,10 +837,7 @@ def _rotate_to_direction(self) -> None: x, y, z = self.direction r = np.sqrt(x**2 + y**2 + z**2) - if r > 0: - theta = np.arccos(z / r) - else: - theta = 0 + theta = np.arccos(z / r) if r > 0 else 0 if x == 0: if y == 0: # along the z axis @@ -906,6 +900,12 @@ class Line3D(Cylinder): The thickness of the line. color The color of the line. + resolution + The resolution of the line. + By default this value is the number of points the line will sampled at. + If you want the line to also come out checkered, use a tuple. + For example, for a line made of 24 points with 4 checker points on each + cylinder, pass the tuple (4, 24). Examples -------- @@ -926,9 +926,11 @@ def __init__( end: np.ndarray = RIGHT, thickness: float = 0.02, color: ParsableManimColor | None = None, + resolution: int | Sequence[int] = 24, **kwargs, ): self.thickness = thickness + self.resolution = (2, resolution) if isinstance(resolution, int) else resolution self.set_start_and_end_attrs(start, end, **kwargs) if color is not None: self.set_color(color) @@ -962,6 +964,7 @@ def set_start_and_end_attrs( height=np.linalg.norm(self.vect), radius=self.thickness, direction=self.direction, + resolution=self.resolution, **kwargs, ) self.shift((self.start + self.end) / 2) @@ -1133,6 +1136,8 @@ class Arrow3D(Line3D): The base radius of the conical tip. color The color of the arrow. + resolution + The resolution of the arrow line. Examples -------- @@ -1159,10 +1164,16 @@ def __init__( height: float = 0.3, base_radius: float = 0.08, color: ParsableManimColor = WHITE, + resolution: int | Sequence[int] = 24, **kwargs, ) -> None: super().__init__( - start=start, end=end, thickness=thickness, color=color, **kwargs + start=start, + end=end, + thickness=thickness, + color=color, + resolution=resolution, + **kwargs, ) self.length = np.linalg.norm(self.vect) diff --git a/manim/mobject/types/image_mobject.py b/manim/mobject/types/image_mobject.py index db0304b502..56029f941e 100644 --- a/manim/mobject/types/image_mobject.py +++ b/manim/mobject/types/image_mobject.py @@ -5,6 +5,7 @@ __all__ = ["AbstractImageMobject", "ImageMobject", "ImageMobjectFromCamera"] import pathlib +from typing import TYPE_CHECKING import numpy as np from PIL import Image @@ -21,6 +22,14 @@ __all__ = ["ImageMobject", "ImageMobjectFromCamera"] +if TYPE_CHECKING: + from typing import Any + + import numpy.typing as npt + from typing_extensions import Self + + from manim.typing import StrPath + class AbstractImageMobject(Mobject): """ @@ -39,23 +48,23 @@ class AbstractImageMobject(Mobject): def __init__( self, scale_to_resolution: int, - pixel_array_dtype="uint8", - resampling_algorithm=Resampling.BICUBIC, - **kwargs, - ): + pixel_array_dtype: str = "uint8", + resampling_algorithm: Resampling = Resampling.BICUBIC, + **kwargs: Any, + ) -> None: self.pixel_array_dtype = pixel_array_dtype self.scale_to_resolution = scale_to_resolution self.set_resampling_algorithm(resampling_algorithm) super().__init__(**kwargs) - def get_pixel_array(self): + def get_pixel_array(self) -> None: raise NotImplementedError() def set_color(self, color, alpha=None, family=True): # Likely to be implemented in subclasses, but no obligation pass - def set_resampling_algorithm(self, resampling_algorithm: int): + def set_resampling_algorithm(self, resampling_algorithm: int) -> Self: """ Sets the interpolation method for upscaling the image. By default the image is interpolated using bicubic algorithm. This method lets you change it. @@ -87,7 +96,7 @@ def set_resampling_algorithm(self, resampling_algorithm: int): ) return self - def reset_points(self): + def reset_points(self) -> None: """Sets :attr:`points` to be the four image corners.""" self.points = np.array( [ @@ -171,15 +180,15 @@ def construct(self): def __init__( self, - filename_or_array, + filename_or_array: StrPath | npt.NDArray, scale_to_resolution: int = QUALITIES[DEFAULT_QUALITY]["pixel_height"], - invert=False, - image_mode="RGBA", - **kwargs, - ): - self.fill_opacity = 1 - self.stroke_opacity = 1 - self.invert = invert + invert: bool = False, + image_mode: str = "RGBA", + **kwargs: Any, + ) -> None: + self.fill_opacity: float = 1 + self.stroke_opacity: float = 1 + self.invert_image = invert self.image_mode = image_mode if isinstance(filename_or_array, (str, pathlib.PurePath)): path = get_full_raster_image_path(filename_or_array) @@ -192,7 +201,7 @@ def __init__( self.pixel_array = change_to_rgba_array( self.pixel_array, self.pixel_array_dtype ) - if self.invert: + if self.invert_image: self.pixel_array[:, :, :3] = ( np.iinfo(self.pixel_array_dtype).max - self.pixel_array[:, :, :3] ) @@ -212,7 +221,7 @@ def set_color(self, color, alpha=None, family=True): self.color = color return self - def set_opacity(self, alpha: float): + def set_opacity(self, alpha: float) -> Self: """Sets the image's opacity. Parameters @@ -226,7 +235,7 @@ def set_opacity(self, alpha: float): self.stroke_opacity = alpha return self - def fade(self, darkness: float = 0.5, family: bool = True): + def fade(self, darkness: float = 0.5, family: bool = True) -> Self: """Sets the image's opacity using a 1 - alpha relationship. Parameters @@ -243,7 +252,7 @@ def fade(self, darkness: float = 0.5, family: bool = True): def interpolate_color( self, mobject1: ImageMobject, mobject2: ImageMobject, alpha: float - ): + ) -> None: """Interpolates the array of pixel color values from one ImageMobject into an array of equal size in the target ImageMobject. @@ -279,7 +288,7 @@ def interpolate_color( alpha, ).astype(self.pixel_array_dtype) - def get_style(self): + def get_style(self) -> dict[str, Any]: return { "fill_color": ManimColor(self.color.get_rgb()).to_hex(), "fill_opacity": self.fill_opacity, @@ -292,7 +301,12 @@ def get_style(self): class ImageMobjectFromCamera(AbstractImageMobject): - def __init__(self, camera, default_display_frame_config=None, **kwargs): + def __init__( + self, + camera, + default_display_frame_config: dict[str, Any] | None = None, + **kwargs: Any, + ) -> None: self.camera = camera if default_display_frame_config is None: default_display_frame_config = { @@ -309,14 +323,14 @@ def get_pixel_array(self): self.pixel_array = self.camera.pixel_array return self.pixel_array - def add_display_frame(self, **kwargs): + def add_display_frame(self, **kwargs: Any) -> Self: config = dict(self.default_display_frame_config) config.update(kwargs) self.display_frame = SurroundingRectangle(self, **config) self.add(self.display_frame) return self - def interpolate_color(self, mobject1, mobject2, alpha): + def interpolate_color(self, mobject1, mobject2, alpha) -> None: assert mobject1.pixel_array.shape == mobject2.pixel_array.shape, ( f"Mobject pixel array shapes incompatible for interpolation.\n" f"Mobject 1 ({mobject1}) : {mobject1.pixel_array.shape}\n" diff --git a/manim/mobject/types/point_cloud_mobject.py b/manim/mobject/types/point_cloud_mobject.py index 4f43dbf597..c9f54e6ed2 100644 --- a/manim/mobject/types/point_cloud_mobject.py +++ b/manim/mobject/types/point_cloud_mobject.py @@ -4,6 +4,8 @@ __all__ = ["PMobject", "Mobject1D", "Mobject2D", "PGroup", "PointCloudDot", "Point"] +from typing import TYPE_CHECKING + import numpy as np from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL @@ -17,6 +19,7 @@ WHITE, YELLOW, ManimColor, + ParsableManimColor, color_gradient, color_to_rgba, rgba_to_color, @@ -25,6 +28,15 @@ __all__ = ["PMobject", "Mobject1D", "Mobject2D", "PGroup", "PointCloudDot", "Point"] +if TYPE_CHECKING: + from collections.abc import Callable + from typing import Any + + import numpy.typing as npt + from typing_extensions import Self + + from manim.typing import ManimFloat, Point3D, Vector3D + class PMobject(Mobject, metaclass=ConvertToOpenGL): """A disc made of a cloud of Dots @@ -55,19 +67,25 @@ def construct(self): """ - def __init__(self, stroke_width=DEFAULT_STROKE_WIDTH, **kwargs): + def __init__(self, stroke_width: int = DEFAULT_STROKE_WIDTH, **kwargs: Any) -> None: self.stroke_width = stroke_width super().__init__(**kwargs) - def reset_points(self): + def reset_points(self) -> Self: self.rgbas = np.zeros((0, 4)) self.points = np.zeros((0, 3)) return self - def get_array_attrs(self): + def get_array_attrs(self) -> list[str]: return super().get_array_attrs() + ["rgbas"] - def add_points(self, points, rgbas=None, color=None, alpha=1): + def add_points( + self, + points: npt.NDArray, + rgbas: npt.NDArray | None = None, + color: ParsableManimColor | None = None, + alpha: float = 1, + ) -> Self: """Add points. Points must be a Nx3 numpy array. @@ -85,24 +103,26 @@ def add_points(self, points, rgbas=None, color=None, alpha=1): self.rgbas = np.append(self.rgbas, rgbas, axis=0) return self - def set_color(self, color=YELLOW, family=True): + def set_color( + self, color: ParsableManimColor = YELLOW, family: bool = True + ) -> Self: rgba = color_to_rgba(color) mobs = self.family_members_with_points() if family else [self] for mob in mobs: mob.rgbas[:, :] = rgba - self.color = color + self.color = ManimColor.parse(color) return self - def get_stroke_width(self): + def get_stroke_width(self) -> int: return self.stroke_width - def set_stroke_width(self, width, family=True): + def set_stroke_width(self, width: int, family: bool = True) -> Self: mobs = self.family_members_with_points() if family else [self] for mob in mobs: mob.stroke_width = width return self - def set_color_by_gradient(self, *colors): + def set_color_by_gradient(self, *colors: ParsableManimColor) -> Self: self.rgbas = np.array( list(map(color_to_rgba, color_gradient(*colors, len(self.points)))), ) @@ -110,11 +130,11 @@ def set_color_by_gradient(self, *colors): def set_colors_by_radial_gradient( self, - center=None, - radius=1, - inner_color=WHITE, - outer_color=BLACK, - ): + center: Point3D | None = None, + radius: float = 1, + inner_color: ParsableManimColor = WHITE, + outer_color: ParsableManimColor = BLACK, + ) -> Self: start_rgba, end_rgba = list(map(color_to_rgba, [inner_color, outer_color])) if center is None: center = self.get_center() @@ -129,48 +149,48 @@ def set_colors_by_radial_gradient( ) return self - def match_colors(self, mobject): + def match_colors(self, mobject: Mobject) -> Self: Mobject.align_data(self, mobject) self.rgbas = np.array(mobject.rgbas) return self - def filter_out(self, condition): + def filter_out(self, condition: npt.NDArray) -> Self: for mob in self.family_members_with_points(): to_eliminate = ~np.apply_along_axis(condition, 1, mob.points) mob.points = mob.points[to_eliminate] mob.rgbas = mob.rgbas[to_eliminate] return self - def thin_out(self, factor=5): - """ - Removes all but every nth point for n = factor - """ + def thin_out(self, factor: int = 5) -> Self: + """Removes all but every nth point for n = factor""" for mob in self.family_members_with_points(): num_points = self.get_num_points() mob.apply_over_attr_arrays( - lambda arr: arr[np.arange(0, num_points, factor)], + lambda arr, n=num_points: arr[np.arange(0, n, factor)], ) return self - def sort_points(self, function=lambda p: p[0]): - """ - Function is any map from R^3 to R - """ + def sort_points( + self, function: Callable[[npt.NDArray[ManimFloat]], float] = lambda p: p[0] + ) -> Self: + """Function is any map from R^3 to R""" for mob in self.family_members_with_points(): indices = np.argsort(np.apply_along_axis(function, 1, mob.points)) - mob.apply_over_attr_arrays(lambda arr: arr[indices]) + mob.apply_over_attr_arrays(lambda arr, idx=indices: arr[idx]) return self - def fade_to(self, color, alpha, family=True): + def fade_to( + self, color: ParsableManimColor, alpha: float, family: bool = True + ) -> Self: self.rgbas = interpolate(self.rgbas, color_to_rgba(color), alpha) for mob in self.submobjects: mob.fade_to(color, alpha, family) return self - def get_all_rgbas(self): + def get_all_rgbas(self) -> npt.NDArray: return self.get_merged_array("rgbas") - def ingest_submobjects(self): + def ingest_submobjects(self) -> Self: attrs = self.get_array_attrs() arrays = list(map(self.get_merged_array, attrs)) for attr, array in zip(attrs, arrays): @@ -178,30 +198,32 @@ def ingest_submobjects(self): self.submobjects = [] return self - def get_color(self): + def get_color(self) -> ManimColor: return rgba_to_color(self.rgbas[0, :]) - def point_from_proportion(self, alpha): + def point_from_proportion(self, alpha: float) -> Any: index = alpha * (self.get_num_points() - 1) - return self.points[index] + return self.points[np.floor(index)] @staticmethod - def get_mobject_type_class(): + def get_mobject_type_class() -> type[PMobject]: return PMobject # Alignment - def align_points_with_larger(self, larger_mobject): + def align_points_with_larger(self, larger_mobject: Mobject) -> None: assert isinstance(larger_mobject, PMobject) self.apply_over_attr_arrays( lambda a: stretch_array_to_length(a, larger_mobject.get_num_points()), ) - def get_point_mobject(self, center=None): + def get_point_mobject(self, center: Point3D | None = None) -> Point: if center is None: center = self.get_center() return Point(center) - def interpolate_color(self, mobject1, mobject2, alpha): + def interpolate_color( + self, mobject1: Mobject, mobject2: Mobject, alpha: float + ) -> Self: self.rgbas = interpolate(mobject1.rgbas, mobject2.rgbas, alpha) self.set_stroke_width( interpolate( @@ -212,7 +234,7 @@ def interpolate_color(self, mobject1, mobject2, alpha): ) return self - def pointwise_become_partial(self, mobject, a, b): + def pointwise_become_partial(self, mobject: Mobject, a: float, b: float) -> None: lower_index, upper_index = (int(x * mobject.get_num_points()) for x in (a, b)) for attr in self.get_array_attrs(): full_array = getattr(mobject, attr) @@ -222,24 +244,31 @@ def pointwise_become_partial(self, mobject, a, b): # TODO, Make the two implementations below non-redundant class Mobject1D(PMobject, metaclass=ConvertToOpenGL): - def __init__(self, density=DEFAULT_POINT_DENSITY_1D, **kwargs): + def __init__(self, density: int = DEFAULT_POINT_DENSITY_1D, **kwargs: Any) -> None: self.density = density self.epsilon = 1.0 / self.density super().__init__(**kwargs) - def add_line(self, start, end, color=None): + def add_line( + self, + start: npt.NDArray, + end: npt.NDArray, + color: ParsableManimColor | None = None, + ) -> None: start, end = list(map(np.array, [start, end])) length = np.linalg.norm(end - start) if length == 0: - points = [start] + points = np.array([start]) else: epsilon = self.epsilon / length - points = [interpolate(start, end, t) for t in np.arange(0, 1, epsilon)] + points = np.array( + [interpolate(start, end, t) for t in np.arange(0, 1, epsilon)] + ) self.add_points(points, color=color) class Mobject2D(PMobject, metaclass=ConvertToOpenGL): - def __init__(self, density=DEFAULT_POINT_DENSITY_2D, **kwargs): + def __init__(self, density: int = DEFAULT_POINT_DENSITY_2D, **kwargs: Any) -> None: self.density = density self.epsilon = 1.0 / self.density super().__init__(**kwargs) @@ -268,7 +297,7 @@ def construct(self): """ - def __init__(self, *pmobs, **kwargs): + def __init__(self, *pmobs: Any, **kwargs: Any) -> None: if not all(isinstance(m, (PMobject, OpenGLPMobject)) for m in pmobs): raise ValueError( "All submobjects must be of type PMobject or OpenGLPMObject" @@ -277,10 +306,13 @@ def __init__(self, *pmobs, **kwargs): super().__init__(**kwargs) self.add(*pmobs) - def fade_to(self, color, alpha, family=True): + def fade_to( + self, color: ParsableManimColor, alpha: float, family: bool = True + ) -> Self: if family: for mob in self.submobjects: mob.fade_to(color, alpha, family) + return self class PointCloudDot(Mobject1D): @@ -317,13 +349,13 @@ def construct(self): def __init__( self, - center=ORIGIN, - radius=2.0, - stroke_width=2, - density=DEFAULT_POINT_DENSITY_1D, - color=YELLOW, - **kwargs, - ): + center: Vector3D = ORIGIN, + radius: float = 2.0, + stroke_width: int = 2, + density: int = DEFAULT_POINT_DENSITY_1D, + color: ManimColor = YELLOW, + **kwargs: Any, + ) -> None: self.radius = radius self.epsilon = 1.0 / density super().__init__( @@ -331,22 +363,24 @@ def __init__( ) self.shift(center) - def init_points(self): + def init_points(self) -> None: self.reset_points() self.generate_points() - def generate_points(self): + def generate_points(self) -> None: self.add_points( - [ - r * (np.cos(theta) * RIGHT + np.sin(theta) * UP) - for r in np.arange(self.epsilon, self.radius, self.epsilon) - # Num is equal to int(stop - start)/ (step + 1) reformulated. - for theta in np.linspace( - 0, - 2 * np.pi, - num=int(2 * np.pi * (r + self.epsilon) / self.epsilon), - ) - ], + np.array( + [ + r * (np.cos(theta) * RIGHT + np.sin(theta) * UP) + for r in np.arange(self.epsilon, self.radius, self.epsilon) + # Num is equal to int(stop - start)/ (step + 1) reformulated. + for theta in np.linspace( + 0, + 2 * np.pi, + num=int(2 * np.pi * (r + self.epsilon) / self.epsilon), + ) + ] + ), ) @@ -371,14 +405,16 @@ def construct(self): self.add(point) """ - def __init__(self, location=ORIGIN, color=BLACK, **kwargs): + def __init__( + self, location: Vector3D = ORIGIN, color: ManimColor = BLACK, **kwargs: Any + ) -> None: self.location = location super().__init__(color=color, **kwargs) - def init_points(self): + def init_points(self) -> None: self.reset_points() self.generate_points() self.set_points([self.location]) - def generate_points(self): - self.add_points([self.location]) + def generate_points(self) -> None: + self.add_points(np.array([self.location])) diff --git a/manim/mobject/types/vectorized_mobject.py b/manim/mobject/types/vectorized_mobject.py index 38c599c3f9..ac36a9672f 100644 --- a/manim/mobject/types/vectorized_mobject.py +++ b/manim/mobject/types/vectorized_mobject.py @@ -14,7 +14,7 @@ import itertools as it import sys -from typing import TYPE_CHECKING, Callable, Generic, Literal +from typing import TYPE_CHECKING, Any, Callable, Generic, Literal import numpy as np from PIL.Image import Image @@ -24,6 +24,7 @@ from manim.constants import * from manim.mobject.mobject import Mobject from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL +from manim.mobject.opengl.opengl_mobject import OpenGLMobject from manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVMobject from manim.mobject.three_d.three_d_utils import ( get_3d_vmob_gradient_start_and_end_points, @@ -55,6 +56,7 @@ from manim.typing import ( BezierPoints, CubicBezierPoints, + InternalPoint3D_Array, ManimFloat, MappingFunction, Point2D, @@ -134,7 +136,7 @@ def __init__( tolerance_for_point_equality: float = 1e-6, n_points_per_cubic_curve: int = 4, cap_style: CapStyleType = CapStyleType.AUTO, - **kwargs, + **kwargs: Any, ): self.fill_opacity = fill_opacity self.stroke_opacity = stroke_opacity @@ -479,6 +481,64 @@ def set_opacity(self, opacity: float, family: bool = True) -> Self: self.set_stroke(opacity=opacity, family=family, background=True) return self + def scale(self, scale_factor: float, scale_stroke: bool = False, **kwargs) -> Self: + r"""Scale the size by a factor. + + Default behavior is to scale about the center of the vmobject. + + Parameters + ---------- + scale_factor + The scaling factor :math:`\alpha`. If :math:`0 < |\alpha| < 1`, the mobject + will shrink, and for :math:`|\alpha| > 1` it will grow. Furthermore, + if :math:`\alpha < 0`, the mobject is also flipped. + scale_stroke + Boolean determining if the object's outline is scaled when the object is scaled. + If enabled, and object with 2px outline is scaled by a factor of .5, it will have an outline of 1px. + kwargs + Additional keyword arguments passed to + :meth:`~.Mobject.scale`. + + Returns + ------- + :class:`VMobject` + ``self`` + + Examples + -------- + + .. manim:: MobjectScaleExample + :save_last_frame: + + class MobjectScaleExample(Scene): + def construct(self): + c1 = Circle(1, RED).set_x(-1) + c2 = Circle(1, GREEN).set_x(1) + + vg = VGroup(c1, c2) + vg.set_stroke(width=50) + self.add(vg) + + self.play( + c1.animate.scale(.25), + c2.animate.scale(.25, + scale_stroke=True) + ) + + See also + -------- + :meth:`move_to` + + """ + if scale_stroke: + self.set_stroke(width=abs(scale_factor) * self.get_stroke_width()) + self.set_stroke( + width=abs(scale_factor) * self.get_stroke_width(background=True), + background=True, + ) + super().scale(scale_factor, **kwargs) + return self + def fade(self, darkness: float = 0.5, family: bool = True) -> Self: factor = 1.0 - darkness self.set_fill(opacity=factor * self.get_fill_opacity(), family=False) @@ -588,7 +648,6 @@ def set_sheen_direction(self, direction: Vector3D, family: bool = True) -> Self: :meth:`~.VMobject.set_sheen` :meth:`~.VMobject.rotate_sheen_direction` """ - direction = np.array(direction) if family: for submob in self.get_family(): @@ -654,7 +713,6 @@ def construct(self): circle = Circle(fill_opacity=1).set_sheen(-0.3, DR) self.add(circle) """ - if family: for submob in self.submobjects: submob.set_sheen(factor, direction, family) @@ -711,7 +769,7 @@ def set_shade_in_3d( return self def set_points(self, points: Point3D_Array) -> Self: - self.points: Point3D_Array = np.array(points) + self.points: InternalPoint3D_Array = np.array(points) return self def resize_points( @@ -1202,9 +1260,7 @@ def consider_points_equals_2d(self, p0: Point2D, p1: Point2D) -> bool: atol = self.tolerance_for_point_equality if abs(p0[0] - p1[0]) > atol + rtol * abs(p1[0]): return False - if abs(p0[1] - p1[1]) > atol + rtol * abs(p1[1]): - return False - return True + return abs(p0[1] - p1[1]) <= atol + rtol * abs(p1[1]) # Information about line def get_cubic_bezier_tuples_from_points( @@ -1382,7 +1438,6 @@ def get_nth_curve_length( length : :class:`float` The length of the nth curve. """ - _, length = self.get_nth_curve_function_with_length(n, sample_points) return length @@ -1408,7 +1463,6 @@ def get_nth_curve_function_with_length( length : :class:`float` The length of the nth curve. """ - curve = self.get_nth_curve_function(n) norms = self.get_nth_curve_length_pieces(n, sample_points=sample_points) length = np.sum(norms) @@ -1436,7 +1490,6 @@ def get_curve_functions( Generator[Callable[[float], Point3D]] The functions for the curves. """ - num_curves = self.get_num_curves() for n in range(num_curves): @@ -1457,7 +1510,6 @@ def get_curve_functions_with_lengths( Generator[tuple[Callable[[float], Point3D], float]] The functions and lengths of the curves. """ - num_curves = self.get_num_curves() for n in range(num_curves): @@ -1499,7 +1551,6 @@ def construct(self): line.point_from_proportion(proportion) )) """ - if alpha < 0 or alpha > 1: raise ValueError(f"Alpha {alpha} not between 0 and 1.") @@ -1596,7 +1647,7 @@ def get_anchors_and_handles(self) -> list[Point3D_Array]: nppcc = self.n_points_per_cubic_curve return [self.points[i::nppcc] for i in range(nppcc)] - def get_start_anchors(self) -> Point3D_Array: + def get_start_anchors(self) -> InternalPoint3D_Array: """Returns the start anchors of the bezier curves. Returns @@ -1651,7 +1702,6 @@ def get_arc_length(self, sample_points_per_curve: int | None = None) -> float: float The length of the :class:`VMobject`. """ - return sum( length for _, length in self.get_curve_functions_with_lengths( @@ -1771,7 +1821,6 @@ def insert_n_curves_to_point_list( ------- Points generated. """ - if len(points) == 1: nppcc = self.n_points_per_cubic_curve return np.repeat(points, nppcc * n, 0) @@ -1832,60 +1881,91 @@ def pointwise_become_partial( a: float, b: float, ) -> Self: - """Given two bounds a and b, transforms the points of the self vmobject into the points of the vmobject - passed as parameter with respect to the bounds. Points here stand for control points of the bezier curves (anchors and handles) + """Given a 2nd :class:`.VMobject` ``vmobject``, a lower bound ``a`` and + an upper bound ``b``, modify this :class:`.VMobject`'s points to + match the portion of the Bézier spline described by ``vmobject.points`` + with the parameter ``t`` between ``a`` and ``b``. Parameters ---------- vmobject - The vmobject that will serve as a model. + The :class:`.VMobject` that will serve as a model. a - upper-bound. + The lower bound for ``t``. b - lower-bound + The upper bound for ``t`` Returns ------- - :class:`VMobject` - ``self`` + :class:`.VMobject` + The :class:`.VMobject` itself, after the transformation. + + Raises + ------ + TypeError + If ``vmobject`` is not an instance of :class:`VMobject`. """ - assert isinstance(vmobject, VMobject) + if not isinstance(vmobject, VMobject): + raise TypeError( + f"Expected a VMobject, got value {vmobject} of type " + f"{type(vmobject).__name__}." + ) # Partial curve includes three portions: - # - A middle section, which matches the curve exactly - # - A start, which is some ending portion of an inner cubic - # - An end, which is the starting portion of a later inner cubic + # - A middle section, which matches the curve exactly. + # - A start, which is some ending portion of an inner cubic. + # - An end, which is the starting portion of a later inner cubic. if a <= 0 and b >= 1: self.set_points(vmobject.points) return self - bezier_quads = vmobject.get_cubic_bezier_tuples() - num_cubics = len(bezier_quads) + num_curves = vmobject.get_num_curves() + if num_curves == 0: + self.clear_points() + return self - # The following two lines will compute which bezier curves of the given mobject need to be processed. - # The residue basically indicates de proportion of the selected bezier curve that have to be selected. - # Ex : if lower_index is 3, and lower_residue is 0.4, then the algorithm will append to the points 0.4 of the third bezier curve - lower_index, lower_residue = integer_interpolate(0, num_cubics, a) - upper_index, upper_residue = integer_interpolate(0, num_cubics, b) + # The following two lines will compute which Bézier curves of the given Mobject must be processed. + # The residue indicates the proportion of the selected Bézier curve which must be selected. + # + # Example: if num_curves is 10, a is 0.34 and b is 0.78, then: + # - lower_index is 3 and lower_residue is 0.4, which means the algorithm will look at the 3rd Bézier + # and select its part which ranges from t=0.4 to t=1. + # - upper_index is 7 and upper_residue is 0.8, which means the algorithm will look at the 7th Bézier + # and select its part which ranges from t=0 to t=0.8. + lower_index, lower_residue = integer_interpolate(0, num_curves, a) + upper_index, upper_residue = integer_interpolate(0, num_curves, b) - self.clear_points() - if num_cubics == 0: - return self + nppc = self.n_points_per_curve + # If both indices coincide, get a part of a single Bézier curve. if lower_index == upper_index: - self.append_points( - partial_bezier_points( - bezier_quads[lower_index], - lower_residue, - upper_residue, - ), + # Look at the "lower_index"-th Bézier curve and select its part from + # t=lower_residue to t=upper_residue. + self.points = partial_bezier_points( + vmobject.points[nppc * lower_index : nppc * (lower_index + 1)], + lower_residue, + upper_residue, ) else: - self.append_points( - partial_bezier_points(bezier_quads[lower_index], lower_residue, 1), + # Allocate space for (upper_index-lower_index+1) Bézier curves. + self.points = np.empty((nppc * (upper_index - lower_index + 1), self.dim)) + # Look at the "lower_index"-th Bezier curve and select its part from + # t=lower_residue to t=1. This is the first curve in self.points. + self.points[:nppc] = partial_bezier_points( + vmobject.points[nppc * lower_index : nppc * (lower_index + 1)], + lower_residue, + 1, ) - for quad in bezier_quads[lower_index + 1 : upper_index]: - self.append_points(quad) - self.append_points( - partial_bezier_points(bezier_quads[upper_index], 0, upper_residue), + # If there are more curves between the "lower_index"-th and the + # "upper_index"-th Béziers, add them all to self.points. + self.points[nppc:-nppc] = vmobject.points[ + nppc * (lower_index + 1) : nppc * upper_index + ] + # Look at the "upper_index"-th Bézier curve and select its part from + # t=0 to t=upper_residue. This is the last curve in self.points. + self.points[-nppc:] = partial_bezier_points( + vmobject.points[nppc * upper_index : nppc * (upper_index + 1)], + 0, + upper_residue, ) + return self def get_subcurve(self, a: float, b: float) -> Self: @@ -2041,7 +2121,9 @@ def construct(self): """ - def __init__(self, *vmobjects: VMobjectT, **kwargs): + def __init__( + self, *vmobjects: VMobjectT | Iterable[VMobjectT], **kwargs: Any + ) -> None: super().__init__(**kwargs) self.add(*vmobjects) @@ -2054,13 +2136,16 @@ def __str__(self) -> str: f"submobject{'s' if len(self.submobjects) > 0 else ''}" ) - def add(self, *vmobjects: VMobject) -> Self: - """Checks if all passed elements are an instance of VMobject and then add them to submobjects + def add( + self, + *vmobjects: VMobject | Iterable[VMobject], + ) -> Self: + """Checks if all passed elements are an instance, or iterables of VMobject and then adds them to submobjects Parameters ---------- vmobjects - List of VMobject to add + List or iterable of VMobjects to add Returns ------- @@ -2069,10 +2154,13 @@ def add(self, *vmobjects: VMobject) -> Self: Raises ------ TypeError - If one element of the list is not an instance of VMobject + If one element of the list, or iterable is not an instance of VMobject Examples -------- + The following example shows how to add individual or multiple `VMobject` instances through the `VGroup` + constructor and its `.add()` method. + .. manim:: AddToVGroup class AddToVGroup(Scene): @@ -2101,8 +2189,65 @@ def construct(self): self.play( # Animate group without component (gr-circle_red).animate.shift(RIGHT) ) + + A `VGroup` can be created using iterables as well. Keep in mind that all generated values from an + iterable must be an instance of `VMobject`. This is demonstrated below: + + .. manim:: AddIterableToVGroupExample + :save_last_frame: + + class AddIterableToVGroupExample(Scene): + def construct(self): + v = VGroup( + Square(), # Singular VMobject instance + [Circle(), Triangle()], # List of VMobject instances + Dot(), + (Dot() for _ in range(2)), # Iterable that generates VMobjects + ) + v.arrange() + self.add(v) + + To facilitate this, the iterable is unpacked before its individual instances are added to the `VGroup`. + As a result, when you index a `VGroup`, you will never get back an iterable. + Instead, you will always receive `VMobject` instances, including those + that were part of the iterable/s that you originally added to the `VGroup`. """ - return super().add(*vmobjects) + + def get_type_error_message(invalid_obj, invalid_indices): + return ( + f"Only values of type {vmobject_render_type.__name__} can be added " + "as submobjects of VGroup, but the value " + f"{repr(invalid_obj)} (at index {invalid_indices[1]} of " + f"parameter {invalid_indices[0]}) is of type " + f"{type(invalid_obj).__name__}." + ) + + vmobject_render_type = ( + OpenGLVMobject if config.renderer == RendererType.OPENGL else VMobject + ) + valid_vmobjects = [] + + for i, vmobject in enumerate(vmobjects): + if isinstance(vmobject, vmobject_render_type): + valid_vmobjects.append(vmobject) + elif isinstance(vmobject, Iterable) and not isinstance( + vmobject, (Mobject, OpenGLMobject) + ): + for j, subvmobject in enumerate(vmobject): + if not isinstance(subvmobject, vmobject_render_type): + raise TypeError(get_type_error_message(subvmobject, (i, j))) + valid_vmobjects.append(subvmobject) + elif isinstance(vmobject, Iterable) and isinstance( + vmobject, (Mobject, OpenGLMobject) + ): + raise TypeError( + f"{get_type_error_message(vmobject, (i, 0))} " + "You can try adding this value into a Group instead." + ) + else: + raise TypeError(get_type_error_message(vmobject, (i, 0))) + + return super().add(*valid_vmobjects) def __add__(self, vmobject: VMobject) -> Self: return VGroup(*self.submobjects, vmobject) @@ -2683,15 +2828,12 @@ def __init__( if vmobject.is_closed(): void_len = (1 - r) / n else: - if n == 1: - void_len = 1 - r - else: - void_len = (1 - r) / (n - 1) + void_len = 1 - r if n == 1 else (1 - r) / (n - 1) period = dash_len + void_len phase_shift = (dash_offset % 1) * period - if vmobject.is_closed(): + if vmobject.is_closed(): # noqa: SIM108 # closed curves have equal amount of dashes and voids pattern_len = 1 else: diff --git a/manim/mobject/value_tracker.py b/manim/mobject/value_tracker.py index f46944041c..9d81035e89 100644 --- a/manim/mobject/value_tracker.py +++ b/manim/mobject/value_tracker.py @@ -165,7 +165,8 @@ def get_value(self): """Get the current value of this value tracker as a complex number. The value is internally stored as a points array [a, b, 0]. This can be accessed directly - to represent the value geometrically, see the usage example.""" + to represent the value geometrically, see the usage example. + """ return complex(*self.points[0, :2]) def set_value(self, z): diff --git a/manim/mobject/vector_field.py b/manim/mobject/vector_field.py index 6df8863f3e..e9cc74bcc7 100644 --- a/manim/mobject/vector_field.py +++ b/manim/mobject/vector_field.py @@ -359,7 +359,6 @@ def start_submobject_movement( This vector field. """ - self.stop_submobject_movement() self.submob_movement_updater = lambda mob, dt: mob.nudge_submobjects( dt * speed, @@ -957,7 +956,6 @@ def construct(self): self.wait(stream_lines.virtual_time / stream_lines.flow_speed) """ - for line in self.stream_lines: run_time = line.duration / flow_speed line.anim = line_animation_class( @@ -1017,7 +1015,6 @@ def construct(self): self.play(stream_lines.end_animation()) """ - if self.flow_animation is None: raise ValueError("You have to start the animation before fading it out.") diff --git a/manim/opengl/__init__.py b/manim/opengl/__init__.py index 83f6a4ccde..e5bad5cd2c 100644 --- a/manim/opengl/__init__.py +++ b/manim/opengl/__init__.py @@ -1,9 +1,9 @@ from __future__ import annotations -try: +import contextlib + +with contextlib.suppress(ImportError): from dearpygui import dearpygui as dpg -except ImportError: - pass from manim.mobject.opengl.dot_cloud import * diff --git a/manim/plugins/__init__.py b/manim/plugins/__init__.py index 06314895e1..d6f82f0923 100644 --- a/manim/plugins/__init__.py +++ b/manim/plugins/__init__.py @@ -1,8 +1,7 @@ from __future__ import annotations -from manim import config, logger - -from .plugins_flags import get_plugins, list_plugins +from manim._config import config, logger +from manim.plugins.plugins_flags import get_plugins, list_plugins __all__ = [ "get_plugins", diff --git a/manim/plugins/plugins_flags.py b/manim/plugins/plugins_flags.py index 3733ac3f3f..3080b6256a 100644 --- a/manim/plugins/plugins_flags.py +++ b/manim/plugins/plugins_flags.py @@ -10,7 +10,7 @@ else: from importlib.metadata import entry_points -from manim import console +from manim._config import console __all__ = ["list_plugins"] @@ -27,5 +27,5 @@ def list_plugins() -> None: console.print("[green bold]Plugins:[/green bold]", justify="left") plugins = get_plugins() - for plugin in plugins: - console.print(f" • {plugin}") + for plugin_name in plugins: + console.print(f" • {plugin_name}") diff --git a/manim/renderer/cairo_renderer.py b/manim/renderer/cairo_renderer.py index b97fa50299..0b13fb8638 100644 --- a/manim/renderer/cairo_renderer.py +++ b/manim/renderer/cairo_renderer.py @@ -252,13 +252,13 @@ def update_skipping_status(self): if config["save_last_frame"]: self.skip_animations = True if ( - config["from_animation_number"] - and self.num_plays < config["from_animation_number"] + config.from_animation_number > 0 + and self.num_plays < config.from_animation_number ): self.skip_animations = True if ( - config["upto_animation_number"] - and self.num_plays > config["upto_animation_number"] + config.upto_animation_number >= 0 + and self.num_plays > config.upto_animation_number ): self.skip_animations = True raise EndSceneEarlyException() diff --git a/manim/renderer/opengl_renderer.py b/manim/renderer/opengl_renderer.py index 8347f8a49e..2f0ad398fe 100644 --- a/manim/renderer/opengl_renderer.py +++ b/manim/renderer/opengl_renderer.py @@ -1,5 +1,6 @@ from __future__ import annotations +import contextlib import itertools as it import time from functools import cached_property @@ -62,12 +63,12 @@ def __init__( if self.orthographic: self.projection_matrix = opengl.orthographic_projection_matrix() self.unformatted_projection_matrix = opengl.orthographic_projection_matrix( - format=False, + format_=False, ) else: self.projection_matrix = opengl.perspective_projection_matrix() self.unformatted_projection_matrix = opengl.perspective_projection_matrix( - format=False, + format_=False, ) if frame_shape is None: @@ -215,7 +216,11 @@ def interpolate(self, *args, **kwargs): class OpenGLRenderer: - def __init__(self, file_writer_class=SceneFileWriter, skip_animations=False): + def __init__( + self, + file_writer_class: type[SceneFileWriter] = SceneFileWriter, + skip_animations: bool = False, + ) -> None: # Measured in pixel widths, used for vector graphics self.anti_alias_width = 1.5 self._file_writer_class = file_writer_class @@ -336,10 +341,8 @@ def render_mobject(self, mobject): shader_wrapper.uniforms.items(), self.perspective_uniforms.items(), ): - try: + with contextlib.suppress(KeyError): shader.set_uniform(name, value) - except KeyError: - pass try: shader.set_uniform( "u_view_matrix", self.scene.camera.formatted_view_matrix @@ -397,13 +400,13 @@ def update_skipping_status(self): if self.file_writer.sections[-1].skip_animations: self.skip_animations = True if ( - config["from_animation_number"] - and self.num_plays < config["from_animation_number"] + config.from_animation_number > 0 + and self.num_plays < config.from_animation_number ): self.skip_animations = True if ( - config["upto_animation_number"] - and self.num_plays > config["upto_animation_number"] + config.upto_animation_number >= 0 + and self.num_plays > config.upto_animation_number ): self.skip_animations = True raise EndSceneEarlyException() diff --git a/manim/renderer/shader.py b/manim/renderer/shader.py index 85b9dad14a..a098ed30ca 100644 --- a/manim/renderer/shader.py +++ b/manim/renderer/shader.py @@ -1,5 +1,6 @@ from __future__ import annotations +import contextlib import inspect import re import textwrap @@ -382,10 +383,8 @@ def __init__( shader_program_cache[self.name] = self.shader_program def set_uniform(self, name, value): - try: + with contextlib.suppress(KeyError): self.shader_program[name] = value - except KeyError: - pass class FullScreenQuad(Mesh): diff --git a/manim/renderer/shader_wrapper.py b/manim/renderer/shader_wrapper.py index 00e111aad6..8a2b0d1fbe 100644 --- a/manim/renderer/shader_wrapper.py +++ b/manim/renderer/shader_wrapper.py @@ -1,14 +1,13 @@ from __future__ import annotations import copy +import logging import re from pathlib import Path import moderngl import numpy as np -from .. import logger - # Mobjects that should be rendered with # the same shader will be organized and # clumped together based on keeping track @@ -17,6 +16,8 @@ __all__ = ["ShaderWrapper"] +logger = logging.getLogger("manim") + def get_shader_dir(): return Path(__file__).parent / "shaders" diff --git a/manim/scene/moving_camera_scene.py b/manim/scene/moving_camera_scene.py index 3adef5fc78..eafc992ef5 100644 --- a/manim/scene/moving_camera_scene.py +++ b/manim/scene/moving_camera_scene.py @@ -64,6 +64,25 @@ def construct(self): self.play(Restore(self.camera.frame)) self.wait() +.. manim:: SlidingMultipleScenes + + class SlidingMultipleScenes(MovingCameraScene): + def construct(self): + def create_scene(number): + frame = Rectangle(width=16,height=9) + circ = Circle().shift(LEFT) + text = Tex(f"This is Scene {str(number)}").next_to(circ, RIGHT) + frame.add(circ,text) + return frame + + group = VGroup(*(create_scene(i) for i in range(4))).arrange_in_grid(buff=4) + self.add(group) + self.camera.auto_zoom(group[0], animate=False) + for scene in group: + self.play(self.camera.auto_zoom(scene)) + self.wait() + + self.play(self.camera.auto_zoom(group, margin=2)) """ from __future__ import annotations @@ -83,8 +102,12 @@ class MovingCameraScene(Scene): This is a Scene, with special configurations and properties that make it suitable for cases where the camera must be moved around. + Note: Examples are included in the moving_camera_scene module + documentation, see below in the 'see also' section. + .. SEEALSO:: + :mod:`.moving_camera_scene` :class:`.MovingCamera` """ diff --git a/manim/scene/scene.py b/manim/scene/scene.py index 3f80c91864..e70c3beb14 100644 --- a/manim/scene/scene.py +++ b/manim/scene/scene.py @@ -52,7 +52,7 @@ from ..utils.iterables import list_difference_update, list_update if TYPE_CHECKING: - from collections.abc import Iterable + from collections.abc import Iterable, Sequence from typing import Callable @@ -100,12 +100,12 @@ def construct(self): def __init__( self, - renderer=None, - camera_class=Camera, - always_update_mobjects=False, - random_seed=None, - skip_animations=False, - ): + renderer: CairoRenderer | OpenGLRenderer | None = None, + camera_class: type[Camera] = Camera, + always_update_mobjects: bool = False, + random_seed: int | None = None, + skip_animations: bool = False, + ) -> None: self.camera_class = camera_class self.always_update_mobjects = always_update_mobjects self.random_seed = random_seed @@ -158,6 +158,11 @@ def __init__( def camera(self): return self.renderer.camera + @property + def time(self) -> float: + """The time since the start of the scene.""" + return self.renderer.time + def __deepcopy__(self, clone_from_id): cls = self.__class__ result = cls.__new__(cls) @@ -308,14 +313,14 @@ def construct(self): def next_section( self, name: str = "unnamed", - type: str = DefaultSectionType.NORMAL, + section_type: str = DefaultSectionType.NORMAL, skip_animations: bool = False, ) -> None: """Create separation here; the last section gets finished and a new one gets created. ``skip_animations`` skips the rendering of all animations in this section. Refer to :doc:`the documentation` on how to use sections. """ - self.renderer.file_writer.next_section(name, type, skip_animations) + self.renderer.file_writer.next_section(name, section_type, skip_animations) def __str__(self): return self.__class__.__name__ @@ -620,7 +625,7 @@ def remove_updater(self, func: Callable[[float], None]) -> None: def restructure_mobjects( self, - to_remove: Mobject, + to_remove: Sequence[Mobject], mobject_list_name: str = "mobjects", extract_families: bool = True, ): @@ -680,7 +685,6 @@ def get_restructured_mobject_list(self, mobjects: list, to_remove: list): list The list of mobjects with the mobjects to remove removed. """ - new_mobjects = [] def add_safe_mobjects_from_list(list_to_examine, set_to_remove): @@ -899,16 +903,16 @@ def compile_animations( for arg in arg_anims: try: animations.append(prepare_animation(arg)) - except TypeError: + except TypeError as e: if inspect.ismethod(arg): raise TypeError( "Passing Mobject methods to Scene.play is no longer" " supported. Use Mobject.animate instead.", - ) + ) from e else: raise TypeError( f"Unexpected argument {arg} passed to Scene.play().", - ) + ) from e for animation in animations: for k, v in kwargs.items(): @@ -1016,6 +1020,35 @@ def get_time_progression( ) return time_progression + @classmethod + def validate_run_time( + cls, + run_time: float, + method: Callable[[Any, ...], Any], + parameter_name: str = "run_time", + ) -> float: + method_name = f"{cls.__name__}.{method.__name__}()" + if run_time <= 0: + raise ValueError( + f"{method_name} has a {parameter_name} of " + f"{run_time:g} <= 0 seconds which Manim cannot render. " + f"The {parameter_name} must be a positive number." + ) + + # config.frame_rate holds the number of frames per second + fps = config.frame_rate + seconds_per_frame = 1 / fps + if run_time < seconds_per_frame: + logger.warning( + f"The original {parameter_name} of {method_name}, " + f"{run_time:g} seconds, is too short for the current frame " + f"rate of {fps:g} FPS. Rendering with the shortest possible " + f"{parameter_name} of {seconds_per_frame:g} seconds instead." + ) + run_time = seconds_per_frame + + return run_time + def get_run_time(self, animations: list[Animation]): """ Gets the total run time for a list of animations. @@ -1031,28 +1064,9 @@ def get_run_time(self, animations: list[Animation]): float The total ``run_time`` of all of the animations in the list. """ - max_run_time = 0 - frame_rate = ( - 1 / config.frame_rate - ) # config.frame_rate holds the number of frames per second - for animation in animations: - if animation.run_time <= 0: - raise ValueError( - f"{animation} has a run_time of <= 0 seconds which Manim cannot render. " - "Please set the run_time to be positive." - ) - elif animation.run_time < frame_rate: - logger.warning( - f"Original run time of {animation} is shorter than current frame " - f"rate (1 frame every {frame_rate:.2f} sec.) which cannot be rendered. " - "Rendering with the shortest possible duration instead." - ) - animation.run_time = frame_rate - - if animation.run_time > max_run_time: - max_run_time = animation.run_time - - return max_run_time + run_time = max(animation.run_time for animation in animations) + run_time = self.validate_run_time(run_time, self.play, "total run_time") + return run_time def play( self, @@ -1105,15 +1119,15 @@ def play( ) return - start_time = self.renderer.time + start_time = self.time self.renderer.play(self, *args, **kwargs) - run_time = self.renderer.time - start_time + run_time = self.time - start_time if subcaption: if subcaption_duration is None: subcaption_duration = run_time # The start of the subcaption needs to be offset by the # run_time of the animation because it is added after - # the animation has already been played (and Scene.renderer.time + # the animation has already been played (and Scene.time # has already been updated). self.add_subcaption( content=subcaption, @@ -1148,6 +1162,7 @@ def wait( -------- :class:`.Wait`, :meth:`.should_mobjects_update` """ + duration = self.validate_run_time(duration, self.wait, "duration") self.play( Wait( run_time=duration, @@ -1171,6 +1186,7 @@ def pause(self, duration: float = DEFAULT_WAIT_TIME): -------- :meth:`.wait`, :class:`.Wait` """ + duration = self.validate_run_time(duration, self.pause, "duration") self.wait(duration=duration, frozen_frame=True) def wait_until(self, stop_condition: Callable[[], bool], max_time: float = 60): @@ -1184,6 +1200,7 @@ def wait_until(self, stop_condition: Callable[[], bool], max_time: float = 60): max_time The maximum wait time in seconds. """ + max_time = self.validate_run_time(max_time, self.wait_until, "max_time") self.wait(max_time, stop_condition=stop_condition) def compile_animation_data( @@ -1315,9 +1332,7 @@ def check_interactive_embed_is_valid(self): return True def interactive_embed(self): - """ - Like embed(), but allows for screen interaction. - """ + """Like embed(), but allows for screen interaction.""" if not self.check_interactive_embed_is_valid(): return self.interactive_mode = True @@ -1525,7 +1540,7 @@ def add_subcaption( r"""Adds an entry in the corresponding subcaption file at the current time stamp. - The current time stamp is obtained from ``Scene.renderer.time``. + The current time stamp is obtained from ``Scene.time``. Parameters ---------- @@ -1562,10 +1577,8 @@ def construct(self): subtitle = srt.Subtitle( index=len(self.renderer.file_writer.subcaptions), content=content, - start=datetime.timedelta(seconds=float(self.renderer.time + offset)), - end=datetime.timedelta( - seconds=float(self.renderer.time + offset + duration) - ), + start=datetime.timedelta(seconds=float(self.time + offset)), + end=datetime.timedelta(seconds=float(self.time + offset + duration)), ) self.renderer.file_writer.subcaptions.append(subtitle) @@ -1613,7 +1626,7 @@ def construct(self): """ if self.renderer.skip_animations: return - time = self.renderer.time + time_offset + time = self.time + time_offset self.renderer.file_writer.add_sound(sound_file, time, gain, **kwargs) def on_mouse_motion(self, point, d_point): diff --git a/manim/scene/scene_file_writer.py b/manim/scene/scene_file_writer.py index 9a2d5eb606..4293de7105 100644 --- a/manim/scene/scene_file_writer.py +++ b/manim/scene/scene_file_writer.py @@ -6,7 +6,11 @@ import json import shutil +from fractions import Fraction from pathlib import Path +from queue import Queue +from tempfile import NamedTemporaryFile +from threading import Thread from typing import TYPE_CHECKING, Any import av @@ -16,6 +20,7 @@ from pydub import AudioSegment from manim import __version__ +from manim.typing import PixelArray from .. import config, logger from .._config.logger_utils import set_file_logger @@ -36,6 +41,38 @@ from manim.renderer.opengl_renderer import OpenGLRenderer +def to_av_frame_rate(fps): + epsilon1 = 1e-4 + epsilon2 = 0.02 + + if isinstance(fps, int): + (num, denom) = (fps, 1) + elif abs(fps - round(fps)) < epsilon1: + (num, denom) = (round(fps), 1) + else: + denom = 1001 + num = round(fps * denom / 1000) * 1000 + if abs(fps - num / denom) >= epsilon2: + raise ValueError("invalid frame rate") + + return Fraction(num, denom) + + +def convert_audio(input_path: Path, output_path: Path, codec_name: str): + with ( + av.open(input_path) as input_audio, + av.open(output_path, "w") as output_audio, + ): + input_audio_stream = input_audio.streams.audio[0] + output_audio_stream = output_audio.add_stream(codec_name) + for frame in input_audio.decode(input_audio_stream): + for packet in output_audio_stream.encode(frame): + output_audio.mux(packet) + + for packet in output_audio_stream.encode(): + output_audio.mux(packet) + + class SceneFileWriter: """ SceneFileWriter is the object that actually writes the animations @@ -78,7 +115,7 @@ def __init__(self, renderer, scene_name, **kwargs): # first section gets automatically created for convenience # if you need the first section to be skipped, add a first section by hand, it will replace this one self.next_section( - name="autocreated", type=DefaultSectionType.NORMAL, skip_animations=False + name="autocreated", type_=DefaultSectionType.NORMAL, skip_animations=False ) def init_output_directories(self, scene_name): @@ -94,10 +131,7 @@ def init_output_directories(self, scene_name): if config["dry_run"]: # in dry-run mode there is no output return - if config["input_file"]: - module_name = config.get_dir("input_file").stem - else: - module_name = "" + module_name = config.get_dir("input_file").stem if config["input_file"] else "" if SceneFileWriter.force_output_as_scene_name: self.output_name = Path(scene_name) @@ -166,7 +200,7 @@ def finish_last_section(self) -> None: if len(self.sections) and self.sections[-1].is_empty(): self.sections.pop() - def next_section(self, name: str, type: str, skip_animations: bool) -> None: + def next_section(self, name: str, type_: str, skip_animations: bool) -> None: """Create segmentation cut here.""" self.finish_last_section() @@ -184,7 +218,7 @@ def next_section(self, name: str, type: str, skip_animations: bool) -> None: self.sections.append( Section( - type, + type_, section_video, name, skip_animations, @@ -247,15 +281,11 @@ def get_resolution_directory(self): # Sound def init_audio(self): - """ - Preps the writer for adding audio to the movie. - """ + """Preps the writer for adding audio to the movie.""" self.includes_sound = False def create_audio_segment(self): - """ - Creates an empty, silent, Audio Segment. - """ + """Creates an empty, silent, Audio Segment.""" self.audio_segment = AudioSegment.silent() def add_audio_segment( @@ -330,7 +360,19 @@ def add_sound( """ file_path = get_full_sound_file_path(sound_file) - new_segment = AudioSegment.from_file(file_path) + # we assume files with .wav / .raw suffix are actually + # .wav and .raw files, respectively. + if file_path.suffix not in (".wav", ".raw"): + # we need to pass delete=False to work on Windows + # TODO: figure out a way to cache the wav file generated (benchmark needed) + with NamedTemporaryFile(suffix=".wav", delete=False) as wav_file_path: + convert_audio(file_path, wav_file_path, "pcm_s16le") + new_segment = AudioSegment.from_file(wav_file_path.name) + logger.info(f"Automatically converted {file_path} to .wav") + Path(wav_file_path.name).unlink() + else: + new_segment = AudioSegment.from_file(file_path) + if gain: new_segment = new_segment.apply_gain(gain) self.add_audio_segment(new_segment, time, **kwargs) @@ -362,6 +404,31 @@ def end_animation(self, allow_write: bool = False): if write_to_movie() and allow_write: self.close_partial_movie_stream() + def listen_and_write(self): + """For internal use only: blocks until new frame is available on the queue.""" + while True: + num_frames, frame_data = self.queue.get() + if frame_data is None: + break + + self.encode_and_write_frame(frame_data, num_frames) + + def encode_and_write_frame(self, frame: PixelArray, num_frames: int) -> None: + """ + For internal use only: takes a given frame in ``np.ndarray`` format and + write it to the stream + """ + for _ in range(num_frames): + # Notes: precomputing reusing packets does not work! + # I.e., you cannot do `packets = encode(...)` + # and reuse it, as it seems that `mux(...)` + # consumes the packet. + # The same issue applies for `av_frame`, + # reusing it renders weird-looking frames. + av_frame = av.VideoFrame.from_ndarray(frame, format="rgba") + for packet in self.video_stream.encode(av_frame): + self.video_container.mux(packet) + def write_frame( self, frame_or_renderer: np.ndarray | OpenGLRenderer, num_frames: int = 1 ): @@ -382,16 +449,9 @@ def write_frame( if config.renderer == RendererType.OPENGL else frame_or_renderer ) - for _ in range(num_frames): - # Notes: precomputing reusing packets does not work! - # I.e., you cannot do `packets = encode(...)` - # and reuse it, as it seems that `mux(...)` - # consumes the packet. - # The same issue applies for `av_frame`, - # reusing it renders weird-looking frames. - av_frame = av.VideoFrame.from_ndarray(frame, format="rgba") - for packet in self.video_stream.encode(av_frame): - self.video_container.mux(packet) + + msg = (num_frames, frame) + self.queue.put(msg) if is_png_format() and not config["dry_run"]: image: Image = ( @@ -433,7 +493,7 @@ def save_final_image(self, image: np.ndarray): image.save(self.image_file_path) self.print_file_ready_message(self.image_file_path) - def finish(self): + def finish(self) -> None: """ Finishes writing to the FFMPEG buffer or writing images to output directory. @@ -443,8 +503,6 @@ def finish(self): frame in the default image directory. """ if write_to_movie(): - if hasattr(self, "writing_process"): - self.writing_process.terminate() self.combine_to_movie() if config.save_sections: self.combine_to_section_videos() @@ -458,7 +516,7 @@ def finish(self): if self.subcaptions: self.write_subcaption_file() - def open_partial_movie_stream(self, file_path=None): + def open_partial_movie_stream(self, file_path=None) -> None: """Open a container holding a video stream. This is used internally by Manim initialize the container holding @@ -468,9 +526,7 @@ def open_partial_movie_stream(self, file_path=None): file_path = self.partial_movie_files[self.renderer.num_plays] self.partial_movie_file_path = file_path - fps = config["frame_rate"] - if fps == int(fps): # fps is integer - fps = int(fps) + fps = to_av_frame_rate(config.frame_rate) partial_movie_file_codec = "libx264" partial_movie_file_pix_fmt = "yuv420p" @@ -479,7 +535,7 @@ def open_partial_movie_stream(self, file_path=None): "crf": "23", # ffmpeg: -crf, constant rate factor (improved bitrate) } - if config.format == "webm": + if config.movie_file_extension == ".webm": partial_movie_file_codec = "libvpx-vp9" av_options["-auto-alt-ref"] = "1" if config.transparent: @@ -492,7 +548,7 @@ def open_partial_movie_stream(self, file_path=None): with av.open(file_path, mode="w") as video_container: stream = video_container.add_stream( partial_movie_file_codec, - rate=config.frame_rate, + rate=fps, options=av_options, ) stream.pix_fmt = partial_movie_file_pix_fmt @@ -502,13 +558,20 @@ def open_partial_movie_stream(self, file_path=None): self.video_container = video_container self.video_stream = stream - def close_partial_movie_stream(self): + self.queue: Queue[tuple[int, PixelArray | None]] = Queue() + self.writer_thread = Thread(target=self.listen_and_write, args=()) + self.writer_thread.start() + + def close_partial_movie_stream(self) -> None: """Close the currently opened video container. Used internally by Manim to first flush the remaining packages in the video stream holding a partial file, and then close the corresponding container. """ + self.queue.put((-1, None)) + self.writer_thread.join() + for packet in self.video_stream.encode(): self.video_container.mux(packet) @@ -577,7 +640,7 @@ def combine_files( codec_name="gif" if create_gif else None, template=partial_movies_stream if not create_gif else None, ) - if config.transparent and config.format == "webm": + if config.transparent and config.movie_file_extension == ".webm": output_stream.pix_fmt = "yuva420p" if create_gif: """ @@ -591,7 +654,7 @@ def combine_files( output_stream.pix_fmt = "pal8" output_stream.width = config.pixel_width output_stream.height = config.pixel_height - output_stream.rate = config.frame_rate + output_stream.rate = to_av_frame_rate(config.frame_rate) graph = av.filter.Graph() input_buffer = graph.add_buffer(template=partial_movies_stream) split = graph.add("split") @@ -618,7 +681,8 @@ def combine_files( while True: try: frame = graph.pull() - frame.time_base = output_stream.codec_context.time_base + if output_stream.codec_context.time_base is not None: + frame.time_base = output_stream.codec_context.time_base frame.pts = frames_written frames_written += 1 output_container.mux(output_stream.encode(frame)) @@ -659,6 +723,7 @@ def combine_to_movie(self): movie_file_path = self.movie_file_path if is_gif_format(): movie_file_path = self.gif_file_path + if len(partial_movie_files) == 0: # Prevent calling concat on empty list logger.info("No animations are contained in this scene.") return @@ -687,21 +752,16 @@ def combine_to_movie(self): # but tries to call ffmpeg via its CLI -- which we want # to avoid. This is why we need to do the conversion # manually. - if config.format == "webm": - with ( - av.open(sound_file_path) as wav_audio, - av.open(sound_file_path.with_suffix(".ogg"), "w") as opus_audio, - ): - wav_audio_stream = wav_audio.streams.audio[0] - opus_audio_stream = opus_audio.add_stream("libvorbis") - for frame in wav_audio.decode(wav_audio_stream): - for packet in opus_audio_stream.encode(frame): - opus_audio.mux(packet) - - for packet in opus_audio_stream.encode(): - opus_audio.mux(packet) - - sound_file_path = sound_file_path.with_suffix(".ogg") + if config.movie_file_extension == ".webm": + ogg_sound_file_path = sound_file_path.with_suffix(".ogg") + convert_audio(sound_file_path, ogg_sound_file_path, "libvorbis") + sound_file_path = ogg_sound_file_path + elif config.movie_file_extension == ".mp4": + # Similarly, pyav may reject wav audio in an .mp4 file; + # convert to AAC. + aac_sound_file_path = sound_file_path.with_suffix(".aac") + convert_audio(sound_file_path, aac_sound_file_path, "aac") + sound_file_path = aac_sound_file_path temp_file_path = movie_file_path.with_name( f"{movie_file_path.stem}_temp{movie_file_path.suffix}" @@ -754,7 +814,6 @@ def combine_to_movie(self): def combine_to_section_videos(self) -> None: """Concatenate partial movie files for each section.""" - self.finish_last_section() sections_index: list[dict[str, Any]] = [] for section in self.sections: diff --git a/manim/scene/section.py b/manim/scene/section.py index a9e4ba2aba..af005b52da 100644 --- a/manim/scene/section.py +++ b/manim/scene/section.py @@ -34,23 +34,23 @@ class PresentationSectionType(str, Enum): class Section: - """A :class:`.Scene` can be segmented into multiple Sections. + r"""A :class:`.Scene` can be segmented into multiple Sections. Refer to :doc:`the documentation` for more info. It consists of multiple animations. Attributes ---------- - type - Can be used by a third party applications to classify different types of sections. - video - Path to video file with animations belonging to section relative to sections directory. - If ``None``, then the section will not be saved. - name - Human readable, non-unique name for this section. - skip_animations - Skip rendering the animations in this section when ``True``. - partial_movie_files - Animations belonging to this section. + type\_ + Can be used by a third party applications to classify different types of sections. + video + Path to video file with animations belonging to section relative to sections directory. + If ``None``, then the section will not be saved. + name + Human readable, non-unique name for this section. + skip_animations + Skip rendering the animations in this section when ``True``. + partial_movie_files + Animations belonging to this section. See Also -------- @@ -59,8 +59,8 @@ class Section: :meth:`.OpenGLRenderer.update_skipping_status` """ - def __init__(self, type: str, video: str | None, name: str, skip_animations: bool): - self.type = type + def __init__(self, type_: str, video: str | None, name: str, skip_animations: bool): + self.type_ = type_ # None when not to be saved -> still keeps section alive self.video: str | None = video self.name = name @@ -94,7 +94,7 @@ def get_dict(self, sections_dir: Path) -> dict[str, Any]: return dict( { "name": self.name, - "type": self.type, + "type": self.type_, "video": self.video, }, **video_metadata, diff --git a/manim/scene/three_d_scene.py b/manim/scene/three_d_scene.py index 919f3cb2c6..7f39f4cf32 100644 --- a/manim/scene/three_d_scene.py +++ b/manim/scene/three_d_scene.py @@ -86,7 +86,6 @@ def set_camera_orientation( The new center of the camera frame in cartesian coordinates. """ - if phi is not None: self.renderer.camera.set_phi(phi) if theta is not None: @@ -135,13 +134,11 @@ def begin_ambient_camera_rotation(self, rate: float = 0.02, about: str = "theta" } cam.add_updater(lambda m, dt: methods[about](rate * dt)) self.add(self.camera) - except Exception: - raise ValueError("Invalid ambient rotation angle.") + except Exception as e: + raise ValueError("Invalid ambient rotation angle.") from e def stop_ambient_camera_rotation(self, about="theta"): - """ - This method stops all ambient camera rotation. - """ + """This method stops all ambient camera rotation.""" about: str = about.lower() try: if config.renderer == RendererType.CAIRO: @@ -155,8 +152,8 @@ def stop_ambient_camera_rotation(self, about="theta"): self.remove(x) elif config.renderer == RendererType.OPENGL: self.camera.clear_updaters() - except Exception: - raise ValueError("Invalid ambient rotation angle.") + except Exception as e: + raise ValueError("Invalid ambient rotation angle.") from e def begin_3dillusion_camera_rotation( self, @@ -205,9 +202,7 @@ def update_phi(m, dt): self.add(self.renderer.camera.phi_tracker) def stop_3dillusion_camera_rotation(self): - """ - This method stops all illusion camera rotations. - """ + """This method stops all illusion camera rotations.""" self.renderer.camera.theta_tracker.clear_updaters() self.remove(self.renderer.camera.theta_tracker) self.renderer.camera.phi_tracker.clear_updaters() @@ -545,7 +540,5 @@ def get_default_camera_position(self): return self.default_angled_camera_position def set_camera_to_default_position(self): - """ - Sets the camera to its default position. - """ + """Sets the camera to its default position.""" self.set_camera_orientation(**self.default_angled_camera_position) diff --git a/manim/scene/vector_space_scene.py b/manim/scene/vector_space_scene.py index dd616dc8aa..27361c42a3 100644 --- a/manim/scene/vector_space_scene.py +++ b/manim/scene/vector_space_scene.py @@ -1002,7 +1002,6 @@ def get_piece_movement(self, pieces: list | tuple | np.ndarray): Animation The animation of the movement. """ - v_pieces = [piece for piece in pieces if isinstance(piece, VMobject)] start = VGroup(*v_pieces) target = VGroup(*(mob.target for mob in v_pieces)) @@ -1093,7 +1092,6 @@ def apply_matrix(self, matrix: np.ndarray | list | tuple, **kwargs): **kwargs Any valid keyword argument of self.apply_transposed_matrix() """ - self.apply_transposed_matrix(np.array(matrix).T, **kwargs) def apply_inverse(self, matrix: np.ndarray | list | tuple, **kwargs): diff --git a/manim/typing.py b/manim/typing.py index 8111ca7398..92815e95e9 100644 --- a/manim/typing.py +++ b/manim/typing.py @@ -41,6 +41,10 @@ "RGBA_Tuple_Int", "HSV_Array_Float", "HSV_Tuple_Float", + "HSL_Array_Float", + "HSL_Tuple_Float", + "HSVA_Array_Float", + "HSVA_Tuple_Float", "ManimColorInternal", "PointDType", "InternalPoint2D", @@ -51,6 +55,10 @@ "Point3D", "InternalPoint3D_Array", "Point3D_Array", + "InternalPointND", + "PointND", + "InternalPointND_Array", + "PointND_Array", "Vector2D", "Vector2D_Array", "Vector3D", @@ -77,10 +85,10 @@ "FunctionOverride", "PathFuncType", "MappingFunction", - "Image", - "GrayscaleImage", - "RGBImage", - "RGBAImage", + "PixelArray", + "GrayscalePixelArray", + "RGBPixelArray", + "RGBAPixelArray", "StrPath", "StrOrBytesPath", ] @@ -215,6 +223,46 @@ Brightness) in the represented color. """ +HSVA_Array_Float: TypeAlias = RGBA_Array_Float +"""``shape: (4,)`` + +A :class:`numpy.ndarray` of 4 floats between 0 and 1, representing a +color in HSVA (or HSBA) format. + +Its components describe, in order, the Hue, Saturation and Value (or +Brightness) in the represented color. +""" + +HSVA_Tuple_Float: TypeAlias = RGBA_Tuple_Float +"""``shape: (4,)`` + +A tuple of 4 floats between 0 and 1, representing a color in HSVA (or +HSBA) format. + +Its components describe, in order, the Hue, Saturation and Value (or +Brightness) in the represented color. +""" + +HSL_Array_Float: TypeAlias = RGB_Array_Float +"""``shape: (3,)`` + +A :class:`numpy.ndarray` of 3 floats between 0 and 1, representing a +color in HSL format. + +Its components describe, in order, the Hue, Saturation and Lightness +in the represented color. +""" + +HSL_Tuple_Float: TypeAlias = RGB_Tuple_Float +"""``shape: (3,)`` + +A :class:`numpy.ndarray` of 3 floats between 0 and 1, representing a +color in HSL format. + +Its components describe, in order, the Hue, Saturation and Lightness +in the represented color. +""" + ManimColorInternal: TypeAlias = RGBA_Array_Float """``shape: (4,)`` @@ -257,7 +305,7 @@ """ InternalPoint2D_Array: TypeAlias = npt.NDArray[PointDType] -"""``shape: (N, 2)`` +"""``shape: (M, 2)`` An array of `InternalPoint2D` objects: ``[[float, float], ...]``. @@ -267,7 +315,7 @@ """ Point2D_Array: TypeAlias = Union[InternalPoint2D_Array, tuple[Point2D, ...]] -"""``shape: (N, 2)`` +"""``shape: (M, 2)`` An array of `Point2D` objects: ``[[float, float], ...]``. @@ -295,7 +343,7 @@ """ InternalPoint3D_Array: TypeAlias = npt.NDArray[PointDType] -"""``shape: (N, 3)`` +"""``shape: (M, 3)`` An array of `Point3D` objects: ``[[float, float, float], ...]``. @@ -305,7 +353,7 @@ """ Point3D_Array: TypeAlias = Union[InternalPoint3D_Array, tuple[Point3D, ...]] -"""``shape: (N, 3)`` +"""``shape: (M, 3)`` An array of `Point3D` objects: ``[[float, float, float], ...]``. @@ -313,6 +361,41 @@ further type information. """ +InternalPointND: TypeAlias = npt.NDArray[PointDType] +"""``shape: (N,)`` + +An N-dimensional point: ``[float, ...]``. + +.. note:: + This type alias is mostly made available for internal use, and + only includes the NumPy type. +""" + +PointND: TypeAlias = Union[InternalPointND, tuple[float, ...]] +"""``shape: (N,)`` + +An N-dimensional point: ``[float, ...]``. +""" + +InternalPointND_Array: TypeAlias = npt.NDArray[PointDType] +"""``shape: (M, N)`` + +An array of `PointND` objects: ``[[float, ...], ...]``. + +.. note:: + This type alias is mostly made available for internal use, and + only includes the NumPy type. +""" + +PointND_Array: TypeAlias = Union[InternalPointND_Array, tuple[PointND, ...]] +"""``shape: (M, N)`` + +An array of `PointND` objects: ``[[float, ...], ...]``. + +Please refer to the documentation of the function you are using for +further type information. +""" + """ [CATEGORY] @@ -582,7 +665,7 @@ Image types """ -Image: TypeAlias = npt.NDArray[ManimInt] +PixelArray: TypeAlias = npt.NDArray[ManimInt] """``shape: (height, width) | (height, width, 3) | (height, width, 4)`` A rasterized image with a height of ``height`` pixels and a width of @@ -595,24 +678,24 @@ `RGBA_Array_Int`. """ -GrayscaleImage: TypeAlias = Image +GrayscalePixelArray: TypeAlias = PixelArray """``shape: (height, width)`` -A 100% opaque grayscale `Image`, where every pixel value is a +A 100% opaque grayscale `PixelArray`, where every pixel value is a `ManimInt` indicating its lightness (black -> gray -> white). """ -RGBImage: TypeAlias = Image +RGBPixelArray: TypeAlias = PixelArray """``shape: (height, width, 3)`` -A 100% opaque `Image` in color, where every pixel value is an +A 100% opaque `PixelArray` in color, where every pixel value is an `RGB_Array_Int` object. """ -RGBAImage: TypeAlias = Image +RGBAPixelArray: TypeAlias = PixelArray """``shape: (height, width, 4)`` -An `Image` in color where pixels can be transparent. Every pixel +A `PixelArray` in color where pixels can be transparent. Every pixel value is an `RGBA_Array_Int` object. """ diff --git a/manim/utils/bezier.py b/manim/utils/bezier.py index c0bbcdf912..09f6f60cae 100644 --- a/manim/utils/bezier.py +++ b/manim/utils/bezier.py @@ -26,9 +26,7 @@ import numpy as np -from manim.typing import PointDType from manim.utils.simple_functions import choose -from manim.utils.space_ops import cross2d, find_intersection if TYPE_CHECKING: import numpy.typing as npt @@ -36,56 +34,138 @@ from manim.typing import ( BezierPoints, BezierPoints_Array, + ColVector, MatrixMN, Point3D, Point3D_Array, + QuadraticBezierPoints_Array, ) # l is a commonly used name in linear algebra # ruff: noqa: E741 +@overload +def bezier( + points: BezierPoints, +) -> Callable[[float | ColVector], Point3D | Point3D_Array]: ... + + +@overload def bezier( - points: Sequence[Point3D] | Point3D_Array, -) -> Callable[[float], Point3D]: - """Classic implementation of a bezier curve. + points: Sequence[Point3D_Array], +) -> Callable[[float | ColVector], Point3D_Array]: ... + + +def bezier(points): + """Classic implementation of a Bézier curve. Parameters ---------- points - points defining the desired bezier curve. + :math:`(d+1, 3)`-shaped array of :math:`d+1` control points defining a single Bézier + curve of degree :math:`d`. Alternatively, for vectorization purposes, ``points`` can + also be a :math:`(d+1, M, 3)`-shaped sequence of :math:`d+1` arrays of :math:`M` + control points each, which define `M` Bézier curves instead. Returns ------- - function describing the bezier curve. - You can pass a t value between 0 and 1 to get the corresponding point on the curve. + bezier_func : :class:`typing.Callable` [[:class:`float` | :class:`~.ColVector`], :class:`~.Point3D` | :class:`~.Point3D_Array`] + Function describing the Bézier curve. The behaviour of this function depends on + the shape of ``points``: + + * If ``points`` was a :math:`(d+1, 3)` array representing a single Bézier curve, + then ``bezier_func`` can receive either: + + * a :class:`float` ``t``, in which case it returns a + single :math:`(1, 3)`-shaped :class:`~.Point3D` representing the evaluation + of the Bézier at ``t``, or + * an :math:`(n, 1)`-shaped :class:`~.ColVector` + containing :math:`n` values to evaluate the Bézier curve at, returning instead + an :math:`(n, 3)`-shaped :class:`~.Point3D_Array` containing the points + resulting from evaluating the Bézier at each of the :math:`n` values. + .. warning:: + If passing a vector of :math:`t`-values to ``bezier_func``, it **must** + be a column vector/matrix of shape :math:`(n, 1)`. Passing an 1D array of + shape :math:`(n,)` is not supported and **will result in undefined behaviour**. + + * If ``points`` was a :math:`(d+1, M, 3)` array describing :math:`M` Bézier curves, + then ``bezier_func`` can receive either: + + * a :class:`float` ``t``, in which case it returns an + :math:`(M, 3)`-shaped :class:`~.Point3D_Array` representing the evaluation + of the :math:`M` Bézier curves at the same value ``t``, or + * an :math:`(M, 1)`-shaped + :class:`~.ColVector` containing :math:`M` values, such that the :math:`i`-th + Bézier curve defined by ``points`` is evaluated at the corresponding :math:`i`-th + value in ``t``, returning again an :math:`(M, 3)`-shaped :class:`~.Point3D_Array` + containing those :math:`M` evaluations. + .. warning:: + Unlike the previous case, if you pass a :class:`~.ColVector` to ``bezier_func``, + it **must** contain exactly :math:`M` values, each value for each of the :math:`M` + Bézier curves defined by ``points``. Any array of shape other than :math:`(M, 1)` + **will result in undefined behaviour**. """ - n = len(points) - 1 - # Cubic Bezier curve - if n == 3: - return lambda t: np.asarray( - (1 - t) ** 3 * points[0] - + 3 * t * (1 - t) ** 2 * points[1] - + 3 * (1 - t) * t**2 * points[2] - + t**3 * points[3], - dtype=PointDType, - ) - # Quadratic Bezier curve - if n == 2: - return lambda t: np.asarray( - (1 - t) ** 2 * points[0] + 2 * t * (1 - t) * points[1] + t**2 * points[2], - dtype=PointDType, - ) + P = np.asarray(points) + degree = P.shape[0] - 1 - return lambda t: np.asarray( - np.asarray( - [ - (((1 - t) ** (n - k)) * (t**k) * choose(n, k) * point) - for k, point in enumerate(points) - ], - dtype=PointDType, - ).sum(axis=0) - ) + if degree == 0: + + def zero_bezier(t): + return np.ones_like(t) * P[0] + + return zero_bezier + + if degree == 1: + + def linear_bezier(t): + return P[0] + t * (P[1] - P[0]) + + return linear_bezier + + if degree == 2: + + def quadratic_bezier(t): + t2 = t * t + mt = 1 - t + mt2 = mt * mt + return mt2 * P[0] + 2 * t * mt * P[1] + t2 * P[2] + + return quadratic_bezier + + if degree == 3: + + def cubic_bezier(t): + t2 = t * t + t3 = t2 * t + mt = 1 - t + mt2 = mt * mt + mt3 = mt2 * mt + return mt3 * P[0] + 3 * t * mt2 * P[1] + 3 * t2 * mt * P[2] + t3 * P[3] + + return cubic_bezier + + def nth_grade_bezier(t): + is_scalar = not isinstance(t, np.ndarray) + if is_scalar: + B = np.empty((1, *P.shape)) + else: + t = t.reshape(-1, *[1 for dim in P.shape]) + B = np.empty((t.shape[0], *P.shape)) + B[:] = P + + for i in range(degree): + # After the i-th iteration (i in [0, ..., d-1]) there are evaluations at t + # of (d-i) Bezier curves of grade (i+1), stored in the first d-i slots of B + B[:, : degree - i] += t * (B[:, 1 : degree - i + 1] - B[:, : degree - i]) + + # In the end, there shall be the evaluation at t of a single Bezier curve of + # grade d, stored in the first slot of B + if is_scalar: + return B[0, 0] + return B[:, 0] + + return nth_grade_bezier def partial_bezier_points(points: BezierPoints, a: float, b: float) -> BezierPoints: @@ -541,7 +621,6 @@ def split_bezier(points: BezierPoints, t: float) -> Point3D_Array: :class:`~.Point3D_Array` An array containing the control points defining the two Bézier curves. """ - points = np.asarray(points) N, dim = points.shape degree = N - 1 @@ -875,9 +954,10 @@ def bezier_remap( An array of multiple Bézier curves of degree :math:`d` to be remapped. The shape of this array must be ``(current_number_of_curves, nppc, dim)``, where: - * ``current_number_of_curves`` is the current amount of curves in the array ``bezier_tuples``, - * ``nppc`` is the amount of points per curve, such that their degree is ``nppc-1``, and - * ``dim`` is the dimension of the points, usually :math:`3`. + * ``current_number_of_curves`` is the current amount of curves in the array ``bezier_tuples``, + * ``nppc`` is the amount of points per curve, such that their degree is ``nppc-1``, and + * ``dim`` is the dimension of the points, usually :math:`3`. + new_number_of_curves The number of curves that the output will contain. This needs to be higher than the current number. @@ -927,14 +1007,47 @@ def bezier_remap( def interpolate(start: float, end: float, alpha: float) -> float: ... +@overload +def interpolate(start: float, end: float, alpha: ColVector) -> ColVector: ... + + @overload def interpolate(start: Point3D, end: Point3D, alpha: float) -> Point3D: ... -def interpolate( - start: int | float | Point3D, end: int | float | Point3D, alpha: float | Point3D -) -> float | Point3D: - return (1 - alpha) * start + alpha * end +@overload +def interpolate(start: Point3D, end: Point3D, alpha: ColVector) -> Point3D_Array: ... + + +def interpolate(start, end, alpha): + """Linearly interpolates between two values ``start`` and ``end``. + + Parameters + ---------- + start + The start of the range. + end + The end of the range. + alpha + A float between 0 and 1, or an :math:`(n, 1)` column vector containing + :math:`n` floats between 0 and 1 to interpolate in a vectorized fashion. + + Returns + ------- + :class:`float` | :class:`~.ColVector` | :class:`~.Point3D` | :class:`~.Point3D_Array` + The result of the linear interpolation. + + * If ``start`` and ``end`` are of type :class:`float`, and: + + * ``alpha`` is also a :class:`float`, the return is simply another :class:`float`. + * ``alpha`` is a :class:`~.ColVector`, the return is another :class:`~.ColVector`. + + * If ``start`` and ``end`` are of type :class:`~.Point3D`, and: + + * ``alpha`` is a :class:`float`, the return is another :class:`~.Point3D`. + * ``alpha`` is a :class:`~.ColVector`, the return is a :class:`~.Point3D_Array`. + """ + return start + alpha * (end - start) def integer_interpolate( @@ -1046,7 +1159,7 @@ def inverse_interpolate( .. code-block:: pycon >>> inverse_interpolate(start=2, end=6, value=4) - 0.5 + np.float64(0.5) >>> start = np.array([1, 2, 1]) >>> end = np.array([7, 8, 11]) @@ -1108,13 +1221,13 @@ def match_interpolate( Examples -------- >>> match_interpolate(0, 100, 10, 20, 15) - 50.0 + np.float64(50.0) """ old_alpha = inverse_interpolate(old_start, old_end, old_value) return interpolate( new_start, new_end, - old_alpha, # type: ignore + old_alpha, # type: ignore[arg-type] ) @@ -1610,74 +1723,147 @@ def get_smooth_open_cubic_bezier_handle_points( return H1, H2 -# Given 4 control points for a cubic bezier curve (or arrays of such) -# return control points for 2 quadratics (or 2n quadratics) approximating them. +@overload def get_quadratic_approximation_of_cubic( a0: Point3D, h0: Point3D, h1: Point3D, a1: Point3D -) -> BezierPoints: - a0 = np.array(a0, ndmin=2) - h0 = np.array(h0, ndmin=2) - h1 = np.array(h1, ndmin=2) - a1 = np.array(a1, ndmin=2) - # Tangent vectors at the start and end. - T0 = h0 - a0 - T1 = a1 - h1 - - # Search for inflection points. If none are found, use the - # midpoint as a cut point. - # Based on http://www.caffeineowl.com/graphics/2d/vectorial/cubic-inflexion.html - has_infl = np.ones(len(a0), dtype=bool) - - p = h0 - a0 - q = h1 - 2 * h0 + a0 - r = a1 - 3 * h1 + 3 * h0 - a0 - - a = cross2d(q, r) - b = cross2d(p, r) - c = cross2d(p, q) - - disc = b * b - 4 * a * c - has_infl &= disc > 0 - sqrt_disc = np.sqrt(np.abs(disc)) - settings = np.seterr(all="ignore") - ti_bounds = [] - for sgn in [-1, +1]: - ti = (-b + sgn * sqrt_disc) / (2 * a) - ti[a == 0] = (-c / b)[a == 0] - ti[(a == 0) & (b == 0)] = 0 - ti_bounds.append(ti) - ti_min, ti_max = ti_bounds - np.seterr(**settings) - ti_min_in_range = has_infl & (0 < ti_min) & (ti_min < 1) - ti_max_in_range = has_infl & (0 < ti_max) & (ti_max < 1) - - # Choose a value of t which starts at 0.5, - # but is updated to one of the inflection points - # if they lie between 0 and 1 - - t_mid = 0.5 * np.ones(len(a0)) - t_mid[ti_min_in_range] = ti_min[ti_min_in_range] - t_mid[ti_max_in_range] = ti_max[ti_max_in_range] - - m, n = a0.shape - t_mid = t_mid.repeat(n).reshape((m, n)) - - # Compute bezier point and tangent at the chosen value of t (these are vectorized) - mid = bezier([a0, h0, h1, a1])(t_mid) # type: ignore - Tm = bezier([h0 - a0, h1 - h0, a1 - h1])(t_mid) # type: ignore - - # Intersection between tangent lines at end points - # and tangent in the middle - i0 = find_intersection(a0, T0, mid, Tm) - i1 = find_intersection(a1, T1, mid, Tm) - - m, n = np.shape(a0) - result = np.zeros((6 * m, n)) +) -> QuadraticBezierPoints_Array: ... + + +@overload +def get_quadratic_approximation_of_cubic( + a0: Point3D_Array, + h0: Point3D_Array, + h1: Point3D_Array, + a1: Point3D_Array, +) -> QuadraticBezierPoints_Array: ... + + +def get_quadratic_approximation_of_cubic(a0, h0, h1, a1): + r"""If ``a0``, ``h0``, ``h1`` and ``a1`` are the control points of a cubic + Bézier curve, approximate the curve with two quadratic Bézier curves and + return an array of 6 points, where the first 3 points represent the first + quadratic curve and the last 3 represent the second one. + + Otherwise, if ``a0``, ``h0``, ``h1`` and ``a1`` are _arrays_ of :math:`N` + points representing :math:`N` cubic Bézier curves, return an array of + :math:`6N` points where each group of :math:`6` consecutive points + approximates each of the :math:`N` curves in a similar way as above. + + .. note:: + If the cubic spline given by the original cubic Bézier curves is + smooth, this algorithm will generate a quadratic spline which is also + smooth. + + If a cubic Bézier is given by + + .. math:: + C(t) = (1-t)^3 A_0 + 3(1-t)^2 t H_0 + 3(1-t)t^2 H_1 + t^3 A_1 + + where :math:`A_0`, :math:`H_0`, :math:`H_1` and :math:`A_1` are its + control points, then this algorithm should generate two quadratic + Béziers given by + + .. math:: + Q_0(t) &= (1-t)^2 A_0 + 2(1-t)t M_0 + t^2 K \\ + Q_1(t) &= (1-t)^2 K + 2(1-t)t M_1 + t^2 A_1 + + where :math:`M_0` and :math:`M_1` are the respective handles to be + found for both curves, and :math:`K` is the end anchor of the 1st curve + and the start anchor of the 2nd, which must also be found. + + To solve for :math:`M_0`, :math:`M_1` and :math:`K`, three conditions + can be imposed: + + 1. :math:`Q_0'(0) = \frac{1}{2}C'(0)`. The derivative of the first + quadratic curve at :math:`t = 0` should be proportional to that of + the original cubic curve, also at :math:`t = 0`. Because the cubic + curve is split into two parts, it is necessary to divide this by + two: the speed of a point travelling through the curve should be + half of the original. This gives: + + .. math:: + Q_0'(0) &= \frac{1}{2}C'(0) \\ + 2(M_0 - A_0) &= \frac{3}{2}(H_0 - A_0) \\ + 2M_0 - 2A_0 &= \frac{3}{2}H_0 - \frac{3}{2}A_0 \\ + 2M_0 &= \frac{3}{2}H_0 + \frac{1}{2}A_0 \\ + M_0 &= \frac{1}{4}(3H_0 + A_0) + + 2. :math:`Q_1'(1) = \frac{1}{2}C'(1)`. The derivative of the second + quadratic curve at :math:`t = 1` should be half of that of the + original cubic curve for the same reasons as above, also at + :math:`t = 1`. This gives: + + .. math:: + Q_1'(1) &= \frac{1}{2}C'(1) \\ + 2(A_1 - M_1) &= \frac{3}{2}(A_1 - H_1) \\ + 2A_1 - 2M_1 &= \frac{3}{2}A_1 - \frac{3}{2}H_1 \\ + -2M_1 &= -\frac{1}{2}A_1 - \frac{3}{2}H_1 \\ + M_1 &= \frac{1}{4}(3H_1 + A_1) + + 3. :math:`Q_0'(1) = Q_1'(0)`. The derivatives of both quadratic curves + should match at the point :math:`K`, in order for the final spline + to be smooth. This gives: + + .. math:: + Q_0'(1) &= Q_1'(0) \\ + 2(K - M_0) &= 2(M_1 - K) \\ + 2K - 2M_0 &= 2M_1 - 2K \\ + 4K &= 2M_0 + 2M_1 \\ + K &= \frac{1}{2}(M_0 + M_1) + + This is sufficient to find proper control points for the quadratic + Bézier curves. + + Parameters + ---------- + a0 + The start anchor of a single cubic Bézier curve, or an array of + :math:`N` start anchors for :math:`N` curves. + h0 + The first handle of a single cubic Bézier curve, or an array of + :math:`N` first handles for :math:`N` curves. + h1 + The second handle of a single cubic Bézier curve, or an array of + :math:`N` second handles for :math:`N` curves. + a1 + The end anchor of a single cubic Bézier curve, or an array of + :math:`N` end anchors for :math:`N` curves. + + Returns + ------- + result + An array containing either 6 points for 2 quadratic Bézier curves + approximating the original cubic curve, or :math:`6N` points for + :math:`2N` quadratic curves approximating :math:`N` cubic curves. + + Raises + ------ + ValueError + If ``a0``, ``h0``, ``h1`` and ``a1`` have different dimensions, or + if their number of dimensions is not 1 or 2. + """ + a0 = np.asarray(a0) + h0 = np.asarray(h0) + h1 = np.asarray(h1) + a1 = np.asarray(a1) + + if all(arr.ndim == 1 for arr in (a0, h0, h1, a1)): + num_curves, dim = 1, a0.shape[0] + elif all(arr.ndim == 2 for arr in (a0, h0, h1, a1)): + num_curves, dim = a0.shape + else: + raise ValueError("All arguments must be Point3D or Point3D_Array.") + + m0 = 0.25 * (3 * h0 + a0) + m1 = 0.25 * (3 * h1 + a1) + k = 0.5 * (m0 + m1) + + result = np.empty((6 * num_curves, dim)) result[0::6] = a0 - result[1::6] = i0 - result[2::6] = mid - result[3::6] = mid - result[4::6] = i1 + result[1::6] = m0 + result[2::6] = k + result[3::6] = k + result[4::6] = m1 result[5::6] = a1 return result @@ -1752,9 +1938,7 @@ def is_closed(points: Point3D_Array) -> bool: return False if abs(end[1] - start[1]) > tolerance[1]: return False - if abs(end[2] - start[2]) > tolerance[2]: - return False - return True + return bool(abs(end[2] - start[2]) <= tolerance[2]) def proportions_along_bezier_curve_for_point( @@ -1830,7 +2014,7 @@ def proportions_along_bezier_curve_for_point( # Roots will be none, but in this specific instance, we don't need to consider that. continue bezier_polynom = np.polynomial.Polynomial(terms[::-1]) - polynom_roots = bezier_polynom.roots() # type: ignore + polynom_roots = bezier_polynom.roots() if len(polynom_roots) > 0: polynom_roots = np.around(polynom_roots, int(np.log10(1 / round_to))) roots.append(polynom_roots) @@ -1838,7 +2022,7 @@ def proportions_along_bezier_curve_for_point( roots = [[root for root in rootlist if root.imag == 0] for rootlist in roots] # Get common roots # arg-type: ignore - roots = reduce(np.intersect1d, roots) # type: ignore + roots = reduce(np.intersect1d, roots) result = np.asarray([r.real for r in roots if 0 <= r.real <= 1]) return result @@ -1870,7 +2054,6 @@ def point_lies_on_bezier( bool Whether the point lies on the curve. """ - roots = proportions_along_bezier_curve_for_point(point, control_points, round_to) return len(roots) > 0 diff --git a/manim/utils/caching.py b/manim/utils/caching.py index d19ba8c0e2..a0e6772443 100644 --- a/manim/utils/caching.py +++ b/manim/utils/caching.py @@ -22,7 +22,6 @@ def handle_caching_play(func: Callable[..., None]): The play like function that has to be written to the video file stream. Take the same parameters as `scene.play`. """ - # NOTE : This is only kept for OpenGL renderer. # The play logic of the cairo renderer as been refactored and does not need this function anymore. # When OpenGL renderer will have a proper testing system, diff --git a/manim/utils/color/DVIPSNAMES.py b/manim/utils/color/DVIPSNAMES.py new file mode 100644 index 0000000000..88fe8cf680 --- /dev/null +++ b/manim/utils/color/DVIPSNAMES.py @@ -0,0 +1,96 @@ +r"""dvips Colors + +This module contains the colors defined in the dvips driver, which are commonly accessed +as named colors in LaTeX via the ``\usepackage[dvipsnames]{xcolor}`` package. + +To use the colors from this list, access them directly from the module (which +is exposed to Manim's global name space): + +.. code:: pycon + + >>> from manim import DVIPSNAMES + >>> DVIPSNAMES.DARKORCHID + ManimColor('#A4538A') + +List of Color Constants +----------------------- + +These hex values are derived from those specified in the ``xcolor`` package +documentation (see https://ctan.org/pkg/xcolor): + +.. automanimcolormodule:: manim.utils.color.DVIPSNAMES + +""" + +from __future__ import annotations + +from .core import ManimColor + +AQUAMARINE = ManimColor("#00B5BE") +BITTERSWEET = ManimColor("#C04F17") +APRICOT = ManimColor("#FBB982") +BLACK = ManimColor("#221E1F") +BLUE = ManimColor("#2D2F92") +BLUEGREEN = ManimColor("#00B3B8") +BLUEVIOLET = ManimColor("#473992") +BRICKRED = ManimColor("#B6321C") +BROWN = ManimColor("#792500") +BURNTORANGE = ManimColor("#F7921D") +CADETBLUE = ManimColor("#74729A") +CARNATIONPINK = ManimColor("#F282B4") +CERULEAN = ManimColor("#00A2E3") +CORNFLOWERBLUE = ManimColor("#41B0E4") +CYAN = ManimColor("#00AEEF") +DANDELION = ManimColor("#FDBC42") +DARKORCHID = ManimColor("#A4538A") +EMERALD = ManimColor("#00A99D") +FORESTGREEN = ManimColor("#009B55") +FUCHSIA = ManimColor("#8C368C") +GOLDENROD = ManimColor("#FFDF42") +GRAY = ManimColor("#949698") +GREEN = ManimColor("#00A64F") +GREENYELLOW = ManimColor("#DFE674") +JUNGLEGREEN = ManimColor("#00A99A") +LAVENDER = ManimColor("#F49EC4") +LIMEGREEN = ManimColor("#8DC73E") +MAGENTA = ManimColor("#EC008C") +MAHOGANY = ManimColor("#A9341F") +MAROON = ManimColor("#AF3235") +MELON = ManimColor("#F89E7B") +MIDNIGHTBLUE = ManimColor("#006795") +MULBERRY = ManimColor("#A93C93") +NAVYBLUE = ManimColor("#006EB8") +OLIVEGREEN = ManimColor("#3C8031") +ORANGE = ManimColor("#F58137") +ORANGERED = ManimColor("#ED135A") +ORCHID = ManimColor("#AF72B0") +PEACH = ManimColor("#F7965A") +PERIWINKLE = ManimColor("#7977B8") +PINEGREEN = ManimColor("#008B72") +PLUM = ManimColor("#92268F") +PROCESSBLUE = ManimColor("#00B0F0") +PURPLE = ManimColor("#99479B") +RAWSIENNA = ManimColor("#974006") +RED = ManimColor("#ED1B23") +REDORANGE = ManimColor("#F26035") +REDVIOLET = ManimColor("#A1246B") +RHODAMINE = ManimColor("#EF559F") +ROYALBLUE = ManimColor("#0071BC") +ROYALPURPLE = ManimColor("#613F99") +RUBINERED = ManimColor("#ED017D") +SALMON = ManimColor("#F69289") +SEAGREEN = ManimColor("#3FBC9D") +SEPIA = ManimColor("#671800") +SKYBLUE = ManimColor("#46C5DD") +SPRINGGREEN = ManimColor("#C6DC67") +TAN = ManimColor("#DA9D76") +TEALBLUE = ManimColor("#00AEB3") +THISTLE = ManimColor("#D883B7") +TURQUOISE = ManimColor("#00B4CE") +VIOLET = ManimColor("#58429B") +VIOLETRED = ManimColor("#EF58A0") +WHITE = ManimColor("#FFFFFF") +WILDSTRAWBERRY = ManimColor("#EE2967") +YELLOW = ManimColor("#FFF200") +YELLOWGREEN = ManimColor("#98CC70") +YELLOWORANGE = ManimColor("#FAA21A") diff --git a/manim/utils/color/SVGNAMES.py b/manim/utils/color/SVGNAMES.py new file mode 100644 index 0000000000..d59eed66b4 --- /dev/null +++ b/manim/utils/color/SVGNAMES.py @@ -0,0 +1,179 @@ +r"""SVG 1.1 Colors + +This module contains the colors defined in the SVG 1.1 specification, which are commonly +accessed as named colors in LaTeX via the ``\usepackage[svgnames]{xcolor}`` package. + +To use the colors from this list, access them directly from the module (which +is exposed to Manim's global name space): + +.. code:: pycon + + >>> from manim import SVGNAMES + >>> SVGNAMES.LIGHTCORAL + ManimColor('#EF7F7F') + +List of Color Constants +----------------------- + +These hex values are derived from those specified in the ``xcolor`` package +documentation (see https://ctan.org/pkg/xcolor): + +.. automanimcolormodule:: manim.utils.color.SVGNAMES + +""" + +from __future__ import annotations + +from .core import ManimColor + +ALICEBLUE = ManimColor("#EFF7FF") +ANTIQUEWHITE = ManimColor("#F9EAD7") +AQUA = ManimColor("#00FFFF") +AQUAMARINE = ManimColor("#7EFFD3") +AZURE = ManimColor("#EFFFFF") +BEIGE = ManimColor("#F4F4DC") +BISQUE = ManimColor("#FFE3C4") +BLACK = ManimColor("#000000") +BLANCHEDALMOND = ManimColor("#FFEACD") +BLUE = ManimColor("#0000FF") +BLUEVIOLET = ManimColor("#892BE2") +BROWN = ManimColor("#A52A2A") +BURLYWOOD = ManimColor("#DDB787") +CADETBLUE = ManimColor("#5E9EA0") +CHARTREUSE = ManimColor("#7EFF00") +CHOCOLATE = ManimColor("#D2681D") +CORAL = ManimColor("#FF7E4F") +CORNFLOWERBLUE = ManimColor("#6395ED") +CORNSILK = ManimColor("#FFF7DC") +CRIMSON = ManimColor("#DC143B") +CYAN = ManimColor("#00FFFF") +DARKBLUE = ManimColor("#00008A") +DARKCYAN = ManimColor("#008A8A") +DARKGOLDENROD = ManimColor("#B7850B") +DARKGRAY = ManimColor("#A9A9A9") +DARKGREEN = ManimColor("#006300") +DARKGREY = ManimColor("#A9A9A9") +DARKKHAKI = ManimColor("#BCB66B") +DARKMAGENTA = ManimColor("#8A008A") +DARKOLIVEGREEN = ManimColor("#546B2F") +DARKORANGE = ManimColor("#FF8C00") +DARKORCHID = ManimColor("#9931CC") +DARKRED = ManimColor("#8A0000") +DARKSALMON = ManimColor("#E8967A") +DARKSEAGREEN = ManimColor("#8EBB8E") +DARKSLATEBLUE = ManimColor("#483D8A") +DARKSLATEGRAY = ManimColor("#2F4F4F") +DARKSLATEGREY = ManimColor("#2F4F4F") +DARKTURQUOISE = ManimColor("#00CED1") +DARKVIOLET = ManimColor("#9300D3") +DEEPPINK = ManimColor("#FF1492") +DEEPSKYBLUE = ManimColor("#00BFFF") +DIMGRAY = ManimColor("#686868") +DIMGREY = ManimColor("#686868") +DODGERBLUE = ManimColor("#1D90FF") +FIREBRICK = ManimColor("#B12121") +FLORALWHITE = ManimColor("#FFF9EF") +FORESTGREEN = ManimColor("#218A21") +FUCHSIA = ManimColor("#FF00FF") +GAINSBORO = ManimColor("#DCDCDC") +GHOSTWHITE = ManimColor("#F7F7FF") +GOLD = ManimColor("#FFD700") +GOLDENROD = ManimColor("#DAA51F") +GRAY = ManimColor("#7F7F7F") +GREEN = ManimColor("#007F00") +GREENYELLOW = ManimColor("#ADFF2F") +GREY = ManimColor("#7F7F7F") +HONEYDEW = ManimColor("#EFFFEF") +HOTPINK = ManimColor("#FF68B3") +INDIANRED = ManimColor("#CD5B5B") +INDIGO = ManimColor("#4A0082") +IVORY = ManimColor("#FFFFEF") +KHAKI = ManimColor("#EFE58C") +LAVENDER = ManimColor("#E5E5F9") +LAVENDERBLUSH = ManimColor("#FFEFF4") +LAWNGREEN = ManimColor("#7CFC00") +LEMONCHIFFON = ManimColor("#FFF9CD") +LIGHTBLUE = ManimColor("#ADD8E5") +LIGHTCORAL = ManimColor("#EF7F7F") +LIGHTCYAN = ManimColor("#E0FFFF") +LIGHTGOLDENROD = ManimColor("#EDDD82") +LIGHTGOLDENRODYELLOW = ManimColor("#F9F9D2") +LIGHTGRAY = ManimColor("#D3D3D3") +LIGHTGREEN = ManimColor("#90ED90") +LIGHTGREY = ManimColor("#D3D3D3") +LIGHTPINK = ManimColor("#FFB5C0") +LIGHTSALMON = ManimColor("#FFA07A") +LIGHTSEAGREEN = ManimColor("#1FB1AA") +LIGHTSKYBLUE = ManimColor("#87CEF9") +LIGHTSLATEBLUE = ManimColor("#8470FF") +LIGHTSLATEGRAY = ManimColor("#778799") +LIGHTSLATEGREY = ManimColor("#778799") +LIGHTSTEELBLUE = ManimColor("#AFC4DD") +LIGHTYELLOW = ManimColor("#FFFFE0") +LIME = ManimColor("#00FF00") +LIMEGREEN = ManimColor("#31CD31") +LINEN = ManimColor("#F9EFE5") +MAGENTA = ManimColor("#FF00FF") +MAROON = ManimColor("#7F0000") +MEDIUMAQUAMARINE = ManimColor("#66CDAA") +MEDIUMBLUE = ManimColor("#0000CD") +MEDIUMORCHID = ManimColor("#BA54D3") +MEDIUMPURPLE = ManimColor("#9270DB") +MEDIUMSEAGREEN = ManimColor("#3BB271") +MEDIUMSLATEBLUE = ManimColor("#7B68ED") +MEDIUMSPRINGGREEN = ManimColor("#00F99A") +MEDIUMTURQUOISE = ManimColor("#48D1CC") +MEDIUMVIOLETRED = ManimColor("#C61584") +MIDNIGHTBLUE = ManimColor("#181870") +MINTCREAM = ManimColor("#F4FFF9") +MISTYROSE = ManimColor("#FFE3E1") +MOCCASIN = ManimColor("#FFE3B5") +NAVAJOWHITE = ManimColor("#FFDDAD") +NAVY = ManimColor("#00007F") +NAVYBLUE = ManimColor("#00007F") +OLDLACE = ManimColor("#FCF4E5") +OLIVE = ManimColor("#7F7F00") +OLIVEDRAB = ManimColor("#6B8D22") +ORANGE = ManimColor("#FFA500") +ORANGERED = ManimColor("#FF4400") +ORCHID = ManimColor("#DA70D6") +PALEGOLDENROD = ManimColor("#EDE8AA") +PALEGREEN = ManimColor("#97FB97") +PALETURQUOISE = ManimColor("#AFEDED") +PALEVIOLETRED = ManimColor("#DB7092") +PAPAYAWHIP = ManimColor("#FFEED4") +PEACHPUFF = ManimColor("#FFDAB8") +PERU = ManimColor("#CD843F") +PINK = ManimColor("#FFBFCA") +PLUM = ManimColor("#DDA0DD") +POWDERBLUE = ManimColor("#AFE0E5") +PURPLE = ManimColor("#7F007F") +RED = ManimColor("#FF0000") +ROSYBROWN = ManimColor("#BB8E8E") +ROYALBLUE = ManimColor("#4168E1") +SADDLEBROWN = ManimColor("#8A4413") +SALMON = ManimColor("#F97F72") +SANDYBROWN = ManimColor("#F3A45F") +SEAGREEN = ManimColor("#2D8A56") +SEASHELL = ManimColor("#FFF4ED") +SIENNA = ManimColor("#A0512C") +SILVER = ManimColor("#BFBFBF") +SKYBLUE = ManimColor("#87CEEA") +SLATEBLUE = ManimColor("#6959CD") +SLATEGRAY = ManimColor("#707F90") +SLATEGREY = ManimColor("#707F90") +SNOW = ManimColor("#FFF9F9") +SPRINGGREEN = ManimColor("#00FF7E") +STEELBLUE = ManimColor("#4682B3") +TAN = ManimColor("#D2B38C") +TEAL = ManimColor("#007F7F") +THISTLE = ManimColor("#D8BFD8") +TOMATO = ManimColor("#FF6347") +TURQUOISE = ManimColor("#3FE0CF") +VIOLET = ManimColor("#ED82ED") +VIOLETRED = ManimColor("#D01F90") +WHEAT = ManimColor("#F4DDB2") +WHITE = ManimColor("#FFFFFF") +WHITESMOKE = ManimColor("#F4F4F4") +YELLOW = ManimColor("#FFFF00") +YELLOWGREEN = ManimColor("#9ACD30") diff --git a/manim/utils/color/__init__.py b/manim/utils/color/__init__.py index 362a31ac25..7ef3cb3505 100644 --- a/manim/utils/color/__init__.py +++ b/manim/utils/color/__init__.py @@ -16,8 +16,9 @@ - The colors listed in :mod:`.color.manim_colors` are loaded into Manim's global name space. -- The colors in :mod:`.color.AS2700`, :mod:`.color.BS381`, :mod:`.color.X11`, - and :mod:`.color.XKCD` need to be accessed via their module (which are available +- The colors in :mod:`.color.AS2700`, :mod:`.color.BS381`, + :mod:`.color.DVIPSNAMES`, :mod:`.color.SVGNAMES`, :mod:`.color.X11` and + :mod:`.color.XKCD` need to be accessed via their module (which are available in Manim's global name space), or imported separately. For example: .. code:: pycon @@ -42,6 +43,8 @@ manim_colors AS2700 BS381 + DVIPSNAMES + SVGNAMES XKCD X11 @@ -49,7 +52,7 @@ from __future__ import annotations -from . import AS2700, BS381, X11, XKCD +from . import AS2700, BS381, DVIPSNAMES, SVGNAMES, X11, XKCD from .core import * from .manim_colors import * diff --git a/manim/utils/color/core.py b/manim/utils/color/core.py index 32c895d100..23864921e0 100644 --- a/manim/utils/color/core.py +++ b/manim/utils/color/core.py @@ -18,6 +18,27 @@ The colors of type "C" have an alias equal to the colorname without a letter, e.g. GREEN = GREEN_C + +=================== +Custom Color Spaces +=================== + +Hello dear visitor, you seem to be interested in implementing a custom color class for a color space we don't currently support. + +The current system is using a few indirections for ensuring a consistent behavior with all other color types in manim. + +To implement a custom color space you must subclass :class:`ManimColor` and implement three important functions + +:attr:`~.ManimColor._internal_value` is an ``@property`` implemented on :class:`ManimColor` with the goal of keeping a consistent internal representation that can be referenced by other functions in :class:`ManimColor`. +The getter should always return a value in the format of ``[r,g,b,a]`` as a numpy array which is in accordance with the type :class:`.ManimColorInternal`. +The setter should always accept a value in the format ``[r,g,b,a]`` which can be converted to whatever attributes you need. +This property acts as a proxy to whatever representation you need in your class. + +:attr:`~ManimColor._internal_space` this is a readonly ``@property`` implemented on :class:`ManimColor` with the goal of a useful representation that can be used by operators and interpolation and color transform functions. +The only constraints on this value are that it needs to be a numpy array and the last value must be the opacity in a range ``0.0`` to ``1.0``. +Additionally your ``__init__`` must support this format as initialization value without additional parameters to ensure correct functionality of all other methods in :class:`ManimColor`. + +:func:`~ManimColor._from_internal` is a ``@classmethod`` that converts an ``[r,g,b,a]`` value into suitable parameters for your ``__init__`` method and calls the cls parameter. """ from __future__ import annotations @@ -32,13 +53,18 @@ import numpy as np import numpy.typing as npt -from typing_extensions import Self, TypeAlias +from typing_extensions import Self, TypeAlias, TypeGuard, override from manim.typing import ( + HSL_Array_Float, + HSL_Tuple_Float, HSV_Array_Float, HSV_Tuple_Float, + HSVA_Array_Float, + HSVA_Tuple_Float, ManimColorDType, ManimColorInternal, + ManimFloat, RGB_Array_Float, RGB_Array_Int, RGB_Tuple_Float, @@ -132,14 +158,14 @@ def __init__( # This is not expected to be called on module initialization time # It can be horribly slow to convert a string to a color because # it has to access the dictionary of colors and find the right color - self._internal_value = ManimColor._internal_from_string(value) + self._internal_value = ManimColor._internal_from_string(value, alpha) elif isinstance(value, (list, tuple, np.ndarray)): length = len(value) if all(isinstance(x, float) for x in value): if length == 3: - self._internal_value = ManimColor._internal_from_rgb(value, alpha) # type: ignore + self._internal_value = ManimColor._internal_from_rgb(value, alpha) # type: ignore[arg-type] elif length == 4: - self._internal_value = ManimColor._internal_from_rgba(value) # type: ignore + self._internal_value = ManimColor._internal_from_rgba(value) # type: ignore[arg-type] else: raise ValueError( f"ManimColor only accepts lists/tuples/arrays of length 3 or 4, not {length}" @@ -147,11 +173,11 @@ def __init__( else: if length == 3: self._internal_value = ManimColor._internal_from_int_rgb( - value, - alpha, # type: ignore + value, # type: ignore[arg-type] + alpha, ) elif length == 4: - self._internal_value = ManimColor._internal_from_int_rgba(value) # type: ignore + self._internal_value = ManimColor._internal_from_int_rgba(value) # type: ignore[arg-type] else: raise ValueError( f"ManimColor only accepts lists/tuples/arrays of length 3 or 4, not {length}" @@ -160,7 +186,6 @@ def __init__( result = re_hex.search(value.get_hex()) if result is None: raise ValueError(f"Failed to parse a color from {value}") - self._internal_value = ManimColor._internal_from_hex_string( result.group(), alpha ) @@ -172,6 +197,14 @@ def __init__( f"list[float, float, float, float], not {type(value)}" ) + @property + def _internal_space(self) -> npt.NDArray[ManimFloat]: + """ + This is a readonly property which is a custom representation for color space operations. + It is used for operators and can be used when implementing a custom color space. + """ + return self._internal_value + @property def _internal_value(self) -> ManimColorInternal: """Returns the internal value of the current Manim color [r,g,b,a] float array @@ -203,6 +236,14 @@ def _internal_value(self, value: ManimColorInternal) -> None: raise TypeError("Array must have 4 values exactly") self.__value: ManimColorInternal = value + @classmethod + def _construct_from_space(cls, _space) -> Self: + """ + This function is used as a proxy for constructing a color with an internal value, + this can be used by subclasses to hook into the construction of new objects using the internal value format + """ + return cls(_space) + @staticmethod def _internal_from_integer(value: int, alpha: float) -> ManimColorInternal: return np.asarray( @@ -215,9 +256,8 @@ def _internal_from_integer(value: int, alpha: float) -> ManimColorInternal: dtype=ManimColorDType, ) - # TODO: Maybe make 8 nibble hex also convertible ? @staticmethod - def _internal_from_hex_string(hex: str, alpha: float) -> ManimColorInternal: + def _internal_from_hex_string(hex_: str, alpha: float) -> ManimColorInternal: """Internal function for converting a hex string into the internal representation of a ManimColor. .. warning:: @@ -231,16 +271,22 @@ def _internal_from_hex_string(hex: str, alpha: float) -> ManimColorInternal: hex : str hex string to be parsed alpha : float - alpha value used for the color + alpha value used for the color if the color is only 3 bytes long, if the color is 4 bytes long the parameter will not be used Returns ------- ManimColorInternal Internal color representation """ - if len(hex) == 6: - hex += "00" - tmp = int(hex, 16) + if len(hex_) == 6: + hex_ += "FF" + elif len(hex_) == 8: + alpha = (int(hex_, 16) & 0xFF) / 255 + else: + raise ValueError( + "Hex colors must be specified with either 0x or # as prefix and contain 6 or 8 hexadecimal numbers" + ) + tmp = int(hex_, 16) return np.asarray( ( ((tmp >> 24) & 0xFF) / 255, @@ -340,7 +386,7 @@ def _internal_from_rgba(rgba: RGBA_Tuple_Float) -> ManimColorInternal: return np.asarray(rgba, dtype=ManimColorDType) @staticmethod - def _internal_from_string(name: str) -> ManimColorInternal: + def _internal_from_string(name: str, alpha: float) -> ManimColorInternal: """Internal function for converting a string into the internal representation of a ManimColor. This is not used for hex strings, please refer to :meth:`_internal_from_hex` for this functionality. @@ -364,10 +410,9 @@ def _internal_from_string(name: str) -> ManimColorInternal: """ from . import _all_color_dict - upper_name = name.upper() - - if upper_name in _all_color_dict: - return _all_color_dict[upper_name]._internal_value + if tmp := _all_color_dict.get(name.upper()): + tmp._internal_value[3] = alpha + return tmp._internal_value.copy() else: raise ValueError(f"Color {name} not found") @@ -382,9 +427,8 @@ def to_integer(self) -> int: .. warning:: This will return only the rgb part of the color """ - return int.from_bytes( - (self._internal_value[:3] * 255).astype(int).tobytes(), "big" - ) + tmp = (self._internal_value[:3] * 255).astype(dtype=np.byte).tobytes() + return int.from_bytes(tmp, "big") def to_rgb(self) -> RGB_Array_Float: """Converts the current ManimColor into a rgb array of floats @@ -498,9 +542,25 @@ def to_hsv(self) -> HSV_Array_Float: HSV_Array_Float A hsv array containing 3 elements of type float ranging from 0 to 1 """ - return colorsys.rgb_to_hsv(*self.to_rgb()) + return np.array(colorsys.rgb_to_hsv(*self.to_rgb())) + + def to_hsl(self) -> HSL_Array_Float: + """Converts the Manim Color to HSL array. + + .. note:: + Be careful this returns an array in the form `[h, s, l]` where the elements are floats. + This might be confusing because rgb can also be an array of floats so you might want to annotate the usage + of this function in your code by typing the variables with :class:`HSL_Array_Float` in order to differentiate + between rgb arrays and hsl arrays - def invert(self, with_alpha=False) -> ManimColor: + Returns + ------- + HSL_Array_Float + A hsl array containing 3 elements of type float ranging from 0 to 1 + """ + return np.array(colorsys.rgb_to_hls(*self.to_rgb())) + + def invert(self, with_alpha=False) -> Self: """Returns an linearly inverted version of the color (no inplace changes) Parameters @@ -517,9 +577,15 @@ def invert(self, with_alpha=False) -> ManimColor: ManimColor The linearly inverted ManimColor """ - return ManimColor(1.0 - self._internal_value, with_alpha) + if with_alpha: + return self._construct_from_space(1.0 - self._internal_space) + else: + alpha = self._internal_space[3] + new = 1.0 - self._internal_space + new[-1] = alpha + return self._construct_from_space(new) - def interpolate(self, other: ManimColor, alpha: float) -> ManimColor: + def interpolate(self, other: Self, alpha: float) -> Self: """Interpolates between the current and the given ManimColor an returns the interpolated color Parameters @@ -536,10 +602,145 @@ def interpolate(self, other: ManimColor, alpha: float) -> ManimColor: ManimColor The interpolated ManimColor """ - return ManimColor( - self._internal_value * (1 - alpha) + other._internal_value * alpha + return self._construct_from_space( + self._internal_space * (1 - alpha) + other._internal_space * alpha ) + def darker(self, blend: float = 0.2) -> Self: + """Returns a new color that is darker than the current color, i.e. + interpolated with black. The opacity is unchanged. + + Parameters + ---------- + blend : float, optional + The blend ratio for the interpolation, from 0 (the current color + unchanged) to 1 (pure black). By default 0.2 which results in a + slightly darker color + + Returns + ------- + ManimColor + The darker ManimColor + + See Also + -------- + :meth:`lighter` + """ + from manim.utils.color.manim_colors import BLACK + + alpha = self._internal_space[3] + black = self._from_internal(BLACK._internal_value) + return self.interpolate(black, blend).opacity(alpha) + + def lighter(self, blend: float = 0.2) -> Self: + """Returns a new color that is lighter than the current color, i.e. + interpolated with white. The opacity is unchanged. + + Parameters + ---------- + blend : float, optional + The blend ratio for the interpolation, from 0 (the current color + unchanged) to 1 (pure white). By default 0.2 which results in a + slightly lighter color + + Returns + ------- + ManimColor + The lighter ManimColor + + See Also + -------- + :meth:`darker` + """ + from manim.utils.color.manim_colors import WHITE + + alpha = self._internal_space[3] + white = self._from_internal(WHITE._internal_value) + return self.interpolate(white, blend).opacity(alpha) + + def contrasting( + self, + threshold: float = 0.5, + light: Self | None = None, + dark: Self | None = None, + ) -> Self: + """Returns one of two colors, light or dark (by default white or black), + that contrasts with the current color (depending on its luminance). + This is typically used to set text in a contrasting color that ensures + it is readable against a background of the current color. + + Parameters + ---------- + threshold : float, optional + The luminance threshold that dictates whether the current color is + considered light or dark (and thus whether to return the dark or + light color, respectively), by default 0.5 + light : ManimColor, optional + The light color to return if the current color is considered dark, + by default pure white + dark : ManimColor, optional + The dark color to return if the current color is considered light, + by default pure black + + Returns + ------- + ManimColor + The contrasting ManimColor + """ + from manim.utils.color.manim_colors import BLACK, WHITE + + luminance, _, _ = colorsys.rgb_to_yiq(*self.to_rgb()) + if luminance < threshold: + if light is not None: + return light + return self._from_internal(WHITE._internal_value) + else: + if dark is not None: + return dark + return self._from_internal(BLACK._internal_value) + + def opacity(self, opacity: float) -> Self: + """Creates a new ManimColor with the given opacity and the same color value as before + + Parameters + ---------- + opacity : float + The new opacity value to be used + + Returns + ------- + ManimColor + The new ManimColor with the same color value but the new opacity + """ + tmp = self._internal_space.copy() + tmp[-1] = opacity + return self._construct_from_space(tmp) + + def into(self, classtype: type[ManimColorT]) -> ManimColorT: + """Converts the current color into a different colorspace that is given without changing the _internal_value + + Parameters + ---------- + classtype : type[ManimColorT] + The class that is used for conversion, it must be a subclass of ManimColor which respects the specification + HSV, RGBA, ... + + Returns + ------- + ManimColorT + Color object of the type passed into classtype with the same internal value as previously + """ + return classtype._from_internal(self._internal_value) + + @classmethod + def _from_internal(cls, value: ManimColorInternal) -> Self: + """This function is intended to be overwritten by custom color space classes which are subtypes of ManimColor. + + The function constructs a new object of the given class by transforming the value in the internal format ``[r,g,b,a]`` + into a format which the constructor of the custom class can understand. Look at :class:`.HSV` for an example. + """ + return cls(value) + @classmethod def from_rgb( cls, @@ -565,7 +766,7 @@ def from_rgb( ManimColor Returns the ManimColor object """ - return cls(rgb, alpha) + return cls._from_internal(ManimColor(rgb, alpha)._internal_value) @classmethod def from_rgba( @@ -590,12 +791,12 @@ def from_rgba( return cls(rgba) @classmethod - def from_hex(cls, hex: str, alpha: float = 1.0) -> Self: + def from_hex(cls, hex_str: str, alpha: float = 1.0) -> Self: """Creates a Manim Color from a hex string, prefixes allowed # and 0x Parameters ---------- - hex : str + hex_str : str The hex string to be converted (currently only supports 6 nibbles) alpha : float, optional alpha value to be used for the hex string, by default 1.0 @@ -605,7 +806,7 @@ def from_hex(cls, hex: str, alpha: float = 1.0) -> Self: ManimColor The ManimColor represented by the hex string """ - return cls(hex, alpha) + return cls._from_internal(ManimColor(hex_str, alpha)._internal_value) @classmethod def from_hsv( @@ -626,7 +827,28 @@ def from_hsv( The ManimColor with the corresponding RGB values to the HSV """ rgb = colorsys.hsv_to_rgb(*hsv) - return cls(rgb, alpha) + return cls._from_internal(ManimColor(rgb, alpha)._internal_value) + + @classmethod + def from_hsl( + cls, hsl: HSL_Array_Float | HSL_Tuple_Float, alpha: float = 1.0 + ) -> Self: + """Creates a ManimColor from an HSL Array + + Parameters + ---------- + hsl : HSL_Array_Float | HSL_Tuple_Float + Any 3 Element Iterable containing floats from 0-1 + alpha : float, optional + the alpha value to be used, by default 1.0 + + Returns + ------- + ManimColor + The ManimColor with the corresponding RGB values to the HSL + """ + rgb = colorsys.hls_to_rgb(*hsl) + return cls._from_internal(ManimColor(rgb, alpha)._internal_value) @overload @classmethod @@ -647,7 +869,7 @@ def parse( @classmethod def parse( cls, - color: ParsableManimColor | list[ParsableManimColor] | None, + color: ParsableManimColor | Sequence[ParsableManimColor] | None, alpha: float = 1.0, ) -> Self | list[Self]: """ @@ -665,9 +887,19 @@ def parse( ManimColor Either a list of colors or a singular color depending on the input """ - if isinstance(color, (list, tuple)): - return [cls(c, alpha) for c in color] # type: ignore - return cls(color, alpha) # type: ignore + + def is_sequence(colors) -> TypeGuard[Sequence[ParsableManimColor]]: + return isinstance(colors, (list, tuple)) + + def is_parsable(color) -> TypeGuard[ParsableManimColor]: + return not isinstance(color, (list, tuple)) + + if is_sequence(color): + return [ + cls._from_internal(ManimColor(c, alpha)._internal_value) for c in color + ] + elif is_parsable(color): + return cls._from_internal(ManimColor(color, alpha)._internal_value) @staticmethod def gradient(colors: list[ManimColor], length: int): @@ -688,35 +920,225 @@ def __eq__(self, other: object) -> bool: ) return np.allclose(self._internal_value, other._internal_value) - def __add__(self, other: ManimColor) -> ManimColor: - return ManimColor(self._internal_value + other._internal_value) + def __add__(self, other: int | float | Self) -> Self: + if isinstance(other, (int, float)): + return self._construct_from_space(self._internal_space + other) + else: + return self._construct_from_space( + self._internal_space + other._internal_space + ) - def __sub__(self, other: ManimColor) -> ManimColor: - return ManimColor(self._internal_value - other._internal_value) + def __radd__(self, other: int | float | Self) -> Self: + return self + other - def __mul__(self, other: ManimColor) -> ManimColor: - return ManimColor(self._internal_value * other._internal_value) + def __sub__(self, other: int | float | Self) -> Self: + if isinstance(other, (int, float)): + return self._construct_from_space(self._internal_space - other) + else: + return self._construct_from_space( + self._internal_space - other._internal_space + ) - def __truediv__(self, other: ManimColor) -> ManimColor: - return ManimColor(self._internal_value / other._internal_value) + def __rsub__(self, other: int | float | Self) -> Self: + return self - other - def __floordiv__(self, other: ManimColor) -> ManimColor: - return ManimColor(self._internal_value // other._internal_value) + def __mul__(self, other: int | float | Self) -> Self: + if isinstance(other, (int, float)): + return self._construct_from_space(self._internal_space * other) + else: + return self._construct_from_space( + self._internal_space * other._internal_space + ) - def __mod__(self, other: ManimColor) -> ManimColor: - return ManimColor(self._internal_value % other._internal_value) + def __rmul__(self, other: int | float | Self) -> Self: + return self * other - def __pow__(self, other: ManimColor) -> ManimColor: - return ManimColor(self._internal_value**other._internal_value) + def __truediv__(self, other: int | float | Self) -> Self: + if isinstance(other, (int, float)): + return self._construct_from_space(self._internal_space / other) + else: + return self._construct_from_space( + self._internal_space / other._internal_space + ) + + def __rtruediv__(self, other: int | float | Self) -> Self: + return self / other + + def __floordiv__(self, other: int | float | Self) -> Self: + if isinstance(other, (int, float)): + return self._construct_from_space(self._internal_space // other) + else: + return self._construct_from_space( + self._internal_space // other._internal_space + ) - def __and__(self, other: ManimColor) -> ManimColor: - return ManimColor(self.to_integer() & other.to_integer()) + def __rfloordiv__(self, other: int | float | Self) -> Self: + return self // other - def __or__(self, other: ManimColor) -> ManimColor: - return ManimColor(self.to_integer() | other.to_integer()) + def __mod__(self, other: int | float | Self) -> Self: + if isinstance(other, (int, float)): + return self._construct_from_space(self._internal_space % other) + else: + return self._construct_from_space( + self._internal_space % other._internal_space + ) + + def __rmod__(self, other: int | float | Self) -> Self: + return self % other + + def __pow__(self, other: int | float | Self) -> Self: + if isinstance(other, (int, float)): + return self._construct_from_space(self._internal_space**other) + else: + return self._construct_from_space( + self._internal_space**other._internal_space + ) + + def __rpow__(self, other: int | float | Self) -> Self: + return self**other + + def __invert__(self) -> Self: + return self.invert() + + def __int__(self) -> int: + return self.to_integer() + + def __getitem__(self, index: int) -> float: + return self._internal_space[index] + + def __and__(self, other: Self) -> Self: + return self._construct_from_space( + self._internal_from_integer(self.to_integer() & int(other), 1.0) + ) + + def __or__(self, other: Self) -> Self: + return self._construct_from_space( + self._internal_from_integer(self.to_integer() | int(other), 1.0) + ) + + def __xor__(self, other: Self) -> Self: + return self._construct_from_space( + self._internal_from_integer(self.to_integer() ^ int(other), 1.0) + ) + + +RGBA = ManimColor +"""RGBA Color Space""" + + +class HSV(ManimColor): + """HSV Color Space""" + + def __init__( + self, + hsv: HSV_Array_Float | HSV_Tuple_Float | HSVA_Array_Float | HSVA_Tuple_Float, + alpha: float = 1.0, + ) -> None: + super().__init__(None) + if len(hsv) == 3: + self.__hsv: HSVA_Array_Float = np.asarray((*hsv, alpha)) + elif len(hsv) == 4: + self.__hsv: HSVA_Array_Float = np.asarray(hsv) + else: + raise ValueError("HSV Color must be an array of 3 values") + + @classmethod + @override + def _from_internal(cls, value: ManimColorInternal) -> Self: + hsv = colorsys.rgb_to_hsv(*value[:3]) + hsva = [*hsv, value[-1]] + return cls(np.array(hsva)) + + @property + def hue(self) -> float: + return self.__hsv[0] - def __xor__(self, other: ManimColor) -> ManimColor: - return ManimColor(self.to_integer() ^ other.to_integer()) + @property + def saturation(self) -> float: + return self.__hsv[1] + + @property + def value(self) -> float: + return self.__hsv[2] + + @hue.setter + def hue(self, value: float) -> None: + self.__hsv[0] = value + + @saturation.setter + def saturation(self, value: float) -> None: + self.__hsv[1] = value + + @value.setter + def value(self, value: float) -> None: + self.__hsv[2] = value + + @property + def h(self) -> float: + return self.__hsv[0] + + @property + def s(self) -> float: + return self.__hsv[1] + + @property + def v(self) -> float: + return self.__hsv[2] + + @h.setter + def h(self, value: float) -> None: + self.__hsv[0] = value + + @s.setter + def s(self, value: float) -> None: + self.__hsv[1] = value + + @v.setter + def v(self, value: float) -> None: + self.__hsv[2] = value + + @property + def _internal_space(self) -> npt.NDArray: + return self.__hsv + + @property + def _internal_value(self) -> ManimColorInternal: + """Returns the internal value of the current Manim color [r,g,b,a] float array + + Returns + ------- + ManimColorInternal + internal color representation + """ + return np.array( + [ + *colorsys.hsv_to_rgb(self.__hsv[0], self.__hsv[1], self.__hsv[2]), + self.__alpha, + ], + dtype=ManimColorDType, + ) + + @_internal_value.setter + def _internal_value(self, value: ManimColorInternal) -> None: + """Overwrites the internal color value of the ManimColor object + + Parameters + ---------- + value : ManimColorInternal + The value which will overwrite the current color + + Raises + ------ + TypeError + Raises a TypeError if an invalid array is passed + """ + if not isinstance(value, np.ndarray): + raise TypeError("value must be a numpy array") + if value.shape[0] != 4: + raise TypeError("Array must have 4 values exactly") + tmp = colorsys.rgb_to_hsv(value[0], value[1], value[2]) + self.__hsv = np.array(tmp) + self.__alpha = value[3] ParsableManimColor: TypeAlias = Union[ @@ -953,7 +1375,7 @@ def color_gradient( def interpolate_color( - color1: ManimColorT, color2: ManimColor, alpha: float + color1: ManimColorT, color2: ManimColorT, alpha: float ) -> ManimColorT: """Standalone function to interpolate two ManimColors and get the result refer to :meth:`interpolate` in :class:`ManimColor` @@ -1053,4 +1475,6 @@ def get_shaded_rgb( "random_bright_color", "random_color", "get_shaded_rgb", + "HSV", + "RGBA", ] diff --git a/manim/utils/color/manim_colors.py b/manim/utils/color/manim_colors.py index a3eacc83a4..44c7a8c0c4 100644 --- a/manim/utils/color/manim_colors.py +++ b/manim/utils/color/manim_colors.py @@ -46,21 +46,22 @@ def subnames(name): for line, char in zip(color_groups[0], "abcde"): color_groups.add(Text(char).scale(0.6).next_to(line, LEFT, buff=0.2)) - def named_lines_group(length, colors, names, text_colors, align_to_block): + def named_lines_group(length, color_names, labels, align_to_block): + colors = [getattr(Colors, color.upper()) for color in color_names] lines = VGroup( *[ Line( ORIGIN, RIGHT * length, stroke_width=55, - color=getattr(Colors, color.upper()), + color=color, ) for color in colors ] ).arrange_submobjects(buff=0.6, direction=DOWN) - for line, name, color in zip(lines, names, text_colors): - line.add(Text(name, color=color).scale(0.6).move_to(line)) + for line, name, color in zip(lines, labels, colors): + line.add(Text(name, color=color.contrasting()).scale(0.6).move_to(line)) lines.next_to(color_groups, DOWN, buff=0.5).align_to( color_groups[align_to_block], LEFT ) @@ -79,7 +80,6 @@ def named_lines_group(length, colors, names, text_colors, align_to_block): 3.2, other_colors, other_colors, - [BLACK] * 4 + [WHITE] * 2, 0, ) @@ -95,7 +95,6 @@ def named_lines_group(length, colors, names, text_colors, align_to_block): "darker_gray / gray_e", "black", ], - [BLACK] * 3 + [WHITE] * 4, 2, ) @@ -109,7 +108,6 @@ def named_lines_group(length, colors, names, text_colors, align_to_block): 3.2, pure_colors, pure_colors, - [BLACK, BLACK, WHITE], 6, ) diff --git a/manim/utils/debug.py b/manim/utils/debug.py index d161948147..a2c56a69d9 100644 --- a/manim/utils/debug.py +++ b/manim/utils/debug.py @@ -67,7 +67,6 @@ def construct(self): self.add(text, indices) """ - labels = VGroup() for n, submob in enumerate(mobject): label = Integer(n, **kwargs) diff --git a/manim/utils/deprecation.py b/manim/utils/deprecation.py index 2d443c5e72..afa9cb41a2 100644 --- a/manim/utils/deprecation.py +++ b/manim/utils/deprecation.py @@ -6,16 +6,17 @@ import inspect +import logging import re from collections.abc import Iterable from typing import Any, Callable from decorator import decorate, decorator -from .. import logger +logger = logging.getLogger("manim") -def _get_callable_info(callable: Callable) -> tuple[str, str]: +def _get_callable_info(callable_: Callable, /) -> tuple[str, str]: """Returns type and name of a callable. Parameters @@ -29,8 +30,8 @@ def _get_callable_info(callable: Callable) -> tuple[str, str]: The type and name of the callable. Type can can be one of "class", "method" (for functions defined in classes) or "function"). For methods, name is Class.method. """ - what = type(callable).__name__ - name = callable.__qualname__ + what = type(callable_).__name__ + name = callable_.__qualname__ if what == "function" and "." in name: what = "method" elif what != "function": diff --git a/manim/utils/docbuild/autoaliasattr_directive.py b/manim/utils/docbuild/autoaliasattr_directive.py index ba42bd1ec4..76ef5a0a18 100644 --- a/manim/utils/docbuild/autoaliasattr_directive.py +++ b/manim/utils/docbuild/autoaliasattr_directive.py @@ -21,7 +21,7 @@ alias_name for module_dict in ALIAS_DOCS_DICT.values() for category_dict in module_dict.values() - for alias_name in category_dict.keys() + for alias_name in category_dict ] @@ -44,7 +44,6 @@ def smart_replace(base: str, alias: str, substitution: str) -> str: str The new string after the alias substitution. """ - occurrences = [] len_alias = len(alias) len_base = len(base) diff --git a/manim/utils/docbuild/autocolor_directive.py b/manim/utils/docbuild/autocolor_directive.py index 574aaedf77..3a699f54d4 100644 --- a/manim/utils/docbuild/autocolor_directive.py +++ b/manim/utils/docbuild/autocolor_directive.py @@ -69,10 +69,7 @@ def run(self) -> list[nodes.Element]: luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b # Choose the font color based on the background luminance - if luminance > 0.5: - font_color = "black" - else: - font_color = "white" + font_color = "black" if luminance > 0.5 else "white" color_elements.append((member_name, member_obj.to_hex(), font_color)) diff --git a/manim/utils/docbuild/manim_directive.py b/manim/utils/docbuild/manim_directive.py index cd277970e3..4576be81dd 100644 --- a/manim/utils/docbuild/manim_directive.py +++ b/manim/utils/docbuild/manim_directive.py @@ -92,7 +92,7 @@ def construct(self): import jinja2 from docutils import nodes -from docutils.parsers.rst import Directive, directives # type: ignore +from docutils.parsers.rst import Directive, directives from docutils.statemachine import StringList from manim import QUALITIES @@ -225,11 +225,7 @@ def run(self) -> list[nodes.Element]: + self.options.get("ref_functions", []) + self.options.get("ref_methods", []) ) - if ref_content: - ref_block = "References: " + " ".join(ref_content) - - else: - ref_block = "" + ref_block = "References: " + " ".join(ref_content) if ref_content else "" if "quality" in self.options: quality = f'{self.options["quality"]}_quality' diff --git a/manim/utils/docbuild/module_parsing.py b/manim/utils/docbuild/module_parsing.py index 57ac9a56aa..24e44be215 100644 --- a/manim/utils/docbuild/module_parsing.py +++ b/manim/utils/docbuild/module_parsing.py @@ -3,6 +3,7 @@ from __future__ import annotations import ast +import sys from pathlib import Path from typing_extensions import TypeAlias @@ -158,27 +159,35 @@ def parse_module_attributes() -> tuple[AliasDocsDict, DataDict, TypeVarDict]: inner_nodes = [node] for node in inner_nodes: - # If we encounter an assignment annotated as "TypeAlias": - if ( + # Check if this node is a TypeAlias (type = ) + # or an AnnAssign annotated as TypeAlias (: TypeAlias = ). + is_type_alias = ( + sys.version_info >= (3, 12) and type(node) is ast.TypeAlias + ) + is_annotated_assignment_with_value = ( type(node) is ast.AnnAssign and type(node.annotation) is ast.Name and node.annotation.id == "TypeAlias" and type(node.target) is ast.Name and node.value is not None - ): - alias_name = node.target.id - def_node = node.value - # If it's an Union, replace it with vertical bar notation + ) + if is_type_alias or is_annotated_assignment_with_value: + alias_name = node.name.id if is_type_alias else node.target.id + definition_node = node.value + + # If the definition is a Union, replace with vertical bar notation. + # Instead of "Union[Type1, Type2]", we'll have "Type1 | Type2". if ( - type(def_node) is ast.Subscript - and type(def_node.value) is ast.Name - and def_node.value.id == "Union" + type(definition_node) is ast.Subscript + and type(definition_node.value) is ast.Name + and definition_node.value.id == "Union" ): + union_elements = definition_node.slice.elts definition = " | ".join( - ast.unparse(elem) for elem in def_node.slice.elts + ast.unparse(elem) for elem in union_elements ) else: - definition = ast.unparse(def_node) + definition = ast.unparse(definition_node) definition = definition.replace("npt.", "") if category_dict is None: @@ -188,7 +197,7 @@ def parse_module_attributes() -> tuple[AliasDocsDict, DataDict, TypeVarDict]: alias_info = category_dict[alias_name] continue - # Check if it is a typing.TypeVar + # Check if it is a typing.TypeVar ( = TypeVar(...)). elif ( type(node) is ast.Assign and type(node.targets[0]) is ast.Name diff --git a/manim/utils/file_ops.py b/manim/utils/file_ops.py index 7efcee02c5..e4fbdebfe5 100644 --- a/manim/utils/file_ops.py +++ b/manim/utils/file_ops.py @@ -28,6 +28,8 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: + from manim.typing import StrPath + from ..scene.scene_file_writer import SceneFileWriter from manim import __version__, config, logger @@ -159,7 +161,7 @@ def guarantee_empty_existence(path: Path) -> Path: def seek_full_path_from_defaults( - file_name: str, default_dir: Path, extensions: list[str] + file_name: StrPath, default_dir: Path, extensions: list[str] ) -> Path: possible_paths = [Path(file_name).expanduser()] possible_paths += [ @@ -186,7 +188,7 @@ def modify_atime(file_path: str) -> None: os.utime(file_path, times=(time.time(), Path(file_path).stat().st_mtime)) -def open_file(file_path, in_browser=False): +def open_file(file_path: Path, in_browser: bool = False) -> None: current_os = platform.system() if current_os == "Windows": os.startfile(file_path if not in_browser else file_path.parent) @@ -249,7 +251,7 @@ def get_template_path() -> Path: return Path.resolve(Path(__file__).parent.parent / "templates") -def add_import_statement(file: Path): +def add_import_statement(file: Path) -> None: """Prepends an import statement in a file Parameters diff --git a/manim/utils/hashing.py b/manim/utils/hashing.py index 9557ba18f1..92b5191503 100644 --- a/manim/utils/hashing.py +++ b/manim/utils/hashing.py @@ -223,7 +223,7 @@ def default(self, obj: Any): # We return the repr and not a list to avoid the JsonEncoder to iterate over it. return repr(obj) elif hasattr(obj, "__dict__"): - temp = getattr(obj, "__dict__") + temp = obj.__dict__ # MappingProxy is scene-caching nightmare. It contains all of the object methods and attributes. We skip it as the mechanism will at some point process the object, but instantiated. # Indeed, there is certainly no case where scene-caching will receive only a non instancied object, as this is never used in the library or encouraged to be used user-side. if isinstance(temp, MappingProxyType): diff --git a/manim/utils/images.py b/manim/utils/images.py index 1ce3dd8c28..7e0accf4ca 100644 --- a/manim/utils/images.py +++ b/manim/utils/images.py @@ -9,7 +9,8 @@ "change_to_rgba_array", ] -from pathlib import Path +from pathlib import Path, PurePath +from typing import TYPE_CHECKING import numpy as np from PIL import Image @@ -17,8 +18,11 @@ from .. import config from ..utils.file_ops import seek_full_path_from_defaults +if TYPE_CHECKING: + import numpy.typing as npt -def get_full_raster_image_path(image_file_name: str) -> Path: + +def get_full_raster_image_path(image_file_name: str | PurePath) -> Path: return seek_full_path_from_defaults( image_file_name, default_dir=config.get_dir("assets_dir"), @@ -26,7 +30,7 @@ def get_full_raster_image_path(image_file_name: str) -> Path: ) -def get_full_vector_image_path(image_file_name: str) -> Path: +def get_full_vector_image_path(image_file_name: str | PurePath) -> Path: return seek_full_path_from_defaults( image_file_name, default_dir=config.get_dir("assets_dir"), @@ -49,7 +53,7 @@ def invert_image(image: np.array) -> Image: return Image.fromarray(arr) -def change_to_rgba_array(image, dtype="uint8"): +def change_to_rgba_array(image: npt.NDArray, dtype="uint8") -> npt.NDArray: """Converts an RGB array into RGBA with the alpha value opacity maxed.""" pa = image if len(pa.shape) == 2: diff --git a/manim/utils/ipython_magic.py b/manim/utils/ipython_magic.py index 601d4d6f8e..1b6c7b316e 100644 --- a/manim/utils/ipython_magic.py +++ b/manim/utils/ipython_magic.py @@ -168,7 +168,7 @@ def construct(self): file_type = mimetypes.guess_type(config["output_file"])[0] embed = config["media_embed"] - if embed is None: + if not embed: # videos need to be embedded when running in google colab. # do this automatically in case config.media_embed has not been # set explicitly. diff --git a/manim/utils/iterables.py b/manim/utils/iterables.py index cf6f664f98..678750deb2 100644 --- a/manim/utils/iterables.py +++ b/manim/utils/iterables.py @@ -33,7 +33,7 @@ T = TypeVar("T") U = TypeVar("U") -F = TypeVar("F", np.float_, np.int_) +F = TypeVar("F", np.float64, np.int_) H = TypeVar("H", bound=Hashable) @@ -311,8 +311,8 @@ def resize_array(nparray: npt.NDArray[F], length: int) -> npt.NDArray[F]: def resize_preserving_order( - nparray: npt.NDArray[np.float_], length: int -) -> npt.NDArray[np.float_]: + nparray: npt.NDArray[np.float64], length: int +) -> npt.NDArray[np.float64]: """Extends/truncates nparray so that ``len(result) == length``. The elements of nparray are duplicated to achieve the desired length (favours earlier elements). diff --git a/manim/utils/opengl.py b/manim/utils/opengl.py index f9844f1b33..d48817b76e 100644 --- a/manim/utils/opengl.py +++ b/manim/utils/opengl.py @@ -31,7 +31,7 @@ def orthographic_projection_matrix( height=None, near=1, far=depth + 1, - format=True, + format_=True, ): if width is None: width = config["frame_width"] @@ -45,13 +45,15 @@ def orthographic_projection_matrix( [0, 0, 0, 1], ], ) - if format: + if format_: return matrix_to_shader_input(projection_matrix) else: return projection_matrix -def perspective_projection_matrix(width=None, height=None, near=2, far=50, format=True): +def perspective_projection_matrix( + width=None, height=None, near=2, far=50, format_=True +): if width is None: width = config["frame_width"] / 6 if height is None: diff --git a/manim/utils/polylabel.py b/manim/utils/polylabel.py new file mode 100644 index 0000000000..e7739b8dc1 --- /dev/null +++ b/manim/utils/polylabel.py @@ -0,0 +1,156 @@ +#!/usr/bin/env python +from __future__ import annotations + +from queue import PriorityQueue +from typing import TYPE_CHECKING + +import numpy as np + +if TYPE_CHECKING: + from collections.abc import Sequence + + from manim.typing import Point3D, Point3D_Array + + +class Polygon: + """ + Initializes the Polygon with the given rings. + + Parameters + ---------- + rings + A collection of closed polygonal ring. + """ + + def __init__(self, rings: Sequence[Point3D_Array]) -> None: + # Flatten Array + csum = np.cumsum([ring.shape[0] for ring in rings]) + self.array = np.concatenate(rings, axis=0) + + # Compute Boundary + self.start = np.delete(self.array, csum - 1, axis=0) + self.stop = np.delete(self.array, csum % csum[-1], axis=0) + self.diff = np.delete(np.diff(self.array, axis=0), csum[:-1] - 1, axis=0) + self.norm = self.diff / np.einsum("ij,ij->i", self.diff, self.diff).reshape( + -1, 1 + ) + + # Compute Centroid + x, y = self.start[:, 0], self.start[:, 1] + xr, yr = self.stop[:, 0], self.stop[:, 1] + self.area = 0.5 * (np.dot(x, yr) - np.dot(xr, y)) + if self.area: + factor = x * yr - xr * y + cx = np.sum((x + xr) * factor) / (6.0 * self.area) + cy = np.sum((y + yr) * factor) / (6.0 * self.area) + self.centroid = np.array([cx, cy]) + + def compute_distance(self, point: Point3D) -> float: + """Compute the minimum distance from a point to the polygon.""" + scalars = np.einsum("ij,ij->i", self.norm, point - self.start) + clips = np.clip(scalars, 0, 1).reshape(-1, 1) + d = np.min(np.linalg.norm(self.start + self.diff * clips - point, axis=1)) + return d if self.inside(point) else -d + + def inside(self, point: Point3D) -> bool: + """Check if a point is inside the polygon.""" + # Views + px, py = point + x, y = self.start[:, 0], self.start[:, 1] + xr, yr = self.stop[:, 0], self.stop[:, 1] + + # Count Crossings (enforce short-circuit) + c = (y > py) != (yr > py) + c = px < x[c] + (py - y[c]) * (xr[c] - x[c]) / (yr[c] - y[c]) + return np.sum(c) % 2 == 1 + + +class Cell: + """ + A square in a mesh covering the :class:`~.Polygon` passed as an argument. + + Parameters + ---------- + c + Center coordinates of the Cell. + h + Half-Size of the Cell. + polygon + :class:`~.Polygon` object for which the distance is computed. + """ + + def __init__(self, c: Point3D, h: float, polygon: Polygon) -> None: + self.c = c + self.h = h + self.d = polygon.compute_distance(self.c) + self.p = self.d + self.h * np.sqrt(2) + + def __lt__(self, other: Cell) -> bool: + return self.d < other.d + + def __gt__(self, other: Cell) -> bool: + return self.d > other.d + + def __le__(self, other: Cell) -> bool: + return self.d <= other.d + + def __ge__(self, other: Cell) -> bool: + return self.d >= other.d + + +def polylabel(rings: Sequence[Point3D_Array], precision: float = 0.01) -> Cell: + """ + Finds the pole of inaccessibility (the point that is farthest from the edges of the polygon) + using an iterative grid-based approach. + + Parameters + ---------- + rings + A list of lists, where each list is a sequence of points representing the rings of the polygon. + Typically, multiple rings indicate holes in the polygon. + precision + The precision of the result (default is 0.01). + + Returns + ------- + Cell + A Cell containing the pole of inaccessibility to a given precision. + """ + # Precompute Polygon Data + array = [np.array(ring)[:, :2] for ring in rings] + polygon = Polygon(array) + + # Bounding Box + mins = np.min(polygon.array, axis=0) + maxs = np.max(polygon.array, axis=0) + dims = maxs - mins + s = np.min(dims) + h = s / 2.0 + + # Initial Grid + queue = PriorityQueue() + xv, yv = np.meshgrid(np.arange(mins[0], maxs[0], s), np.arange(mins[1], maxs[1], s)) + for corner in np.vstack([xv.ravel(), yv.ravel()]).T: + queue.put(Cell(corner + h, h, polygon)) + + # Initial Guess + best = Cell(polygon.centroid, 0, polygon) + bbox = Cell(mins + (dims / 2), 0, polygon) + if bbox.d > best.d: + best = bbox + + # While there are cells to consider... + directions = np.array([[-1, -1], [1, -1], [-1, 1], [1, 1]]) + while not queue.empty(): + cell = queue.get() + if cell > best: + best = cell + # If a cell is promising, subdivide! + if cell.p - best.d > precision: + h = cell.h / 2.0 + offsets = cell.c + directions * h + queue.put(Cell(offsets[0], h, polygon)) + queue.put(Cell(offsets[1], h, polygon)) + queue.put(Cell(offsets[2], h, polygon)) + queue.put(Cell(offsets[3], h, polygon)) + return best diff --git a/manim/utils/qhull.py b/manim/utils/qhull.py new file mode 100644 index 0000000000..215f114b59 --- /dev/null +++ b/manim/utils/qhull.py @@ -0,0 +1,196 @@ +#!/usr/bin/env python +from __future__ import annotations + +from typing import TYPE_CHECKING + +import numpy as np + +if TYPE_CHECKING: + from manim.typing import PointND, PointND_Array + + +class QuickHullPoint: + def __init__(self, coordinates: PointND_Array) -> None: + self.coordinates = coordinates + + def __hash__(self) -> int: + return hash(self.coordinates.tobytes()) + + def __eq__(self, other: QuickHullPoint) -> bool: + return np.array_equal(self.coordinates, other.coordinates) + + +class SubFacet: + def __init__(self, coordinates: PointND_Array) -> None: + self.coordinates = coordinates + self.points = frozenset(QuickHullPoint(c) for c in coordinates) + + def __hash__(self) -> int: + return hash(self.points) + + def __eq__(self, other: SubFacet) -> bool: + return self.points == other.points + + +class Facet: + def __init__(self, coordinates: PointND_Array, internal: PointND) -> None: + self.coordinates = coordinates + self.center = np.mean(coordinates, axis=0) + self.normal = self.compute_normal(internal) + self.subfacets = frozenset( + SubFacet(np.delete(self.coordinates, i, axis=0)) + for i in range(self.coordinates.shape[0]) + ) + + def compute_normal(self, internal: PointND) -> PointND: + centered = self.coordinates - self.center + _, _, vh = np.linalg.svd(centered) + normal = vh[-1, :] + normal /= np.linalg.norm(normal) + + # If the normal points towards the internal point, flip it! + if np.dot(normal, self.center - internal) < 0: + normal *= -1 + + return normal + + def __hash__(self) -> int: + return hash(self.subfacets) + + def __eq__(self, other: Facet) -> bool: + return self.subfacets == other.subfacets + + +class Horizon: + def __init__(self) -> None: + self.facets: set[Facet] = set() + self.boundary: list[SubFacet] = [] + + +class QuickHull: + """ + QuickHull algorithm for constructing a convex hull from a set of points. + + Parameters + ---------- + tolerance + A tolerance threshold for determining when points lie on the convex hull (default is 1e-5). + + Attributes + ---------- + facets + List of facets considered. + removed + Set of internal facets that have been removed from the hull during the construction process. + outside + Dictionary mapping each facet to its outside points and eye point. + neighbors + Mapping of subfacets to their neighboring facets. Each subfacet links precisely two neighbors. + unclaimed + Points that have not yet been classified as inside or outside the current hull. + internal + An internal point (i.e., the center of the initial simplex) used as a reference during hull construction. + tolerance + The tolerance used to determine if points are considered outside the current hull. + """ + + def __init__(self, tolerance: float = 1e-5) -> None: + self.facets: list[Facet] = [] + self.removed: set[Facet] = set() + self.outside: dict[Facet, tuple[PointND_Array, PointND | None]] = {} + self.neighbors: dict[SubFacet, set[Facet]] = {} + self.unclaimed: PointND_Array | None = None + self.internal: PointND | None = None + self.tolerance = tolerance + + def initialize(self, points: PointND_Array) -> None: + # Sample Points + simplex = points[ + np.random.choice(points.shape[0], points.shape[1] + 1, replace=False) + ] + self.unclaimed = points + self.internal = np.mean(simplex, axis=0) + + # Build Simplex + for c in range(simplex.shape[0]): + facet = Facet(np.delete(simplex, c, axis=0), internal=self.internal) + self.classify(facet) + self.facets.append(facet) + + # Attach Neighbors + for f in self.facets: + for sf in f.subfacets: + self.neighbors.setdefault(sf, set()).add(f) + + def classify(self, facet: Facet) -> None: + if not self.unclaimed.size: + self.outside[facet] = (None, None) + return + + # Compute Projections + projections = (self.unclaimed - facet.center) @ facet.normal + arg = np.argmax(projections) + mask = projections > self.tolerance + + # Identify Eye and Outside Set + eye = self.unclaimed[arg] if projections[arg] > self.tolerance else None + outside = self.unclaimed[mask] + self.outside[facet] = (outside, eye) + self.unclaimed = self.unclaimed[~mask] + + def compute_horizon(self, eye: PointND, start_facet: Facet) -> Horizon: + horizon = Horizon() + self._recursive_horizon(eye, start_facet, horizon) + return horizon + + def _recursive_horizon(self, eye: PointND, facet: Facet, horizon: Horizon) -> int: + visible = np.dot(facet.normal, eye - facet.center) > 0 + if not visible: + return False + # If the eye is visible from the facet... + else: + # Label the facet as visible and cross each edge + horizon.facets.add(facet) + for subfacet in facet.subfacets: + neighbor = (self.neighbors[subfacet] - {facet}).pop() + # If the neighbor is not visible, then the edge shared must be on the boundary + if neighbor not in horizon.facets and not self._recursive_horizon( + eye, neighbor, horizon + ): + horizon.boundary.append(subfacet) + return True + + def build(self, points: PointND_Array): + num, dim = points.shape + if (dim == 0) or (num < dim + 1): + raise ValueError("Not enough points supplied to build Convex Hull!") + if dim == 1: + raise ValueError("The Convex Hull of 1D data is its min-max!") + + self.initialize(points) + while True: + updated = False + for facet in self.facets: + if facet in self.removed: + continue + outside, eye = self.outside[facet] + if eye is not None: + updated = True + horizon = self.compute_horizon(eye, facet) + for f in horizon.facets: + self.unclaimed = np.vstack((self.unclaimed, self.outside[f][0])) + self.removed.add(f) + for sf in f.subfacets: + self.neighbors[sf].discard(f) + if self.neighbors[sf] == set(): + del self.neighbors[sf] + for sf in horizon.boundary: + nf = Facet( + np.vstack((sf.coordinates, eye)), internal=self.internal + ) + self.classify(nf) + self.facets.append(nf) + for nsf in nf.subfacets: + self.neighbors.setdefault(nsf, set()).add(nf) + if not updated: + break diff --git a/manim/utils/simple_functions.py b/manim/utils/simple_functions.py index 898c1d527b..10c9a15878 100644 --- a/manim/utils/simple_functions.py +++ b/manim/utils/simple_functions.py @@ -40,10 +40,10 @@ def binary_search( :: >>> solution = binary_search(lambda x: x**2 + 3*x + 1, 11, 0, 5) - >>> abs(solution - 2) < 1e-4 + >>> bool(abs(solution - 2) < 1e-4) True >>> solution = binary_search(lambda x: x**2 + 3*x + 1, 11, 0, 5, tolerance=0.01) - >>> abs(solution - 2) < 0.01 + >>> bool(abs(solution - 2) < 0.01) True Searching in the interval :math:`[0, 5]` for a target value of :math:`71` diff --git a/manim/utils/space_ops.py b/manim/utils/space_ops.py index 197621fce6..19d2989388 100644 --- a/manim/utils/space_ops.py +++ b/manim/utils/space_ops.py @@ -193,7 +193,6 @@ def rotate_vector( ValueError If vector is not of dimension 2 or 3. """ - if len(vector) > 3: raise ValueError("Vector must have the correct dimensions.") if len(vector) == 2: @@ -249,9 +248,7 @@ def rotation_matrix( axis: np.ndarray, homogeneous: bool = False, ) -> np.ndarray: - """ - Rotation in R^3 about a specified axis of rotation. - """ + """Rotation in R^3 about a specified axis of rotation.""" inhomogeneous_rotation_matrix = Rotation.from_rotvec( angle * normalize(np.array(axis)) ).as_matrix() @@ -341,7 +338,6 @@ def angle_between_vectors(v1: np.ndarray, v2: np.ndarray) -> float: float The angle between the vectors. """ - return 2 * np.arctan2( np.linalg.norm(normalize(v1) - normalize(v2)), np.linalg.norm(normalize(v1) + normalize(v2)), @@ -474,12 +470,8 @@ def regular_vertices( start_angle : :class:`float` The angle the vertices start at. """ - if start_angle is None: - if n % 2 == 0: - start_angle = 0 - else: - start_angle = TAU / 4 + start_angle = 0 if n % 2 == 0 else TAU / 4 start_vector = rotate_vector(RIGHT * radius, start_angle) vertices = compass_directions(n, start_vector) @@ -621,11 +613,11 @@ def get_winding_number(points: Sequence[np.ndarray]) -> float: >>> from manim import Square, get_winding_number >>> polygon = Square() >>> get_winding_number(polygon.get_vertices()) - 1.0 + np.float64(1.0) >>> polygon.shift(2 * UP) Square >>> get_winding_number(polygon.get_vertices()) - 0.0 + np.float64(0.0) """ total_angle = 0 for p1, p2 in adjacent_pairs(points): @@ -688,7 +680,7 @@ def cross2d( .. code-block:: pycon >>> cross2d(np.array([1, 2]), np.array([3, 4])) - -2 + np.int64(-2) >>> cross2d( ... np.array([[1, 2, 0], [1, 0, 0]]), ... np.array([[3, 4, 0], [0, 1, 0]]), diff --git a/manim/utils/testing/_frames_testers.py b/manim/utils/testing/_frames_testers.py index be0bc38447..bef6184937 100644 --- a/manim/utils/testing/_frames_testers.py +++ b/manim/utils/testing/_frames_testers.py @@ -1,18 +1,19 @@ from __future__ import annotations import contextlib +import logging import warnings from pathlib import Path import numpy as np -from manim import logger - from ._show_diff import show_diff_helper FRAME_ABSOLUTE_TOLERANCE = 1.01 FRAME_MISMATCH_RATIO_TOLERANCE = 1e-5 +logger = logging.getLogger("manim") + class _FramesTester: def __init__(self, file_path: Path, show_diff=False) -> None: @@ -63,7 +64,8 @@ def check_frame(self, frame_number: int, frame: np.ndarray): warnings.warn( f"Mismatch of {number_of_mismatches} pixel values in frame {frame_number} " f"against control data in {self._file_path}. Below error threshold, " - "continuing..." + "continuing...", + stacklevel=1, ) return diff --git a/manim/utils/testing/_test_class_makers.py b/manim/utils/testing/_test_class_makers.py index ac5886d494..fe127be1c7 100644 --- a/manim/utils/testing/_test_class_makers.py +++ b/manim/utils/testing/_test_class_makers.py @@ -15,7 +15,7 @@ def _make_test_scene_class( ) -> type[Scene]: class _TestedScene(base_scene): def __init__(self, *args, **kwargs): - super().__init__(renderer=test_renderer, *args, **kwargs) + super().__init__(*args, renderer=test_renderer, **kwargs) def construct(self): construct_test(self) diff --git a/manim/utils/testing/frames_comparison.py b/manim/utils/testing/frames_comparison.py index e3814ea696..a298585b29 100644 --- a/manim/utils/testing/frames_comparison.py +++ b/manim/utils/testing/frames_comparison.py @@ -150,7 +150,7 @@ def wrapper(*args, request: FixtureRequest, tmp_path, **kwargs): # Reach a bit into pytest internals to hoist the marks from our wrapped # function. - setattr(wrapper, "pytestmark", []) + wrapper.pytestmark = [] new_marks = getattr(tested_scene_construct, "pytestmark", []) wrapper.pytestmark = new_marks return wrapper @@ -192,7 +192,6 @@ def _make_test_comparing_frames( Callable[[], None] The pytest test. """ - if is_set_test_data_test: frames_tester = _ControlDataWriter(file_path, size_frame=size_frame) else: diff --git a/manim/utils/tex.py b/manim/utils/tex.py index f642abad72..41e19bcd57 100644 --- a/manim/utils/tex.py +++ b/manim/utils/tex.py @@ -181,7 +181,6 @@ def _texcode_for_environment(environment: str) -> tuple[str, str]: A pair of strings representing the opening and closing of the tex environment, e.g. ``\begin{tabular}{cccl}`` and ``\end{tabular}`` """ - environment.removeprefix(r"\begin").removeprefix("{") # The \begin command takes everything and closes with a brace @@ -191,7 +190,7 @@ def _texcode_for_environment(environment: str) -> tuple[str, str]: begin += "}" # While the \end command terminates at the first closing brace - split_at_brace = re.split("}", environment, 1) + split_at_brace = re.split("}", environment, maxsplit=1) end = r"\end{" + split_at_brace[0] + "}" return begin, end diff --git a/manim/utils/tex_file_writing.py b/manim/utils/tex_file_writing.py index b18f81e637..45e84d4907 100644 --- a/manim/utils/tex_file_writing.py +++ b/manim/utils/tex_file_writing.py @@ -9,8 +9,8 @@ from __future__ import annotations import hashlib -import os import re +import subprocess import unicodedata from collections.abc import Iterable from pathlib import Path @@ -35,7 +35,7 @@ def tex_to_svg_file( environment: str | None = None, tex_template: TexTemplate | None = None, ): - """Takes a tex expression and returns the svg version of the compiled tex + r"""Takes a tex expression and returns the svg version of the compiled tex Parameters ---------- @@ -76,7 +76,7 @@ def generate_tex_file( environment: str | None = None, tex_template: TexTemplate | None = None, ) -> Path: - """Takes a tex expression (and an optional tex environment), + r"""Takes a tex expression (and an optional tex environment), and returns a fully formed tex file ready for compilation. Parameters @@ -114,10 +114,11 @@ def generate_tex_file( return result -def tex_compilation_command( +def make_tex_compilation_command( tex_compiler: str, output_format: str, tex_file: Path, tex_dir: Path -) -> str: - """Prepares the tex compilation command with all necessary cli flags +) -> list[str]: + """Prepares the TeX compilation command, i.e. the TeX compiler name + and all necessary CLI flags. Parameters ---------- @@ -132,40 +133,36 @@ def tex_compilation_command( Returns ------- - :class:`str` + :class:`list[str]` Compilation command according to given parameters """ if tex_compiler in {"latex", "pdflatex", "luatex", "lualatex"}: - commands = [ + command = [ tex_compiler, "-interaction=batchmode", - f'-output-format="{output_format[1:]}"', + f"-output-format={output_format[1:]}", "-halt-on-error", - f'-output-directory="{tex_dir.as_posix()}"', - f'"{tex_file.as_posix()}"', - ">", - os.devnull, + f"-output-directory={tex_dir.as_posix()}", + f"{tex_file.as_posix()}", ] elif tex_compiler == "xelatex": if output_format == ".xdv": - outflag = "-no-pdf" + outflag = ["-no-pdf"] elif output_format == ".pdf": - outflag = "" + outflag = [] else: raise ValueError("xelatex output is either pdf or xdv") - commands = [ + command = [ "xelatex", - outflag, + *outflag, "-interaction=batchmode", "-halt-on-error", - f'-output-directory="{tex_dir.as_posix()}"', - f'"{tex_file.as_posix()}"', - ">", - os.devnull, + f"-output-directory={tex_dir.as_posix()}", + f"{tex_file.as_posix()}", ] else: raise ValueError(f"Tex compiler {tex_compiler} unknown.") - return " ".join(commands) + return command def insight_inputenc_error(matching): @@ -200,14 +197,14 @@ def compile_tex(tex_file: Path, tex_compiler: str, output_format: str) -> Path: result = tex_file.with_suffix(output_format) tex_dir = config.get_dir("tex_dir") if not result.exists(): - command = tex_compilation_command( + command = make_tex_compilation_command( tex_compiler, output_format, tex_file, tex_dir, ) - exit_code = os.system(command) - if exit_code != 0: + cp = subprocess.run(command, stdout=subprocess.DEVNULL) + if cp.returncode != 0: log_file = tex_file.with_suffix(".log") print_all_tex_errors(log_file, tex_compiler, tex_file) raise ValueError( @@ -237,18 +234,16 @@ def convert_to_svg(dvi_file: Path, extension: str, page: int = 1): """ result = dvi_file.with_suffix(".svg") if not result.exists(): - commands = [ + command = [ "dvisvgm", - "--pdf" if extension == ".pdf" else "", - "-p " + str(page), - f'"{dvi_file.as_posix()}"', - "-n", - "-v 0", - "-o " + f'"{result.as_posix()}"', - ">", - os.devnull, + *(["--pdf"] if extension == ".pdf" else []), + f"--page={page}", + "--no-fonts", + "--verbosity=0", + f"--output={result.as_posix()}", + f"{dvi_file.as_posix()}", ] - os.system(" ".join(commands)) + subprocess.run(command, stdout=subprocess.DEVNULL) # if the file does not exist now, this means conversion failed if not result.exists(): @@ -271,7 +266,6 @@ def delete_nonsvg_files(additional_endings: Iterable[str] = ()) -> None: additional_endings Additional endings to whitelist """ - tex_dir = config.get_dir("tex_dir") file_suffix_whitelist = {".svg", ".tex", *additional_endings} diff --git a/mypy.ini b/mypy.ini index 956b44ae21..160daf488b 100644 --- a/mypy.ini +++ b/mypy.ini @@ -59,10 +59,10 @@ ignore_errors = True ignore_errors = True [mypy-manim.cli.*] -ignore_errors = True +ignore_errors = False [mypy-manim.cli.cfg.*] -ignore_errors = True +ignore_errors = False [mypy-manim.gui.*] ignore_errors = True @@ -70,8 +70,8 @@ ignore_errors = True [mypy-manim.mobject.*] ignore_errors = True -[mypy-manim.plugins.*] -ignore_errors = True +[mypy-manim.mobject.geometry.*] +ignore_errors = False [mypy-manim.renderer.*] ignore_errors = True @@ -86,9 +86,6 @@ ignore_errors = True ignore_errors = False warn_return_any = False -[mypy-manim.__main__] -ignore_errors = True - # ---------------- We can't properly type this ------------------------ diff --git a/poetry.lock b/poetry.lock index 8480752e78..4cce1eba32 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. [[package]] name = "alabaster" @@ -13,13 +13,13 @@ files = [ [[package]] name = "anyio" -version = "4.3.0" +version = "4.6.2.post1" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "anyio-4.3.0-py3-none-any.whl", hash = "sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8"}, - {file = "anyio-4.3.0.tar.gz", hash = "sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6"}, + {file = "anyio-4.6.2.post1-py3-none-any.whl", hash = "sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d"}, + {file = "anyio-4.6.2.post1.tar.gz", hash = "sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c"}, ] [package.dependencies] @@ -29,9 +29,9 @@ sniffio = ">=1.1" typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""} [package.extras] -doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] -trio = ["trio (>=0.23)"] +doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21.0b1)"] +trio = ["trio (>=0.26.1)"] [[package]] name = "appnope" @@ -120,34 +120,20 @@ types-python-dateutil = ">=2.8.10" doc = ["doc8", "sphinx (>=7.0.0)", "sphinx-autobuild", "sphinx-autodoc-typehints", "sphinx_rtd_theme (>=1.3.0)"] test = ["dateparser (==1.*)", "pre-commit", "pytest", "pytest-cov", "pytest-mock", "pytz (==2021.1)", "simplejson (==3.*)"] -[[package]] -name = "astor" -version = "0.8.1" -description = "Read/rewrite/write Python ASTs" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" -files = [ - {file = "astor-0.8.1-py2.py3-none-any.whl", hash = "sha256:070a54e890cefb5b3739d19f30f5a5ec840ffc9c50ffa7d23cc9fc1a38ebbfc5"}, - {file = "astor-0.8.1.tar.gz", hash = "sha256:6a6effda93f4e1ce9f618779b2dd1d9d84f1e32812c23a29b3fff6fd7f63fa5e"}, -] - [[package]] name = "asttokens" -version = "2.4.1" +version = "3.0.0" description = "Annotate AST trees with source code positions" optional = true -python-versions = "*" +python-versions = ">=3.8" files = [ - {file = "asttokens-2.4.1-py2.py3-none-any.whl", hash = "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24"}, - {file = "asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0"}, + {file = "asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2"}, + {file = "asttokens-3.0.0.tar.gz", hash = "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7"}, ] -[package.dependencies] -six = ">=1.12.0" - [package.extras] -astroid = ["astroid (>=1,<2)", "astroid (>=2,<4)"] -test = ["astroid (>=1,<2)", "astroid (>=2,<4)", "pytest"] +astroid = ["astroid (>=2,<4)"] +test = ["astroid (>=2,<4)", "pytest", "pytest-cov", "pytest-xdist"] [[package]] name = "async-lru" @@ -165,86 +151,126 @@ typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} [[package]] name = "attrs" -version = "23.2.0" +version = "24.2.0" description = "Classes Without Boilerplate" -optional = false +optional = true python-versions = ">=3.7" files = [ - {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, - {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, + {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"}, + {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"}, ] [package.extras] -cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] -dev = ["attrs[tests]", "pre-commit"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] -tests = ["attrs[tests-no-zope]", "zope-interface"] -tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] -tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] +benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] + +[[package]] +name = "audioop-lts" +version = "0.2.1" +description = "LTS Port of Python audioop" +optional = false +python-versions = ">=3.13" +files = [ + {file = "audioop_lts-0.2.1-cp313-abi3-macosx_10_13_universal2.whl", hash = "sha256:fd1345ae99e17e6910f47ce7d52673c6a1a70820d78b67de1b7abb3af29c426a"}, + {file = "audioop_lts-0.2.1-cp313-abi3-macosx_10_13_x86_64.whl", hash = "sha256:e175350da05d2087e12cea8e72a70a1a8b14a17e92ed2022952a4419689ede5e"}, + {file = "audioop_lts-0.2.1-cp313-abi3-macosx_11_0_arm64.whl", hash = "sha256:4a8dd6a81770f6ecf019c4b6d659e000dc26571b273953cef7cd1d5ce2ff3ae6"}, + {file = "audioop_lts-0.2.1-cp313-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1cd3c0b6f2ca25c7d2b1c3adeecbe23e65689839ba73331ebc7d893fcda7ffe"}, + {file = "audioop_lts-0.2.1-cp313-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ff3f97b3372c97782e9c6d3d7fdbe83bce8f70de719605bd7ee1839cd1ab360a"}, + {file = "audioop_lts-0.2.1-cp313-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a351af79edefc2a1bd2234bfd8b339935f389209943043913a919df4b0f13300"}, + {file = "audioop_lts-0.2.1-cp313-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2aeb6f96f7f6da80354330470b9134d81b4cf544cdd1c549f2f45fe964d28059"}, + {file = "audioop_lts-0.2.1-cp313-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c589f06407e8340e81962575fcffbba1e92671879a221186c3d4662de9fe804e"}, + {file = "audioop_lts-0.2.1-cp313-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fbae5d6925d7c26e712f0beda5ed69ebb40e14212c185d129b8dfbfcc335eb48"}, + {file = "audioop_lts-0.2.1-cp313-abi3-musllinux_1_2_i686.whl", hash = "sha256:d2d5434717f33117f29b5691fbdf142d36573d751716249a288fbb96ba26a281"}, + {file = "audioop_lts-0.2.1-cp313-abi3-musllinux_1_2_ppc64le.whl", hash = "sha256:f626a01c0a186b08f7ff61431c01c055961ee28769591efa8800beadd27a2959"}, + {file = "audioop_lts-0.2.1-cp313-abi3-musllinux_1_2_s390x.whl", hash = "sha256:05da64e73837f88ee5c6217d732d2584cf638003ac72df124740460531e95e47"}, + {file = "audioop_lts-0.2.1-cp313-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:56b7a0a4dba8e353436f31a932f3045d108a67b5943b30f85a5563f4d8488d77"}, + {file = "audioop_lts-0.2.1-cp313-abi3-win32.whl", hash = "sha256:6e899eb8874dc2413b11926b5fb3857ec0ab55222840e38016a6ba2ea9b7d5e3"}, + {file = "audioop_lts-0.2.1-cp313-abi3-win_amd64.whl", hash = "sha256:64562c5c771fb0a8b6262829b9b4f37a7b886c01b4d3ecdbae1d629717db08b4"}, + {file = "audioop_lts-0.2.1-cp313-abi3-win_arm64.whl", hash = "sha256:c45317debeb64002e980077642afbd977773a25fa3dfd7ed0c84dccfc1fafcb0"}, + {file = "audioop_lts-0.2.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:3827e3fce6fee4d69d96a3d00cd2ab07f3c0d844cb1e44e26f719b34a5b15455"}, + {file = "audioop_lts-0.2.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:161249db9343b3c9780ca92c0be0d1ccbfecdbccac6844f3d0d44b9c4a00a17f"}, + {file = "audioop_lts-0.2.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5b7b4ff9de7a44e0ad2618afdc2ac920b91f4a6d3509520ee65339d4acde5abf"}, + {file = "audioop_lts-0.2.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:72e37f416adb43b0ced93419de0122b42753ee74e87070777b53c5d2241e7fab"}, + {file = "audioop_lts-0.2.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:534ce808e6bab6adb65548723c8cbe189a3379245db89b9d555c4210b4aaa9b6"}, + {file = "audioop_lts-0.2.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2de9b6fb8b1cf9f03990b299a9112bfdf8b86b6987003ca9e8a6c4f56d39543"}, + {file = "audioop_lts-0.2.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f24865991b5ed4b038add5edbf424639d1358144f4e2a3e7a84bc6ba23e35074"}, + {file = "audioop_lts-0.2.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bdb3b7912ccd57ea53197943f1bbc67262dcf29802c4a6df79ec1c715d45a78"}, + {file = "audioop_lts-0.2.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:120678b208cca1158f0a12d667af592e067f7a50df9adc4dc8f6ad8d065a93fb"}, + {file = "audioop_lts-0.2.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:54cd4520fc830b23c7d223693ed3e1b4d464997dd3abc7c15dce9a1f9bd76ab2"}, + {file = "audioop_lts-0.2.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:d6bd20c7a10abcb0fb3d8aaa7508c0bf3d40dfad7515c572014da4b979d3310a"}, + {file = "audioop_lts-0.2.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:f0ed1ad9bd862539ea875fb339ecb18fcc4148f8d9908f4502df28f94d23491a"}, + {file = "audioop_lts-0.2.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e1af3ff32b8c38a7d900382646e91f2fc515fd19dea37e9392275a5cbfdbff63"}, + {file = "audioop_lts-0.2.1-cp313-cp313t-win32.whl", hash = "sha256:f51bb55122a89f7a0817d7ac2319744b4640b5b446c4c3efcea5764ea99ae509"}, + {file = "audioop_lts-0.2.1-cp313-cp313t-win_amd64.whl", hash = "sha256:f0f2f336aa2aee2bce0b0dcc32bbba9178995454c7b979cf6ce086a8801e14c7"}, + {file = "audioop_lts-0.2.1-cp313-cp313t-win_arm64.whl", hash = "sha256:78bfb3703388c780edf900be66e07de5a3d4105ca8e8720c5c4d67927e0b15d0"}, + {file = "audioop_lts-0.2.1.tar.gz", hash = "sha256:e81268da0baa880431b68b1308ab7257eb33f356e57a5f9b1f915dfb13dd1387"}, +] [[package]] name = "av" -version = "12.0.0" +version = "13.1.0" description = "Pythonic bindings for FFmpeg's libraries." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "av-12.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b9d0890553951f76c479a9f2bb952aebae902b1c7d52feea614d37e1cd728a44"}, - {file = "av-12.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5d7f229a253c2e3fea9682c09c5ae179bd6d5d2da38d89eb7f29ef7bed10cb2f"}, - {file = "av-12.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61b3555d143aacf02e0446f6030319403538eba4dc713c18dfa653a2a23e7f9c"}, - {file = "av-12.0.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:607e13b2c2b26159a37525d7b6f647a32ce78711fccff23d146d3e255ffa115f"}, - {file = "av-12.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39f0b4cfb89f4f06b339c766f92648e798a96747d4163f2fa78660d1ab1f1b5e"}, - {file = "av-12.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:41dcb8c269fa58a56edf3a3c814c32a0c69586827f132b4e395a951b0ce14fad"}, - {file = "av-12.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4fa78fbe0e4469226512380180063116105048c66cb12e18ab4b518466c57e6c"}, - {file = "av-12.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:60a869be1d6af916e65ea461cb93922f5db0698655ed7a7eae7c3ecd4af4debb"}, - {file = "av-12.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df61811cc551c186f0a0e530d97b8b139453534d0f92c1790a923f666522ceda"}, - {file = "av-12.0.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99cd2fc53091ebfb9a2fa9dd3580267f5bd1c040d0efd99fbc1a162576b271cb"}, - {file = "av-12.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a6d4f1e261df48932128e6495772faa4cc23f5dd1512eec73daab82ad9f3240"}, - {file = "av-12.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:6aec88e41a498b1e01e2dce5371557e20f9a51aae0c16decc5924ec0be2e22b6"}, - {file = "av-12.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:90eb8f2d548e96cbc6f78e89c911cdb15a3d80fd944f31111660ce45939cd037"}, - {file = "av-12.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d7f3a02910e77d750dbd516256a16db15030e5371530ff5a5ae902dc03d9005d"}, - {file = "av-12.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2477cc51526aa50575313d66e5e8ad7ab944588469be5e557b360ed572ae536"}, - {file = "av-12.0.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a2f47149d3ca6deb79f3e515b8bef50e27ebdb160813e6d67dba77278d2a7883"}, - {file = "av-12.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3306e4a3ce8b5bfcc3075793d4ed3a2df69179d8fba22cb944a6164dc235dfb6"}, - {file = "av-12.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:dc1b742e7f6df1b499fb960bd6697d1dd8e7ada7484a041a8c20e70a87225f53"}, - {file = "av-12.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0183be6889e835e1b074b4037bfce4fd44671c606cf1c4ab92ea2f271b544aec"}, - {file = "av-12.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:57337f20b208292ec8d3b11e4d289d8688a43d728174850a81b865d3253fff2c"}, - {file = "av-12.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ec915e8f6521545a38566eefc281042ee504ea3cee0618d8558e4920588b3b2"}, - {file = "av-12.0.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33ad5c0a23c45b72bd6bd47f3b2c1adcd2935ee3d0b6178ed66bba62b964ff31"}, - {file = "av-12.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfc3a652b12c93120514d56cf025da47442c5ba51530cdf7ba3660257dbb0de1"}, - {file = "av-12.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:037f793dd1ef4a1f57f090191a7f803ad10ec82da0d04ea26bbe0b8a145fe927"}, - {file = "av-12.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fc532376aa264722fae55063abd1871d17a563dc895978e142c8ecfcdeb3a2e8"}, - {file = "av-12.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:abf0c4bc40a0af8a30f4cd96f3be6f19fbce0f21222d7fcec148e085127153f7"}, - {file = "av-12.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81cedd1c072fbebf606724c406b1a1b00adc711f1dfd2bc04c633ce39d8439d8"}, - {file = "av-12.0.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02d60f48be9f15dcda37d50f3ce8d7249d9a455643d4322dd3449986bacfc628"}, - {file = "av-12.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d2619e4c26d661eecfc404f7d739d8b35f0dcef353fabe61512e030254b7031"}, - {file = "av-12.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:1892cc91c888d101777d5432d54e0554c11d1c3a2c65d02a2cae0a2256a8fbb9"}, - {file = "av-12.0.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4819e3ef6c3a44ef6f75907229133a1ee7f688245b2cf49b6b8e969a81ca72c9"}, - {file = "av-12.0.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb16bb314cf1503b0250fc46b2c455ee196584231101be0123f4f78638227b62"}, - {file = "av-12.0.0-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3e6a62bda9a1e144feeb59bbee046d7a2d98399634a30f57e4990197313c158"}, - {file = "av-12.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e08175ffbafa3a70c7b2f81083e160e34122a208cdf70f150b8f5d02c2de6965"}, - {file = "av-12.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e1d255be317b7c1ebdc4dae98935b9f3869161112dc829c625e54f90d8bdd7ab"}, - {file = "av-12.0.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:17964b36e08435910aabd5b3f7dca12f99536902529767d276026bc08f94ced7"}, - {file = "av-12.0.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2d5f78de29edee06ddcdd4c2b759914575492d6a0cd4de2ce31ee63a4953eff"}, - {file = "av-12.0.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:309b32bc97158d0f0c19e273b8e17a855a86806b7194aebc23bd497326cff11f"}, - {file = "av-12.0.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c409c71bd9c7c2f8d018c822f36b1447cfa96eca158381a96f3319bb0ff6e79e"}, - {file = "av-12.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:08fc5eaef60a257d622998626e233bf3ff90d2f817f6695d6a27e0ffcfe9dcff"}, - {file = "av-12.0.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:746ab0eff8a7a21a6c6d16e6b6e61709527eba2ad1a524d92a01bb60d02a3df7"}, - {file = "av-12.0.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:013b3ac3de3aa1c137af0cedafd364fd1c7524ab3e1cd53e04564fd1632ac04d"}, - {file = "av-12.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fa55923527648f51ac005e44fe2797ebc67f53ad4850e0194d3753761ee33a2"}, - {file = "av-12.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:35d514f4dee0cf67e9e6b2a65fb4a28f98da88e71e8c7f7960bd04625d9fe965"}, - {file = "av-12.0.0.tar.gz", hash = "sha256:bcf21ebb722d4538b4099e5a78f730d78814dd70003511c185941dba5651b14d"}, + {file = "av-13.1.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:a2af44fae6d16c3a40dd1c85bda41b449be08a2c172d8f44fb63395ccf6e6fb4"}, + {file = "av-13.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0fea71fe06fd0dfe90a089200eb6468034797f860a321fa2d62e07d619c74749"}, + {file = "av-13.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:756997810dcca11811b598d209561cabd2071e5b472b867c295bb3e7022eecde"}, + {file = "av-13.1.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7f432102edaec4ee90087a675acf486bff0c81b47d98b85eb3218afe84575b60"}, + {file = "av-13.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d568c4d7a36df52c0774d52e6d730148775ead16daed81c10dafc2569b5a38d"}, + {file = "av-13.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:aa6f76e7c5e77bc5f99a27ada29f78c64fd4e0d42da2c4d203badc650bc0a686"}, + {file = "av-13.1.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:867385e6701464a5c95903e24d2e0df1c7e0dbf211ed91d0ce639cd687373e10"}, + {file = "av-13.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cb7a3f319401a46b0017771268ff4928501e77cf00b1a2aa0721e20b2fd1146e"}, + {file = "av-13.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad904f860147bceaca65b0d3174a8153f35c570d465161d210f1879970b15559"}, + {file = "av-13.1.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a906e017b29d0eb80d9ccf7a98d19268122da792dbb68eb741cfebba156e6aed"}, + {file = "av-13.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ce894d7847897da7be63277a0875bd93c51327134ac226c67978de014c7979f"}, + {file = "av-13.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:384bcdb5fc3238a263a5a25cc9efc690859fa4148cc4b07e00fae927178db22a"}, + {file = "av-13.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:261dbc3f4b55f4f8f3375b10b2258fca7f2ab7a6365c01bc65e77a0d5327a195"}, + {file = "av-13.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83d259ef86b9054eb914bc7c6a7f6092a6d75cb939295e70ee979cfd92a67b99"}, + {file = "av-13.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3b4d3ca159eceab97e3c0fb08fe756520fb95508417f76e48198fda2a5b0806"}, + {file = "av-13.1.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40e8f757e373b73a2dc4640852a00cce4a4a92ef19b2e642a96d6994cd1fffbf"}, + {file = "av-13.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8aaec2c0bfd024359db3821d679009d4e637e1bee0321d20f61c54ed6b20f41"}, + {file = "av-13.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:5ea0deab0e6a739cb742fba2a3983d8102f7516a3cdf3c46669f3cac0ed1f351"}, + {file = "av-13.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:47642ebaebfe20519b2391bd5b7c38b596efcd052bfd09c8d33058f94ddd0fd6"}, + {file = "av-13.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2f079c2daa3ae06557b3f6e9bed4fb9c876e8012175bec645ccd007199a302db"}, + {file = "av-13.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f0de8252deeeb1887637e88d4d9d18514e5cfe276bdb9e6ca8e9eef89d1667a"}, + {file = "av-13.1.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9ad0024f4def11b0cedfeee478fa6c6fd7ed3955e13387e0f27261fdda6121b4"}, + {file = "av-13.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb88e2590eaed45233eb117f1dfab1a43ed9a997b2c46da9f08468dd00f14895"}, + {file = "av-13.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:c927e4fa4f6aeed4340b3e3b16b237d7cb743e5c1a55b92307407590ca4112aa"}, + {file = "av-13.1.0-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:fa398f0e0579bdeca4f0c31eb46e88c29562988e135e44972f73bb7525d1454e"}, + {file = "av-13.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cd38601a0e83061af90106e5a312649cd04b1f0bba508f3895ac8dc7930bcf68"}, + {file = "av-13.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a18b67c5b4ad725c5cd4d0d6cd825d91e39f50654e4148cb179a02913b6bd42"}, + {file = "av-13.1.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c53917f326e460e784cf599da3e2b4d5c76c02c9fd2d32c4b8e24b86b159b6ba"}, + {file = "av-13.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5bc5e8a5f3811dab471c412c50b7850912d85c804f500b75358b6af93e8ee8b"}, + {file = "av-13.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:6d7ae8510ff011fb4df0e0a6c50ef495a980d70968db17d138a7ccca322896cd"}, + {file = "av-13.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:fc5118f78ee712b2c396f345e4c51e60e61e28f1f606adbd4060c4dc44b0b652"}, + {file = "av-13.1.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:81bcbd3545e523e7a350613be1866b515a5ee3fafa1d9d257d7ed02531fc2636"}, + {file = "av-13.1.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83b2bc641e8e16bbf058de35f1ba79ebed358ac6fe3cb5a665366294774fdb18"}, + {file = "av-13.1.0-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d956ae3e68fabdc45eb2b986c2e842a31df084d8cfc90336509f07a727a9df62"}, + {file = "av-13.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ef076fcdf172aafcb21ea3ef7bd68cc9151b050016a8ace13b3dae3d08a4427"}, + {file = "av-13.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:bbf90397b7a466ff2879bd0944d55f796ad76c073fce50304315b83ad00113bd"}, + {file = "av-13.1.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3804b57d04dc512c7ae15da9499373f37b8af7a80631899a9b3afd4c9007433b"}, + {file = "av-13.1.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:1b94ee5ee160794c9874b4977e5c4d76d7250b2fd6f27202c66a4df4ad23e822"}, + {file = "av-13.1.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6073ff4202e4a0c3aecab35ef99f84a3c4b4414c4b8ae771c965a2b52394148c"}, + {file = "av-13.1.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5ab17663b783e112837fb1c5f67098a561627e4a542cdf5bf1524f48478b897"}, + {file = "av-13.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f422360f801a6f878d73aee4d404110ee6bb8f04846bf8815edb218da83bec49"}, + {file = "av-13.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:799cf56dc9399a1696e0445dcee6e17dfa67e2a76030934d678cfa7d7ae40172"}, + {file = "av-13.1.0.tar.gz", hash = "sha256:d3da736c55847d8596eb8c26c60e036f193001db3bc5c10da8665622d906c17e"}, ] [[package]] name = "babel" -version = "2.15.0" +version = "2.16.0" description = "Internationalization utilities" optional = false python-versions = ">=3.8" files = [ - {file = "Babel-2.15.0-py3-none-any.whl", hash = "sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb"}, - {file = "babel-2.15.0.tar.gz", hash = "sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413"}, + {file = "babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b"}, + {file = "babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316"}, ] [package.extras] @@ -271,140 +297,108 @@ charset-normalizer = ["charset-normalizer"] html5lib = ["html5lib"] lxml = ["lxml"] -[[package]] -name = "black" -version = "24.4.2" -description = "The uncompromising code formatter." -optional = false -python-versions = ">=3.8" -files = [ - {file = "black-24.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dd1b5a14e417189db4c7b64a6540f31730713d173f0b63e55fabd52d61d8fdce"}, - {file = "black-24.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e537d281831ad0e71007dcdcbe50a71470b978c453fa41ce77186bbe0ed6021"}, - {file = "black-24.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaea3008c281f1038edb473c1aa8ed8143a5535ff18f978a318f10302b254063"}, - {file = "black-24.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:7768a0dbf16a39aa5e9a3ded568bb545c8c2727396d063bbaf847df05b08cd96"}, - {file = "black-24.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:257d724c2c9b1660f353b36c802ccece186a30accc7742c176d29c146df6e474"}, - {file = "black-24.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bdde6f877a18f24844e381d45e9947a49e97933573ac9d4345399be37621e26c"}, - {file = "black-24.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e151054aa00bad1f4e1f04919542885f89f5f7d086b8a59e5000e6c616896ffb"}, - {file = "black-24.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:7e122b1c4fb252fd85df3ca93578732b4749d9be076593076ef4d07a0233c3e1"}, - {file = "black-24.4.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:accf49e151c8ed2c0cdc528691838afd217c50412534e876a19270fea1e28e2d"}, - {file = "black-24.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:88c57dc656038f1ab9f92b3eb5335ee9b021412feaa46330d5eba4e51fe49b04"}, - {file = "black-24.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be8bef99eb46d5021bf053114442914baeb3649a89dc5f3a555c88737e5e98fc"}, - {file = "black-24.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:415e686e87dbbe6f4cd5ef0fbf764af7b89f9057b97c908742b6008cc554b9c0"}, - {file = "black-24.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bf10f7310db693bb62692609b397e8d67257c55f949abde4c67f9cc574492cc7"}, - {file = "black-24.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:98e123f1d5cfd42f886624d84464f7756f60ff6eab89ae845210631714f6db94"}, - {file = "black-24.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48a85f2cb5e6799a9ef05347b476cce6c182d6c71ee36925a6c194d074336ef8"}, - {file = "black-24.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:b1530ae42e9d6d5b670a34db49a94115a64596bc77710b1d05e9801e62ca0a7c"}, - {file = "black-24.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:37aae07b029fa0174d39daf02748b379399b909652a806e5708199bd93899da1"}, - {file = "black-24.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da33a1a5e49c4122ccdfd56cd021ff1ebc4a1ec4e2d01594fef9b6f267a9e741"}, - {file = "black-24.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef703f83fc32e131e9bcc0a5094cfe85599e7109f896fe8bc96cc402f3eb4b6e"}, - {file = "black-24.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:b9176b9832e84308818a99a561e90aa479e73c523b3f77afd07913380ae2eab7"}, - {file = "black-24.4.2-py3-none-any.whl", hash = "sha256:d36ed1124bb81b32f8614555b34cc4259c3fbc7eec17870e8ff8ded335b58d8c"}, - {file = "black-24.4.2.tar.gz", hash = "sha256:c872b53057f000085da66a19c55d68f6f8ddcac2642392ad3a355878406fbd4d"}, -] - -[package.dependencies] -click = ">=8.0.0" -mypy-extensions = ">=0.4.3" -packaging = ">=22.0" -pathspec = ">=0.9.0" -platformdirs = ">=2" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -uvloop = ["uvloop (>=0.15.2)"] - [[package]] name = "bleach" -version = "6.1.0" +version = "6.2.0" description = "An easy safelist-based HTML-sanitizing tool." optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "bleach-6.1.0-py3-none-any.whl", hash = "sha256:3225f354cfc436b9789c66c4ee030194bee0568fbf9cbdad3bc8b5c26c5f12b6"}, - {file = "bleach-6.1.0.tar.gz", hash = "sha256:0a31f1837963c41d46bbf1331b8778e1308ea0791db03cc4e7357b97cf42a8fe"}, + {file = "bleach-6.2.0-py3-none-any.whl", hash = "sha256:117d9c6097a7c3d22fd578fcd8d35ff1e125df6736f554da4e432fdd63f31e5e"}, + {file = "bleach-6.2.0.tar.gz", hash = "sha256:123e894118b8a599fd80d3ec1a6d4cc7ce4e5882b1317a7e1ba69b56e95f991f"}, ] [package.dependencies] -six = ">=1.9.0" webencodings = "*" [package.extras] -css = ["tinycss2 (>=1.1.0,<1.3)"] +css = ["tinycss2 (>=1.1.0,<1.5)"] [[package]] name = "certifi" -version = "2024.2.2" +version = "2024.8.30" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, - {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, + {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, + {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, ] [[package]] name = "cffi" -version = "1.16.0" +version = "1.17.1" description = "Foreign Function Interface for Python calling C code." optional = false python-versions = ">=3.8" files = [ - {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, - {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, - {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, - {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, - {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, - {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, - {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, - {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, - {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, - {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, - {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, - {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, - {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, - {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, - {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, - {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, - {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, - {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, - {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, - {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, - {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, - {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, - {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, - {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, - {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, - {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, - {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, + {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, + {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"}, + {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"}, + {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, + {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, + {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, + {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, + {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, + {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, + {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, + {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"}, + {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"}, + {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"}, + {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"}, + {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, + {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, ] [package.dependencies] @@ -423,101 +417,116 @@ files = [ [[package]] name = "charset-normalizer" -version = "3.3.2" +version = "3.4.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7.0" files = [ - {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, - {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win32.whl", hash = "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win32.whl", hash = "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win32.whl", hash = "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca"}, + {file = "charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079"}, + {file = "charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"}, ] [[package]] @@ -578,126 +587,157 @@ test = ["pytest"] [[package]] name = "contourpy" -version = "1.2.1" +version = "1.3.0" description = "Python library for calculating contours of 2D quadrilateral grids" optional = false python-versions = ">=3.9" files = [ - {file = "contourpy-1.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bd7c23df857d488f418439686d3b10ae2fbf9bc256cd045b37a8c16575ea1040"}, - {file = "contourpy-1.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5b9eb0ca724a241683c9685a484da9d35c872fd42756574a7cfbf58af26677fd"}, - {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c75507d0a55378240f781599c30e7776674dbaf883a46d1c90f37e563453480"}, - {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:11959f0ce4a6f7b76ec578576a0b61a28bdc0696194b6347ba3f1c53827178b9"}, - {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eb3315a8a236ee19b6df481fc5f997436e8ade24a9f03dfdc6bd490fea20c6da"}, - {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39f3ecaf76cd98e802f094e0d4fbc6dc9c45a8d0c4d185f0f6c2234e14e5f75b"}, - {file = "contourpy-1.2.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:94b34f32646ca0414237168d68a9157cb3889f06b096612afdd296003fdd32fd"}, - {file = "contourpy-1.2.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:457499c79fa84593f22454bbd27670227874cd2ff5d6c84e60575c8b50a69619"}, - {file = "contourpy-1.2.1-cp310-cp310-win32.whl", hash = "sha256:ac58bdee53cbeba2ecad824fa8159493f0bf3b8ea4e93feb06c9a465d6c87da8"}, - {file = "contourpy-1.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:9cffe0f850e89d7c0012a1fb8730f75edd4320a0a731ed0c183904fe6ecfc3a9"}, - {file = "contourpy-1.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6022cecf8f44e36af10bd9118ca71f371078b4c168b6e0fab43d4a889985dbb5"}, - {file = "contourpy-1.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ef5adb9a3b1d0c645ff694f9bca7702ec2c70f4d734f9922ea34de02294fdf72"}, - {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6150ffa5c767bc6332df27157d95442c379b7dce3a38dff89c0f39b63275696f"}, - {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c863140fafc615c14a4bf4efd0f4425c02230eb8ef02784c9a156461e62c965"}, - {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:00e5388f71c1a0610e6fe56b5c44ab7ba14165cdd6d695429c5cd94021e390b2"}, - {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4492d82b3bc7fbb7e3610747b159869468079fe149ec5c4d771fa1f614a14df"}, - {file = "contourpy-1.2.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:49e70d111fee47284d9dd867c9bb9a7058a3c617274900780c43e38d90fe1205"}, - {file = "contourpy-1.2.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b59c0ffceff8d4d3996a45f2bb6f4c207f94684a96bf3d9728dbb77428dd8cb8"}, - {file = "contourpy-1.2.1-cp311-cp311-win32.whl", hash = "sha256:7b4182299f251060996af5249c286bae9361fa8c6a9cda5efc29fe8bfd6062ec"}, - {file = "contourpy-1.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2855c8b0b55958265e8b5888d6a615ba02883b225f2227461aa9127c578a4922"}, - {file = "contourpy-1.2.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:62828cada4a2b850dbef89c81f5a33741898b305db244904de418cc957ff05dc"}, - {file = "contourpy-1.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:309be79c0a354afff9ff7da4aaed7c3257e77edf6c1b448a779329431ee79d7e"}, - {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e785e0f2ef0d567099b9ff92cbfb958d71c2d5b9259981cd9bee81bd194c9a4"}, - {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1cac0a8f71a041aa587410424ad46dfa6a11f6149ceb219ce7dd48f6b02b87a7"}, - {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af3f4485884750dddd9c25cb7e3915d83c2db92488b38ccb77dd594eac84c4a0"}, - {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ce6889abac9a42afd07a562c2d6d4b2b7134f83f18571d859b25624a331c90b"}, - {file = "contourpy-1.2.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a1eea9aecf761c661d096d39ed9026574de8adb2ae1c5bd7b33558af884fb2ce"}, - {file = "contourpy-1.2.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:187fa1d4c6acc06adb0fae5544c59898ad781409e61a926ac7e84b8f276dcef4"}, - {file = "contourpy-1.2.1-cp312-cp312-win32.whl", hash = "sha256:c2528d60e398c7c4c799d56f907664673a807635b857df18f7ae64d3e6ce2d9f"}, - {file = "contourpy-1.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:1a07fc092a4088ee952ddae19a2b2a85757b923217b7eed584fdf25f53a6e7ce"}, - {file = "contourpy-1.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bb6834cbd983b19f06908b45bfc2dad6ac9479ae04abe923a275b5f48f1a186b"}, - {file = "contourpy-1.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1d59e739ab0e3520e62a26c60707cc3ab0365d2f8fecea74bfe4de72dc56388f"}, - {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd3db01f59fdcbce5b22afad19e390260d6d0222f35a1023d9adc5690a889364"}, - {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a12a813949e5066148712a0626895c26b2578874e4cc63160bb007e6df3436fe"}, - {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe0ccca550bb8e5abc22f530ec0466136379c01321fd94f30a22231e8a48d985"}, - {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1d59258c3c67c865435d8fbeb35f8c59b8bef3d6f46c1f29f6123556af28445"}, - {file = "contourpy-1.2.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f32c38afb74bd98ce26de7cc74a67b40afb7b05aae7b42924ea990d51e4dac02"}, - {file = "contourpy-1.2.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d31a63bc6e6d87f77d71e1abbd7387ab817a66733734883d1fc0021ed9bfa083"}, - {file = "contourpy-1.2.1-cp39-cp39-win32.whl", hash = "sha256:ddcb8581510311e13421b1f544403c16e901c4e8f09083c881fab2be80ee31ba"}, - {file = "contourpy-1.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:10a37ae557aabf2509c79715cd20b62e4c7c28b8cd62dd7d99e5ed3ce28c3fd9"}, - {file = "contourpy-1.2.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a31f94983fecbac95e58388210427d68cd30fe8a36927980fab9c20062645609"}, - {file = "contourpy-1.2.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef2b055471c0eb466033760a521efb9d8a32b99ab907fc8358481a1dd29e3bd3"}, - {file = "contourpy-1.2.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b33d2bc4f69caedcd0a275329eb2198f560b325605810895627be5d4b876bf7f"}, - {file = "contourpy-1.2.1.tar.gz", hash = "sha256:4d8908b3bee1c889e547867ca4cdc54e5ab6be6d3e078556814a22457f49423c"}, + {file = "contourpy-1.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:880ea32e5c774634f9fcd46504bf9f080a41ad855f4fef54f5380f5133d343c7"}, + {file = "contourpy-1.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:76c905ef940a4474a6289c71d53122a4f77766eef23c03cd57016ce19d0f7b42"}, + {file = "contourpy-1.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92f8557cbb07415a4d6fa191f20fd9d2d9eb9c0b61d1b2f52a8926e43c6e9af7"}, + {file = "contourpy-1.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:36f965570cff02b874773c49bfe85562b47030805d7d8360748f3eca570f4cab"}, + {file = "contourpy-1.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cacd81e2d4b6f89c9f8a5b69b86490152ff39afc58a95af002a398273e5ce589"}, + {file = "contourpy-1.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:69375194457ad0fad3a839b9e29aa0b0ed53bb54db1bfb6c3ae43d111c31ce41"}, + {file = "contourpy-1.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a52040312b1a858b5e31ef28c2e865376a386c60c0e248370bbea2d3f3b760d"}, + {file = "contourpy-1.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3faeb2998e4fcb256542e8a926d08da08977f7f5e62cf733f3c211c2a5586223"}, + {file = "contourpy-1.3.0-cp310-cp310-win32.whl", hash = "sha256:36e0cff201bcb17a0a8ecc7f454fe078437fa6bda730e695a92f2d9932bd507f"}, + {file = "contourpy-1.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:87ddffef1dbe5e669b5c2440b643d3fdd8622a348fe1983fad7a0f0ccb1cd67b"}, + {file = "contourpy-1.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0fa4c02abe6c446ba70d96ece336e621efa4aecae43eaa9b030ae5fb92b309ad"}, + {file = "contourpy-1.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:834e0cfe17ba12f79963861e0f908556b2cedd52e1f75e6578801febcc6a9f49"}, + {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dbc4c3217eee163fa3984fd1567632b48d6dfd29216da3ded3d7b844a8014a66"}, + {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4865cd1d419e0c7a7bf6de1777b185eebdc51470800a9f42b9e9decf17762081"}, + {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:303c252947ab4b14c08afeb52375b26781ccd6a5ccd81abcdfc1fafd14cf93c1"}, + {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:637f674226be46f6ba372fd29d9523dd977a291f66ab2a74fbeb5530bb3f445d"}, + {file = "contourpy-1.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:76a896b2f195b57db25d6b44e7e03f221d32fe318d03ede41f8b4d9ba1bff53c"}, + {file = "contourpy-1.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e1fd23e9d01591bab45546c089ae89d926917a66dceb3abcf01f6105d927e2cb"}, + {file = "contourpy-1.3.0-cp311-cp311-win32.whl", hash = "sha256:d402880b84df3bec6eab53cd0cf802cae6a2ef9537e70cf75e91618a3801c20c"}, + {file = "contourpy-1.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:6cb6cc968059db9c62cb35fbf70248f40994dfcd7aa10444bbf8b3faeb7c2d67"}, + {file = "contourpy-1.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:570ef7cf892f0afbe5b2ee410c507ce12e15a5fa91017a0009f79f7d93a1268f"}, + {file = "contourpy-1.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:da84c537cb8b97d153e9fb208c221c45605f73147bd4cadd23bdae915042aad6"}, + {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0be4d8425bfa755e0fd76ee1e019636ccc7c29f77a7c86b4328a9eb6a26d0639"}, + {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9c0da700bf58f6e0b65312d0a5e695179a71d0163957fa381bb3c1f72972537c"}, + {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eb8b141bb00fa977d9122636b16aa67d37fd40a3d8b52dd837e536d64b9a4d06"}, + {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3634b5385c6716c258d0419c46d05c8aa7dc8cb70326c9a4fb66b69ad2b52e09"}, + {file = "contourpy-1.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0dce35502151b6bd35027ac39ba6e5a44be13a68f55735c3612c568cac3805fd"}, + {file = "contourpy-1.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:aea348f053c645100612b333adc5983d87be69acdc6d77d3169c090d3b01dc35"}, + {file = "contourpy-1.3.0-cp312-cp312-win32.whl", hash = "sha256:90f73a5116ad1ba7174341ef3ea5c3150ddf20b024b98fb0c3b29034752c8aeb"}, + {file = "contourpy-1.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:b11b39aea6be6764f84360fce6c82211a9db32a7c7de8fa6dd5397cf1d079c3b"}, + {file = "contourpy-1.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3e1c7fa44aaae40a2247e2e8e0627f4bea3dd257014764aa644f319a5f8600e3"}, + {file = "contourpy-1.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:364174c2a76057feef647c802652f00953b575723062560498dc7930fc9b1cb7"}, + {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32b238b3b3b649e09ce9aaf51f0c261d38644bdfa35cbaf7b263457850957a84"}, + {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d51fca85f9f7ad0b65b4b9fe800406d0d77017d7270d31ec3fb1cc07358fdea0"}, + {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:732896af21716b29ab3e988d4ce14bc5133733b85956316fb0c56355f398099b"}, + {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d73f659398a0904e125280836ae6f88ba9b178b2fed6884f3b1f95b989d2c8da"}, + {file = "contourpy-1.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c6c7c2408b7048082932cf4e641fa3b8ca848259212f51c8c59c45aa7ac18f14"}, + {file = "contourpy-1.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f317576606de89da6b7e0861cf6061f6146ead3528acabff9236458a6ba467f8"}, + {file = "contourpy-1.3.0-cp313-cp313-win32.whl", hash = "sha256:31cd3a85dbdf1fc002280c65caa7e2b5f65e4a973fcdf70dd2fdcb9868069294"}, + {file = "contourpy-1.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:4553c421929ec95fb07b3aaca0fae668b2eb5a5203d1217ca7c34c063c53d087"}, + {file = "contourpy-1.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:345af746d7766821d05d72cb8f3845dfd08dd137101a2cb9b24de277d716def8"}, + {file = "contourpy-1.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3bb3808858a9dc68f6f03d319acd5f1b8a337e6cdda197f02f4b8ff67ad2057b"}, + {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:420d39daa61aab1221567b42eecb01112908b2cab7f1b4106a52caaec8d36973"}, + {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4d63ee447261e963af02642ffcb864e5a2ee4cbfd78080657a9880b8b1868e18"}, + {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:167d6c890815e1dac9536dca00828b445d5d0df4d6a8c6adb4a7ec3166812fa8"}, + {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:710a26b3dc80c0e4febf04555de66f5fd17e9cf7170a7b08000601a10570bda6"}, + {file = "contourpy-1.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:75ee7cb1a14c617f34a51d11fa7524173e56551646828353c4af859c56b766e2"}, + {file = "contourpy-1.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:33c92cdae89ec5135d036e7218e69b0bb2851206077251f04a6c4e0e21f03927"}, + {file = "contourpy-1.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a11077e395f67ffc2c44ec2418cfebed032cd6da3022a94fc227b6faf8e2acb8"}, + {file = "contourpy-1.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e8134301d7e204c88ed7ab50028ba06c683000040ede1d617298611f9dc6240c"}, + {file = "contourpy-1.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e12968fdfd5bb45ffdf6192a590bd8ddd3ba9e58360b29683c6bb71a7b41edca"}, + {file = "contourpy-1.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fd2a0fc506eccaaa7595b7e1418951f213cf8255be2600f1ea1b61e46a60c55f"}, + {file = "contourpy-1.3.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4cfb5c62ce023dfc410d6059c936dcf96442ba40814aefbfa575425a3a7f19dc"}, + {file = "contourpy-1.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68a32389b06b82c2fdd68276148d7b9275b5f5cf13e5417e4252f6d1a34f72a2"}, + {file = "contourpy-1.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:94e848a6b83da10898cbf1311a815f770acc9b6a3f2d646f330d57eb4e87592e"}, + {file = "contourpy-1.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:d78ab28a03c854a873787a0a42254a0ccb3cb133c672f645c9f9c8f3ae9d0800"}, + {file = "contourpy-1.3.0-cp39-cp39-win32.whl", hash = "sha256:81cb5ed4952aae6014bc9d0421dec7c5835c9c8c31cdf51910b708f548cf58e5"}, + {file = "contourpy-1.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:14e262f67bd7e6eb6880bc564dcda30b15e351a594657e55b7eec94b6ef72843"}, + {file = "contourpy-1.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:fe41b41505a5a33aeaed2a613dccaeaa74e0e3ead6dd6fd3a118fb471644fd6c"}, + {file = "contourpy-1.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eca7e17a65f72a5133bdbec9ecf22401c62bcf4821361ef7811faee695799779"}, + {file = "contourpy-1.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:1ec4dc6bf570f5b22ed0d7efba0dfa9c5b9e0431aeea7581aa217542d9e809a4"}, + {file = "contourpy-1.3.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:00ccd0dbaad6d804ab259820fa7cb0b8036bda0686ef844d24125d8287178ce0"}, + {file = "contourpy-1.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ca947601224119117f7c19c9cdf6b3ab54c5726ef1d906aa4a69dfb6dd58102"}, + {file = "contourpy-1.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c6ec93afeb848a0845a18989da3beca3eec2c0f852322efe21af1931147d12cb"}, + {file = "contourpy-1.3.0.tar.gz", hash = "sha256:7ffa0db17717a8ffb127efd0c95a4362d996b892c2904db72428d5b52e1938a4"}, ] [package.dependencies] -numpy = ">=1.20" +numpy = ">=1.23" [package.extras] bokeh = ["bokeh", "selenium"] docs = ["furo", "sphinx (>=7.2)", "sphinx-copybutton"] -mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.8.0)", "types-Pillow"] +mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.11.1)", "types-Pillow"] test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] -test-no-images = ["pytest", "pytest-cov", "pytest-xdist", "wurlitzer"] +test-no-images = ["pytest", "pytest-cov", "pytest-rerunfailures", "pytest-xdist", "wurlitzer"] [[package]] name = "coverage" -version = "7.5.1" +version = "7.6.8" description = "Code coverage measurement for Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "coverage-7.5.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c0884920835a033b78d1c73b6d3bbcda8161a900f38a488829a83982925f6c2e"}, - {file = "coverage-7.5.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:39afcd3d4339329c5f58de48a52f6e4e50f6578dd6099961cf22228feb25f38f"}, - {file = "coverage-7.5.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a7b0ceee8147444347da6a66be737c9d78f3353b0681715b668b72e79203e4a"}, - {file = "coverage-7.5.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a9ca3f2fae0088c3c71d743d85404cec8df9be818a005ea065495bedc33da35"}, - {file = "coverage-7.5.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fd215c0c7d7aab005221608a3c2b46f58c0285a819565887ee0b718c052aa4e"}, - {file = "coverage-7.5.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4bf0655ab60d754491004a5efd7f9cccefcc1081a74c9ef2da4735d6ee4a6223"}, - {file = "coverage-7.5.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:61c4bf1ba021817de12b813338c9be9f0ad5b1e781b9b340a6d29fc13e7c1b5e"}, - {file = "coverage-7.5.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:db66fc317a046556a96b453a58eced5024af4582a8dbdc0c23ca4dbc0d5b3146"}, - {file = "coverage-7.5.1-cp310-cp310-win32.whl", hash = "sha256:b016ea6b959d3b9556cb401c55a37547135a587db0115635a443b2ce8f1c7228"}, - {file = "coverage-7.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:df4e745a81c110e7446b1cc8131bf986157770fa405fe90e15e850aaf7619bc8"}, - {file = "coverage-7.5.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:796a79f63eca8814ca3317a1ea443645c9ff0d18b188de470ed7ccd45ae79428"}, - {file = "coverage-7.5.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4fc84a37bfd98db31beae3c2748811a3fa72bf2007ff7902f68746d9757f3746"}, - {file = "coverage-7.5.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6175d1a0559986c6ee3f7fccfc4a90ecd12ba0a383dcc2da30c2b9918d67d8a3"}, - {file = "coverage-7.5.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fc81d5878cd6274ce971e0a3a18a8803c3fe25457165314271cf78e3aae3aa2"}, - {file = "coverage-7.5.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:556cf1a7cbc8028cb60e1ff0be806be2eded2daf8129b8811c63e2b9a6c43bca"}, - {file = "coverage-7.5.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9981706d300c18d8b220995ad22627647be11a4276721c10911e0e9fa44c83e8"}, - {file = "coverage-7.5.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d7fed867ee50edf1a0b4a11e8e5d0895150e572af1cd6d315d557758bfa9c057"}, - {file = "coverage-7.5.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ef48e2707fb320c8f139424a596f5b69955a85b178f15af261bab871873bb987"}, - {file = "coverage-7.5.1-cp311-cp311-win32.whl", hash = "sha256:9314d5678dcc665330df5b69c1e726a0e49b27df0461c08ca12674bcc19ef136"}, - {file = "coverage-7.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:5fa567e99765fe98f4e7d7394ce623e794d7cabb170f2ca2ac5a4174437e90dd"}, - {file = "coverage-7.5.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b6cf3764c030e5338e7f61f95bd21147963cf6aa16e09d2f74f1fa52013c1206"}, - {file = "coverage-7.5.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2ec92012fefebee89a6b9c79bc39051a6cb3891d562b9270ab10ecfdadbc0c34"}, - {file = "coverage-7.5.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16db7f26000a07efcf6aea00316f6ac57e7d9a96501e990a36f40c965ec7a95d"}, - {file = "coverage-7.5.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:beccf7b8a10b09c4ae543582c1319c6df47d78fd732f854ac68d518ee1fb97fa"}, - {file = "coverage-7.5.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8748731ad392d736cc9ccac03c9845b13bb07d020a33423fa5b3a36521ac6e4e"}, - {file = "coverage-7.5.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7352b9161b33fd0b643ccd1f21f3a3908daaddf414f1c6cb9d3a2fd618bf2572"}, - {file = "coverage-7.5.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:7a588d39e0925f6a2bff87154752481273cdb1736270642aeb3635cb9b4cad07"}, - {file = "coverage-7.5.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:68f962d9b72ce69ea8621f57551b2fa9c70509af757ee3b8105d4f51b92b41a7"}, - {file = "coverage-7.5.1-cp312-cp312-win32.whl", hash = "sha256:f152cbf5b88aaeb836127d920dd0f5e7edff5a66f10c079157306c4343d86c19"}, - {file = "coverage-7.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:5a5740d1fb60ddf268a3811bcd353de34eb56dc24e8f52a7f05ee513b2d4f596"}, - {file = "coverage-7.5.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e2213def81a50519d7cc56ed643c9e93e0247f5bbe0d1247d15fa520814a7cd7"}, - {file = "coverage-7.5.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5037f8fcc2a95b1f0e80585bd9d1ec31068a9bcb157d9750a172836e98bc7a90"}, - {file = "coverage-7.5.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c3721c2c9e4c4953a41a26c14f4cef64330392a6d2d675c8b1db3b645e31f0e"}, - {file = "coverage-7.5.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca498687ca46a62ae590253fba634a1fe9836bc56f626852fb2720f334c9e4e5"}, - {file = "coverage-7.5.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0cdcbc320b14c3e5877ee79e649677cb7d89ef588852e9583e6b24c2e5072661"}, - {file = "coverage-7.5.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:57e0204b5b745594e5bc14b9b50006da722827f0b8c776949f1135677e88d0b8"}, - {file = "coverage-7.5.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8fe7502616b67b234482c3ce276ff26f39ffe88adca2acf0261df4b8454668b4"}, - {file = "coverage-7.5.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:9e78295f4144f9dacfed4f92935fbe1780021247c2fabf73a819b17f0ccfff8d"}, - {file = "coverage-7.5.1-cp38-cp38-win32.whl", hash = "sha256:1434e088b41594baa71188a17533083eabf5609e8e72f16ce8c186001e6b8c41"}, - {file = "coverage-7.5.1-cp38-cp38-win_amd64.whl", hash = "sha256:0646599e9b139988b63704d704af8e8df7fa4cbc4a1f33df69d97f36cb0a38de"}, - {file = "coverage-7.5.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4cc37def103a2725bc672f84bd939a6fe4522310503207aae4d56351644682f1"}, - {file = "coverage-7.5.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fc0b4d8bfeabd25ea75e94632f5b6e047eef8adaed0c2161ada1e922e7f7cece"}, - {file = "coverage-7.5.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d0a0f5e06881ecedfe6f3dd2f56dcb057b6dbeb3327fd32d4b12854df36bf26"}, - {file = "coverage-7.5.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9735317685ba6ec7e3754798c8871c2f49aa5e687cc794a0b1d284b2389d1bd5"}, - {file = "coverage-7.5.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d21918e9ef11edf36764b93101e2ae8cc82aa5efdc7c5a4e9c6c35a48496d601"}, - {file = "coverage-7.5.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c3e757949f268364b96ca894b4c342b41dc6f8f8b66c37878aacef5930db61be"}, - {file = "coverage-7.5.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:79afb6197e2f7f60c4824dd4b2d4c2ec5801ceb6ba9ce5d2c3080e5660d51a4f"}, - {file = "coverage-7.5.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d1d0d98d95dd18fe29dc66808e1accf59f037d5716f86a501fc0256455219668"}, - {file = "coverage-7.5.1-cp39-cp39-win32.whl", hash = "sha256:1cc0fe9b0b3a8364093c53b0b4c0c2dd4bb23acbec4c9240b5f284095ccf7981"}, - {file = "coverage-7.5.1-cp39-cp39-win_amd64.whl", hash = "sha256:dde0070c40ea8bb3641e811c1cfbf18e265d024deff6de52c5950677a8fb1e0f"}, - {file = "coverage-7.5.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:6537e7c10cc47c595828b8a8be04c72144725c383c4702703ff4e42e44577312"}, - {file = "coverage-7.5.1.tar.gz", hash = "sha256:54de9ef3a9da981f7af93eafde4ede199e0846cd819eb27c88e2b712aae9708c"}, + {file = "coverage-7.6.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b39e6011cd06822eb964d038d5dff5da5d98652b81f5ecd439277b32361a3a50"}, + {file = "coverage-7.6.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:63c19702db10ad79151a059d2d6336fe0c470f2e18d0d4d1a57f7f9713875dcf"}, + {file = "coverage-7.6.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3985b9be361d8fb6b2d1adc9924d01dec575a1d7453a14cccd73225cb79243ee"}, + {file = "coverage-7.6.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:644ec81edec0f4ad17d51c838a7d01e42811054543b76d4ba2c5d6af741ce2a6"}, + {file = "coverage-7.6.8-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f188a2402f8359cf0c4b1fe89eea40dc13b52e7b4fd4812450da9fcd210181d"}, + {file = "coverage-7.6.8-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e19122296822deafce89a0c5e8685704c067ae65d45e79718c92df7b3ec3d331"}, + {file = "coverage-7.6.8-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:13618bed0c38acc418896005732e565b317aa9e98d855a0e9f211a7ffc2d6638"}, + {file = "coverage-7.6.8-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:193e3bffca48ad74b8c764fb4492dd875038a2f9925530cb094db92bb5e47bed"}, + {file = "coverage-7.6.8-cp310-cp310-win32.whl", hash = "sha256:3988665ee376abce49613701336544041f2117de7b7fbfe91b93d8ff8b151c8e"}, + {file = "coverage-7.6.8-cp310-cp310-win_amd64.whl", hash = "sha256:f56f49b2553d7dd85fd86e029515a221e5c1f8cb3d9c38b470bc38bde7b8445a"}, + {file = "coverage-7.6.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:86cffe9c6dfcfe22e28027069725c7f57f4b868a3f86e81d1c62462764dc46d4"}, + {file = "coverage-7.6.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d82ab6816c3277dc962cfcdc85b1efa0e5f50fb2c449432deaf2398a2928ab94"}, + {file = "coverage-7.6.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13690e923a3932e4fad4c0ebfb9cb5988e03d9dcb4c5150b5fcbf58fd8bddfc4"}, + {file = "coverage-7.6.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4be32da0c3827ac9132bb488d331cb32e8d9638dd41a0557c5569d57cf22c9c1"}, + {file = "coverage-7.6.8-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44e6c85bbdc809383b509d732b06419fb4544dca29ebe18480379633623baafb"}, + {file = "coverage-7.6.8-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:768939f7c4353c0fac2f7c37897e10b1414b571fd85dd9fc49e6a87e37a2e0d8"}, + {file = "coverage-7.6.8-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e44961e36cb13c495806d4cac67640ac2866cb99044e210895b506c26ee63d3a"}, + {file = "coverage-7.6.8-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3ea8bb1ab9558374c0ab591783808511d135a833c3ca64a18ec927f20c4030f0"}, + {file = "coverage-7.6.8-cp311-cp311-win32.whl", hash = "sha256:629a1ba2115dce8bf75a5cce9f2486ae483cb89c0145795603d6554bdc83e801"}, + {file = "coverage-7.6.8-cp311-cp311-win_amd64.whl", hash = "sha256:fb9fc32399dca861584d96eccd6c980b69bbcd7c228d06fb74fe53e007aa8ef9"}, + {file = "coverage-7.6.8-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e683e6ecc587643f8cde8f5da6768e9d165cd31edf39ee90ed7034f9ca0eefee"}, + {file = "coverage-7.6.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1defe91d41ce1bd44b40fabf071e6a01a5aa14de4a31b986aa9dfd1b3e3e414a"}, + {file = "coverage-7.6.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7ad66e8e50225ebf4236368cc43c37f59d5e6728f15f6e258c8639fa0dd8e6d"}, + {file = "coverage-7.6.8-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3fe47da3e4fda5f1abb5709c156eca207eacf8007304ce3019eb001e7a7204cb"}, + {file = "coverage-7.6.8-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:202a2d645c5a46b84992f55b0a3affe4f0ba6b4c611abec32ee88358db4bb649"}, + {file = "coverage-7.6.8-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4674f0daa1823c295845b6a740d98a840d7a1c11df00d1fd62614545c1583787"}, + {file = "coverage-7.6.8-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:74610105ebd6f33d7c10f8907afed696e79c59e3043c5f20eaa3a46fddf33b4c"}, + {file = "coverage-7.6.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:37cda8712145917105e07aab96388ae76e787270ec04bcb9d5cc786d7cbb8443"}, + {file = "coverage-7.6.8-cp312-cp312-win32.whl", hash = "sha256:9e89d5c8509fbd6c03d0dd1972925b22f50db0792ce06324ba069f10787429ad"}, + {file = "coverage-7.6.8-cp312-cp312-win_amd64.whl", hash = "sha256:379c111d3558272a2cae3d8e57e6b6e6f4fe652905692d54bad5ea0ca37c5ad4"}, + {file = "coverage-7.6.8-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0b0c69f4f724c64dfbfe79f5dfb503b42fe6127b8d479b2677f2b227478db2eb"}, + {file = "coverage-7.6.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c15b32a7aca8038ed7644f854bf17b663bc38e1671b5d6f43f9a2b2bd0c46f63"}, + {file = "coverage-7.6.8-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63068a11171e4276f6ece913bde059e77c713b48c3a848814a6537f35afb8365"}, + {file = "coverage-7.6.8-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f4548c5ead23ad13fb7a2c8ea541357474ec13c2b736feb02e19a3085fac002"}, + {file = "coverage-7.6.8-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b4b4299dd0d2c67caaaf286d58aef5e75b125b95615dda4542561a5a566a1e3"}, + {file = "coverage-7.6.8-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c9ebfb2507751f7196995142f057d1324afdab56db1d9743aab7f50289abd022"}, + {file = "coverage-7.6.8-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c1b4474beee02ede1eef86c25ad4600a424fe36cff01a6103cb4533c6bf0169e"}, + {file = "coverage-7.6.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d9fd2547e6decdbf985d579cf3fc78e4c1d662b9b0ff7cc7862baaab71c9cc5b"}, + {file = "coverage-7.6.8-cp313-cp313-win32.whl", hash = "sha256:8aae5aea53cbfe024919715eca696b1a3201886ce83790537d1c3668459c7146"}, + {file = "coverage-7.6.8-cp313-cp313-win_amd64.whl", hash = "sha256:ae270e79f7e169ccfe23284ff5ea2d52a6f401dc01b337efb54b3783e2ce3f28"}, + {file = "coverage-7.6.8-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:de38add67a0af869b0d79c525d3e4588ac1ffa92f39116dbe0ed9753f26eba7d"}, + {file = "coverage-7.6.8-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b07c25d52b1c16ce5de088046cd2432b30f9ad5e224ff17c8f496d9cb7d1d451"}, + {file = "coverage-7.6.8-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62a66ff235e4c2e37ed3b6104d8b478d767ff73838d1222132a7a026aa548764"}, + {file = "coverage-7.6.8-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09b9f848b28081e7b975a3626e9081574a7b9196cde26604540582da60235fdf"}, + {file = "coverage-7.6.8-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:093896e530c38c8e9c996901858ac63f3d4171268db2c9c8b373a228f459bbc5"}, + {file = "coverage-7.6.8-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9a7b8ac36fd688c8361cbc7bf1cb5866977ece6e0b17c34aa0df58bda4fa18a4"}, + {file = "coverage-7.6.8-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:38c51297b35b3ed91670e1e4efb702b790002e3245a28c76e627478aa3c10d83"}, + {file = "coverage-7.6.8-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2e4e0f60cb4bd7396108823548e82fdab72d4d8a65e58e2c19bbbc2f1e2bfa4b"}, + {file = "coverage-7.6.8-cp313-cp313t-win32.whl", hash = "sha256:6535d996f6537ecb298b4e287a855f37deaf64ff007162ec0afb9ab8ba3b8b71"}, + {file = "coverage-7.6.8-cp313-cp313t-win_amd64.whl", hash = "sha256:c79c0685f142ca53256722a384540832420dff4ab15fec1863d7e5bc8691bdcc"}, + {file = "coverage-7.6.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3ac47fa29d8d41059ea3df65bd3ade92f97ee4910ed638e87075b8e8ce69599e"}, + {file = "coverage-7.6.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:24eda3a24a38157eee639ca9afe45eefa8d2420d49468819ac5f88b10de84f4c"}, + {file = "coverage-7.6.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4c81ed2820b9023a9a90717020315e63b17b18c274a332e3b6437d7ff70abe0"}, + {file = "coverage-7.6.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bd55f8fc8fa494958772a2a7302b0354ab16e0b9272b3c3d83cdb5bec5bd1779"}, + {file = "coverage-7.6.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f39e2f3530ed1626c66e7493be7a8423b023ca852aacdc91fb30162c350d2a92"}, + {file = "coverage-7.6.8-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:716a78a342679cd1177bc8c2fe957e0ab91405bd43a17094324845200b2fddf4"}, + {file = "coverage-7.6.8-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:177f01eeaa3aee4a5ffb0d1439c5952b53d5010f86e9d2667963e632e30082cc"}, + {file = "coverage-7.6.8-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:912e95017ff51dc3d7b6e2be158dedc889d9a5cc3382445589ce554f1a34c0ea"}, + {file = "coverage-7.6.8-cp39-cp39-win32.whl", hash = "sha256:4db3ed6a907b555e57cc2e6f14dc3a4c2458cdad8919e40b5357ab9b6db6c43e"}, + {file = "coverage-7.6.8-cp39-cp39-win_amd64.whl", hash = "sha256:428ac484592f780e8cd7b6b14eb568f7c85460c92e2a37cb0c0e5186e1a0d076"}, + {file = "coverage-7.6.8-pp39.pp310-none-any.whl", hash = "sha256:5c52a036535d12590c32c49209e79cabaad9f9ad8aa4cbd875b68c4d67a9cbce"}, + {file = "coverage-7.6.8.tar.gz", hash = "sha256:8b2b8503edb06822c86d82fa64a4a5cb0760bb8f31f26e138ec743f422f37cfc"}, ] [package.dependencies] @@ -708,43 +748,38 @@ toml = ["tomli"] [[package]] name = "cryptography" -version = "42.0.7" +version = "43.0.3" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = ">=3.7" files = [ - {file = "cryptography-42.0.7-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:a987f840718078212fdf4504d0fd4c6effe34a7e4740378e59d47696e8dfb477"}, - {file = "cryptography-42.0.7-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:bd13b5e9b543532453de08bcdc3cc7cebec6f9883e886fd20a92f26940fd3e7a"}, - {file = "cryptography-42.0.7-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a79165431551042cc9d1d90e6145d5d0d3ab0f2d66326c201d9b0e7f5bf43604"}, - {file = "cryptography-42.0.7-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a47787a5e3649008a1102d3df55424e86606c9bae6fb77ac59afe06d234605f8"}, - {file = "cryptography-42.0.7-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:02c0eee2d7133bdbbc5e24441258d5d2244beb31da5ed19fbb80315f4bbbff55"}, - {file = "cryptography-42.0.7-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:5e44507bf8d14b36b8389b226665d597bc0f18ea035d75b4e53c7b1ea84583cc"}, - {file = "cryptography-42.0.7-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:7f8b25fa616d8b846aef64b15c606bb0828dbc35faf90566eb139aa9cff67af2"}, - {file = "cryptography-42.0.7-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:93a3209f6bb2b33e725ed08ee0991b92976dfdcf4e8b38646540674fc7508e13"}, - {file = "cryptography-42.0.7-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e6b8f1881dac458c34778d0a424ae5769de30544fc678eac51c1c8bb2183e9da"}, - {file = "cryptography-42.0.7-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3de9a45d3b2b7d8088c3fbf1ed4395dfeff79d07842217b38df14ef09ce1d8d7"}, - {file = "cryptography-42.0.7-cp37-abi3-win32.whl", hash = "sha256:789caea816c6704f63f6241a519bfa347f72fbd67ba28d04636b7c6b7da94b0b"}, - {file = "cryptography-42.0.7-cp37-abi3-win_amd64.whl", hash = "sha256:8cb8ce7c3347fcf9446f201dc30e2d5a3c898d009126010cbd1f443f28b52678"}, - {file = "cryptography-42.0.7-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:a3a5ac8b56fe37f3125e5b72b61dcde43283e5370827f5233893d461b7360cd4"}, - {file = "cryptography-42.0.7-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:779245e13b9a6638df14641d029add5dc17edbef6ec915688f3acb9e720a5858"}, - {file = "cryptography-42.0.7-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d563795db98b4cd57742a78a288cdbdc9daedac29f2239793071fe114f13785"}, - {file = "cryptography-42.0.7-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:31adb7d06fe4383226c3e963471f6837742889b3c4caa55aac20ad951bc8ffda"}, - {file = "cryptography-42.0.7-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:efd0bf5205240182e0f13bcaea41be4fdf5c22c5129fc7ced4a0282ac86998c9"}, - {file = "cryptography-42.0.7-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a9bc127cdc4ecf87a5ea22a2556cab6c7eda2923f84e4f3cc588e8470ce4e42e"}, - {file = "cryptography-42.0.7-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:3577d029bc3f4827dd5bf8bf7710cac13527b470bbf1820a3f394adb38ed7d5f"}, - {file = "cryptography-42.0.7-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2e47577f9b18723fa294b0ea9a17d5e53a227867a0a4904a1a076d1646d45ca1"}, - {file = "cryptography-42.0.7-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1a58839984d9cb34c855197043eaae2c187d930ca6d644612843b4fe8513c886"}, - {file = "cryptography-42.0.7-cp39-abi3-win32.whl", hash = "sha256:e6b79d0adb01aae87e8a44c2b64bc3f3fe59515280e00fb6d57a7267a2583cda"}, - {file = "cryptography-42.0.7-cp39-abi3-win_amd64.whl", hash = "sha256:16268d46086bb8ad5bf0a2b5544d8a9ed87a0e33f5e77dd3c3301e63d941a83b"}, - {file = "cryptography-42.0.7-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2954fccea107026512b15afb4aa664a5640cd0af630e2ee3962f2602693f0c82"}, - {file = "cryptography-42.0.7-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:362e7197754c231797ec45ee081f3088a27a47c6c01eff2ac83f60f85a50fe60"}, - {file = "cryptography-42.0.7-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4f698edacf9c9e0371112792558d2f705b5645076cc0aaae02f816a0171770fd"}, - {file = "cryptography-42.0.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5482e789294854c28237bba77c4c83be698be740e31a3ae5e879ee5444166582"}, - {file = "cryptography-42.0.7-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e9b2a6309f14c0497f348d08a065d52f3020656f675819fc405fb63bbcd26562"}, - {file = "cryptography-42.0.7-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d8e3098721b84392ee45af2dd554c947c32cc52f862b6a3ae982dbb90f577f14"}, - {file = "cryptography-42.0.7-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c65f96dad14f8528a447414125e1fc8feb2ad5a272b8f68477abbcc1ea7d94b9"}, - {file = "cryptography-42.0.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:36017400817987670037fbb0324d71489b6ead6231c9604f8fc1f7d008087c68"}, - {file = "cryptography-42.0.7.tar.gz", hash = "sha256:ecbfbc00bf55888edda9868a4cf927205de8499e7fabe6c050322298382953f2"}, + {file = "cryptography-43.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18"}, + {file = "cryptography-43.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd"}, + {file = "cryptography-43.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73"}, + {file = "cryptography-43.0.3-cp37-abi3-win32.whl", hash = "sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2"}, + {file = "cryptography-43.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd"}, + {file = "cryptography-43.0.3-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405"}, + {file = "cryptography-43.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16"}, + {file = "cryptography-43.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73"}, + {file = "cryptography-43.0.3-cp39-abi3-win32.whl", hash = "sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995"}, + {file = "cryptography-43.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d03b5621a135bffecad2c73e9f4deb1a0f977b9a8ffe6f8e002bf6c9d07b918c"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a2a431ee15799d6db9fe80c82b055bae5a752bef645bba795e8e52687c69efe3"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:281c945d0e28c92ca5e5930664c1cefd85efe80e5c0d2bc58dd63383fda29f83"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f18c716be16bc1fea8e95def49edf46b82fccaa88587a45f8dc0ff6ab5d8e0a7"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4a02ded6cd4f0a5562a8887df8b3bd14e822a90f97ac5e544c162899bc467664"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:53a583b6637ab4c4e3591a15bc9db855b8d9dee9a669b550f311480acab6eb08"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1ec0bcf7e17c0c5669d881b1cd38c4972fade441b27bda1051665faaa89bdcaa"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2ce6fae5bdad59577b44e4dfed356944fbf1d925269114c28be377692643b4ff"}, + {file = "cryptography-43.0.3.tar.gz", hash = "sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805"}, ] [package.dependencies] @@ -757,7 +792,7 @@ nox = ["nox"] pep8test = ["check-sdist", "click", "mypy", "ruff"] sdist = ["build"] ssh = ["bcrypt (>=3.1.5)"] -test = ["certifi", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test = ["certifi", "cryptography-vectors (==43.0.3)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] test-randomorder = ["pytest-randomly"] [[package]] @@ -777,127 +812,143 @@ tests = ["pytest", "pytest-cov", "pytest-xdist"] [[package]] name = "cython" -version = "3.0.10" +version = "3.0.11" description = "The Cython compiler for writing C extensions in the Python language." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" files = [ - {file = "Cython-3.0.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e876272548d73583e90babda94c1299537006cad7a34e515a06c51b41f8657aa"}, - {file = "Cython-3.0.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:adc377aa33c3309191e617bf675fdbb51ca727acb9dc1aa23fc698d8121f7e23"}, - {file = "Cython-3.0.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:401aba1869a57aba2922ccb656a6320447e55ace42709b504c2f8e8b166f46e1"}, - {file = "Cython-3.0.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:541fbe725d6534a90b93f8c577eb70924d664b227a4631b90a6e0506d1469591"}, - {file = "Cython-3.0.10-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:86998b01f6a6d48398df8467292c7637e57f7e3a2ca68655367f13f66fed7734"}, - {file = "Cython-3.0.10-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d092c0ddba7e9e530a5c5be4ac06db8360258acc27675d1fc86294a5dc8994c5"}, - {file = "Cython-3.0.10-cp310-cp310-win32.whl", hash = "sha256:3cffb666e649dba23810732497442fb339ee67ba4e0be1f0579991e83fcc2436"}, - {file = "Cython-3.0.10-cp310-cp310-win_amd64.whl", hash = "sha256:9ea31184c7b3a728ef1f81fccb161d8948c05aa86c79f63b74fb6f3ddec860ec"}, - {file = "Cython-3.0.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:051069638abfb076900b0c2bcb6facf545655b3f429e80dd14365192074af5a4"}, - {file = "Cython-3.0.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:712760879600907189c7d0d346851525545484e13cd8b787e94bfd293da8ccf0"}, - {file = "Cython-3.0.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38d40fa1324ac47c04483d151f5e092406a147eac88a18aec789cf01c089c3f2"}, - {file = "Cython-3.0.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5bd49a3a9fdff65446a3e1c2bfc0ec85c6ce4c3cad27cd4ad7ba150a62b7fb59"}, - {file = "Cython-3.0.10-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e8df79b596633b8295eaa48b1157d796775c2bb078f32267d32f3001b687f2fd"}, - {file = "Cython-3.0.10-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bcc9795990e525c192bc5c0775e441d7d56d7a7d02210451e9e13c0448dba51b"}, - {file = "Cython-3.0.10-cp311-cp311-win32.whl", hash = "sha256:09f2000041db482cad3bfce94e1fa3a4c82b0e57390a164c02566cbbda8c4f12"}, - {file = "Cython-3.0.10-cp311-cp311-win_amd64.whl", hash = "sha256:3919a55ec9b6c7db6f68a004c21c05ed540c40dbe459ced5d801d5a1f326a053"}, - {file = "Cython-3.0.10-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:8f2864ab5fcd27a346f0b50f901ebeb8f60b25a60a575ccfd982e7f3e9674914"}, - {file = "Cython-3.0.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:407840c56385b9c085826fe300213e0e76ba15d1d47daf4b58569078ecb94446"}, - {file = "Cython-3.0.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a036d00caa73550a3a976432ef21c1e3fa12637e1616aab32caded35331ae96"}, - {file = "Cython-3.0.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9cc6a0e7e23a96dec3f3c9d39690d4281beabd5297855140d0d30855f950275e"}, - {file = "Cython-3.0.10-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a5e14a8c6a8157d2b0cdc2e8e3444905d20a0e78e19d2a097e89fb8b04b51f6b"}, - {file = "Cython-3.0.10-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f8a2b8fa0fd8358bccb5f3304be563c4750aae175100463d212d5ea0ec74cbe0"}, - {file = "Cython-3.0.10-cp312-cp312-win32.whl", hash = "sha256:2d29e617fd23cf4b83afe8f93f2966566c9f565918ad1e86a4502fe825cc0a79"}, - {file = "Cython-3.0.10-cp312-cp312-win_amd64.whl", hash = "sha256:6c5af936940a38c300977b81598d9c0901158f220a58c177820e17e1774f1cf1"}, - {file = "Cython-3.0.10-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:5f465443917d5c0f69825fca3b52b64c74ac3de0143b1fff6db8ba5b48c9fb4a"}, - {file = "Cython-3.0.10-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4fadb84193c25641973666e583df8df4e27c52cdc05ddce7c6f6510d690ba34a"}, - {file = "Cython-3.0.10-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fa9e7786083b6aa61594c16979d621b62e61fcd9c2edd4761641b95c7fb34b2"}, - {file = "Cython-3.0.10-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f4780d0f98ce28191c4d841c4358b5d5e79d96520650910cd59904123821c52d"}, - {file = "Cython-3.0.10-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:32fbad02d1189be75eb96456d9c73f5548078e5338d8fa153ecb0115b6ee279f"}, - {file = "Cython-3.0.10-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:90e2f514fc753b55245351305a399463103ec18666150bb1c36779b9862388e9"}, - {file = "Cython-3.0.10-cp36-cp36m-win32.whl", hash = "sha256:a9c976e9ec429539a4367cb4b24d15a1e46b925976f4341143f49f5f161171f5"}, - {file = "Cython-3.0.10-cp36-cp36m-win_amd64.whl", hash = "sha256:a9bb402674788a7f4061aeef8057632ec440123e74ed0fb425308a59afdfa10e"}, - {file = "Cython-3.0.10-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:206e803598010ecc3813db8748ed685f7beeca6c413f982df9f8a505fce56563"}, - {file = "Cython-3.0.10-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15b6d397f4ee5ad54e373589522af37935a32863f1b23fa8c6922adf833e28e2"}, - {file = "Cython-3.0.10-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a181144c2f893ed8e6a994d43d0b96300bc99873f21e3b7334ca26c61c37b680"}, - {file = "Cython-3.0.10-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b74b700d6a793113d03fb54b63bdbadba6365379424bac7c0470605672769260"}, - {file = "Cython-3.0.10-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:076e9fd4e0ca33c5fa00a7479180dbfb62f17fe928e2909f82da814536e96d2b"}, - {file = "Cython-3.0.10-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:269f06e6961e8591d56e30b46e1a51b6ccb42cab04c29fa3b30d3e8723485fb4"}, - {file = "Cython-3.0.10-cp37-cp37m-win32.whl", hash = "sha256:d4e83a8ceff7af60064da4ccfce0ac82372544dd5392f1b350c34f1b04d0fae6"}, - {file = "Cython-3.0.10-cp37-cp37m-win_amd64.whl", hash = "sha256:40fac59c3a7fbcd9c25aea64c342c890a5e2270ce64a1525e840807800167799"}, - {file = "Cython-3.0.10-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f43a58bf2434870d2fc42ac2e9ff8138c9e00c6251468de279d93fa279e9ba3b"}, - {file = "Cython-3.0.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e9a885ec63d3955a08cefc4eec39fefa9fe14989c6e5e2382bd4aeb6bdb9bc3"}, - {file = "Cython-3.0.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acfbe0fff364d54906058fc61f2393f38cd7fa07d344d80923937b87e339adcf"}, - {file = "Cython-3.0.10-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8adcde00a8a88fab27509b558cd8c2959ab0c70c65d3814cfea8c68b83fa6dcd"}, - {file = "Cython-3.0.10-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2c9c1e3e78909488f3b16fabae02308423fa6369ed96ab1e250807d344cfffd7"}, - {file = "Cython-3.0.10-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fc6e0faf5b57523b073f0cdefadcaef3a51235d519a0594865925cadb3aeadf0"}, - {file = "Cython-3.0.10-cp38-cp38-win32.whl", hash = "sha256:35f6ede7c74024ed1982832ae61c9fad7cf60cc3f5b8c6a63bb34e38bc291936"}, - {file = "Cython-3.0.10-cp38-cp38-win_amd64.whl", hash = "sha256:950c0c7b770d2a7cec74fb6f5ccc321d0b51d151f48c075c0d0db635a60ba1b5"}, - {file = "Cython-3.0.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:077b61ee789e48700e25d4a16daa4258b8e65167136e457174df400cf9b4feab"}, - {file = "Cython-3.0.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64f1f8bba9d8f37c0cffc934792b4ac7c42d0891077127c11deebe9fa0a0f7e4"}, - {file = "Cython-3.0.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:651a15a8534ebfb9b58cb0b87c269c70984b6f9c88bfe65e4f635f0e3f07dfcd"}, - {file = "Cython-3.0.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d10fc9aa82e5e53a0b7fd118f9771199cddac8feb4a6d8350b7d4109085aa775"}, - {file = "Cython-3.0.10-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4f610964ab252a83e573a427e28b103e2f1dd3c23bee54f32319f9e73c3c5499"}, - {file = "Cython-3.0.10-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8c9c4c4f3ab8f8c02817b0e16e8fa7b8cc880f76e9b63fe9c010e60c1a6c2b13"}, - {file = "Cython-3.0.10-cp39-cp39-win32.whl", hash = "sha256:0bac3ccdd4e03924028220c62ae3529e17efa8ca7e9df9330de95de02f582b26"}, - {file = "Cython-3.0.10-cp39-cp39-win_amd64.whl", hash = "sha256:81f356c1c8c0885b8435bfc468025f545c5d764aa9c75ab662616dd1193c331e"}, - {file = "Cython-3.0.10-py2.py3-none-any.whl", hash = "sha256:fcbb679c0b43514d591577fd0d20021c55c240ca9ccafbdb82d3fb95e5edfee2"}, - {file = "Cython-3.0.10.tar.gz", hash = "sha256:dcc96739331fb854dcf503f94607576cfe8488066c61ca50dfd55836f132de99"}, + {file = "Cython-3.0.11-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:44292aae17524abb4b70a25111fe7dec1a0ad718711d47e3786a211d5408fdaa"}, + {file = "Cython-3.0.11-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a75d45fbc20651c1b72e4111149fed3b33d270b0a4fb78328c54d965f28d55e1"}, + {file = "Cython-3.0.11-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d89a82937ce4037f092e9848a7bbcc65bc8e9fc9aef2bb74f5c15e7d21a73080"}, + {file = "Cython-3.0.11-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a8ea2e7e2d3bc0d8630dafe6c4a5a89485598ff8a61885b74f8ed882597efd5"}, + {file = "Cython-3.0.11-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cee29846471ce60226b18e931d8c1c66a158db94853e3e79bc2da9bd22345008"}, + {file = "Cython-3.0.11-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:eeb6860b0f4bfa402de8929833fe5370fa34069c7ebacb2d543cb017f21fb891"}, + {file = "Cython-3.0.11-cp310-cp310-win32.whl", hash = "sha256:3699391125ab344d8d25438074d1097d9ba0fb674d0320599316cfe7cf5f002a"}, + {file = "Cython-3.0.11-cp310-cp310-win_amd64.whl", hash = "sha256:d02f4ebe15aac7cdacce1a628e556c1983f26d140fd2e0ac5e0a090e605a2d38"}, + {file = "Cython-3.0.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:75ba1c70b6deeaffbac123856b8d35f253da13552207aa969078611c197377e4"}, + {file = "Cython-3.0.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af91497dc098718e634d6ec8f91b182aea6bb3690f333fc9a7777bc70abe8810"}, + {file = "Cython-3.0.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3999fb52d3328a6a5e8c63122b0a8bd110dfcdb98dda585a3def1426b991cba7"}, + {file = "Cython-3.0.11-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d566a4e09b8979be8ab9f843bac0dd216c81f5e5f45661a9b25cd162ed80508c"}, + {file = "Cython-3.0.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:46aec30f217bdf096175a1a639203d44ac73a36fe7fa3dd06bd012e8f39eca0f"}, + {file = "Cython-3.0.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ddd1fe25af330f4e003421636746a546474e4ccd8f239f55d2898d80983d20ed"}, + {file = "Cython-3.0.11-cp311-cp311-win32.whl", hash = "sha256:221de0b48bf387f209003508e602ce839a80463522fc6f583ad3c8d5c890d2c1"}, + {file = "Cython-3.0.11-cp311-cp311-win_amd64.whl", hash = "sha256:3ff8ac1f0ecd4f505db4ab051e58e4531f5d098b6ac03b91c3b902e8d10c67b3"}, + {file = "Cython-3.0.11-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:11996c40c32abf843ba652a6d53cb15944c88d91f91fc4e6f0028f5df8a8f8a1"}, + {file = "Cython-3.0.11-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63f2c892e9f9c1698ecfee78205541623eb31cd3a1b682668be7ac12de94aa8e"}, + {file = "Cython-3.0.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b14c24f1dc4c4c9d997cca8d1b7fb01187a218aab932328247dcf5694a10102"}, + {file = "Cython-3.0.11-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c8eed5c015685106db15dd103fd040948ddca9197b1dd02222711815ea782a27"}, + {file = "Cython-3.0.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:780f89c95b8aec1e403005b3bf2f0a2afa060b3eba168c86830f079339adad89"}, + {file = "Cython-3.0.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a690f2ff460682ea985e8d38ec541be97e0977fa0544aadc21efc116ff8d7579"}, + {file = "Cython-3.0.11-cp312-cp312-win32.whl", hash = "sha256:2252b5aa57621848e310fe7fa6f7dce5f73aa452884a183d201a8bcebfa05a00"}, + {file = "Cython-3.0.11-cp312-cp312-win_amd64.whl", hash = "sha256:da394654c6da15c1d37f0b7ec5afd325c69a15ceafee2afba14b67a5df8a82c8"}, + {file = "Cython-3.0.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4341d6a64d47112884e0bcf31e6c075268220ee4cd02223047182d4dda94d637"}, + {file = "Cython-3.0.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:351955559b37e6c98b48aecb178894c311be9d731b297782f2b78d111f0c9015"}, + {file = "Cython-3.0.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c02361af9bfa10ff1ccf967fc75159e56b1c8093caf565739ed77a559c1f29f"}, + {file = "Cython-3.0.11-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6823aef13669a32caf18bbb036de56065c485d9f558551a9b55061acf9c4c27f"}, + {file = "Cython-3.0.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6fb68cef33684f8cc97987bee6ae919eee7e18ee6a3ad7ed9516b8386ef95ae6"}, + {file = "Cython-3.0.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:790263b74432cb997740d73665f4d8d00b9cd1cecbdd981d93591ddf993d4f12"}, + {file = "Cython-3.0.11-cp313-cp313-win32.whl", hash = "sha256:e6dd395d1a704e34a9fac00b25f0036dce6654c6b898be6f872ac2bb4f2eda48"}, + {file = "Cython-3.0.11-cp313-cp313-win_amd64.whl", hash = "sha256:52186101d51497519e99b60d955fd5cb3bf747c67f00d742e70ab913f1e42d31"}, + {file = "Cython-3.0.11-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c69d5cad51388522b98a99b4be1b77316de85b0c0523fa865e0ea58bbb622e0a"}, + {file = "Cython-3.0.11-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8acdc87e9009110adbceb7569765eb0980129055cc954c62f99fe9f094c9505e"}, + {file = "Cython-3.0.11-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1dd47865f4c0a224da73acf83d113f93488d17624e2457dce1753acdfb1cc40c"}, + {file = "Cython-3.0.11-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:301bde949b4f312a1c70e214b0c3bc51a3f955d466010d2f68eb042df36447b0"}, + {file = "Cython-3.0.11-cp36-cp36m-musllinux_1_2_aarch64.whl", hash = "sha256:f3953d2f504176f929862e5579cfc421860c33e9707f585d70d24e1096accdf7"}, + {file = "Cython-3.0.11-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:3f2b062f6df67e8a56c75e500ca330cf62c85ac26dd7fd006f07ef0f83aebfa3"}, + {file = "Cython-3.0.11-cp36-cp36m-win32.whl", hash = "sha256:c3d68751668c66c7a140b6023dba5d5d507f72063407bb609d3a5b0f3b8dfbe4"}, + {file = "Cython-3.0.11-cp36-cp36m-win_amd64.whl", hash = "sha256:bcd29945fafd12484cf37b1d84f12f0e7a33ba3eac5836531c6bd5283a6b3a0c"}, + {file = "Cython-3.0.11-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4e9a8d92978b15a0c7ca7f98447c6c578dc8923a0941d9d172d0b077cb69c576"}, + {file = "Cython-3.0.11-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:421017466e9260aca86823974e26e158e6358622f27c0f4da9c682f3b6d2e624"}, + {file = "Cython-3.0.11-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d80a7232938d523c1a12f6b1794ab5efb1ae77ad3fde79de4bb558d8ab261619"}, + {file = "Cython-3.0.11-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfa550d9ae39e827a6e7198076df763571cb53397084974a6948af558355e028"}, + {file = "Cython-3.0.11-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:aedceb6090a60854b31bf9571dc55f642a3fa5b91f11b62bcef167c52cac93d8"}, + {file = "Cython-3.0.11-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:473d35681d9f93ce380e6a7c8feb2d65fc6333bd7117fbc62989e404e241dbb0"}, + {file = "Cython-3.0.11-cp37-cp37m-win32.whl", hash = "sha256:3379c6521e25aa6cd7703bb7d635eaca75c0f9c7f1b0fdd6dd15a03bfac5f68d"}, + {file = "Cython-3.0.11-cp37-cp37m-win_amd64.whl", hash = "sha256:14701edb3107a5d9305a82d9d646c4f28bfecbba74b26cc1ee2f4be08f602057"}, + {file = "Cython-3.0.11-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:598699165cfa7c6d69513ee1bffc9e1fdd63b00b624409174c388538aa217975"}, + {file = "Cython-3.0.11-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0583076c4152b417a3a8a5d81ec02f58c09b67d3f22d5857e64c8734ceada8c"}, + {file = "Cython-3.0.11-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52205347e916dd65d2400b977df4c697390c3aae0e96275a438cc4ae85dadc08"}, + {file = "Cython-3.0.11-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:989899a85f0d9a57cebb508bd1f194cb52f0e3f7e22ac259f33d148d6422375c"}, + {file = "Cython-3.0.11-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:53b6072a89049a991d07f42060f65398448365c59c9cb515c5925b9bdc9d71f8"}, + {file = "Cython-3.0.11-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:f988f7f8164a6079c705c39e2d75dbe9967e3dacafe041420d9af7b9ee424162"}, + {file = "Cython-3.0.11-cp38-cp38-win32.whl", hash = "sha256:a1f4cbc70f6b7f0c939522118820e708e0d490edca42d852fa8004ec16780be2"}, + {file = "Cython-3.0.11-cp38-cp38-win_amd64.whl", hash = "sha256:187685e25e037320cae513b8cc4bf9dbc4465c037051aede509cbbf207524de2"}, + {file = "Cython-3.0.11-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0fc6fdd6fa493be7bdda22355689d5446ac944cd71286f6f44a14b0d67ee3ff5"}, + {file = "Cython-3.0.11-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b1d1f6f94cc5d42a4591f6d60d616786b9cd15576b112bc92a23131fcf38020"}, + {file = "Cython-3.0.11-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4ab2b92a3e6ed552adbe9350fd2ef3aa0cc7853cf91569f9dbed0c0699bbeab"}, + {file = "Cython-3.0.11-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:104d6f2f2c827ccc5e9e42c80ef6773a6aa94752fe6bc5b24a4eab4306fb7f07"}, + {file = "Cython-3.0.11-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:13062ce556a1e98d2821f7a0253b50569fdc98c36efd6653a65b21e3f8bbbf5f"}, + {file = "Cython-3.0.11-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:525d09b3405534763fa73bd78c8e51ac8264036ce4c16d37dfd1555a7da6d3a7"}, + {file = "Cython-3.0.11-cp39-cp39-win32.whl", hash = "sha256:b8c7e514075696ca0f60c337f9e416e61d7ccbc1aa879a56c39181ed90ec3059"}, + {file = "Cython-3.0.11-cp39-cp39-win_amd64.whl", hash = "sha256:8948802e1f5677a673ea5d22a1e7e273ca5f83e7a452786ca286eebf97cee67c"}, + {file = "Cython-3.0.11-py2.py3-none-any.whl", hash = "sha256:0e25f6425ad4a700d7f77cd468da9161e63658837d1bc34861a9861a4ef6346d"}, + {file = "cython-3.0.11.tar.gz", hash = "sha256:7146dd2af8682b4ca61331851e6aebce9fe5158e75300343f80c07ca80b1faff"}, ] [[package]] name = "dearpygui" -version = "1.11.1" +version = "2.0.0" description = "DearPyGui: A simple Python GUI Toolkit" optional = true -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "dearpygui-1.11.1-cp310-cp310-macosx_10_6_x86_64.whl", hash = "sha256:b668f28aab63d8ad0b2768add4e689bedb7480e8c3390edcce7a0f5d296fd61f"}, - {file = "dearpygui-1.11.1-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:39d099b1ca97fd7d36934a5187fc4cd868d4772e504290a70fc95eda03c5125d"}, - {file = "dearpygui-1.11.1-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:3ba12334d993b653df2d07fe34c93c4ec65e54c022066ba245cd596a18b43a68"}, - {file = "dearpygui-1.11.1-cp310-cp310-win_amd64.whl", hash = "sha256:6cf4c44db1f016ff3eab367f7bde7f169bad5f2f90b974c202808112a69a2b15"}, - {file = "dearpygui-1.11.1-cp311-cp311-macosx_10_6_x86_64.whl", hash = "sha256:cc15cd13c1aeae2847ed9c4b2201169add3efdedf564eb706f5b5896ddaa5d8a"}, - {file = "dearpygui-1.11.1-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:9eb7d581863d39543b213252041ed25856acbfa58c57291e6acb6ccbf0c2727b"}, - {file = "dearpygui-1.11.1-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:564ff3af657f7becd059b6611e162cc9cd8148befaf8aadb10e4fb76d57df3ef"}, - {file = "dearpygui-1.11.1-cp311-cp311-win_amd64.whl", hash = "sha256:ac6e9bde61dcb3cc253da59e70fe2b743d3c3b5791d415eaa8d307f4517048ca"}, - {file = "dearpygui-1.11.1-cp312-cp312-macosx_10_6_x86_64.whl", hash = "sha256:ccf576117ed2159cd66b419458d060923c9dcebe7fe57c65b4f4c4889287845d"}, - {file = "dearpygui-1.11.1-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:1d632e1acdaa986a8c32b57112b84685b92d9a41f18580e14d463d7ed7a52673"}, - {file = "dearpygui-1.11.1-cp312-cp312-manylinux1_x86_64.whl", hash = "sha256:ca4f7ba667f64ee682dfcb3399d9d43df6821b2d962b96b4fa4535de5776f538"}, - {file = "dearpygui-1.11.1-cp312-cp312-win_amd64.whl", hash = "sha256:8ce9881a629de72e05ca8b1ce7cefcdd77b624eb7eba6f7d6629848d84a797f6"}, - {file = "dearpygui-1.11.1-cp38-cp38-macosx_10_6_x86_64.whl", hash = "sha256:39011ccb3a3ecfe3ebccfd8c4211c2c1446abd2865cbe4ccb67dc50a7a812bfb"}, - {file = "dearpygui-1.11.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:e1dde63d20ac062530debee001ad649190a7e09622762601454c4191799f13b8"}, - {file = "dearpygui-1.11.1-cp38-cp38-win_amd64.whl", hash = "sha256:23ce7ce8e5ba24d31bd6468cc43b56f8f257ace4dce3bc5fe449c546c340893a"}, - {file = "dearpygui-1.11.1-cp39-cp39-macosx_10_6_x86_64.whl", hash = "sha256:d22285f9a5f1377d87effd1f27020eec3ae0386f7c15a4893809909b82c62b1b"}, - {file = "dearpygui-1.11.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f632bd94772e00313d0956bb9f9822c3ebcb7aa93f135f09e2fa187f3b06cea8"}, - {file = "dearpygui-1.11.1-cp39-cp39-win_amd64.whl", hash = "sha256:0c7c4849bc674e825750be69ee480450c3589c7d159955032776aaef5e7fda58"}, + {file = "dearpygui-2.0.0-cp310-cp310-macosx_10_6_x86_64.whl", hash = "sha256:6126eec4217de6dfbe0aef4b96a0f4b385f85dab538ee806d51c5f9a5ba77c6b"}, + {file = "dearpygui-2.0.0-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:340ddc3884740aabcddf696f984c1ff2a06b91050bf5030ab264dc9908f1329a"}, + {file = "dearpygui-2.0.0-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:68f749fcd36ffc9cef399fb64b0dab5a4075c63574150a163208f8204f778859"}, + {file = "dearpygui-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:d287233603338a811b59da0af8194ff7cd7b8da768c1d056fe17b6d8a7b36a6f"}, + {file = "dearpygui-2.0.0-cp311-cp311-macosx_10_6_x86_64.whl", hash = "sha256:ee81dd58b06161b5098e11fce5514f621f1fe7670c63711a4397cb1bc108dfe5"}, + {file = "dearpygui-2.0.0-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:5802886d4c44362764882b9339a0dbe85f9b445a98560f791acb164febc4df32"}, + {file = "dearpygui-2.0.0-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:8d5049aa54835a51cc304752a0831ad71a6ca05ee7a33e0b82f7e7e8c8ecda21"}, + {file = "dearpygui-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:73643b3528dd4b03cb22ad64afe960dc8ddd3023f211fd405eabb861fc4dd129"}, + {file = "dearpygui-2.0.0-cp312-cp312-macosx_10_6_x86_64.whl", hash = "sha256:f0383d74f628ae4622863afff84ab262c9f5163a769836eb470c7243dc9ced0c"}, + {file = "dearpygui-2.0.0-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:52c32da6911881564b6cbd95e110d6956095f7a417d2e0c12dcda8274c4fbe72"}, + {file = "dearpygui-2.0.0-cp312-cp312-manylinux1_x86_64.whl", hash = "sha256:d27f7e64a282c7f0c1387003ec3b247b2c3c1583aea9427283633ad508aa2da6"}, + {file = "dearpygui-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:29881d01e5d0cce0980a8d8b9761c74ff2f30d16aa800e6002a244bbc894b34e"}, + {file = "dearpygui-2.0.0-cp313-cp313-macosx_10_6_x86_64.whl", hash = "sha256:3bf0aa19baedb4f130b8de636d4644740ffd9b7008481794c574bf59240808dc"}, + {file = "dearpygui-2.0.0-cp313-cp313-macosx_13_0_arm64.whl", hash = "sha256:ae6fc9aa3390b29387c2bc2bf3ac7a92c10eae2b479818171864fc29a7de344e"}, + {file = "dearpygui-2.0.0-cp313-cp313-manylinux1_x86_64.whl", hash = "sha256:f02b0ab56700a775d7e6446e3c424d5bed3386efe721a04518d02461851daadf"}, + {file = "dearpygui-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:e3d52057f49773b10808962806711c3b3119e829d36407afb84ad50522edc9b0"}, + {file = "dearpygui-2.0.0-cp38-cp38-macosx_10_6_x86_64.whl", hash = "sha256:3aaa549d7e9b4b9e591cd785f9cdbe3650fea724ee099f774e066ad97c374c55"}, + {file = "dearpygui-2.0.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:400b0a209674dfaf3e223b5465838e1d9fd25102203eed81518ff842f9caf7f1"}, + {file = "dearpygui-2.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:52cabe531449804b35e1ac36e48e1cf9b784b1c1752395dabf95df8d607fc2d8"}, + {file = "dearpygui-2.0.0-cp39-cp39-macosx_10_6_x86_64.whl", hash = "sha256:751f58355631924b17b543db1c366d69ca056f050556952c23e051ebd1a8ac76"}, + {file = "dearpygui-2.0.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:9a3f0562d47e664c044bcb75868d7f3cc22456866f32f6b4bad22e377d4eef3a"}, + {file = "dearpygui-2.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:ffe10b14f836cea82881fb9f66e464877429ce3ff2fbc3e33d239881cd52bada"}, ] [[package]] name = "debugpy" -version = "1.8.1" +version = "1.8.9" description = "An implementation of the Debug Adapter Protocol for Python" optional = true python-versions = ">=3.8" files = [ - {file = "debugpy-1.8.1-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:3bda0f1e943d386cc7a0e71bfa59f4137909e2ed947fb3946c506e113000f741"}, - {file = "debugpy-1.8.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dda73bf69ea479c8577a0448f8c707691152e6c4de7f0c4dec5a4bc11dee516e"}, - {file = "debugpy-1.8.1-cp310-cp310-win32.whl", hash = "sha256:3a79c6f62adef994b2dbe9fc2cc9cc3864a23575b6e387339ab739873bea53d0"}, - {file = "debugpy-1.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:7eb7bd2b56ea3bedb009616d9e2f64aab8fc7000d481faec3cd26c98a964bcdd"}, - {file = "debugpy-1.8.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:016a9fcfc2c6b57f939673c874310d8581d51a0fe0858e7fac4e240c5eb743cb"}, - {file = "debugpy-1.8.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd97ed11a4c7f6d042d320ce03d83b20c3fb40da892f994bc041bbc415d7a099"}, - {file = "debugpy-1.8.1-cp311-cp311-win32.whl", hash = "sha256:0de56aba8249c28a300bdb0672a9b94785074eb82eb672db66c8144fff673146"}, - {file = "debugpy-1.8.1-cp311-cp311-win_amd64.whl", hash = "sha256:1a9fe0829c2b854757b4fd0a338d93bc17249a3bf69ecf765c61d4c522bb92a8"}, - {file = "debugpy-1.8.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3ebb70ba1a6524d19fa7bb122f44b74170c447d5746a503e36adc244a20ac539"}, - {file = "debugpy-1.8.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2e658a9630f27534e63922ebf655a6ab60c370f4d2fc5c02a5b19baf4410ace"}, - {file = "debugpy-1.8.1-cp312-cp312-win32.whl", hash = "sha256:caad2846e21188797a1f17fc09c31b84c7c3c23baf2516fed5b40b378515bbf0"}, - {file = "debugpy-1.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:edcc9f58ec0fd121a25bc950d4578df47428d72e1a0d66c07403b04eb93bcf98"}, - {file = "debugpy-1.8.1-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:7a3afa222f6fd3d9dfecd52729bc2e12c93e22a7491405a0ecbf9e1d32d45b39"}, - {file = "debugpy-1.8.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d915a18f0597ef685e88bb35e5d7ab968964b7befefe1aaea1eb5b2640b586c7"}, - {file = "debugpy-1.8.1-cp38-cp38-win32.whl", hash = "sha256:92116039b5500633cc8d44ecc187abe2dfa9b90f7a82bbf81d079fcdd506bae9"}, - {file = "debugpy-1.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:e38beb7992b5afd9d5244e96ad5fa9135e94993b0c551ceebf3fe1a5d9beb234"}, - {file = "debugpy-1.8.1-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:bfb20cb57486c8e4793d41996652e5a6a885b4d9175dd369045dad59eaacea42"}, - {file = "debugpy-1.8.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efd3fdd3f67a7e576dd869c184c5dd71d9aaa36ded271939da352880c012e703"}, - {file = "debugpy-1.8.1-cp39-cp39-win32.whl", hash = "sha256:58911e8521ca0c785ac7a0539f1e77e0ce2df753f786188f382229278b4cdf23"}, - {file = "debugpy-1.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:6df9aa9599eb05ca179fb0b810282255202a66835c6efb1d112d21ecb830ddd3"}, - {file = "debugpy-1.8.1-py2.py3-none-any.whl", hash = "sha256:28acbe2241222b87e255260c76741e1fbf04fdc3b6d094fcf57b6c6f75ce1242"}, - {file = "debugpy-1.8.1.zip", hash = "sha256:f696d6be15be87aef621917585f9bb94b1dc9e8aced570db1b8a6fc14e8f9b42"}, + {file = "debugpy-1.8.9-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:cfe1e6c6ad7178265f74981edf1154ffce97b69005212fbc90ca22ddfe3d017e"}, + {file = "debugpy-1.8.9-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ada7fb65102a4d2c9ab62e8908e9e9f12aed9d76ef44880367bc9308ebe49a0f"}, + {file = "debugpy-1.8.9-cp310-cp310-win32.whl", hash = "sha256:c36856343cbaa448171cba62a721531e10e7ffb0abff838004701454149bc037"}, + {file = "debugpy-1.8.9-cp310-cp310-win_amd64.whl", hash = "sha256:17c5e0297678442511cf00a745c9709e928ea4ca263d764e90d233208889a19e"}, + {file = "debugpy-1.8.9-cp311-cp311-macosx_14_0_universal2.whl", hash = "sha256:b74a49753e21e33e7cf030883a92fa607bddc4ede1aa4145172debc637780040"}, + {file = "debugpy-1.8.9-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62d22dacdb0e296966d7d74a7141aaab4bec123fa43d1a35ddcb39bf9fd29d70"}, + {file = "debugpy-1.8.9-cp311-cp311-win32.whl", hash = "sha256:8138efff315cd09b8dcd14226a21afda4ca582284bf4215126d87342bba1cc66"}, + {file = "debugpy-1.8.9-cp311-cp311-win_amd64.whl", hash = "sha256:ff54ef77ad9f5c425398efb150239f6fe8e20c53ae2f68367eba7ece1e96226d"}, + {file = "debugpy-1.8.9-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:957363d9a7a6612a37458d9a15e72d03a635047f946e5fceee74b50d52a9c8e2"}, + {file = "debugpy-1.8.9-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e565fc54b680292b418bb809f1386f17081d1346dca9a871bf69a8ac4071afe"}, + {file = "debugpy-1.8.9-cp312-cp312-win32.whl", hash = "sha256:3e59842d6c4569c65ceb3751075ff8d7e6a6ada209ceca6308c9bde932bcef11"}, + {file = "debugpy-1.8.9-cp312-cp312-win_amd64.whl", hash = "sha256:66eeae42f3137eb428ea3a86d4a55f28da9bd5a4a3d369ba95ecc3a92c1bba53"}, + {file = "debugpy-1.8.9-cp313-cp313-macosx_14_0_universal2.whl", hash = "sha256:957ecffff80d47cafa9b6545de9e016ae8c9547c98a538ee96ab5947115fb3dd"}, + {file = "debugpy-1.8.9-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1efbb3ff61487e2c16b3e033bc8595aea578222c08aaf3c4bf0f93fadbd662ee"}, + {file = "debugpy-1.8.9-cp313-cp313-win32.whl", hash = "sha256:7c4d65d03bee875bcb211c76c1d8f10f600c305dbd734beaed4077e902606fee"}, + {file = "debugpy-1.8.9-cp313-cp313-win_amd64.whl", hash = "sha256:e46b420dc1bea64e5bbedd678148be512442bc589b0111bd799367cde051e71a"}, + {file = "debugpy-1.8.9-cp38-cp38-macosx_14_0_x86_64.whl", hash = "sha256:472a3994999fe6c0756945ffa359e9e7e2d690fb55d251639d07208dbc37caea"}, + {file = "debugpy-1.8.9-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:365e556a4772d7d0d151d7eb0e77ec4db03bcd95f26b67b15742b88cacff88e9"}, + {file = "debugpy-1.8.9-cp38-cp38-win32.whl", hash = "sha256:54a7e6d3014c408eb37b0b06021366ee985f1539e12fe49ca2ee0d392d9ceca5"}, + {file = "debugpy-1.8.9-cp38-cp38-win_amd64.whl", hash = "sha256:8e99c0b1cc7bf86d83fb95d5ccdc4ad0586d4432d489d1f54e4055bcc795f693"}, + {file = "debugpy-1.8.9-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:7e8b079323a56f719977fde9d8115590cb5e7a1cba2fcee0986ef8817116e7c1"}, + {file = "debugpy-1.8.9-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6953b335b804a41f16a192fa2e7851bdcfd92173cbb2f9f777bb934f49baab65"}, + {file = "debugpy-1.8.9-cp39-cp39-win32.whl", hash = "sha256:7e646e62d4602bb8956db88b1e72fe63172148c1e25c041e03b103a25f36673c"}, + {file = "debugpy-1.8.9-cp39-cp39-win_amd64.whl", hash = "sha256:3d9755e77a2d680ce3d2c5394a444cf42be4a592caaf246dbfbdd100ffcf7ae5"}, + {file = "debugpy-1.8.9-py2.py3-none-any.whl", hash = "sha256:cc37a6c9987ad743d9c3a14fa1b1a14b7e4e6041f9dd0c8abf8895fe7a97b899"}, + {file = "debugpy-1.8.9.zip", hash = "sha256:1339e14c7d980407248f09824d1b25ff5c5616651689f1e0f0e51bdead3ea13e"}, ] [[package]] @@ -924,30 +975,30 @@ files = [ [[package]] name = "deprecated" -version = "1.2.14" +version = "1.2.15" description = "Python @deprecated decorator to deprecate old python classes, functions or methods." optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" files = [ - {file = "Deprecated-1.2.14-py2.py3-none-any.whl", hash = "sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c"}, - {file = "Deprecated-1.2.14.tar.gz", hash = "sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3"}, + {file = "Deprecated-1.2.15-py2.py3-none-any.whl", hash = "sha256:353bc4a8ac4bfc96800ddab349d89c25dec1079f65fd53acdcc1e0b975b21320"}, + {file = "deprecated-1.2.15.tar.gz", hash = "sha256:683e561a90de76239796e6b6feac66b99030d2dd3fcf61ef996330f14bbb9b0d"}, ] [package.dependencies] wrapt = ">=1.10,<2" [package.extras] -dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "sphinx (<2)", "tox"] +dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "jinja2 (>=3.0.3,<3.1.0)", "setuptools", "sphinx (<2)", "tox"] [[package]] name = "distlib" -version = "0.3.8" +version = "0.3.9" description = "Distribution utilities" optional = false python-versions = "*" files = [ - {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, - {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, + {file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"}, + {file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"}, ] [[package]] @@ -963,13 +1014,13 @@ files = [ [[package]] name = "exceptiongroup" -version = "1.2.1" +version = "1.2.2" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"}, - {file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"}, + {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, + {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, ] [package.extras] @@ -991,13 +1042,13 @@ testing = ["hatch", "pre-commit", "pytest", "tox"] [[package]] name = "executing" -version = "2.0.1" +version = "2.1.0" description = "Get the currently executing AST node of a frame, and other information" optional = true -python-versions = ">=3.5" +python-versions = ">=3.8" files = [ - {file = "executing-2.0.1-py2.py3-none-any.whl", hash = "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc"}, - {file = "executing-2.0.1.tar.gz", hash = "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147"}, + {file = "executing-2.1.0-py2.py3-none-any.whl", hash = "sha256:8d63781349375b5ebccc3142f4b30350c0cd9c79f921cde38be2be4637e98eaf"}, + {file = "executing-2.1.0.tar.gz", hash = "sha256:8ea27ddd260da8150fa5a708269c4a10e76161e2496ec3e587da9e3c0fe4b9ab"}, ] [package.extras] @@ -1005,13 +1056,13 @@ tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipyth [[package]] name = "fastjsonschema" -version = "2.19.1" +version = "2.21.1" description = "Fastest Python implementation of JSON schema" optional = true python-versions = "*" files = [ - {file = "fastjsonschema-2.19.1-py3-none-any.whl", hash = "sha256:3672b47bc94178c9f23dbb654bf47440155d4db9df5f7bc47643315f9c405cd0"}, - {file = "fastjsonschema-2.19.1.tar.gz", hash = "sha256:e3126a94bdc4623d3de4485f8d468a12f02a67921315ddc87836d6e456dc789d"}, + {file = "fastjsonschema-2.21.1-py3-none-any.whl", hash = "sha256:c9e5b7e908310918cf494a434eeb31384dd84a98b57a30bcb1f535015b554667"}, + {file = "fastjsonschema-2.21.1.tar.gz", hash = "sha256:794d4f0a58f848961ba16af7b9c85a3e88cd360df008c59aac6fc5ae9323b5d4"}, ] [package.extras] @@ -1019,208 +1070,77 @@ devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benc [[package]] name = "filelock" -version = "3.14.0" +version = "3.16.1" description = "A platform independent file lock." optional = false python-versions = ">=3.8" files = [ - {file = "filelock-3.14.0-py3-none-any.whl", hash = "sha256:43339835842f110ca7ae60f1e1c160714c5a6afd15a2873419ab185334975c0f"}, - {file = "filelock-3.14.0.tar.gz", hash = "sha256:6ea72da3be9b8c82afd3edcf99f2fffbb5076335a5ae4d03248bb5b6c3eae78a"}, -] - -[package.extras] -docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] -typing = ["typing-extensions (>=4.8)"] - -[[package]] -name = "flake8" -version = "6.1.0" -description = "the modular source code checker: pep8 pyflakes and co" -optional = false -python-versions = ">=3.8.1" -files = [ - {file = "flake8-6.1.0-py2.py3-none-any.whl", hash = "sha256:ffdfce58ea94c6580c77888a86506937f9a1a227dfcd15f245d694ae20a6b6e5"}, - {file = "flake8-6.1.0.tar.gz", hash = "sha256:d5b3857f07c030bdb5bf41c7f53799571d75c4491748a3adcd47de929e34cd23"}, -] - -[package.dependencies] -mccabe = ">=0.7.0,<0.8.0" -pycodestyle = ">=2.11.0,<2.12.0" -pyflakes = ">=3.1.0,<3.2.0" - -[[package]] -name = "flake8-bugbear" -version = "23.12.2" -description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle." -optional = false -python-versions = ">=3.8.1" -files = [ - {file = "flake8-bugbear-23.12.2.tar.gz", hash = "sha256:32b2903e22331ae04885dae25756a32a8c666c85142e933f43512a70f342052a"}, - {file = "flake8_bugbear-23.12.2-py3-none-any.whl", hash = "sha256:83324bad4d90fee4bf64dd69c61aff94debf8073fbd807c8b6a36eec7a2f0719"}, -] - -[package.dependencies] -attrs = ">=19.2.0" -flake8 = ">=6.0.0" - -[package.extras] -dev = ["coverage", "hypothesis", "hypothesmith (>=0.2)", "pre-commit", "pytest", "tox"] - -[[package]] -name = "flake8-builtins" -version = "2.5.0" -description = "Check for python builtins being used as variables or parameters" -optional = false -python-versions = ">=3.8" -files = [ - {file = "flake8_builtins-2.5.0-py3-none-any.whl", hash = "sha256:8cac7c52c6f0708c0902b46b385bc7e368a9068965083796f1431c0d2e6550cf"}, - {file = "flake8_builtins-2.5.0.tar.gz", hash = "sha256:bdaa3dd823e4f5308c5e712d19fa5f69daa52781ea874f5ea9c3637bcf56faa6"}, -] - -[package.dependencies] -flake8 = "*" - -[package.extras] -test = ["pytest"] - -[[package]] -name = "flake8-comprehensions" -version = "3.14.0" -description = "A flake8 plugin to help you write better list/set/dict comprehensions." -optional = false -python-versions = ">=3.8" -files = [ - {file = "flake8_comprehensions-3.14.0-py3-none-any.whl", hash = "sha256:7b9d07d94aa88e62099a6d1931ddf16c344d4157deedf90fe0d8ee2846f30e97"}, - {file = "flake8_comprehensions-3.14.0.tar.gz", hash = "sha256:81768c61bfc064e1a06222df08a2580d97de10cb388694becaf987c331c6c0cf"}, -] - -[package.dependencies] -flake8 = ">=3.0,<3.2.0 || >3.2.0" - -[[package]] -name = "flake8-docstrings" -version = "1.7.0" -description = "Extension for flake8 which uses pydocstyle to check docstrings" -optional = false -python-versions = ">=3.7" -files = [ - {file = "flake8_docstrings-1.7.0-py2.py3-none-any.whl", hash = "sha256:51f2344026da083fc084166a9353f5082b01f72901df422f74b4d953ae88ac75"}, - {file = "flake8_docstrings-1.7.0.tar.gz", hash = "sha256:4c8cc748dc16e6869728699e5d0d685da9a10b0ea718e090b1ba088e67a941af"}, -] - -[package.dependencies] -flake8 = ">=3" -pydocstyle = ">=2.1" - -[[package]] -name = "flake8-plugin-utils" -version = "1.3.3" -description = "The package provides base classes and utils for flake8 plugin writing" -optional = false -python-versions = ">=3.6,<4.0" -files = [ - {file = "flake8-plugin-utils-1.3.3.tar.gz", hash = "sha256:39f6f338d038b301c6fd344b06f2e81e382b68fa03c0560dff0d9b1791a11a2c"}, - {file = "flake8_plugin_utils-1.3.3-py3-none-any.whl", hash = "sha256:e4848c57d9d50f19100c2d75fa794b72df068666a9041b4b0409be923356a3ed"}, -] - -[[package]] -name = "flake8-pytest-style" -version = "1.7.2" -description = "A flake8 plugin checking common style issues or inconsistencies with pytest-based tests." -optional = false -python-versions = ">=3.7.2,<4.0.0" -files = [ - {file = "flake8_pytest_style-1.7.2-py3-none-any.whl", hash = "sha256:f5d2aa3219163a052dd92226589d45fab8ea027a3269922f0c4029f548ea5cd1"}, - {file = "flake8_pytest_style-1.7.2.tar.gz", hash = "sha256:b924197c99b951315949920b0e5547f34900b1844348432e67a44ab191582109"}, -] - -[package.dependencies] -flake8-plugin-utils = ">=1.3.2,<2.0.0" - -[[package]] -name = "flake8-rst-docstrings" -version = "0.3.0" -description = "Python docstring reStructuredText (RST) validator for flake8" -optional = false -python-versions = ">=3.7" -files = [ - {file = "flake8-rst-docstrings-0.3.0.tar.gz", hash = "sha256:d1ce22b4bd37b73cd86b8d980e946ef198cfcc18ed82fedb674ceaa2f8d1afa4"}, - {file = "flake8_rst_docstrings-0.3.0-py3-none-any.whl", hash = "sha256:f8c3c6892ff402292651c31983a38da082480ad3ba253743de52989bdc84ca1c"}, + {file = "filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0"}, + {file = "filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435"}, ] -[package.dependencies] -flake8 = ">=3" -pygments = "*" -restructuredtext-lint = "*" - [package.extras] -develop = ["build", "twine"] - -[[package]] -name = "flake8-simplify" -version = "0.14.6" -description = "flake8 plugin which checks for code that can be simplified" -optional = false -python-versions = ">=3.6.1" -files = [ - {file = "flake8_simplify-0.14.6-py3-none-any.whl", hash = "sha256:8831fb8ff46dee1018d0b4c29f043a010cffafce7309fca536fde8461b98b6f6"}, - {file = "flake8_simplify-0.14.6.tar.gz", hash = "sha256:c4008db8016707684a1f0502ee69f3c2da37687d3cf7031cc1f326bf5986bf47"}, -] - -[package.dependencies] -astor = ">=0.1" -flake8 = ">=3.7" +docs = ["furo (>=2024.8.6)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4.1)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "diff-cover (>=9.2)", "pytest (>=8.3.3)", "pytest-asyncio (>=0.24)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.26.4)"] +typing = ["typing-extensions (>=4.12.2)"] [[package]] name = "fonttools" -version = "4.51.0" +version = "4.55.1" description = "Tools to manipulate font files" optional = false python-versions = ">=3.8" files = [ - {file = "fonttools-4.51.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:84d7751f4468dd8cdd03ddada18b8b0857a5beec80bce9f435742abc9a851a74"}, - {file = "fonttools-4.51.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8b4850fa2ef2cfbc1d1f689bc159ef0f45d8d83298c1425838095bf53ef46308"}, - {file = "fonttools-4.51.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5b48a1121117047d82695d276c2af2ee3a24ffe0f502ed581acc2673ecf1037"}, - {file = "fonttools-4.51.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:180194c7fe60c989bb627d7ed5011f2bef1c4d36ecf3ec64daec8302f1ae0716"}, - {file = "fonttools-4.51.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:96a48e137c36be55e68845fc4284533bda2980f8d6f835e26bca79d7e2006438"}, - {file = "fonttools-4.51.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:806e7912c32a657fa39d2d6eb1d3012d35f841387c8fc6cf349ed70b7c340039"}, - {file = "fonttools-4.51.0-cp310-cp310-win32.whl", hash = "sha256:32b17504696f605e9e960647c5f64b35704782a502cc26a37b800b4d69ff3c77"}, - {file = "fonttools-4.51.0-cp310-cp310-win_amd64.whl", hash = "sha256:c7e91abdfae1b5c9e3a543f48ce96013f9a08c6c9668f1e6be0beabf0a569c1b"}, - {file = "fonttools-4.51.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a8feca65bab31479d795b0d16c9a9852902e3a3c0630678efb0b2b7941ea9c74"}, - {file = "fonttools-4.51.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8ac27f436e8af7779f0bb4d5425aa3535270494d3bc5459ed27de3f03151e4c2"}, - {file = "fonttools-4.51.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e19bd9e9964a09cd2433a4b100ca7f34e34731e0758e13ba9a1ed6e5468cc0f"}, - {file = "fonttools-4.51.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2b92381f37b39ba2fc98c3a45a9d6383bfc9916a87d66ccb6553f7bdd129097"}, - {file = "fonttools-4.51.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5f6bc991d1610f5c3bbe997b0233cbc234b8e82fa99fc0b2932dc1ca5e5afec0"}, - {file = "fonttools-4.51.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9696fe9f3f0c32e9a321d5268208a7cc9205a52f99b89479d1b035ed54c923f1"}, - {file = "fonttools-4.51.0-cp311-cp311-win32.whl", hash = "sha256:3bee3f3bd9fa1d5ee616ccfd13b27ca605c2b4270e45715bd2883e9504735034"}, - {file = "fonttools-4.51.0-cp311-cp311-win_amd64.whl", hash = "sha256:0f08c901d3866a8905363619e3741c33f0a83a680d92a9f0e575985c2634fcc1"}, - {file = "fonttools-4.51.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:4060acc2bfa2d8e98117828a238889f13b6f69d59f4f2d5857eece5277b829ba"}, - {file = "fonttools-4.51.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1250e818b5f8a679ad79660855528120a8f0288f8f30ec88b83db51515411fcc"}, - {file = "fonttools-4.51.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76f1777d8b3386479ffb4a282e74318e730014d86ce60f016908d9801af9ca2a"}, - {file = "fonttools-4.51.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b5ad456813d93b9c4b7ee55302208db2b45324315129d85275c01f5cb7e61a2"}, - {file = "fonttools-4.51.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:68b3fb7775a923be73e739f92f7e8a72725fd333eab24834041365d2278c3671"}, - {file = "fonttools-4.51.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8e2f1a4499e3b5ee82c19b5ee57f0294673125c65b0a1ff3764ea1f9db2f9ef5"}, - {file = "fonttools-4.51.0-cp312-cp312-win32.whl", hash = "sha256:278e50f6b003c6aed19bae2242b364e575bcb16304b53f2b64f6551b9c000e15"}, - {file = "fonttools-4.51.0-cp312-cp312-win_amd64.whl", hash = "sha256:b3c61423f22165541b9403ee39874dcae84cd57a9078b82e1dce8cb06b07fa2e"}, - {file = "fonttools-4.51.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:1621ee57da887c17312acc4b0e7ac30d3a4fb0fec6174b2e3754a74c26bbed1e"}, - {file = "fonttools-4.51.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e9d9298be7a05bb4801f558522adbe2feea1b0b103d5294ebf24a92dd49b78e5"}, - {file = "fonttools-4.51.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee1af4be1c5afe4c96ca23badd368d8dc75f611887fb0c0dac9f71ee5d6f110e"}, - {file = "fonttools-4.51.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c18b49adc721a7d0b8dfe7c3130c89b8704baf599fb396396d07d4aa69b824a1"}, - {file = "fonttools-4.51.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:de7c29bdbdd35811f14493ffd2534b88f0ce1b9065316433b22d63ca1cd21f14"}, - {file = "fonttools-4.51.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:cadf4e12a608ef1d13e039864f484c8a968840afa0258b0b843a0556497ea9ed"}, - {file = "fonttools-4.51.0-cp38-cp38-win32.whl", hash = "sha256:aefa011207ed36cd280babfaa8510b8176f1a77261833e895a9d96e57e44802f"}, - {file = "fonttools-4.51.0-cp38-cp38-win_amd64.whl", hash = "sha256:865a58b6e60b0938874af0968cd0553bcd88e0b2cb6e588727117bd099eef836"}, - {file = "fonttools-4.51.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:60a3409c9112aec02d5fb546f557bca6efa773dcb32ac147c6baf5f742e6258b"}, - {file = "fonttools-4.51.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f7e89853d8bea103c8e3514b9f9dc86b5b4120afb4583b57eb10dfa5afbe0936"}, - {file = "fonttools-4.51.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56fc244f2585d6c00b9bcc59e6593e646cf095a96fe68d62cd4da53dd1287b55"}, - {file = "fonttools-4.51.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d145976194a5242fdd22df18a1b451481a88071feadf251221af110ca8f00ce"}, - {file = "fonttools-4.51.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c5b8cab0c137ca229433570151b5c1fc6af212680b58b15abd797dcdd9dd5051"}, - {file = "fonttools-4.51.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:54dcf21a2f2d06ded676e3c3f9f74b2bafded3a8ff12f0983160b13e9f2fb4a7"}, - {file = "fonttools-4.51.0-cp39-cp39-win32.whl", hash = "sha256:0118ef998a0699a96c7b28457f15546815015a2710a1b23a7bf6c1be60c01636"}, - {file = "fonttools-4.51.0-cp39-cp39-win_amd64.whl", hash = "sha256:599bdb75e220241cedc6faebfafedd7670335d2e29620d207dd0378a4e9ccc5a"}, - {file = "fonttools-4.51.0-py3-none-any.whl", hash = "sha256:15c94eeef6b095831067f72c825eb0e2d48bb4cea0647c1b05c981ecba2bf39f"}, - {file = "fonttools-4.51.0.tar.gz", hash = "sha256:dc0673361331566d7a663d7ce0f6fdcbfbdc1f59c6e3ed1165ad7202ca183c68"}, + {file = "fonttools-4.55.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c17a6f9814f83772cd6d9c9009928e1afa4ab66210a31ced721556651075a9a0"}, + {file = "fonttools-4.55.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c4d14eecc814826a01db87a40af3407c892ba49996bc6e49961e386cd78b537c"}, + {file = "fonttools-4.55.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8589f9a15dc005592b94ecdc45b4dfae9bbe9e73542e89af5a5e776e745db83b"}, + {file = "fonttools-4.55.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfee95bd9395bcd9e6c78955387554335109b6a613db71ef006020b42f761c58"}, + {file = "fonttools-4.55.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:34fa2ecc0bf1923d1a51bf2216a006de2c3c0db02c6aa1470ea50b62b8619bd5"}, + {file = "fonttools-4.55.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9c1c48483148bfb1b9ad951133ceea957faa004f6cb475b67e7bc75d482b48f8"}, + {file = "fonttools-4.55.1-cp310-cp310-win32.whl", hash = "sha256:3e2fc388ca7d023b3c45badd71016fd4185f93e51a22cfe4bd65378af7fba759"}, + {file = "fonttools-4.55.1-cp310-cp310-win_amd64.whl", hash = "sha256:c4c36c71f69d2b3ee30394b0986e5f8b2c461e7eff48dde49b08a90ded9fcdbd"}, + {file = "fonttools-4.55.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5daab3a55d460577f45bb8f5a8eca01fa6cde43ef2ab943b527991f54b735c41"}, + {file = "fonttools-4.55.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:acf1e80cf96c2fbc79e46f669d8713a9a79faaebcc68e31a9fbe600cf8027992"}, + {file = "fonttools-4.55.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e88a0329f7f88a210f09f79c088fb64f8032fc3ab65e2390a40b7d3a11773026"}, + {file = "fonttools-4.55.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03105b42259a8a94b2f0cbf1bee45f7a8a34e7b26c946a8fb89b4967e44091a8"}, + {file = "fonttools-4.55.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9af3577e821649879ab5774ad0e060af34816af556c77c6d3820345d12bf415e"}, + {file = "fonttools-4.55.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:34bd5de3d0ad085359b79a96575cd6bd1bc2976320ef24a2aa152ead36dbf656"}, + {file = "fonttools-4.55.1-cp311-cp311-win32.whl", hash = "sha256:5da92c4b637f0155a41f345fa81143c8e17425260fcb21521cb2ad4d2cea2a95"}, + {file = "fonttools-4.55.1-cp311-cp311-win_amd64.whl", hash = "sha256:f70234253d15f844e6da1178f019a931f03181463ce0c7b19648b8c370527b07"}, + {file = "fonttools-4.55.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9c372e527d58ba64b695f15f8014e97bc8826cf64d3380fc89b4196edd3c0fa8"}, + {file = "fonttools-4.55.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:845a967d3bef3245ba81fb5582dc731f6c2c8417fa211f1068c56893504bc000"}, + {file = "fonttools-4.55.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f03be82bcd4ba4418adf10e6165743f824bb09d6594c2743d7f93ea50968805b"}, + {file = "fonttools-4.55.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c42e935cf146f826f556d977660dac88f2fa3fb2efa27d5636c0b89a60c16edf"}, + {file = "fonttools-4.55.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:96328bf91e05621d8e40d9f854af7a262cb0e8313e9b38e7f3a7f3c4c0caaa8b"}, + {file = "fonttools-4.55.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:291acec4d774e8cd2d8472d88c04643a77a3324a15247951bd6cfc969799b69e"}, + {file = "fonttools-4.55.1-cp312-cp312-win32.whl", hash = "sha256:6d768d6632809aec1c3fa8f195b173386d85602334701a6894a601a4d3c80368"}, + {file = "fonttools-4.55.1-cp312-cp312-win_amd64.whl", hash = "sha256:2a3850afdb0be1f79a1e95340a2059226511675c5b68098d4e49bfbeb48a8aab"}, + {file = "fonttools-4.55.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:0c88d427eaf8bd8497b9051f56e0f5f9fb96a311aa7c72cda35e03e18d59cd16"}, + {file = "fonttools-4.55.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f062c95a725a79fd908fe8407b6ad63e230e1c7d6dece2d5d6ecaf843d6927f6"}, + {file = "fonttools-4.55.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f298c5324c45cad073475146bf560f4110ce2dc2488ff12231a343ec489f77bc"}, + {file = "fonttools-4.55.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f06dbb71344ffd85a6cb7e27970a178952f0bdd8d319ed938e64ba4bcc41700"}, + {file = "fonttools-4.55.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4c46b3525166976f5855b1f039b02433dc51eb635fb54d6a111e0c5d6e6cdc4c"}, + {file = "fonttools-4.55.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:af46f52a21e086a2f89b87bd941c9f0f91e5f769e1a5eb3b37c912228814d3e5"}, + {file = "fonttools-4.55.1-cp313-cp313-win32.whl", hash = "sha256:cd7f36335c5725a3fd724cc667c10c3f5254e779bdc5bffefebb33cf5a75ecb1"}, + {file = "fonttools-4.55.1-cp313-cp313-win_amd64.whl", hash = "sha256:5d6394897710ccac7f74df48492d7f02b9586ff0588c66a2c218844e90534b22"}, + {file = "fonttools-4.55.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:52c4f4b383c56e1a4fe8dab1b63c2269ba9eab0695d2d8e033fa037e61e6f1ef"}, + {file = "fonttools-4.55.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d83892dafdbd62b56545c77b6bd4fa49eef6ec1d6b95e042ee2c930503d1831e"}, + {file = "fonttools-4.55.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:604d5bf16f811fcaaaec2dde139f7ce958462487565edcd54b6fadacb2942083"}, + {file = "fonttools-4.55.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3324b92feb5fd084923a8e89a8248afd5b9f9d81ab9517d7b07cc84403bd448"}, + {file = "fonttools-4.55.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:30f8b1ca9b919c04850678d026fc330c19acaa9e3b282fcacc09a5eb3c8d20c3"}, + {file = "fonttools-4.55.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:1835c98df2cf28c86a66d234895c87df7b9325fd079a8019c5053a389ff55d23"}, + {file = "fonttools-4.55.1-cp38-cp38-win32.whl", hash = "sha256:9f202703720a7cc0049f2ed1a2047925e264384eb5cc4d34f80200d7b17f1b6a"}, + {file = "fonttools-4.55.1-cp38-cp38-win_amd64.whl", hash = "sha256:2efff20aed0338d37c2ff58766bd67f4b9607ded61cf3d6baf1b3e25ea74e119"}, + {file = "fonttools-4.55.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3032d9bf010c395e6eca2851666cafb1f4ecde85d420188555e928ad0144326e"}, + {file = "fonttools-4.55.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0794055588c30ffe25426048e8a7c0a5271942727cd61fc939391e37f4d580d5"}, + {file = "fonttools-4.55.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13ba980e3ffd3206b8c63a365f90dc10eeec27da946d5ee5373c3a325a46d77c"}, + {file = "fonttools-4.55.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d7063babd7434a17a5e355e87de9b2306c85a5c19c7da0794be15c58aab0c39"}, + {file = "fonttools-4.55.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ed84c15144015a58ef550dd6312884c9fb31a2dbc31a6467bcdafd63be7db476"}, + {file = "fonttools-4.55.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e89419d88b0bbfdb55209e03a17afa2d20db3c2fa0d785543c9d0875668195d5"}, + {file = "fonttools-4.55.1-cp39-cp39-win32.whl", hash = "sha256:6eb781e401b93cda99356bc043ababead2a5096550984d8a4ecf3d5c9f859dc2"}, + {file = "fonttools-4.55.1-cp39-cp39-win_amd64.whl", hash = "sha256:db1031acf04523c5a51c3e1ae19c21a1c32bc5f820a477dd4659a02f9cb82002"}, + {file = "fonttools-4.55.1-py3-none-any.whl", hash = "sha256:4bcfb11f90f48b48c366dd638d773a52fca0d1b9e056dc01df766bf5835baa08"}, + {file = "fonttools-4.55.1.tar.gz", hash = "sha256:85bb2e985718b0df96afc659abfe194c171726054314b019dbbfed31581673c7"}, ] [package.extras] @@ -1239,13 +1159,13 @@ woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] [[package]] name = "fqdn" -version = "1.5.1" -description = "Validates fully-qualified domain names against RFC 1123, so that they are acceptable to modern bowsers" +version = "1.4.0" +description = "Validate fully-qualified domain names compliant to RFC 1035 and the preferred form in RFC 3686 s. 2." optional = true -python-versions = ">=2.7, !=3.0, !=3.1, !=3.2, !=3.3, !=3.4, <4" +python-versions = "*" files = [ - {file = "fqdn-1.5.1-py3-none-any.whl", hash = "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014"}, - {file = "fqdn-1.5.1.tar.gz", hash = "sha256:105ed3677e767fb5ca086a0c1f4bb66ebc3c100be518f0e0d755d9eae164d89f"}, + {file = "fqdn-1.4.0-py3-none-any.whl", hash = "sha256:e935616ae81c9c60a22267593fe8e6af68cecc68549cc71bb9bfbcbbcb383386"}, + {file = "fqdn-1.4.0.tar.gz", hash = "sha256:30e8f2e685ce87cdace4712fd97c5d09f5e6fa519bbb66e8f188f6a7cb3a5c4e"}, ] [[package]] @@ -1299,77 +1219,75 @@ test = ["coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", [[package]] name = "glcontext" -version = "2.5.0" -description = "Portable OpenGL Context" +version = "3.0.0" +description = "Portable Headless OpenGL Context" optional = false python-versions = "*" files = [ - {file = "glcontext-2.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3e0f3fbbe483f3e671ae04698a2d38234cb9a5682d2edd49d5bce08a32d48ff1"}, - {file = "glcontext-2.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:837ae9ed985dc8185b7f7ac62bc2727d58806f1eb125b3766f576a3957aa078b"}, - {file = "glcontext-2.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c056bfbc4af86337837fbea0899b1c439673b9e2bf9aaaf78862cb68ccaeb41"}, - {file = "glcontext-2.5.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:198d6f80a271668995f595492b7cde0e7f354e927398d85c20976a7eaf18742b"}, - {file = "glcontext-2.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f435118eabef929e5281bf609eeaae343a0d3f7e34c2a4b0f026451f63a8baab"}, - {file = "glcontext-2.5.0-cp310-cp310-win32.whl", hash = "sha256:9ac01ea37deb27cc53a15eb9a8ec30389cd5421c668842e0197360a502448e11"}, - {file = "glcontext-2.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:194b2657f46310cd86662d946d85162710b43e4abbef800c83a61f44b09352ad"}, - {file = "glcontext-2.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:798bc74604e306386f858be11aa1fe47c88296ac6fb9b5718a1c5a4cfb24416c"}, - {file = "glcontext-2.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c36383ef0f21a179cfd7d6907eb04d7736b724a231a7199edec194528c986b0c"}, - {file = "glcontext-2.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:25da4a8a8707f88e66d1597c5f03be31b354b6d6186907ad06b4735f981aa25e"}, - {file = "glcontext-2.5.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6abae09cadd947c9b3e39c424517eb76e4d6caeca9415c44b290f3425ffb51da"}, - {file = "glcontext-2.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:be62e4ce64c7f72730fccbb09efb37b3aad4e54b6f547b18161233c2a9bf9fc2"}, - {file = "glcontext-2.5.0-cp311-cp311-win32.whl", hash = "sha256:a4441744dadf811f923ab2aff52ba2dc175b6f99bcc208e362399461c96c085f"}, - {file = "glcontext-2.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:7d50c62fae0af1b19daa95571d52a5c56f3f1537483f105b4d092be5eb160c9d"}, - {file = "glcontext-2.5.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cc2a13791007d18b71fc9eccd3423be0a3d5c16b8d1ac4410767665a9824cc21"}, - {file = "glcontext-2.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cbe2684a689cc77e659e90254dcd897af773ddda43308196c7db889d8558f9d1"}, - {file = "glcontext-2.5.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd0f159c01dfaab990fedb9672f4be040ae7fe066afb2ce7413c63afa9475f38"}, - {file = "glcontext-2.5.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:7669583276cc2b4e38b1f62f5d10afdde518ffd5ff6ccfabf22157e081a0abe6"}, - {file = "glcontext-2.5.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:74530549706fabbaecab437102c9d490adba8e27e4ca01bb9ce0050b0d558ff9"}, - {file = "glcontext-2.5.0-cp312-cp312-win32.whl", hash = "sha256:762ee1231f1c5896c527ce29c76921e4868a9f21b0f305b048516a479fe500bf"}, - {file = "glcontext-2.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:942486de098c035dad9165e4cb6ad6342edb8c98b11ee5cdfe97088c7c6840aa"}, - {file = "glcontext-2.5.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:9519f31c464cf1ab1232411e8700829d5bad1fb79470fde99d0aa25296cd4ec7"}, - {file = "glcontext-2.5.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fb33a0e3d2d7a1c3f51652489ed4d1ad16fa71ca1452bf4f983f14446d062592"}, - {file = "glcontext-2.5.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab8dd3d2ea53ce6735dd9915d69572b7dd001f7fe2d35d362182e69b923193e4"}, - {file = "glcontext-2.5.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:ec64bc8a6cdfb51c91c601b0d82744bfa85637fe6259f3587f73d67b5d124937"}, - {file = "glcontext-2.5.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:0e9c890c0fee8ff5c5ec356b0382093e8519a8bdf99ba5ced9f2ac641a37d4ec"}, - {file = "glcontext-2.5.0-cp36-cp36m-win32.whl", hash = "sha256:41a3fa100962ac8733835dd15163e102d165bf65d9247b98e5bcbaa90e94666d"}, - {file = "glcontext-2.5.0-cp36-cp36m-win_amd64.whl", hash = "sha256:73828d76e764f9d22704dd0304f27ec6af18cb075de0df201a23f1456d2b502e"}, - {file = "glcontext-2.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f10a15975c1798bbe4f2d783e1b9c0e32f0dbdc7829a73dce21efb3ee1e24867"}, - {file = "glcontext-2.5.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:23700a43c3ced889d8ac18cb7902a76096634761f87d8139ca956bcadc3feabd"}, - {file = "glcontext-2.5.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b95675cd7c16249fde2ea9690c8b2bd39a551b67e9929eeecfdbcbc82d9c6fc4"}, - {file = "glcontext-2.5.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:efc8a1ec7f6cdc205515e2e4e6ba0a02c2f7207a1340cce80960d63002785405"}, - {file = "glcontext-2.5.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:464f2296474ec07318466f2381748c8259c8a587c5fcd6485ad53bbe1702363b"}, - {file = "glcontext-2.5.0-cp37-cp37m-win32.whl", hash = "sha256:352cf17ade6ea429bd548384ea715024124bb83fdbf3ea06f69f53b6a9e3111f"}, - {file = "glcontext-2.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:9cacc6b068f74f789729dc0512611b6889a95cf6f2ff4c90aea1f741010e0d7a"}, - {file = "glcontext-2.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1204fe22c96d9b36299fac20de7d9319e018e80770964e3d71375853d1b5373d"}, - {file = "glcontext-2.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54e9f848ad21a471e970a0e1eedd3b85025821a0d3c4d63d09d2b97f1a7280b8"}, - {file = "glcontext-2.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3a8e3022da94316a4bb44e064d85e4b05c13f9eef6e68f6395644122a362ec0"}, - {file = "glcontext-2.5.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:73c289fdfce7e8b736034f75e206be8bcc6144d132e910c816e33d2419b984b7"}, - {file = "glcontext-2.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:47dc72cb63f35523f0fa6a27fcb819c3aa19e96c01a2ee8594132ffa834fab18"}, - {file = "glcontext-2.5.0-cp38-cp38-win32.whl", hash = "sha256:2f71d800e8d720fa52aeeebf22d066c17528d756234e586d48b8c82b2fd65372"}, - {file = "glcontext-2.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:3ba303e28a54491cd49caa6f0626b3f1992160ca1d82c2347ce30c50a16ee9b6"}, - {file = "glcontext-2.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bf968a827c04d5210afc2a84d825719fa3025fd9def4aea4820e75a607d09ccf"}, - {file = "glcontext-2.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:586778f6d476f34b8ddbb99d77b65cb7126cd3f501a2cb1e6e12f0bc997ca9b8"}, - {file = "glcontext-2.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675091975c2bf8b59e9c41d1daa6684006162c3cf3d9e2a1acda31b35181d9d2"}, - {file = "glcontext-2.5.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:cf928dfbed4fceb3a816452828e8745e46b8348869c0fdda312f6c73f0796906"}, - {file = "glcontext-2.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1aee2105c66d1a5470d2c2de7d80977c67ee2b2cf4db6fa2b3dcbd586b888b51"}, - {file = "glcontext-2.5.0-cp39-cp39-win32.whl", hash = "sha256:b1200d841b7a1ef1051fafe6aad6a472c784bc4fb906375160b0efa7d7acae71"}, - {file = "glcontext-2.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:7a7962f89350966966a4a5628fd4861a81dc4f76014571567a54db4c1573e04d"}, - {file = "glcontext-2.5.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9eee5426fad207fb1c572ee7e4b8341ee8f6529189f06cbd32b132ee4de31a8e"}, - {file = "glcontext-2.5.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:433e14a9c3d368c51940a480d4f548b671ad339d5efa0604bd0d5236fae4e564"}, - {file = "glcontext-2.5.0-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2342642732609c7cb3d681771e096fe769df58e49bdb3348bfc9f5732103c444"}, - {file = "glcontext-2.5.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:16057bf3736f38005a7f700188a50de597cd86650d6718a115bd835d69ba554b"}, - {file = "glcontext-2.5.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8ba64f9c14009132625b7b1f1b8545298c6ddd1d3abc78618b0f9553c219d053"}, - {file = "glcontext-2.5.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:811276496f46f3f9b204e43a9d35c6213f1f0a8e58d8da203d477e21e8367fc0"}, - {file = "glcontext-2.5.0-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe0be5cf5a9598379e994d7d96d84ce506e6a7680a098c1f1112de7aaa036ebd"}, - {file = "glcontext-2.5.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:1914d44374d7ee94df779681218639324ab79b3b8e27e8fb6154a8db55e3928e"}, - {file = "glcontext-2.5.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:916fa56a544f57ff3d53cc60d3d1f0da66c67e6cf5092e3d7ef8bbaedd47a266"}, - {file = "glcontext-2.5.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1abdc499c59e4a1dd59e321151171ecb583f3fac07af428c47a8b8e3ce5ff5bf"}, - {file = "glcontext-2.5.0-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c73882865f3daf8a02fae1486c933146dc2f1bb8de3be26907b145523df4afc1"}, - {file = "glcontext-2.5.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:136ab0d4f966adc7a2f397e8f17debf3da18afb4b5b8684db59ea9c9452fe2f6"}, - {file = "glcontext-2.5.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:95e6805475552254d9e1a65c2433c150e364da0081dcc6fa79d90bf74665384b"}, - {file = "glcontext-2.5.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:60343a07fd30c024c6889687d10524c4b9f321c3991666e6c23eb0e695f60ae1"}, - {file = "glcontext-2.5.0-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e7db3961200f3cf607ac68eb0df0640e5d538f1c029c6d9433722ee04f37960"}, - {file = "glcontext-2.5.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7017ac46784adce071cdcda5e3ce07523bbc10186c0c9cc3120aba91f0633817"}, - {file = "glcontext-2.5.0.tar.gz", hash = "sha256:0f70d4be0cdd2b532a16da76c8f786b6367754a4086aaadffdbf3e37badbad02"}, + {file = "glcontext-3.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b154c25a57e16dbb073478d0cbe2c0090649d135c4c9f87e753b6181b97ec848"}, + {file = "glcontext-3.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fa5a14778d13ecf4a0dd60a7825427bf6ac0383eacb3b8b1a9c23e4976aa0c8c"}, + {file = "glcontext-3.0.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c229290a3a33004a59799b94a50bc5e6f8addd1b5bc5039ef9e78f86d888b31"}, + {file = "glcontext-3.0.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1445a03d8795113034e1f9ffa662f795df65ae69ee21b26ed3b1d66100ba3f8c"}, + {file = "glcontext-3.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:09247011c09c37b8d30eca9aa24659288de2febaeaa6a817b33b1498b5ef164c"}, + {file = "glcontext-3.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c8c1223f1cbcfc0b88428e1717baca829ee863ed5d88e9b5574c7ed6598249cd"}, + {file = "glcontext-3.0.0-cp310-cp310-win32.whl", hash = "sha256:c13dedb3636328b133c4d53c047ce69040ae784095e8f239432ad74d6f921712"}, + {file = "glcontext-3.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:4817f4cd52c7fe5410c92ca12b6712435548918719373882ade76f8f75d80abd"}, + {file = "glcontext-3.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3a9e56fa3597cc709cfd0fdf2ae682cda36510a13faac2b3142f401e823b64f4"}, + {file = "glcontext-3.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a0484308af75e04b0e56066dc2324a8fb9f1443b76ddb98833439982322b2a39"}, + {file = "glcontext-3.0.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:983231394396aa2a1e2b96df49404cc8f8aa729d462ed40e605a74b079c46342"}, + {file = "glcontext-3.0.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7fa413f4420abff2bbb5aa5770a3e1deffcdc13e0ef2f459b145fa79c36909e7"}, + {file = "glcontext-3.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7d0ac35ac07fc91eccea093beb9d1c1a4eae250bc33836047deff01a3b5f4757"}, + {file = "glcontext-3.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7145d17a70adc5784ca59ebbe19a56435ba21816070b8b433f43aa2dfb8be71a"}, + {file = "glcontext-3.0.0-cp311-cp311-win32.whl", hash = "sha256:b31808ca2517fedcac8ca5b296ff46c8af012911eaa2080889a1f244d329ef9a"}, + {file = "glcontext-3.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:ef4b4ec35e2b720f4cd250bb92cf6417add445490bf780345596da5a796a0e6f"}, + {file = "glcontext-3.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:848f870a2bc72a29de7ab6756b9e8f2e6ce052e17873ebc6b3f25129b6e0d58a"}, + {file = "glcontext-3.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4b3b12a66f57379566dd4d36899ac265abdbe040f3fc3293f50cd6678a1dcc9b"}, + {file = "glcontext-3.0.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:449eaefd89c0519900715b8363ead59ac4aa32457722ca521ce01297441edb34"}, + {file = "glcontext-3.0.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:04921720740438ceea8fb8a38b5665963520c7c8f27bef03df8aeb3ea3cfbfb6"}, + {file = "glcontext-3.0.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:25538bdb106f673638d70e8a16a0c037a92a24c4cf40a05f0d3fa14b483d6194"}, + {file = "glcontext-3.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d11f7701b900a5a34c994e1d91c547be1cc469b73f881471460fd905f69f9e4c"}, + {file = "glcontext-3.0.0-cp312-cp312-win32.whl", hash = "sha256:5d2b567eaf34adb016aadce81fd2f1d4c8e4a39e3d6f2a395ce528e2a350dd3f"}, + {file = "glcontext-3.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:e80bb37ba727bd20c192f2754aea40c437a7665005c1001c10752f91913964e9"}, + {file = "glcontext-3.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5bd37089570d3cdb01c6c0b315c49ce8a4dcdab2c431f5ba9f37a8b633cebfdf"}, + {file = "glcontext-3.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:857fd83e60f15580afd369dfb651a10d84a70ec35995622d253551bfb3ff9477"}, + {file = "glcontext-3.0.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93fda9b378ce6d91f366e83e71ebdafdd167280a9834d1d6341ce6457c4e42ed"}, + {file = "glcontext-3.0.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89ad50d34aa62f03f6aaf6ae39fc27afd1b0eaefb0281aac51f686dc5672d473"}, + {file = "glcontext-3.0.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2634d5e9647a6d7b0c5a5c0c57e91ac98aa79759bffb42459af4374b049fab01"}, + {file = "glcontext-3.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0140c5df37cb48271527355062d35589dc3e1e7e73b51adf9962ed5048115f69"}, + {file = "glcontext-3.0.0-cp313-cp313-win32.whl", hash = "sha256:6678e0552b516fa8fe62f500ef2b953bec991e82a003be2a9840d16556d03d2e"}, + {file = "glcontext-3.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:18aa4b1df50e8c8ea39bd0f775f39bcc987521f92c4ed019ec7d70078471354d"}, + {file = "glcontext-3.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:17a1339db9c1df55eb0b7341dd3da1e45c9992d59aa3a72afefd5bd43d588c92"}, + {file = "glcontext-3.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9ca980d9ac22045ef2489cac8cf3800748b1baa716f74a53705003405664950c"}, + {file = "glcontext-3.0.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b5a7fb8ab69fc4f076282622e94284ea4cbf7022a1f6ed50938d076b982f653e"}, + {file = "glcontext-3.0.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5825e1df53bdf941c3a5ea5ff6d1869491dfeb9f2c30d97f45bbbcb12d91dc1f"}, + {file = "glcontext-3.0.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:f3be86fa6587eca16f3fe2b46ee72e2a188fdccedafff0de7515b1d5e72f265e"}, + {file = "glcontext-3.0.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:b4a06207c487f0aa79e49bf1c19d0f2633ff1e1889704196993d24b342763344"}, + {file = "glcontext-3.0.0-cp38-cp38-win32.whl", hash = "sha256:3eb55b653fc00a4ec415acacbbf1e8f03ee10b5a685f63fce43ad75b4cef5d4e"}, + {file = "glcontext-3.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:7e51f04bb3a3a12147106036676a237c5405297a95b8209f7686d624f013bc17"}, + {file = "glcontext-3.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7043f59d126feb26896a6419ebfeecc78c07ffefced2a2f59104dd7a2f71ebb5"}, + {file = "glcontext-3.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4a2972f92da9a6fb06860e117de05f5b8adc2e2d827bbc0ccc7acbe7325acd1e"}, + {file = "glcontext-3.0.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fb2eb1c455d589005567b36642db8059b31bb1752f0525c6dbe70ceeeb0131d5"}, + {file = "glcontext-3.0.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdd81e8b580e43c1fe1c48c0fc3909e6c1f37ee4cfd8c990c03b2df3b463bd37"}, + {file = "glcontext-3.0.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:64eb425f0f0c54c60527e1b112465d4d69b010af42a3b0e69f22317fffd8faea"}, + {file = "glcontext-3.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:def2b9956fbd3da94b4cadeb85d947a6321582ddfea2e58c4134178bfabce0f8"}, + {file = "glcontext-3.0.0-cp39-cp39-win32.whl", hash = "sha256:cfdc763adffcd20509b9e6ac964a9abf7b2a898bb32d7bd4efce9db8af2caaf5"}, + {file = "glcontext-3.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:12c2abef8efabb8ab7e35d16785968de888ae7349d1b83c765080f35fcd3c6e5"}, + {file = "glcontext-3.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:f4e285e5d40e7a9bafeb0651c3d8f1a7c822525dec7091e97109ba87a70dbd1e"}, + {file = "glcontext-3.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:96d1bbe62c5bc5315ca2f84a2abae6fa7b7d645dd368415a0cd1ee5ba6f3f8f7"}, + {file = "glcontext-3.0.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3a190b1cdb39110c7b56c33857dbff493a364633bfd0ff402a1ce205956c94ca"}, + {file = "glcontext-3.0.0-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d467cce2dac8c3928847e90310eb6bdfdfa69f8df39b76a74734046faa15e688"}, + {file = "glcontext-3.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2b0c5240125d75498a8f14596484233e4effe98a6a035f566872dd2fdf472ceb"}, + {file = "glcontext-3.0.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d89a6bcf0129f27594c07eb9aafc33389e9dd66f344fe1e255fe297bbc123317"}, + {file = "glcontext-3.0.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:d9b0bd64b01be0ecad521ca4869153893ed10f8c9043dcd8d1a81c8f686008c9"}, + {file = "glcontext-3.0.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1ba5af7ca9309bb42b89cf25f576cc28ae36671be01ecdfce264308a007880ac"}, + {file = "glcontext-3.0.0-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbb413b6bf3b2ded2e5bf4235b75eb9ac9d36361af38393c53c689dfcc096eba"}, + {file = "glcontext-3.0.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:dfea7fc7b22afce49027d8470a84f9c7c6f06a09b43f6606030b53b3240df0d1"}, + {file = "glcontext-3.0.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:cf5af894228b4357b088a6e26761438d799c2af907e33f17935072fe46903c2d"}, + {file = "glcontext-3.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:1712d7a7216b687b181291098e5117e5fae1f1df466583b4290dc2e80d9a72c8"}, + {file = "glcontext-3.0.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07980350ba2aac9f793185f90c4f561ae1aa03cc11b58cce4b51e20a70e8c6e3"}, + {file = "glcontext-3.0.0-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed5135fdb0da5e0decea1cb26ca10a279188aa0bc4462f1c77e214d6f956a710"}, + {file = "glcontext-3.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c3648e13478d77128a74dd25baa98faf9ddb9cbcba5af39775ef3a496f71fd10"}, + {file = "glcontext-3.0.0.tar.gz", hash = "sha256:57168edcd38df2fc0d70c318edf6f7e59091fba1cd3dadb289d0aa50449211ef"}, ] [[package]] @@ -1385,13 +1303,13 @@ files = [ [[package]] name = "httpcore" -version = "1.0.5" +version = "1.0.7" description = "A minimal low-level HTTP client." optional = true python-versions = ">=3.8" files = [ - {file = "httpcore-1.0.5-py3-none-any.whl", hash = "sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5"}, - {file = "httpcore-1.0.5.tar.gz", hash = "sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61"}, + {file = "httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd"}, + {file = "httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c"}, ] [package.dependencies] @@ -1402,17 +1320,17 @@ h11 = ">=0.13,<0.15" asyncio = ["anyio (>=4.0,<5.0)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] -trio = ["trio (>=0.22.0,<0.26.0)"] +trio = ["trio (>=0.22.0,<1.0)"] [[package]] name = "httpx" -version = "0.27.0" +version = "0.28.0" description = "The next generation HTTP client." optional = true python-versions = ">=3.8" files = [ - {file = "httpx-0.27.0-py3-none-any.whl", hash = "sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5"}, - {file = "httpx-0.27.0.tar.gz", hash = "sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5"}, + {file = "httpx-0.28.0-py3-none-any.whl", hash = "sha256:dc0b419a0cfeb6e8b34e85167c0da2671206f5095f1baa9663d23bcfd6b535fc"}, + {file = "httpx-0.28.0.tar.gz", hash = "sha256:0858d3bab51ba7e386637f22a61d8ccddaeec5f3fe4209da3a6168dbb91573e0"}, ] [package.dependencies] @@ -1420,23 +1338,23 @@ anyio = "*" certifi = "*" httpcore = "==1.*" idna = "*" -sniffio = "*" [package.extras] brotli = ["brotli", "brotlicffi"] cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] +zstd = ["zstandard (>=0.18.0)"] [[package]] name = "identify" -version = "2.5.36" +version = "2.6.3" description = "File identification library for Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "identify-2.5.36-py2.py3-none-any.whl", hash = "sha256:37d93f380f4de590500d9dba7db359d0d3da95ffe7f9de1753faa159e71e7dfa"}, - {file = "identify-2.5.36.tar.gz", hash = "sha256:e5e00f54165f9047fbebeb4a560f9acfb8af4c88232be60a488e9b68d122745d"}, + {file = "identify-2.6.3-py2.py3-none-any.whl", hash = "sha256:9edba65473324c2ea9684b1f944fe3191db3345e50b6d04571d10ed164f8d7bd"}, + {file = "identify-2.6.3.tar.gz", hash = "sha256:62f5dae9b5fef52c84cc188514e9ea4f3f636b1d8799ab5ebc475471f9e47a02"}, ] [package.extras] @@ -1444,15 +1362,18 @@ license = ["ukkonen"] [[package]] name = "idna" -version = "3.7" +version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" files = [ - {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, - {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, ] +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + [[package]] name = "imagesize" version = "1.4.1" @@ -1466,40 +1387,48 @@ files = [ [[package]] name = "importlib-metadata" -version = "7.1.0" +version = "8.5.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-7.1.0-py3-none-any.whl", hash = "sha256:30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570"}, - {file = "importlib_metadata-7.1.0.tar.gz", hash = "sha256:b78938b926ee8d5f020fc4772d487045805a55ddbad2ecf21c6d60938dc7fcd2"}, + {file = "importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b"}, + {file = "importlib_metadata-8.5.0.tar.gz", hash = "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7"}, ] [package.dependencies] -zipp = ">=0.5" +zipp = ">=3.20" [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] perf = ["ipython"] -testing = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] +test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] +type = ["pytest-mypy"] [[package]] name = "importlib-resources" -version = "6.4.0" +version = "6.4.5" description = "Read resources from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_resources-6.4.0-py3-none-any.whl", hash = "sha256:50d10f043df931902d4194ea07ec57960f66a80449ff867bfe782b4c486ba78c"}, - {file = "importlib_resources-6.4.0.tar.gz", hash = "sha256:cdb2b453b8046ca4e3798eb1d84f3cce1446a0e8e7b5ef4efb600f19fc398145"}, + {file = "importlib_resources-6.4.5-py3-none-any.whl", hash = "sha256:ac29d5f956f01d5e4bb63102a5a19957f1b9175e45649977264a1416783bb717"}, + {file = "importlib_resources-6.4.5.tar.gz", hash = "sha256:980862a1d16c9e147a59603677fa2aa5fd82b87f223b6cb870695bcfce830065"}, ] [package.dependencies] zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["jaraco.test (>=5.4)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "zipp (>=3.17)"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["jaraco.test (>=5.4)", "pytest (>=6,!=8.1.*)", "zipp (>=3.17)"] +type = ["pytest-mypy"] [[package]] name = "iniconfig" @@ -1514,13 +1443,13 @@ files = [ [[package]] name = "ipykernel" -version = "6.29.4" +version = "6.29.5" description = "IPython Kernel for Jupyter" optional = true python-versions = ">=3.8" files = [ - {file = "ipykernel-6.29.4-py3-none-any.whl", hash = "sha256:1181e653d95c6808039c509ef8e67c4126b3b3af7781496c7cbfb5ed938a27da"}, - {file = "ipykernel-6.29.4.tar.gz", hash = "sha256:3d44070060f9475ac2092b760123fadf105d2e2493c24848b6691a7c4f42af5c"}, + {file = "ipykernel-6.29.5-py3-none-any.whl", hash = "sha256:afdb66ba5aa354b09b91379bac28ae4afebbb30e8b39510c9690afb7a10421b5"}, + {file = "ipykernel-6.29.5.tar.gz", hash = "sha256:f093a22c4a40f8828f8e330a9c297cb93dcab13bd9678ded6de8e5cf81c56215"}, ] [package.dependencies] @@ -1626,22 +1555,22 @@ numpy = "*" [[package]] name = "jedi" -version = "0.19.1" +version = "0.19.2" description = "An autocompletion tool for Python that can be used for text editors." optional = true python-versions = ">=3.6" files = [ - {file = "jedi-0.19.1-py2.py3-none-any.whl", hash = "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0"}, - {file = "jedi-0.19.1.tar.gz", hash = "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd"}, + {file = "jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9"}, + {file = "jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0"}, ] [package.dependencies] -parso = ">=0.8.3,<0.9.0" +parso = ">=0.8.4,<0.9.0" [package.extras] docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"] qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] -testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] +testing = ["Django", "attrs", "colorama", "docopt", "pytest (<9.0.0)"] [[package]] name = "jinja2" @@ -1662,35 +1591,38 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "json5" -version = "0.9.25" +version = "0.10.0" description = "A Python implementation of the JSON5 data format." optional = true -python-versions = ">=3.8" +python-versions = ">=3.8.0" files = [ - {file = "json5-0.9.25-py3-none-any.whl", hash = "sha256:34ed7d834b1341a86987ed52f3f76cd8ee184394906b6e22a1e0deb9ab294e8f"}, - {file = "json5-0.9.25.tar.gz", hash = "sha256:548e41b9be043f9426776f05df8635a00fe06104ea51ed24b67f908856e151ae"}, + {file = "json5-0.10.0-py3-none-any.whl", hash = "sha256:19b23410220a7271e8377f81ba8aacba2fdd56947fbb137ee5977cbe1f5e8dfa"}, + {file = "json5-0.10.0.tar.gz", hash = "sha256:e66941c8f0a02026943c52c2eb34ebeb2a6f819a0be05920a6f5243cd30fd559"}, ] +[package.extras] +dev = ["build (==1.2.2.post1)", "coverage (==7.5.3)", "mypy (==1.13.0)", "pip (==24.3.1)", "pylint (==3.2.3)", "ruff (==0.7.3)", "twine (==5.1.1)", "uv (==0.5.1)"] + [[package]] name = "jsonpointer" -version = "2.4" +version = "3.0.0" description = "Identify specific nodes in a JSON document (RFC 6901)" optional = true -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" +python-versions = ">=3.7" files = [ - {file = "jsonpointer-2.4-py2.py3-none-any.whl", hash = "sha256:15d51bba20eea3165644553647711d150376234112651b4f1811022aecad7d7a"}, - {file = "jsonpointer-2.4.tar.gz", hash = "sha256:585cee82b70211fa9e6043b7bb89db6e1aa49524340dde8ad6b63206ea689d88"}, + {file = "jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942"}, + {file = "jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef"}, ] [[package]] name = "jsonschema" -version = "4.22.0" +version = "4.23.0" description = "An implementation of JSON Schema validation for Python" optional = true python-versions = ">=3.8" files = [ - {file = "jsonschema-4.22.0-py3-none-any.whl", hash = "sha256:ff4cfd6b1367a40e7bc6411caec72effadd3db0bbe5017de188f2d6108335802"}, - {file = "jsonschema-4.22.0.tar.gz", hash = "sha256:5b22d434a45935119af990552c862e5d6d564e8f6601206b305a61fdf661a2b7"}, + {file = "jsonschema-4.23.0-py3-none-any.whl", hash = "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566"}, + {file = "jsonschema-4.23.0.tar.gz", hash = "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4"}, ] [package.dependencies] @@ -1705,21 +1637,21 @@ rfc3339-validator = {version = "*", optional = true, markers = "extra == \"forma rfc3986-validator = {version = ">0.1.0", optional = true, markers = "extra == \"format-nongpl\""} rpds-py = ">=0.7.1" uri-template = {version = "*", optional = true, markers = "extra == \"format-nongpl\""} -webcolors = {version = ">=1.11", optional = true, markers = "extra == \"format-nongpl\""} +webcolors = {version = ">=24.6.0", optional = true, markers = "extra == \"format-nongpl\""} [package.extras] format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] -format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"] +format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=24.6.0)"] [[package]] name = "jsonschema-specifications" -version = "2023.12.1" +version = "2024.10.1" description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "jsonschema_specifications-2023.12.1-py3-none-any.whl", hash = "sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c"}, - {file = "jsonschema_specifications-2023.12.1.tar.gz", hash = "sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc"}, + {file = "jsonschema_specifications-2024.10.1-py3-none-any.whl", hash = "sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf"}, + {file = "jsonschema_specifications-2024.10.1.tar.gz", hash = "sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272"}, ] [package.dependencies] @@ -1727,13 +1659,13 @@ referencing = ">=0.31.0" [[package]] name = "jupyter-client" -version = "8.6.1" +version = "8.6.3" description = "Jupyter protocol implementation and client libraries" optional = true python-versions = ">=3.8" files = [ - {file = "jupyter_client-8.6.1-py3-none-any.whl", hash = "sha256:3b7bd22f058434e3b9a7ea4b1500ed47de2713872288c0d511d19926f99b459f"}, - {file = "jupyter_client-8.6.1.tar.gz", hash = "sha256:e842515e2bab8e19186d89fdfea7abd15e39dd581f94e399f00e2af5a1652d3f"}, + {file = "jupyter_client-8.6.3-py3-none-any.whl", hash = "sha256:e8a19cc986cc45905ac3362915f410f3af85424b4c0905e94fa5f2cb08e8f23f"}, + {file = "jupyter_client-8.6.3.tar.gz", hash = "sha256:35b3a0947c4a6e9d589eb97d7d4cd5e90f910ee73101611f01283732bd6d9419"}, ] [package.dependencies] @@ -1746,7 +1678,7 @@ traitlets = ">=5.3" [package.extras] docs = ["ipykernel", "myst-parser", "pydata-sphinx-theme", "sphinx (>=4)", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] -test = ["coverage", "ipykernel (>=6.14)", "mypy", "paramiko", "pre-commit", "pytest", "pytest-cov", "pytest-jupyter[client] (>=0.4.1)", "pytest-timeout"] +test = ["coverage", "ipykernel (>=6.14)", "mypy", "paramiko", "pre-commit", "pytest (<8.2.0)", "pytest-cov", "pytest-jupyter[client] (>=0.4.1)", "pytest-timeout"] [[package]] name = "jupyter-core" @@ -1810,13 +1742,13 @@ jupyter-server = ">=1.1.2" [[package]] name = "jupyter-server" -version = "2.14.0" +version = "2.14.2" description = "The backend—i.e. core services, APIs, and REST endpoints—to Jupyter web applications." optional = true python-versions = ">=3.8" files = [ - {file = "jupyter_server-2.14.0-py3-none-any.whl", hash = "sha256:fb6be52c713e80e004fac34b35a0990d6d36ba06fd0a2b2ed82b899143a64210"}, - {file = "jupyter_server-2.14.0.tar.gz", hash = "sha256:659154cea512083434fd7c93b7fe0897af7a2fd0b9dd4749282b42eaac4ae677"}, + {file = "jupyter_server-2.14.2-py3-none-any.whl", hash = "sha256:47ff506127c2f7851a17bf4713434208fc490955d0e8632e95014a9a9afbeefd"}, + {file = "jupyter_server-2.14.2.tar.gz", hash = "sha256:66095021aa9638ced276c248b1d81862e4c50f292d575920bbe960de1c56b12b"}, ] [package.dependencies] @@ -1841,7 +1773,7 @@ traitlets = ">=5.6.0" websocket-client = ">=1.7" [package.extras] -docs = ["ipykernel", "jinja2", "jupyter-client", "jupyter-server", "myst-parser", "nbformat", "prometheus-client", "pydata-sphinx-theme", "send2trash", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-openapi (>=0.8.0)", "sphinxcontrib-spelling", "sphinxemoji", "tornado", "typing-extensions"] +docs = ["ipykernel", "jinja2", "jupyter-client", "myst-parser", "nbformat", "prometheus-client", "pydata-sphinx-theme", "send2trash", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-openapi (>=0.8.0)", "sphinxcontrib-spelling", "sphinxemoji", "tornado", "typing-extensions"] test = ["flaky", "ipykernel", "pre-commit", "pytest (>=7.0,<9)", "pytest-console-scripts", "pytest-jupyter[server] (>=0.7)", "pytest-timeout", "requests"] [[package]] @@ -1865,13 +1797,13 @@ test = ["jupyter-server (>=2.0.0)", "pytest (>=7.0)", "pytest-jupyter[server] (> [[package]] name = "jupyterlab" -version = "4.2.0" +version = "4.3.1" description = "JupyterLab computational environment" optional = true python-versions = ">=3.8" files = [ - {file = "jupyterlab-4.2.0-py3-none-any.whl", hash = "sha256:0dfe9278e25a145362289c555d9beb505697d269c10e99909766af7c440ad3cc"}, - {file = "jupyterlab-4.2.0.tar.gz", hash = "sha256:356e9205a6a2ab689c47c8fe4919dba6c076e376d03f26baadc05748c2435dd5"}, + {file = "jupyterlab-4.3.1-py3-none-any.whl", hash = "sha256:2d9a1c305bc748e277819a17a5d5e22452e533e835f4237b2f30f3b0e491e01f"}, + {file = "jupyterlab-4.3.1.tar.gz", hash = "sha256:a4a338327556443521731d82f2a6ccf926df478914ca029616621704d47c3c65"}, ] [package.dependencies] @@ -1886,16 +1818,17 @@ jupyter-server = ">=2.4.0,<3" jupyterlab-server = ">=2.27.1,<3" notebook-shim = ">=0.2" packaging = "*" +setuptools = ">=40.1.0" tomli = {version = ">=1.2.2", markers = "python_version < \"3.11\""} tornado = ">=6.2.0" traitlets = "*" [package.extras] -dev = ["build", "bump2version", "coverage", "hatch", "pre-commit", "pytest-cov", "ruff (==0.3.5)"] -docs = ["jsx-lexer", "myst-parser", "pydata-sphinx-theme (>=0.13.0)", "pytest", "pytest-check-links", "pytest-jupyter", "sphinx (>=1.8,<7.3.0)", "sphinx-copybutton"] -docs-screenshots = ["altair (==5.3.0)", "ipython (==8.16.1)", "ipywidgets (==8.1.2)", "jupyterlab-geojson (==3.4.0)", "jupyterlab-language-pack-zh-cn (==4.1.post2)", "matplotlib (==3.8.3)", "nbconvert (>=7.0.0)", "pandas (==2.2.1)", "scipy (==1.12.0)", "vega-datasets (==0.9.0)"] +dev = ["build", "bump2version", "coverage", "hatch", "pre-commit", "pytest-cov", "ruff (==0.6.9)"] +docs = ["jsx-lexer", "myst-parser", "pydata-sphinx-theme (>=0.13.0)", "pytest", "pytest-check-links", "pytest-jupyter", "sphinx (>=1.8,<8.1.0)", "sphinx-copybutton"] +docs-screenshots = ["altair (==5.4.1)", "ipython (==8.16.1)", "ipywidgets (==8.1.5)", "jupyterlab-geojson (==3.4.0)", "jupyterlab-language-pack-zh-cn (==4.2.post3)", "matplotlib (==3.9.2)", "nbconvert (>=7.0.0)", "pandas (==2.2.3)", "scipy (==1.14.1)", "vega-datasets (==0.9.0)"] test = ["coverage", "pytest (>=7.0)", "pytest-check-links (>=0.7)", "pytest-console-scripts", "pytest-cov", "pytest-jupyter (>=0.5.3)", "pytest-timeout", "pytest-tornasync", "requests", "requests-cache", "virtualenv"] -upgrade-extension = ["copier (>=8,<10)", "jinja2-time (<0.3)", "pydantic (<2.0)", "pyyaml-include (<2.0)", "tomli-w (<2.0)"] +upgrade-extension = ["copier (>=9,<10)", "jinja2-time (<0.3)", "pydantic (<3.0)", "pyyaml-include (<3.0)", "tomli-w (<2.0)"] [[package]] name = "jupyterlab-pygments" @@ -1910,13 +1843,13 @@ files = [ [[package]] name = "jupyterlab-server" -version = "2.27.1" +version = "2.27.3" description = "A set of server components for JupyterLab and JupyterLab like applications." optional = true python-versions = ">=3.8" files = [ - {file = "jupyterlab_server-2.27.1-py3-none-any.whl", hash = "sha256:f5e26156e5258b24d532c84e7c74cc212e203bff93eb856f81c24c16daeecc75"}, - {file = "jupyterlab_server-2.27.1.tar.gz", hash = "sha256:097b5ac709b676c7284ac9c5e373f11930a561f52cd5a86e4fc7e5a9c8a8631d"}, + {file = "jupyterlab_server-2.27.3-py3-none-any.whl", hash = "sha256:e697488f66c3db49df675158a77b3b017520d772c6e1548c7d9bcc5df7944ee4"}, + {file = "jupyterlab_server-2.27.3.tar.gz", hash = "sha256:eb36caca59e74471988f0ae25c77945610b887f777255aa21f8065def9e51ed4"}, ] [package.dependencies] @@ -1936,216 +1869,197 @@ test = ["hatch", "ipykernel", "openapi-core (>=0.18.0,<0.19.0)", "openapi-spec-v [[package]] name = "kiwisolver" -version = "1.4.5" +version = "1.4.7" description = "A fast implementation of the Cassowary constraint solver" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:05703cf211d585109fcd72207a31bb170a0f22144d68298dc5e61b3c946518af"}, - {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:146d14bebb7f1dc4d5fbf74f8a6cb15ac42baadee8912eb84ac0b3b2a3dc6ac3"}, - {file = "kiwisolver-1.4.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ef7afcd2d281494c0a9101d5c571970708ad911d028137cd558f02b851c08b4"}, - {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9eaa8b117dc8337728e834b9c6e2611f10c79e38f65157c4c38e9400286f5cb1"}, - {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ec20916e7b4cbfb1f12380e46486ec4bcbaa91a9c448b97023fde0d5bbf9e4ff"}, - {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39b42c68602539407884cf70d6a480a469b93b81b7701378ba5e2328660c847a"}, - {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa12042de0171fad672b6c59df69106d20d5596e4f87b5e8f76df757a7c399aa"}, - {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a40773c71d7ccdd3798f6489aaac9eee213d566850a9533f8d26332d626b82c"}, - {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:19df6e621f6d8b4b9c4d45f40a66839294ff2bb235e64d2178f7522d9170ac5b"}, - {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:83d78376d0d4fd884e2c114d0621624b73d2aba4e2788182d286309ebdeed770"}, - {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e391b1f0a8a5a10ab3b9bb6afcfd74f2175f24f8975fb87ecae700d1503cdee0"}, - {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:852542f9481f4a62dbb5dd99e8ab7aedfeb8fb6342349a181d4036877410f525"}, - {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59edc41b24031bc25108e210c0def6f6c2191210492a972d585a06ff246bb79b"}, - {file = "kiwisolver-1.4.5-cp310-cp310-win32.whl", hash = "sha256:a6aa6315319a052b4ee378aa171959c898a6183f15c1e541821c5c59beaa0238"}, - {file = "kiwisolver-1.4.5-cp310-cp310-win_amd64.whl", hash = "sha256:d0ef46024e6a3d79c01ff13801cb19d0cad7fd859b15037aec74315540acc276"}, - {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:11863aa14a51fd6ec28688d76f1735f8f69ab1fabf388851a595d0721af042f5"}, - {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8ab3919a9997ab7ef2fbbed0cc99bb28d3c13e6d4b1ad36e97e482558a91be90"}, - {file = "kiwisolver-1.4.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fcc700eadbbccbf6bc1bcb9dbe0786b4b1cb91ca0dcda336eef5c2beed37b797"}, - {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dfdd7c0b105af050eb3d64997809dc21da247cf44e63dc73ff0fd20b96be55a9"}, - {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76c6a5964640638cdeaa0c359382e5703e9293030fe730018ca06bc2010c4437"}, - {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbea0db94288e29afcc4c28afbf3a7ccaf2d7e027489c449cf7e8f83c6346eb9"}, - {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ceec1a6bc6cab1d6ff5d06592a91a692f90ec7505d6463a88a52cc0eb58545da"}, - {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:040c1aebeda72197ef477a906782b5ab0d387642e93bda547336b8957c61022e"}, - {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f91de7223d4c7b793867797bacd1ee53bfe7359bd70d27b7b58a04efbb9436c8"}, - {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:faae4860798c31530dd184046a900e652c95513796ef51a12bc086710c2eec4d"}, - {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:b0157420efcb803e71d1b28e2c287518b8808b7cf1ab8af36718fd0a2c453eb0"}, - {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:06f54715b7737c2fecdbf140d1afb11a33d59508a47bf11bb38ecf21dc9ab79f"}, - {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fdb7adb641a0d13bdcd4ef48e062363d8a9ad4a182ac7647ec88f695e719ae9f"}, - {file = "kiwisolver-1.4.5-cp311-cp311-win32.whl", hash = "sha256:bb86433b1cfe686da83ce32a9d3a8dd308e85c76b60896d58f082136f10bffac"}, - {file = "kiwisolver-1.4.5-cp311-cp311-win_amd64.whl", hash = "sha256:6c08e1312a9cf1074d17b17728d3dfce2a5125b2d791527f33ffbe805200a355"}, - {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:32d5cf40c4f7c7b3ca500f8985eb3fb3a7dfc023215e876f207956b5ea26632a"}, - {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f846c260f483d1fd217fe5ed7c173fb109efa6b1fc8381c8b7552c5781756192"}, - {file = "kiwisolver-1.4.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5ff5cf3571589b6d13bfbfd6bcd7a3f659e42f96b5fd1c4830c4cf21d4f5ef45"}, - {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7269d9e5f1084a653d575c7ec012ff57f0c042258bf5db0954bf551c158466e7"}, - {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da802a19d6e15dffe4b0c24b38b3af68e6c1a68e6e1d8f30148c83864f3881db"}, - {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3aba7311af82e335dd1e36ffff68aaca609ca6290c2cb6d821a39aa075d8e3ff"}, - {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:763773d53f07244148ccac5b084da5adb90bfaee39c197554f01b286cf869228"}, - {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2270953c0d8cdab5d422bee7d2007f043473f9d2999631c86a223c9db56cbd16"}, - {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d099e745a512f7e3bbe7249ca835f4d357c586d78d79ae8f1dcd4d8adeb9bda9"}, - {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:74db36e14a7d1ce0986fa104f7d5637aea5c82ca6326ed0ec5694280942d1162"}, - {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:7e5bab140c309cb3a6ce373a9e71eb7e4873c70c2dda01df6820474f9889d6d4"}, - {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0f114aa76dc1b8f636d077979c0ac22e7cd8f3493abbab152f20eb8d3cda71f3"}, - {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:88a2df29d4724b9237fc0c6eaf2a1adae0cdc0b3e9f4d8e7dc54b16812d2d81a"}, - {file = "kiwisolver-1.4.5-cp312-cp312-win32.whl", hash = "sha256:72d40b33e834371fd330fb1472ca19d9b8327acb79a5821d4008391db8e29f20"}, - {file = "kiwisolver-1.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:2c5674c4e74d939b9d91dda0fae10597ac7521768fec9e399c70a1f27e2ea2d9"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3a2b053a0ab7a3960c98725cfb0bf5b48ba82f64ec95fe06f1d06c99b552e130"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cd32d6c13807e5c66a7cbb79f90b553642f296ae4518a60d8d76243b0ad2898"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59ec7b7c7e1a61061850d53aaf8e93db63dce0c936db1fda2658b70e4a1be709"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da4cfb373035def307905d05041c1d06d8936452fe89d464743ae7fb8371078b"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2400873bccc260b6ae184b2b8a4fec0e4082d30648eadb7c3d9a13405d861e89"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1b04139c4236a0f3aff534479b58f6f849a8b351e1314826c2d230849ed48985"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:4e66e81a5779b65ac21764c295087de82235597a2293d18d943f8e9e32746265"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:7931d8f1f67c4be9ba1dd9c451fb0eeca1a25b89e4d3f89e828fe12a519b782a"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b3f7e75f3015df442238cca659f8baa5f42ce2a8582727981cbfa15fee0ee205"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:bbf1d63eef84b2e8c89011b7f2235b1e0bf7dacc11cac9431fc6468e99ac77fb"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4c380469bd3f970ef677bf2bcba2b6b0b4d5c75e7a020fb863ef75084efad66f"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-win32.whl", hash = "sha256:9408acf3270c4b6baad483865191e3e582b638b1654a007c62e3efe96f09a9a3"}, - {file = "kiwisolver-1.4.5-cp37-cp37m-win_amd64.whl", hash = "sha256:5b94529f9b2591b7af5f3e0e730a4e0a41ea174af35a4fd067775f9bdfeee01a"}, - {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:11c7de8f692fc99816e8ac50d1d1aef4f75126eefc33ac79aac02c099fd3db71"}, - {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:53abb58632235cd154176ced1ae8f0d29a6657aa1aa9decf50b899b755bc2b93"}, - {file = "kiwisolver-1.4.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:88b9f257ca61b838b6f8094a62418421f87ac2a1069f7e896c36a7d86b5d4c29"}, - {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3195782b26fc03aa9c6913d5bad5aeb864bdc372924c093b0f1cebad603dd712"}, - {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc579bf0f502e54926519451b920e875f433aceb4624a3646b3252b5caa9e0b6"}, - {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a580c91d686376f0f7c295357595c5a026e6cbc3d77b7c36e290201e7c11ecb"}, - {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cfe6ab8da05c01ba6fbea630377b5da2cd9bcbc6338510116b01c1bc939a2c18"}, - {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:d2e5a98f0ec99beb3c10e13b387f8db39106d53993f498b295f0c914328b1333"}, - {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a51a263952b1429e429ff236d2f5a21c5125437861baeed77f5e1cc2d2c7c6da"}, - {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3edd2fa14e68c9be82c5b16689e8d63d89fe927e56debd6e1dbce7a26a17f81b"}, - {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:74d1b44c6cfc897df648cc9fdaa09bc3e7679926e6f96df05775d4fb3946571c"}, - {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:76d9289ed3f7501012e05abb8358bbb129149dbd173f1f57a1bf1c22d19ab7cc"}, - {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:92dea1ffe3714fa8eb6a314d2b3c773208d865a0e0d35e713ec54eea08a66250"}, - {file = "kiwisolver-1.4.5-cp38-cp38-win32.whl", hash = "sha256:5c90ae8c8d32e472be041e76f9d2f2dbff4d0b0be8bd4041770eddb18cf49a4e"}, - {file = "kiwisolver-1.4.5-cp38-cp38-win_amd64.whl", hash = "sha256:c7940c1dc63eb37a67721b10d703247552416f719c4188c54e04334321351ced"}, - {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9407b6a5f0d675e8a827ad8742e1d6b49d9c1a1da5d952a67d50ef5f4170b18d"}, - {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15568384086b6df3c65353820a4473575dbad192e35010f622c6ce3eebd57af9"}, - {file = "kiwisolver-1.4.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0dc9db8e79f0036e8173c466d21ef18e1befc02de8bf8aa8dc0813a6dc8a7046"}, - {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:cdc8a402aaee9a798b50d8b827d7ecf75edc5fb35ea0f91f213ff927c15f4ff0"}, - {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6c3bd3cde54cafb87d74d8db50b909705c62b17c2099b8f2e25b461882e544ff"}, - {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:955e8513d07a283056b1396e9a57ceddbd272d9252c14f154d450d227606eb54"}, - {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:346f5343b9e3f00b8db8ba359350eb124b98c99efd0b408728ac6ebf38173958"}, - {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9098e0049e88c6a24ff64545cdfc50807818ba6c1b739cae221bbbcbc58aad3"}, - {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:00bd361b903dc4bbf4eb165f24d1acbee754fce22ded24c3d56eec268658a5cf"}, - {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7b8b454bac16428b22560d0a1cf0a09875339cab69df61d7805bf48919415901"}, - {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f1d072c2eb0ad60d4c183f3fb44ac6f73fb7a8f16a2694a91f988275cbf352f9"}, - {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:31a82d498054cac9f6d0b53d02bb85811185bcb477d4b60144f915f3b3126342"}, - {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6512cb89e334e4700febbffaaa52761b65b4f5a3cf33f960213d5656cea36a77"}, - {file = "kiwisolver-1.4.5-cp39-cp39-win32.whl", hash = "sha256:9db8ea4c388fdb0f780fe91346fd438657ea602d58348753d9fb265ce1bca67f"}, - {file = "kiwisolver-1.4.5-cp39-cp39-win_amd64.whl", hash = "sha256:59415f46a37f7f2efeec758353dd2eae1b07640d8ca0f0c42548ec4125492635"}, - {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5c7b3b3a728dc6faf3fc372ef24f21d1e3cee2ac3e9596691d746e5a536de920"}, - {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:620ced262a86244e2be10a676b646f29c34537d0d9cc8eb26c08f53d98013390"}, - {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:378a214a1e3bbf5ac4a8708304318b4f890da88c9e6a07699c4ae7174c09a68d"}, - {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf7be1207676ac608a50cd08f102f6742dbfc70e8d60c4db1c6897f62f71523"}, - {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ba55dce0a9b8ff59495ddd050a0225d58bd0983d09f87cfe2b6aec4f2c1234e4"}, - {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fd32ea360bcbb92d28933fc05ed09bffcb1704ba3fc7942e81db0fd4f81a7892"}, - {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5e7139af55d1688f8b960ee9ad5adafc4ac17c1c473fe07133ac092310d76544"}, - {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dced8146011d2bc2e883f9bd68618b8247387f4bbec46d7392b3c3b032640126"}, - {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9bf3325c47b11b2e51bca0824ea217c7cd84491d8ac4eefd1e409705ef092bd"}, - {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5794cf59533bc3f1b1c821f7206a3617999db9fbefc345360aafe2e067514929"}, - {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e368f200bbc2e4f905b8e71eb38b3c04333bddaa6a2464a6355487b02bb7fb09"}, - {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5d706eba36b4c4d5bc6c6377bb6568098765e990cfc21ee16d13963fab7b3e7"}, - {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85267bd1aa8880a9c88a8cb71e18d3d64d2751a790e6ca6c27b8ccc724bcd5ad"}, - {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:210ef2c3a1f03272649aff1ef992df2e724748918c4bc2d5a90352849eb40bea"}, - {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:11d011a7574eb3b82bcc9c1a1d35c1d7075677fdd15de527d91b46bd35e935ee"}, - {file = "kiwisolver-1.4.5.tar.gz", hash = "sha256:e57e563a57fb22a142da34f38acc2fc1a5c864bc29ca1517a88abc963e60d6ec"}, + {file = "kiwisolver-1.4.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8a9c83f75223d5e48b0bc9cb1bf2776cf01563e00ade8775ffe13b0b6e1af3a6"}, + {file = "kiwisolver-1.4.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:58370b1ffbd35407444d57057b57da5d6549d2d854fa30249771775c63b5fe17"}, + {file = "kiwisolver-1.4.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:aa0abdf853e09aff551db11fce173e2177d00786c688203f52c87ad7fcd91ef9"}, + {file = "kiwisolver-1.4.7-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8d53103597a252fb3ab8b5845af04c7a26d5e7ea8122303dd7a021176a87e8b9"}, + {file = "kiwisolver-1.4.7-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:88f17c5ffa8e9462fb79f62746428dd57b46eb931698e42e990ad63103f35e6c"}, + {file = "kiwisolver-1.4.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88a9ca9c710d598fd75ee5de59d5bda2684d9db36a9f50b6125eaea3969c2599"}, + {file = "kiwisolver-1.4.7-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f4d742cb7af1c28303a51b7a27aaee540e71bb8e24f68c736f6f2ffc82f2bf05"}, + {file = "kiwisolver-1.4.7-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e28c7fea2196bf4c2f8d46a0415c77a1c480cc0724722f23d7410ffe9842c407"}, + {file = "kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e968b84db54f9d42046cf154e02911e39c0435c9801681e3fc9ce8a3c4130278"}, + {file = "kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0c18ec74c0472de033e1bebb2911c3c310eef5649133dd0bedf2a169a1b269e5"}, + {file = "kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8f0ea6da6d393d8b2e187e6a5e3fb81f5862010a40c3945e2c6d12ae45cfb2ad"}, + {file = "kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:f106407dda69ae456dd1227966bf445b157ccc80ba0dff3802bb63f30b74e895"}, + {file = "kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:84ec80df401cfee1457063732d90022f93951944b5b58975d34ab56bb150dfb3"}, + {file = "kiwisolver-1.4.7-cp310-cp310-win32.whl", hash = "sha256:71bb308552200fb2c195e35ef05de12f0c878c07fc91c270eb3d6e41698c3bcc"}, + {file = "kiwisolver-1.4.7-cp310-cp310-win_amd64.whl", hash = "sha256:44756f9fd339de0fb6ee4f8c1696cfd19b2422e0d70b4cefc1cc7f1f64045a8c"}, + {file = "kiwisolver-1.4.7-cp310-cp310-win_arm64.whl", hash = "sha256:78a42513018c41c2ffd262eb676442315cbfe3c44eed82385c2ed043bc63210a"}, + {file = "kiwisolver-1.4.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d2b0e12a42fb4e72d509fc994713d099cbb15ebf1103545e8a45f14da2dfca54"}, + {file = "kiwisolver-1.4.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2a8781ac3edc42ea4b90bc23e7d37b665d89423818e26eb6df90698aa2287c95"}, + {file = "kiwisolver-1.4.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:46707a10836894b559e04b0fd143e343945c97fd170d69a2d26d640b4e297935"}, + {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef97b8df011141c9b0f6caf23b29379f87dd13183c978a30a3c546d2c47314cb"}, + {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ab58c12a2cd0fc769089e6d38466c46d7f76aced0a1f54c77652446733d2d02"}, + {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:803b8e1459341c1bb56d1c5c010406d5edec8a0713a0945851290a7930679b51"}, + {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f9a9e8a507420fe35992ee9ecb302dab68550dedc0da9e2880dd88071c5fb052"}, + {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18077b53dc3bb490e330669a99920c5e6a496889ae8c63b58fbc57c3d7f33a18"}, + {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6af936f79086a89b3680a280c47ea90b4df7047b5bdf3aa5c524bbedddb9e545"}, + {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3abc5b19d24af4b77d1598a585b8a719beb8569a71568b66f4ebe1fb0449460b"}, + {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:933d4de052939d90afbe6e9d5273ae05fb836cc86c15b686edd4b3560cc0ee36"}, + {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:65e720d2ab2b53f1f72fb5da5fb477455905ce2c88aaa671ff0a447c2c80e8e3"}, + {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3bf1ed55088f214ba6427484c59553123fdd9b218a42bbc8c6496d6754b1e523"}, + {file = "kiwisolver-1.4.7-cp311-cp311-win32.whl", hash = "sha256:4c00336b9dd5ad96d0a558fd18a8b6f711b7449acce4c157e7343ba92dd0cf3d"}, + {file = "kiwisolver-1.4.7-cp311-cp311-win_amd64.whl", hash = "sha256:929e294c1ac1e9f615c62a4e4313ca1823ba37326c164ec720a803287c4c499b"}, + {file = "kiwisolver-1.4.7-cp311-cp311-win_arm64.whl", hash = "sha256:e33e8fbd440c917106b237ef1a2f1449dfbb9b6f6e1ce17c94cd6a1e0d438376"}, + {file = "kiwisolver-1.4.7-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:5360cc32706dab3931f738d3079652d20982511f7c0ac5711483e6eab08efff2"}, + {file = "kiwisolver-1.4.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:942216596dc64ddb25adb215c3c783215b23626f8d84e8eff8d6d45c3f29f75a"}, + {file = "kiwisolver-1.4.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:48b571ecd8bae15702e4f22d3ff6a0f13e54d3d00cd25216d5e7f658242065ee"}, + {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ad42ba922c67c5f219097b28fae965e10045ddf145d2928bfac2eb2e17673640"}, + {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:612a10bdae23404a72941a0fc8fa2660c6ea1217c4ce0dbcab8a8f6543ea9e7f"}, + {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9e838bba3a3bac0fe06d849d29772eb1afb9745a59710762e4ba3f4cb8424483"}, + {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:22f499f6157236c19f4bbbd472fa55b063db77a16cd74d49afe28992dff8c258"}, + {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:693902d433cf585133699972b6d7c42a8b9f8f826ebcaf0132ff55200afc599e"}, + {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4e77f2126c3e0b0d055f44513ed349038ac180371ed9b52fe96a32aa071a5107"}, + {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:657a05857bda581c3656bfc3b20e353c232e9193eb167766ad2dc58b56504948"}, + {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4bfa75a048c056a411f9705856abfc872558e33c055d80af6a380e3658766038"}, + {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:34ea1de54beef1c104422d210c47c7d2a4999bdecf42c7b5718fbe59a4cac383"}, + {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:90da3b5f694b85231cf93586dad5e90e2d71b9428f9aad96952c99055582f520"}, + {file = "kiwisolver-1.4.7-cp312-cp312-win32.whl", hash = "sha256:18e0cca3e008e17fe9b164b55735a325140a5a35faad8de92dd80265cd5eb80b"}, + {file = "kiwisolver-1.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:58cb20602b18f86f83a5c87d3ee1c766a79c0d452f8def86d925e6c60fbf7bfb"}, + {file = "kiwisolver-1.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:f5a8b53bdc0b3961f8b6125e198617c40aeed638b387913bf1ce78afb1b0be2a"}, + {file = "kiwisolver-1.4.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2e6039dcbe79a8e0f044f1c39db1986a1b8071051efba3ee4d74f5b365f5226e"}, + {file = "kiwisolver-1.4.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a1ecf0ac1c518487d9d23b1cd7139a6a65bc460cd101ab01f1be82ecf09794b6"}, + {file = "kiwisolver-1.4.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7ab9ccab2b5bd5702ab0803676a580fffa2aa178c2badc5557a84cc943fcf750"}, + {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f816dd2277f8d63d79f9c8473a79fe54047bc0467754962840782c575522224d"}, + {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf8bcc23ceb5a1b624572a1623b9f79d2c3b337c8c455405ef231933a10da379"}, + {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dea0bf229319828467d7fca8c7c189780aa9ff679c94539eed7532ebe33ed37c"}, + {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c06a4c7cf15ec739ce0e5971b26c93638730090add60e183530d70848ebdd34"}, + {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:913983ad2deb14e66d83c28b632fd35ba2b825031f2fa4ca29675e665dfecbe1"}, + {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5337ec7809bcd0f424c6b705ecf97941c46279cf5ed92311782c7c9c2026f07f"}, + {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4c26ed10c4f6fa6ddb329a5120ba3b6db349ca192ae211e882970bfc9d91420b"}, + {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c619b101e6de2222c1fcb0531e1b17bbffbe54294bfba43ea0d411d428618c27"}, + {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:073a36c8273647592ea332e816e75ef8da5c303236ec0167196793eb1e34657a"}, + {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3ce6b2b0231bda412463e152fc18335ba32faf4e8c23a754ad50ffa70e4091ee"}, + {file = "kiwisolver-1.4.7-cp313-cp313-win32.whl", hash = "sha256:f4c9aee212bc89d4e13f58be11a56cc8036cabad119259d12ace14b34476fd07"}, + {file = "kiwisolver-1.4.7-cp313-cp313-win_amd64.whl", hash = "sha256:8a3ec5aa8e38fc4c8af308917ce12c536f1c88452ce554027e55b22cbbfbff76"}, + {file = "kiwisolver-1.4.7-cp313-cp313-win_arm64.whl", hash = "sha256:76c8094ac20ec259471ac53e774623eb62e6e1f56cd8690c67ce6ce4fcb05650"}, + {file = "kiwisolver-1.4.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5d5abf8f8ec1f4e22882273c423e16cae834c36856cac348cfbfa68e01c40f3a"}, + {file = "kiwisolver-1.4.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:aeb3531b196ef6f11776c21674dba836aeea9d5bd1cf630f869e3d90b16cfade"}, + {file = "kiwisolver-1.4.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b7d755065e4e866a8086c9bdada157133ff466476a2ad7861828e17b6026e22c"}, + {file = "kiwisolver-1.4.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08471d4d86cbaec61f86b217dd938a83d85e03785f51121e791a6e6689a3be95"}, + {file = "kiwisolver-1.4.7-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7bbfcb7165ce3d54a3dfbe731e470f65739c4c1f85bb1018ee912bae139e263b"}, + {file = "kiwisolver-1.4.7-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d34eb8494bea691a1a450141ebb5385e4b69d38bb8403b5146ad279f4b30fa3"}, + {file = "kiwisolver-1.4.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9242795d174daa40105c1d86aba618e8eab7bf96ba8c3ee614da8302a9f95503"}, + {file = "kiwisolver-1.4.7-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a0f64a48bb81af7450e641e3fe0b0394d7381e342805479178b3d335d60ca7cf"}, + {file = "kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:8e045731a5416357638d1700927529e2b8ab304811671f665b225f8bf8d8f933"}, + {file = "kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:4322872d5772cae7369f8351da1edf255a604ea7087fe295411397d0cfd9655e"}, + {file = "kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:e1631290ee9271dffe3062d2634c3ecac02c83890ada077d225e081aca8aab89"}, + {file = "kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:edcfc407e4eb17e037bca59be0e85a2031a2ac87e4fed26d3e9df88b4165f92d"}, + {file = "kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:4d05d81ecb47d11e7f8932bd8b61b720bf0b41199358f3f5e36d38e28f0532c5"}, + {file = "kiwisolver-1.4.7-cp38-cp38-win32.whl", hash = "sha256:b38ac83d5f04b15e515fd86f312479d950d05ce2368d5413d46c088dda7de90a"}, + {file = "kiwisolver-1.4.7-cp38-cp38-win_amd64.whl", hash = "sha256:d83db7cde68459fc803052a55ace60bea2bae361fc3b7a6d5da07e11954e4b09"}, + {file = "kiwisolver-1.4.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3f9362ecfca44c863569d3d3c033dbe8ba452ff8eed6f6b5806382741a1334bd"}, + {file = "kiwisolver-1.4.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e8df2eb9b2bac43ef8b082e06f750350fbbaf2887534a5be97f6cf07b19d9583"}, + {file = "kiwisolver-1.4.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f32d6edbc638cde7652bd690c3e728b25332acbadd7cad670cc4a02558d9c417"}, + {file = "kiwisolver-1.4.7-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:e2e6c39bd7b9372b0be21456caab138e8e69cc0fc1190a9dfa92bd45a1e6e904"}, + {file = "kiwisolver-1.4.7-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dda56c24d869b1193fcc763f1284b9126550eaf84b88bbc7256e15028f19188a"}, + {file = "kiwisolver-1.4.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79849239c39b5e1fd906556c474d9b0439ea6792b637511f3fe3a41158d89ca8"}, + {file = "kiwisolver-1.4.7-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5e3bc157fed2a4c02ec468de4ecd12a6e22818d4f09cde2c31ee3226ffbefab2"}, + {file = "kiwisolver-1.4.7-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3da53da805b71e41053dc670f9a820d1157aae77b6b944e08024d17bcd51ef88"}, + {file = "kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8705f17dfeb43139a692298cb6637ee2e59c0194538153e83e9ee0c75c2eddde"}, + {file = "kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:82a5c2f4b87c26bb1a0ef3d16b5c4753434633b83d365cc0ddf2770c93829e3c"}, + {file = "kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce8be0466f4c0d585cdb6c1e2ed07232221df101a4c6f28821d2aa754ca2d9e2"}, + {file = "kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:409afdfe1e2e90e6ee7fc896f3df9a7fec8e793e58bfa0d052c8a82f99c37abb"}, + {file = "kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5b9c3f4ee0b9a439d2415012bd1b1cc2df59e4d6a9939f4d669241d30b414327"}, + {file = "kiwisolver-1.4.7-cp39-cp39-win32.whl", hash = "sha256:a79ae34384df2b615eefca647a2873842ac3b596418032bef9a7283675962644"}, + {file = "kiwisolver-1.4.7-cp39-cp39-win_amd64.whl", hash = "sha256:cf0438b42121a66a3a667de17e779330fc0f20b0d97d59d2f2121e182b0505e4"}, + {file = "kiwisolver-1.4.7-cp39-cp39-win_arm64.whl", hash = "sha256:764202cc7e70f767dab49e8df52c7455e8de0df5d858fa801a11aa0d882ccf3f"}, + {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:94252291e3fe68001b1dd747b4c0b3be12582839b95ad4d1b641924d68fd4643"}, + {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5b7dfa3b546da08a9f622bb6becdb14b3e24aaa30adba66749d38f3cc7ea9706"}, + {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bd3de6481f4ed8b734da5df134cd5a6a64fe32124fe83dde1e5b5f29fe30b1e6"}, + {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a91b5f9f1205845d488c928e8570dcb62b893372f63b8b6e98b863ebd2368ff2"}, + {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40fa14dbd66b8b8f470d5fc79c089a66185619d31645f9b0773b88b19f7223c4"}, + {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:eb542fe7933aa09d8d8f9d9097ef37532a7df6497819d16efe4359890a2f417a"}, + {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bfa1acfa0c54932d5607e19a2c24646fb4c1ae2694437789129cf099789a3b00"}, + {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:eee3ea935c3d227d49b4eb85660ff631556841f6e567f0f7bda972df6c2c9935"}, + {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f3160309af4396e0ed04db259c3ccbfdc3621b5559b5453075e5de555e1f3a1b"}, + {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a17f6a29cf8935e587cc8a4dbfc8368c55edc645283db0ce9801016f83526c2d"}, + {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:10849fb2c1ecbfae45a693c070e0320a91b35dd4bcf58172c023b994283a124d"}, + {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:ac542bf38a8a4be2dc6b15248d36315ccc65f0743f7b1a76688ffb6b5129a5c2"}, + {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:8b01aac285f91ca889c800042c35ad3b239e704b150cfd3382adfc9dcc780e39"}, + {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:48be928f59a1f5c8207154f935334d374e79f2b5d212826307d072595ad76a2e"}, + {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f37cfe618a117e50d8c240555331160d73d0411422b59b5ee217843d7b693608"}, + {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:599b5c873c63a1f6ed7eead644a8a380cfbdf5db91dcb6f85707aaab213b1674"}, + {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:801fa7802e5cfabe3ab0c81a34c323a319b097dfb5004be950482d882f3d7225"}, + {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:0c6c43471bc764fad4bc99c5c2d6d16a676b1abf844ca7c8702bdae92df01ee0"}, + {file = "kiwisolver-1.4.7.tar.gz", hash = "sha256:9893ff81bd7107f7b685d3017cc6583daadb4fc26e4a888350df530e41980a60"}, ] [[package]] name = "manimpango" -version = "0.5.0" +version = "0.6.0" description = "Bindings for Pango for using with Manim." optional = false python-versions = ">=3.8" files = [ - {file = "ManimPango-0.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b3309536038e11a4020bf5422d36b691e5583d38f616311c75527faa853fa948"}, - {file = "ManimPango-0.5.0-cp310-cp310-win32.whl", hash = "sha256:7e301f0d2ceeb05b82dbb5ddd1e2397b6de7ef4ab556d04c0765eb29f18be981"}, - {file = "ManimPango-0.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:26053a59e352c11e33fa224be6fde095a08c9db2665895ada7689fdeb225064c"}, - {file = "ManimPango-0.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f8a866a03c8a569dfaf08035748aea5c56f5e729d12682aae5d25fbe837a6270"}, - {file = "ManimPango-0.5.0-cp311-cp311-win32.whl", hash = "sha256:5de05ac673b1ac597cc3e4e0e05756195b387f8f96b81cd03767a9f12f8af3f4"}, - {file = "ManimPango-0.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:86e68c085e455d4bd607c2f63fcce41d1496a873dde29c413a3fbd98ff99c258"}, - {file = "ManimPango-0.5.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:bf4a09fe1989763ea041fcce044ce501d89678bcc14084949f6792fc3b204517"}, - {file = "ManimPango-0.5.0-cp312-cp312-win32.whl", hash = "sha256:0b5e47755cce7848fa268b5f77f17fc4fe363d30f5412fef845560df26dece82"}, - {file = "ManimPango-0.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:aef7151c210fce42518eff7a00e4b07d497a2516e13945d56b9b4a6427fae3f6"}, - {file = "ManimPango-0.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f1b614dc33b1cc012ef38a49b04def005e80a14592bdd389be91a9073a71be30"}, - {file = "ManimPango-0.5.0-cp38-cp38-win32.whl", hash = "sha256:d135fbc2049b3cb22fa941e7333c10a42b29aa080871dd4e80d169da2337b797"}, - {file = "ManimPango-0.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:9bb032625d5c663c4727bae61870e3c16696278c569c98a094b14953f22a70c8"}, - {file = "ManimPango-0.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5d58e736ccf2afb3398c42ad1d478b84176785ad19cb994dfc9575030bfd040f"}, - {file = "ManimPango-0.5.0-cp39-cp39-win32.whl", hash = "sha256:8c453e9511d5888c92aa1f7b120b7f3318fc21fd7a4862156c9b094986f2e17d"}, - {file = "ManimPango-0.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:b81d815b1a5e78376ae9b6aa2d7606d38cc19e31eb89480471462bbdf0fcd3c7"}, - {file = "ManimPango-0.5.0.tar.gz", hash = "sha256:299913bbccb0f15954b64401cf9df24607e1a01edda589ea77de1ed4cc2bc284"}, + {file = "ManimPango-0.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:025605af4e789dad2d8895b0c820d4e5c8001929a2998a4a694518869f32e5f8"}, + {file = "ManimPango-0.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:72d70b8110f1fb5641fe0d1c9483d10aa7cd190c099490ce809acfab3dce6b69"}, + {file = "ManimPango-0.6.0-cp310-cp310-win32.whl", hash = "sha256:287205a4c82e35b84c259a5f03068295d544b105d387457cb670c167e2a13598"}, + {file = "ManimPango-0.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:b1e1a86ed9e814cdd230958f7c9bb874400f6808bff29e6b76abc55faa9b4899"}, + {file = "ManimPango-0.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:af1f631bc8fd925db351e0c9498aec8bf6639dcd3ad99ca5fce73766ad137640"}, + {file = "ManimPango-0.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:92d4c20845eb5920f5487e0929ac3dab517f623d1093ef1524ab7679b01b11fb"}, + {file = "ManimPango-0.6.0-cp311-cp311-win32.whl", hash = "sha256:f6ba4d65bbc157705a92cb7f07bad0d8a82a392cec8b23347fa2e2f756793fbb"}, + {file = "ManimPango-0.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:386c4ea41cfbab2d68b1ccc982510cdd2a9aef25e63c92f6ac7d0dee48e3513b"}, + {file = "ManimPango-0.6.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:9d10bf902dbb66c98f28909ac9327296da141eaa696986a59b3459e3358d9a34"}, + {file = "ManimPango-0.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6ab751239d82233d9c9ea1aa8f9cb23257733ee0607e82a76abc0cd75dde66e5"}, + {file = "ManimPango-0.6.0-cp312-cp312-win32.whl", hash = "sha256:7a8e2c164e7f03e2152e94fd5bf597e977ef67fbbf1031c72f2254479fc892af"}, + {file = "ManimPango-0.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:061fd61a9f27df0c8ed75beb1fa4e5c06d5186eb37a5830a852aa3ac0737fcfe"}, + {file = "ManimPango-0.6.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5156dc1fa2a6321f64a4110aa9dbe0c5ba507839f947fa3dfc72b5c63d729c88"}, + {file = "ManimPango-0.6.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:67809f65ec10397361a2650069ccac9fcf64babf75daf58eb38d9bcfb49e968b"}, + {file = "ManimPango-0.6.0-cp313-cp313-win32.whl", hash = "sha256:ba6279fd087ac3ac0a64c24a8b47fa0bdf0c8351c177cd07e3e793252899bd2d"}, + {file = "ManimPango-0.6.0-cp313-cp313-win_amd64.whl", hash = "sha256:bb13f56a41ba251f70fd57643dc42cee689a1ebbec5eaf305722c7100008e253"}, + {file = "ManimPango-0.6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c88297f21091fb4031173f66bc55ea4e11d1df4412ba4edf3a5ccdb06dbf2c0f"}, + {file = "ManimPango-0.6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5c0c1bb36588d4951d5560ce1ee6831f23f0f7d22c93b4fd9dcf0752908d9d57"}, + {file = "ManimPango-0.6.0-cp39-cp39-win32.whl", hash = "sha256:ff9e515f9a79f7010c68efd9da19d5c11ba33bd139d1c53b0a18b73d9f20ce7d"}, + {file = "ManimPango-0.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:93ae1b0f2fd4b4f1774dd5b2f4a3b834043d5ee42efc3dfb351755f4f548059d"}, + {file = "manimpango-0.6.0.tar.gz", hash = "sha256:d959708e5c05e87317b37df5f6c5258aa9d1ed694a0b25b19d6a4f861841e191"}, ] [[package]] name = "mapbox-earcut" -version = "1.0.1" -description = "Python bindings for the mapbox earcut C++ polygon triangulation library." +version = "1.0.2" +description = "Python bindings for the mapbox earcut C++ polygon triangulation library." optional = false -python-versions = "*" +python-versions = ">=3.9" files = [ - {file = "mapbox_earcut-1.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:60f8299b724b5ad1f171c2666a12591845536b0e9318ddc9649f75805096686c"}, - {file = "mapbox_earcut-1.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4af0911ed9d1920c36c54b500ea69fbcc948f409c66f632c75b15fee04c7544e"}, - {file = "mapbox_earcut-1.0.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:584fd2f7de878f14b3268257ec3c55bac146f1adc1887a64f0ecbf91ee39489f"}, - {file = "mapbox_earcut-1.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20929541c1c9f5fefde45c6c33e8ed3138c7bdd1034ced998877913878f3457c"}, - {file = "mapbox_earcut-1.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:48e8d8ebadd4e4d0dfd87374d43ca3caf8c8e692f1b6897588594d12527d5020"}, - {file = "mapbox_earcut-1.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:352f92997fd39024919a258db29df1642dd98632807ca96e737242adf64b5e96"}, - {file = "mapbox_earcut-1.0.1-cp310-cp310-win32.whl", hash = "sha256:5cf359c5ae1a5dcdd6d9c150ec43a820a289c28596ae7c52de09075543cc19ae"}, - {file = "mapbox_earcut-1.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f5cd49d6e13b3627c6cd6d3a945285e1ce7e9b193f3ce5ca53f0b7b86acd41e"}, - {file = "mapbox_earcut-1.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1e02d61d01aa1239ffbe1b8384cdc224d7c67db604eb7bfc34dd39fb1dc515c2"}, - {file = "mapbox_earcut-1.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d170d0a79b4ef3c9591ec6727a0ab35bae9e267b389122365343d6f55f9027a0"}, - {file = "mapbox_earcut-1.0.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78945356229992d7aa6da750059f401f329651adc76c000505a0e9e4f93be5df"}, - {file = "mapbox_earcut-1.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66cf29a2434d3366889c69fc50e6d2f9f1abf3a8a4154c7e03ef8f180d3bea40"}, - {file = "mapbox_earcut-1.0.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:a73f6f422932b2758b03f78e92aa5c4d5b5f7ce6456483f5993f4677b0bbde23"}, - {file = "mapbox_earcut-1.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9af9369266bf0ca32f4d401152217c46c699392513f22639c6b1be32bde9c1cc"}, - {file = "mapbox_earcut-1.0.1-cp311-cp311-win32.whl", hash = "sha256:ff9a13be4364625697b0e0e04ba6a0f77300148b871bba0a85bfa67e972e85c4"}, - {file = "mapbox_earcut-1.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:5e736557539c74fa969e866889c2b0149fc12668f35e3ae33667d837ff2880d3"}, - {file = "mapbox_earcut-1.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4fe92174410e4120022393013705d77cb856ead5bdf6c81bec614a70df4feb5d"}, - {file = "mapbox_earcut-1.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:082f70a865c6164a60af039aa1c377073901cf1f94fd37b1c5610dfbae2a7369"}, - {file = "mapbox_earcut-1.0.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43d268ece49d0c9e22cb4f92cd54c2cc64f71bf1c5e10800c189880d923e1292"}, - {file = "mapbox_earcut-1.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7748f1730fd36dd1fcf0809d8f872d7e1ddaa945f66a6a466ad37ef3c552ae93"}, - {file = "mapbox_earcut-1.0.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:5a82d10c8dec2a0bd9a6a6c90aca7044017c8dad79f7e209fd0667826f842325"}, - {file = "mapbox_earcut-1.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:01b292588cd3f6bad7d76ee31c004ed1b557a92bbd9602a72d2be15513b755be"}, - {file = "mapbox_earcut-1.0.1-cp312-cp312-win32.whl", hash = "sha256:fce236ddc3a56ea7260acc94601a832c260e6ac5619374bb2cec2e73e7414ff0"}, - {file = "mapbox_earcut-1.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:1ce86407353b4f09f5778c436518bbbc6f258f46c5736446f25074fe3d3a3bd8"}, - {file = "mapbox_earcut-1.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:aa6111a18efacb79c081f3d3cdd7d25d0585bb0e9f28896b207ebe1d56efa40e"}, - {file = "mapbox_earcut-1.0.1-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2911829d1e6e5e1282fbe2840fadf578f606580f02ed436346c2d51c92f810b"}, - {file = "mapbox_earcut-1.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01ff909a7b8405a923abedd701b53633c997cc2b5dc9d5b78462f51c25ec2c33"}, - {file = "mapbox_earcut-1.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:b7e73477b4ef3951ef5c32848126f047ac7fd2dd04dc033444a85261a346ed08"}, - {file = "mapbox_earcut-1.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:dae325af3553afa4d0ca0caa5afe57dc3d2e3a90a51dfbabc49a5ce1ea1009f7"}, - {file = "mapbox_earcut-1.0.1-cp36-cp36m-win32.whl", hash = "sha256:29f8f746a9c68f1509084b0c78227d4e142241a2e30aab6def872e53a46f7281"}, - {file = "mapbox_earcut-1.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:3c487b93b0e1059b404be4daea62c22cfc8054ffd88591377848c8e399d4abeb"}, - {file = "mapbox_earcut-1.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f85f8d95503dba4612a2dd5c076ed18845a46cea4ba38660e4929efccb5a594a"}, - {file = "mapbox_earcut-1.0.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8ade6c4822be1680c933bda32af0bb23a73e63e951db348ac1adef8de137239"}, - {file = "mapbox_earcut-1.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:04431a498a836c62aba5d807572daf3c8b064b25ab83e79994498455524ce517"}, - {file = "mapbox_earcut-1.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:714d33603c59d7306650615d7b05d51da273f1aa5b41c3b462207271a2283fa7"}, - {file = "mapbox_earcut-1.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:065faa6b4a7525faa48e46e692176cbcf9587ade7a1abdb2c96cb6477ab0004d"}, - {file = "mapbox_earcut-1.0.1-cp37-cp37m-win32.whl", hash = "sha256:9f433276f54e302aa0c3ef0f8edb7a4092cdd677aafc623fab2b81e1db9f2729"}, - {file = "mapbox_earcut-1.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:2ac93a18a19acffaa7dc42646534f3850b545d6ad31469f3b7157efc9da113db"}, - {file = "mapbox_earcut-1.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b23d0b41d5d7e72fa197e981c3e317f234336b4594bb64252837a0558c9c505d"}, - {file = "mapbox_earcut-1.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:57337d9cf95a97b926eab57845525501df61abb0334ed59502a6485cf9216f64"}, - {file = "mapbox_earcut-1.0.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5447f35b1dda5f89a6d5c95e9a1831f1c5aaf1eeac853f0b2f3df97ec81c2c75"}, - {file = "mapbox_earcut-1.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dffb3e2a0253e3e2e1b7638df80a029d4d80f38db42a7736f92a8e8d4d1a3209"}, - {file = "mapbox_earcut-1.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:202761e67b0974b1618e638b83a1bb24d0a421a0c773435833a368b9b4f0ee2b"}, - {file = "mapbox_earcut-1.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:9c37424997c46f45f16a8ec42fc892a011f9528257f207e2aae4bd14cfcd7c3d"}, - {file = "mapbox_earcut-1.0.1-cp38-cp38-win32.whl", hash = "sha256:ed5ec84c85a6e6cbfa294bdcbf567d3fa0abec9191acc8f362552946b8b7b398"}, - {file = "mapbox_earcut-1.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:da5eeb66f50b01e77340b00f29867fa89df4b9e28646f9a0b8f6b5c8827515fd"}, - {file = "mapbox_earcut-1.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:eb4aa9a7d1c5f92458d73f460d1f063fbcb38c50ff1f0b7e3485b8dc0f1f6635"}, - {file = "mapbox_earcut-1.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f7f779084b11bd74be374be69054803ac36095a68d1a0da1d499a47d3c7f7ccc"}, - {file = "mapbox_earcut-1.0.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5190425932e82e22e3e35dfb892f5eb441aef155c45fa055da027c72c124b3d1"}, - {file = "mapbox_earcut-1.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d68b47dc4ab2aaa9ec163c18bc6133c74739990b5013d17e13bac2d1b5c9afea"}, - {file = "mapbox_earcut-1.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e1b737d4b7b1c52c3915b898714e036990149a422343ec1481ac66b35df17f24"}, - {file = "mapbox_earcut-1.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3b77f444324a3b0e91ba2b4b2d533a66503f8fb7103e4901d0064ec2413bff8c"}, - {file = "mapbox_earcut-1.0.1-cp39-cp39-win32.whl", hash = "sha256:db61cec2374ff063e314c40b3a868237d2af1b0d98f3ec1217bc0f881e7cc40a"}, - {file = "mapbox_earcut-1.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:86b8c3732fb93f4e8ed8b1cc8388b93a72d0e9755a00f324e780b15a00fe5bc0"}, - {file = "mapbox_earcut-1.0.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0b5ad819f3fd57fc8a18c7b61a244e63b2a24475195f57e826a066e007a7a877"}, - {file = "mapbox_earcut-1.0.1-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:732e5c86037692f6c635dc4e139520be8366cde0fd39dbe122480f657b2cca90"}, - {file = "mapbox_earcut-1.0.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6cf7c0d0d862addc99fe0b33150c8f5c06baafa320b6dd6f67d17309512d1e9a"}, - {file = "mapbox_earcut-1.0.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:8416071bd3af616afab4513347b064274899f73e0ffe309c2a1be66600736c98"}, - {file = "mapbox_earcut-1.0.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1310c3e208e0bfd6da090ae65226ee49adba4078fe1ed2d95197c3b97ad513b9"}, - {file = "mapbox_earcut-1.0.1-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b657a30f677de4005f497c79ab3bb2827ba01e2642cb58ac30242f7cff48e40b"}, - {file = "mapbox_earcut-1.0.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:34e3476d9af878887fd0d9cce759d6951fe0cc6c240e13afed1ff38fc23fc9d5"}, - {file = "mapbox_earcut-1.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e480ce4794b0c391f0b829362c78ec74b690104ef36866160a7e14232b2d3779"}, - {file = "mapbox_earcut-1.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c21271dd89263d037af5caeac425e54a8fba727ea30d1b42e3ce94cc675df15a"}, - {file = "mapbox_earcut-1.0.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11c784ba52c981dcf709bcc8de99d75a214a476f7c16369d219ca4751c7f6f6f"}, - {file = "mapbox_earcut-1.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be37a75c94017a2efaffc8763475867d4860fc4cb3262b6839d635690403d28f"}, - {file = "mapbox_earcut-1.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2ad50f947d44c8c1c0900c3e1869a4a550509450117b87b0368b06014f66590b"}, - {file = "mapbox_earcut-1.0.1.tar.gz", hash = "sha256:9f155e429a22e27387cfd7a6372c3a3865aafa609ad725e2c4465257f154a438"}, + {file = "mapbox_earcut-1.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:97203bf92a654f430d6aed9fde363a8fe25f2124b030bbe1a53860ce33ebd7a3"}, + {file = "mapbox_earcut-1.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ae5241af655f0148657b9de6c83782cae0c8d34f114957e128556273fc875f55"}, + {file = "mapbox_earcut-1.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f87262025203f258230823a1614d6d9ab10f327b4aacc15029e76c127cf471c"}, + {file = "mapbox_earcut-1.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af83d40e98729aefce4a9e4ab54af239856ae600de7384134df15534545bccad"}, + {file = "mapbox_earcut-1.0.2-cp310-cp310-win32.whl", hash = "sha256:ae990d62be6d2ed305b33845d4553def84711655b70bed1d26b50dd7ff9679d2"}, + {file = "mapbox_earcut-1.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:df7451676d145f9157758ca44398eb9d385e844264113b84a4e0571946ad6253"}, + {file = "mapbox_earcut-1.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:02d80b510e5ed078537bbb969eb852d7577d4053669546d71b376aa1ccd0296b"}, + {file = "mapbox_earcut-1.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:606dd427c554e8ddfba69b3283442410451a27222cb774ec348c3a30c0089d66"}, + {file = "mapbox_earcut-1.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8945a66c511e01a5e3e5524351527e4c7c13a95c9c513db55420cdbbcffbcdc"}, + {file = "mapbox_earcut-1.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e5c6d9031ba3e72aa4431fff64a39e019948564cc0677f44a2a3949b4f19a466"}, + {file = "mapbox_earcut-1.0.2-cp311-cp311-win32.whl", hash = "sha256:441f613ecafbed2608783f00584c89fa922c2cc954881204ed319a673d5dc762"}, + {file = "mapbox_earcut-1.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:6b3b1562da8545287097a8c5ddd8ee509350575e37e6185c047fe7710578fd80"}, + {file = "mapbox_earcut-1.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:40c3d8d2ae66e184ef90874f26bf2678928587e8d6ec64388b226801c39dee8b"}, + {file = "mapbox_earcut-1.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c432668b46bf80c76cd03ea7ae3f8137c5de10dc78efd38197f4ce82a80f84b2"}, + {file = "mapbox_earcut-1.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17cb7dcadb09eb239c1b0c47c7853ca3aa82d8828d5cd826a72ce53d61c1240b"}, + {file = "mapbox_earcut-1.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fa187a1f18363fe6ecdbf46b1c5cca9b7fc4e4333fa95120ecd5f99cb6a3fb36"}, + {file = "mapbox_earcut-1.0.2-cp312-cp312-win32.whl", hash = "sha256:c698c255f9e7f8b040fa5e886d44784db92617d4126851c484ac431065310af2"}, + {file = "mapbox_earcut-1.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:a1eb860bc40db2dd82d920835820cb5d5f488460dfef1dfc24f7a53f3c78bb59"}, + {file = "mapbox_earcut-1.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3ef8096385d46b07b80bdbe9311bef6f19e777d82b9ea47de50a7f10c2ce08f4"}, + {file = "mapbox_earcut-1.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3b0c83439dc69fadbd893886f49b952d27cb080745baeb1615ad5f0a0354e854"}, + {file = "mapbox_earcut-1.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72cfd7f6ff0d8dd19bd982661091e47d2878717584b390ec43e9f83dbfe60616"}, + {file = "mapbox_earcut-1.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:49432419ada8a6d74fd827df0331faad52b21cbd39ff91d701aec5e5db553c51"}, + {file = "mapbox_earcut-1.0.2-cp39-cp39-win32.whl", hash = "sha256:464f2469dba2d852b735dc7be1ff9bc3559555d1d985ac3af22f14042beb16f8"}, + {file = "mapbox_earcut-1.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:0ba2b51d4f336db774d9874a08ca47313a09f22a8368c7f7021c0c2768827b81"}, + {file = "mapbox_earcut-1.0.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:dfc64fad3686a2ce2ea63a28c173580f489048a1cd36a4449959533bc5675788"}, + {file = "mapbox_earcut-1.0.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:a62e46c55b5b5256052954d0eb20a0ba5cc7019adfdb0ff8cfba15ecf781b0c5"}, + {file = "mapbox_earcut-1.0.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6e44d5f5dbe2dd26c94de9a24ace47c034f86cb96d68fe01561334e4f50d5dc"}, + {file = "mapbox_earcut-1.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:1f96a52d8eaf041821d0aefaa53ea908fefede4f4826ab9384e0449314403478"}, + {file = "mapbox_earcut-1.0.2-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7483171c540c1e91dd2c6d5ac864cbe98ad70a460907b863c3ffb25cb4493416"}, + {file = "mapbox_earcut-1.0.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:8fc9597aa789d36d262a29b87432d6139def095ebd1499c035fa2123a393eacd"}, + {file = "mapbox_earcut-1.0.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37475996c833f3d95fbf721df0d88593f5a152b48a1a5603b7da3979911a6519"}, + {file = "mapbox_earcut-1.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:5444d9af72d23e581d0eaf1be342193c1f4c2bd2c8b70cdf692a58185b3637c0"}, + {file = "mapbox_earcut-1.0.2.tar.gz", hash = "sha256:83fa0468bcc23f300a1cbf9611bdc30c77aace9ab1d36821649f439490ee7d52"}, ] [package.dependencies] @@ -2180,109 +2094,122 @@ testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] [[package]] name = "markupsafe" -version = "2.1.5" +version = "3.0.2" description = "Safely add untrusted strings to HTML/XML markup." optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, - {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a"}, + {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, ] [[package]] name = "matplotlib" -version = "3.9.0" +version = "3.9.3" description = "Python plotting package" optional = false python-versions = ">=3.9" files = [ - {file = "matplotlib-3.9.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2bcee1dffaf60fe7656183ac2190bd630842ff87b3153afb3e384d966b57fe56"}, - {file = "matplotlib-3.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3f988bafb0fa39d1074ddd5bacd958c853e11def40800c5824556eb630f94d3b"}, - {file = "matplotlib-3.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe428e191ea016bb278758c8ee82a8129c51d81d8c4bc0846c09e7e8e9057241"}, - {file = "matplotlib-3.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaf3978060a106fab40c328778b148f590e27f6fa3cd15a19d6892575bce387d"}, - {file = "matplotlib-3.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2e7f03e5cbbfacdd48c8ea394d365d91ee8f3cae7e6ec611409927b5ed997ee4"}, - {file = "matplotlib-3.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:13beb4840317d45ffd4183a778685e215939be7b08616f431c7795276e067463"}, - {file = "matplotlib-3.9.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:063af8587fceeac13b0936c42a2b6c732c2ab1c98d38abc3337e430e1ff75e38"}, - {file = "matplotlib-3.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9a2fa6d899e17ddca6d6526cf6e7ba677738bf2a6a9590d702c277204a7c6152"}, - {file = "matplotlib-3.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:550cdda3adbd596078cca7d13ed50b77879104e2e46392dcd7c75259d8f00e85"}, - {file = "matplotlib-3.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76cce0f31b351e3551d1f3779420cf8f6ec0d4a8cf9c0237a3b549fd28eb4abb"}, - {file = "matplotlib-3.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c53aeb514ccbbcbab55a27f912d79ea30ab21ee0531ee2c09f13800efb272674"}, - {file = "matplotlib-3.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:a5be985db2596d761cdf0c2eaf52396f26e6a64ab46bd8cd810c48972349d1be"}, - {file = "matplotlib-3.9.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:c79f3a585f1368da6049318bdf1f85568d8d04b2e89fc24b7e02cc9b62017382"}, - {file = "matplotlib-3.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bdd1ecbe268eb3e7653e04f451635f0fb0f77f07fd070242b44c076c9106da84"}, - {file = "matplotlib-3.9.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d38e85a1a6d732f645f1403ce5e6727fd9418cd4574521d5803d3d94911038e5"}, - {file = "matplotlib-3.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a490715b3b9984fa609116481b22178348c1a220a4499cda79132000a79b4db"}, - {file = "matplotlib-3.9.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8146ce83cbc5dc71c223a74a1996d446cd35cfb6a04b683e1446b7e6c73603b7"}, - {file = "matplotlib-3.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:d91a4ffc587bacf5c4ce4ecfe4bcd23a4b675e76315f2866e588686cc97fccdf"}, - {file = "matplotlib-3.9.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:616fabf4981a3b3c5a15cd95eba359c8489c4e20e03717aea42866d8d0465956"}, - {file = "matplotlib-3.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cd53c79fd02f1c1808d2cfc87dd3cf4dbc63c5244a58ee7944497107469c8d8a"}, - {file = "matplotlib-3.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06a478f0d67636554fa78558cfbcd7b9dba85b51f5c3b5a0c9be49010cf5f321"}, - {file = "matplotlib-3.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81c40af649d19c85f8073e25e5806926986806fa6d54be506fbf02aef47d5a89"}, - {file = "matplotlib-3.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:52146fc3bd7813cc784562cb93a15788be0b2875c4655e2cc6ea646bfa30344b"}, - {file = "matplotlib-3.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:0fc51eaa5262553868461c083d9adadb11a6017315f3a757fc45ec6ec5f02888"}, - {file = "matplotlib-3.9.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:bd4f2831168afac55b881db82a7730992aa41c4f007f1913465fb182d6fb20c0"}, - {file = "matplotlib-3.9.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:290d304e59be2b33ef5c2d768d0237f5bd132986bdcc66f80bc9bcc300066a03"}, - {file = "matplotlib-3.9.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ff2e239c26be4f24bfa45860c20ffccd118d270c5b5d081fa4ea409b5469fcd"}, - {file = "matplotlib-3.9.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:af4001b7cae70f7eaacfb063db605280058246de590fa7874f00f62259f2df7e"}, - {file = "matplotlib-3.9.0.tar.gz", hash = "sha256:e6d29ea6c19e34b30fb7d88b7081f869a03014f66fe06d62cc77d5a6ea88ed7a"}, + {file = "matplotlib-3.9.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:41b016e3be4e740b66c79a031a0a6e145728dbc248142e751e8dab4f3188ca1d"}, + {file = "matplotlib-3.9.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e0143975fc2a6d7136c97e19c637321288371e8f09cff2564ecd73e865ea0b9"}, + {file = "matplotlib-3.9.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f459c8ee2c086455744723628264e43c884be0c7d7b45d84b8cd981310b4815"}, + {file = "matplotlib-3.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:687df7ceff57b8f070d02b4db66f75566370e7ae182a0782b6d3d21b0d6917dc"}, + {file = "matplotlib-3.9.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:edd14cf733fdc4f6e6fe3f705af97676a7e52859bf0044aa2c84e55be739241c"}, + {file = "matplotlib-3.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:1c40c244221a1adbb1256692b1133c6fb89418df27bf759a31a333e7912a4010"}, + {file = "matplotlib-3.9.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:cf2a60daf6cecff6828bc608df00dbc794380e7234d2411c0ec612811f01969d"}, + {file = "matplotlib-3.9.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:213d6dc25ce686516208d8a3e91120c6a4fdae4a3e06b8505ced5b716b50cc04"}, + {file = "matplotlib-3.9.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c52f48eb75fcc119a4fdb68ba83eb5f71656999420375df7c94cc68e0e14686e"}, + {file = "matplotlib-3.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3c93796b44fa111049b88a24105e947f03c01966b5c0cc782e2ee3887b790a3"}, + {file = "matplotlib-3.9.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:cd1077b9a09b16d8c3c7075a8add5ffbfe6a69156a57e290c800ed4d435bef1d"}, + {file = "matplotlib-3.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:c96eeeb8c68b662c7747f91a385688d4b449687d29b691eff7068a4602fe6dc4"}, + {file = "matplotlib-3.9.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0a361bd5583bf0bcc08841df3c10269617ee2a36b99ac39d455a767da908bbbc"}, + {file = "matplotlib-3.9.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e14485bb1b83eeb3d55b6878f9560240981e7bbc7a8d4e1e8c38b9bd6ec8d2de"}, + {file = "matplotlib-3.9.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a8d279f78844aad213c4935c18f8292a9432d51af2d88bca99072c903948045"}, + {file = "matplotlib-3.9.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6c12514329ac0d03128cf1dcceb335f4fbf7c11da98bca68dca8dcb983153a9"}, + {file = "matplotlib-3.9.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6e9de2b390d253a508dd497e9b5579f3a851f208763ed67fdca5dc0c3ea6849c"}, + {file = "matplotlib-3.9.3-cp312-cp312-win_amd64.whl", hash = "sha256:d796272408f8567ff7eaa00eb2856b3a00524490e47ad505b0b4ca6bb8a7411f"}, + {file = "matplotlib-3.9.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:203d18df84f5288973b2d56de63d4678cc748250026ca9e1ad8f8a0fd8a75d83"}, + {file = "matplotlib-3.9.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b651b0d3642991259109dc0351fc33ad44c624801367bb8307be9bfc35e427ad"}, + {file = "matplotlib-3.9.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:66d7b171fecf96940ce069923a08ba3df33ef542de82c2ff4fe8caa8346fa95a"}, + {file = "matplotlib-3.9.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6be0ba61f6ff2e6b68e4270fb63b6813c9e7dec3d15fc3a93f47480444fd72f0"}, + {file = "matplotlib-3.9.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9d6b2e8856dec3a6db1ae51aec85c82223e834b228c1d3228aede87eee2b34f9"}, + {file = "matplotlib-3.9.3-cp313-cp313-win_amd64.whl", hash = "sha256:90a85a004fefed9e583597478420bf904bb1a065b0b0ee5b9d8d31b04b0f3f70"}, + {file = "matplotlib-3.9.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:3119b2f16de7f7b9212ba76d8fe6a0e9f90b27a1e04683cd89833a991682f639"}, + {file = "matplotlib-3.9.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:87ad73763d93add1b6c1f9fcd33af662fd62ed70e620c52fcb79f3ac427cf3a6"}, + {file = "matplotlib-3.9.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:026bdf3137ab6022c866efa4813b6bbeddc2ed4c9e7e02f0e323a7bca380dfa0"}, + {file = "matplotlib-3.9.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:760a5e89ebbb172989e8273024a1024b0f084510b9105261b3b00c15e9c9f006"}, + {file = "matplotlib-3.9.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a42b9dc42de2cfe357efa27d9c50c7833fc5ab9b2eb7252ccd5d5f836a84e1e4"}, + {file = "matplotlib-3.9.3-cp313-cp313t-win_amd64.whl", hash = "sha256:e0fcb7da73fbf67b5f4bdaa57d85bb585a4e913d4a10f3e15b32baea56a67f0a"}, + {file = "matplotlib-3.9.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:031b7f5b8e595cc07def77ec5b58464e9bb67dc5760be5d6f26d9da24892481d"}, + {file = "matplotlib-3.9.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9fa6e193c14d6944e0685cdb527cb6b38b0e4a518043e7212f214113af7391da"}, + {file = "matplotlib-3.9.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e6eefae6effa0c35bbbc18c25ee6e0b1da44d2359c3cd526eb0c9e703cf055d"}, + {file = "matplotlib-3.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10d3e5c7a99bd28afb957e1ae661323b0800d75b419f24d041ed1cc5d844a764"}, + {file = "matplotlib-3.9.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:816a966d5d376bf24c92af8f379e78e67278833e4c7cbc9fa41872eec629a060"}, + {file = "matplotlib-3.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fb0b37c896172899a4a93d9442ffdc6f870165f59e05ce2e07c6fded1c15749"}, + {file = "matplotlib-3.9.3-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5f2a4ea08e6876206d511365b0bc234edc813d90b930be72c3011bbd7898796f"}, + {file = "matplotlib-3.9.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:9b081dac96ab19c54fd8558fac17c9d2c9cb5cc4656e7ed3261ddc927ba3e2c5"}, + {file = "matplotlib-3.9.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a0a63cb8404d1d1f94968ef35738900038137dab8af836b6c21bb6f03d75465"}, + {file = "matplotlib-3.9.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:896774766fd6be4571a43bc2fcbcb1dcca0807e53cab4a5bf88c4aa861a08e12"}, + {file = "matplotlib-3.9.3.tar.gz", hash = "sha256:cd5dbbc8e25cad5f706845c4d100e2c8b34691b412b93717ce38d8ae803bcfa5"}, ] [package.dependencies] @@ -2298,7 +2225,7 @@ pyparsing = ">=2.3.1" python-dateutil = ">=2.7" [package.extras] -dev = ["meson-python (>=0.13.1)", "numpy (>=1.25)", "pybind11 (>=2.6)", "setuptools (>=64)", "setuptools_scm (>=7)"] +dev = ["meson-python (>=0.13.1)", "numpy (>=1.25)", "pybind11 (>=2.6,!=2.13.3)", "setuptools (>=64)", "setuptools_scm (>=7)"] [[package]] name = "matplotlib-inline" @@ -2314,26 +2241,15 @@ files = [ [package.dependencies] traitlets = "*" -[[package]] -name = "mccabe" -version = "0.7.0" -description = "McCabe checker, plugin for flake8" -optional = false -python-versions = ">=3.6" -files = [ - {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, - {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, -] - [[package]] name = "mdit-py-plugins" -version = "0.4.1" +version = "0.4.2" description = "Collection of plugins for markdown-it-py" optional = false python-versions = ">=3.8" files = [ - {file = "mdit_py_plugins-0.4.1-py3-none-any.whl", hash = "sha256:1020dfe4e6bfc2c79fb49ae4e3f5b297f5ccd20f010187acc52af2921e27dc6a"}, - {file = "mdit_py_plugins-0.4.1.tar.gz", hash = "sha256:834b8ac23d1cd60cec703646ffd22ae97b7955a6d596eb1d304be1e251ae499c"}, + {file = "mdit_py_plugins-0.4.2-py3-none-any.whl", hash = "sha256:0c673c3f889399a33b95e88d2f0d111b4447bdfea7f237dab2d488f459835636"}, + {file = "mdit_py_plugins-0.4.2.tar.gz", hash = "sha256:5f2cd1fdb606ddf152d37ec30e46101a60512bc0e5fa1a7002c36647b09e26b5"}, ] [package.dependencies] @@ -2368,102 +2284,92 @@ files = [ [[package]] name = "moderngl" -version = "5.10.0" +version = "5.12.0" description = "ModernGL: High performance rendering for Python 3" optional = false python-versions = ">=3.7" files = [ - {file = "moderngl-5.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ec38a4883bbfa9a094b7fec8f37c5aed031df0e060ff5451842bd4db9e30f340"}, - {file = "moderngl-5.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:461b4185b56fc318d42f965160809f08955b8e857545c99cfa89a6734044d256"}, - {file = "moderngl-5.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:046a85cc3cffbdac5a45ed53c8f10c601e4737a172e3c1307a05b3693733d6e0"}, - {file = "moderngl-5.10.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:111dd17837ec3a62a38fb8fb78376a09dcb39910554ed0df45fbb3db84d1db4e"}, - {file = "moderngl-5.10.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:72dc0169e3264391905cebd11ed379ba45724329cebc9cd32b2d928f3a33ed5a"}, - {file = "moderngl-5.10.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bf4814039f365c0ad9da00fb8fb884fdce0d4e63bb042a8c1c551bce13d0ff06"}, - {file = "moderngl-5.10.0-cp310-cp310-win32.whl", hash = "sha256:33b0bbd26319cdef724326997484768eb092f223245edc394541cafe59523568"}, - {file = "moderngl-5.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:28c45e477cc2e47189bc6696b73777072d4c76ad59de4f8fd027ba5c6561b2c0"}, - {file = "moderngl-5.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d31c49eb5ffeddb62d6d2b09737d7d7713faa8bc4eb293623cc625f0b4ed6020"}, - {file = "moderngl-5.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ded56b6a182b216bdd63d63b6d373c4f4a58f20816e71c53d555cde9fba366d6"}, - {file = "moderngl-5.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd105d15c7b73ba972d0bbf962cd2bbb762b9937fdfdd658990c7c9d2805e183"}, - {file = "moderngl-5.10.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9e853e869c421632572a0fda929131f2c7a290ad50f45dcbcbcebca78b0d688"}, - {file = "moderngl-5.10.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:61cd81ec6914745e416c2d9feec25541a9f800aeb387952ec73569ced3054ff9"}, - {file = "moderngl-5.10.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:164d03e4a54d36cfa17165e1aa61f321068b84b5792e55490b447929bcdf973c"}, - {file = "moderngl-5.10.0-cp311-cp311-win32.whl", hash = "sha256:cd11dbe2b598ff4e43424120b6bf9f222a4be095be1d37b0ea43b208937a7e67"}, - {file = "moderngl-5.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:996e2963df7b9d0d82cedc80e970f4cbf214cc98b09d14cc2681f2e786477367"}, - {file = "moderngl-5.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1996348331a458d79e60efe6c21e9b1997f338913cd441a4b40635f8202ffed5"}, - {file = "moderngl-5.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9d4c3199ec68ab6dfaa931c1f851897d00b7cfc8df20fcfdb5d36427ee74d19"}, - {file = "moderngl-5.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d37297241bd819f2e70747fdac3b8e8d12e1ace06078baea53164fa5b6f2c5a8"}, - {file = "moderngl-5.10.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6421d352685fe3f54641efb03c7f10f1c8e9e99739ccb6f09cd7fded13cf6530"}, - {file = "moderngl-5.10.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:249e9e2e82f8ef8f8167ddede17e19c9255d81b3327e3e875842fa4779b8bbc7"}, - {file = "moderngl-5.10.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:51e7732ae0af7cb367db3f211808aeacde4d4d02da09a5e1413c7a505f44b63a"}, - {file = "moderngl-5.10.0-cp312-cp312-win32.whl", hash = "sha256:fbf3cf3034271d5cff7fe7002a05fd2b6277beee9daf9d47d7772e62daf29a8a"}, - {file = "moderngl-5.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:e92ab93fb4d948879b8a0d2d2905493015f1f4ffb7b43aa3d9c9c88e26daa393"}, - {file = "moderngl-5.10.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:ae28c3ca47724c023de886afc205cb73afdd5fb8593514bb58b6181504958580"}, - {file = "moderngl-5.10.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17ea8080802252b0bed60bf0490321c8c6a0d4cfad4b0924e967a7c802c6396e"}, - {file = "moderngl-5.10.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:160fcabf2a98057608fdde72105f23495d204dd643aab1083ed8f775fde70a25"}, - {file = "moderngl-5.10.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:64ede63c5b0eb598c8d4c4afc7bd1d257522f11d78765749c248f96a2994c3a4"}, - {file = "moderngl-5.10.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:3e4de1d3fffb39b6d790b3713602f05772976e2cb2c6ad4eb91dd0ce19689906"}, - {file = "moderngl-5.10.0-cp37-cp37m-win32.whl", hash = "sha256:79803b3e475b9b9eb87ebe02ccde9694b4a3aa0d988894a35e571b6c265199d6"}, - {file = "moderngl-5.10.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d0b8df2d54cd81ff95a2281f88331fadce9a58b340bc03b74d178eca760805f4"}, - {file = "moderngl-5.10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d9db7aa884a561d912a0d545d38d0d2dfe587ed8230271fac3143af5141349fe"}, - {file = "moderngl-5.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:81a287198055d2818571976e920b32975e13e1bcdbaf51ca2e13ef314b3479b2"}, - {file = "moderngl-5.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d116513974c7f2177cab352678d8db1f3181385000bd10c6c2d8e3892c4a2c3"}, - {file = "moderngl-5.10.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01a932fb195fd48a3a9e850397b6b952f48aa238f9da24073730f53c31773665"}, - {file = "moderngl-5.10.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6cdb4f9542536b1e23a30f5049eced10010568ff6762b381c5ee47f18d4885be"}, - {file = "moderngl-5.10.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3dc94d9ca08d712650ca465ca355bab49ad2a3a2ab4841f90f00cc575c09d760"}, - {file = "moderngl-5.10.0-cp38-cp38-win32.whl", hash = "sha256:5f00c5e8e94d4fc8e74bc0e91ce120e5b83c9d470d33db96f2ccd54d8ffd84bf"}, - {file = "moderngl-5.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:90b29cf49cb9fb95176446489d9c448f9bf21d683d66b09f9f3fffcb1dbd7aed"}, - {file = "moderngl-5.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e8a0957053488983e853e881e4d7b1bb5cec8208956dfbe9fb6e1454113d3921"}, - {file = "moderngl-5.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3c3600f33d453b77c3f577f46585807eab3a7c14d9b4555c6c553ee883794223"}, - {file = "moderngl-5.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a28a10cce3656768f1fb1f1a49a87b2b0803f30e775a9605ce2875f5ae3d740a"}, - {file = "moderngl-5.10.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02828648a362ac6d399f4babeb156cf1ccdc94053c94c9d80cbf436365f15877"}, - {file = "moderngl-5.10.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:5dd8802df9e33e035ff11428a0b813ce9d3ba7e6c852685b30dbe6d6ecf78219"}, - {file = "moderngl-5.10.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:72e3e9a5d6fb7ae25d091603b3770e53c6f0f148a2ce82a6d7c0dcd50c03f221"}, - {file = "moderngl-5.10.0-cp39-cp39-win32.whl", hash = "sha256:6ab3d8848d926cb5768daef7b15b596f833f4a699ff9c87f92f264da9cfd5f8d"}, - {file = "moderngl-5.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:3fd5e3ff2eda7d8152e2191d281ed9744708789049c9feaf32e3f8480ad36ac6"}, - {file = "moderngl-5.10.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d40c48e3d4af310807d10be4952b67d390aef83d9c1188a4562724b137381cd8"}, - {file = "moderngl-5.10.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4e02ba34dee05bce0c6f13eff2b705f12d8b869156d16ac39146616b7b8fd75"}, - {file = "moderngl-5.10.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48a71dcaa94b2d9d89cff53d76b7b7ba8b98b9c98983851968710d143c29260b"}, - {file = "moderngl-5.10.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:6933e00279414ea82487262b1418843c813770d34f3b49ffa491a489629d83a8"}, - {file = "moderngl-5.10.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8d2b579e151a68e96f46962c85dcb0ef87c1eef78f9997a1eb38c93a05d78105"}, - {file = "moderngl-5.10.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8762385bc961c3e8c4d62ee3d565b70699df69674613c8815cc6a72260a455b"}, - {file = "moderngl-5.10.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e3b2d4d631b0119790d3fc56a9dd6047aa5bc302b5851c0cec5e7504e6ebf5fc"}, - {file = "moderngl-5.10.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:319e8a5baf1fc681b541666bbbb3eb3df0bd127be96ffd751bc995cef7c1ffe3"}, - {file = "moderngl-5.10.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:744a4c1c6c5cd959046f000b1d0af2ec5f8e75df115b91a1e4aa07a67f531520"}, - {file = "moderngl-5.10.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf92d9645f390ac3caa2d21388c04952b6df64694199bfdfcb1bad512c530bb"}, - {file = "moderngl-5.10.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:70964094e98a7209a566c17264b70c9a075a11d7181d943742bfc86e2baa334d"}, - {file = "moderngl-5.10.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:ed976286ff722d4de657dcad0bc14a89a07671ef1ba797b89592e733956600a3"}, - {file = "moderngl-5.10.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ea8bac3464cfe63f910b76cc55f2f11194fe2325fed43edb63bed33b4aee1756"}, - {file = "moderngl-5.10.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e5e88ed0192f15600cc810726a47508a5cc97f3ddfc33aa381c8d9f2d58d54a"}, - {file = "moderngl-5.10.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee4777d2630b575ab5a5dd109b3ab24312e9ea793b8d5a3453f23f16a92a1851"}, - {file = "moderngl-5.10.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:6ce7020588529aba4ea8b55c0861e93f997b4a2cf310eef990942cc5fa1ec8fa"}, - {file = "moderngl-5.10.0.tar.gz", hash = "sha256:119c8d364dde3cd8d1c09f237ed4916617ba759954a1952df4694e51ee4f6511"}, + {file = "moderngl-5.12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:105cdee2ee29a7e6ebbc76cf178941503656a185c6945933bc7ef395ba8e65a7"}, + {file = "moderngl-5.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:18deb8bebd0a4277d92c76dbedf8e4b4b68bf0a8a878404c6b26aed750890d3b"}, + {file = "moderngl-5.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f0c4f7c42425177168938386a4fabd734ca3bbb5de2d1fd1176cfa6f980fc13"}, + {file = "moderngl-5.12.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:878cdf593204d85c020305f21d306f979353a67c932b9df58ea936f6e5ad13e7"}, + {file = "moderngl-5.12.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:00d94f9cb485d87c85088edad624201e152d8ac401793a024b16cd9e2bc4dbf6"}, + {file = "moderngl-5.12.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:edd91057b8d76beebac0d7b0c741466ee8f37eaf3c07856785c2872afe0b35ac"}, + {file = "moderngl-5.12.0-cp310-cp310-win32.whl", hash = "sha256:3d066eae2eb44e81bd7addf565adebc041bdee119e7ac6e4f95831d6f327a938"}, + {file = "moderngl-5.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:76d966194d51852f48c42a6e786a4520f1e1be5f93e2626423d673663422d559"}, + {file = "moderngl-5.12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:28cdba5dcf2d03c89bb25dc3b2f5770ac4104470ed5bbe680a15494fa52a537d"}, + {file = "moderngl-5.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dad93893e3fcb2410bfd31e854f20e1370b4fbafa07a737f1046f5fbd29ba0f4"}, + {file = "moderngl-5.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7fc0f8788bc84433d2124e9a4893adbe40f93c7d213abb8ad7b909540cb0161f"}, + {file = "moderngl-5.12.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6efd3fe0d2c9652af21e2c1f5a936a2b971abac5bdd777da7182a54962466cab"}, + {file = "moderngl-5.12.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6f3bd2d534fc081cde30545b84ebca63aef847ba8bd533217b9a37f565614ade"}, + {file = "moderngl-5.12.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:eaa3de9446c6febec4d5f888e6f1a4e9398bc5a5ea70b1570ea447213641d4a6"}, + {file = "moderngl-5.12.0-cp311-cp311-win32.whl", hash = "sha256:9fdb76f1fd890db67727c8cdee4db2ee6319068c7ce92be0308366f8745e28ab"}, + {file = "moderngl-5.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:0c210e8d52a60025f6586ca015c39feb1e57e6dc792c3ff44800f6493a541b1a"}, + {file = "moderngl-5.12.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2750547707c1ec3790dfbeb9c90fb808672ff13f61cac392c706ba09fda10db0"}, + {file = "moderngl-5.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c5c2a5fe06c7021183d9274df798f25516409c8d55898c324dae8a0b2de10144"}, + {file = "moderngl-5.12.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6c4972f3ddd10a3de6c30311da2c25bc493d023796e16c5d4e0f8bd6d5770be"}, + {file = "moderngl-5.12.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4d497ec6a3f6afa9ebd0be816d9bfe2fe20fec2105acfb88d956619c3ed8eb4"}, + {file = "moderngl-5.12.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:2f3d240e9bc5d83257378bae59f8f35638b89d22bb003cf674b88fd7932161ce"}, + {file = "moderngl-5.12.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6fa667d560d842e778e2a5968305fb78f9781616a11b1b93acd2562f97262ccf"}, + {file = "moderngl-5.12.0-cp312-cp312-win32.whl", hash = "sha256:0a02fddd54dccee1ca6060bfed75a2e6a17dd3ee06920fac418506d8a8233849"}, + {file = "moderngl-5.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:8698a59ad03539a2982125b7998efc1c107ba31d5d03437b6fcd72cb2c226922"}, + {file = "moderngl-5.12.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f6efb432f5164f871471d1da36e3a4be9dc3efd7a1e48d0ac6b751e556af5d02"}, + {file = "moderngl-5.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9b09d8d15b2eaab41c8646a664429ec86af225fa25096758497cd212489d2e1e"}, + {file = "moderngl-5.12.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:071042dd4846e58cbe204cf49341b62cd209fdcb6d48018feb5a61c66707fcb2"}, + {file = "moderngl-5.12.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91db8302ac7f5d7a82a967388677e1378ff078f1e16d05da37ce77f4633b93b1"}, + {file = "moderngl-5.12.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:51971d65ec96a212a814350c8b324ae0754353e1b61826d1a06aa2d060df170e"}, + {file = "moderngl-5.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d56827360c19e831e986243b5daaf6a51006f1ec0d5372084ad446308763d19f"}, + {file = "moderngl-5.12.0-cp313-cp313-win32.whl", hash = "sha256:caa432c12b138a6c9571719075c4d103bdc2504cd31aeda38a00ad10fcf268cb"}, + {file = "moderngl-5.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:e34d1cd38f7998258f76a08bb5e87f351ec653b7ea1928b2711f8719c10cefd1"}, + {file = "moderngl-5.12.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b0712fcce0ebbee962f5e93628118aedcb568d56b5c59f2e9aac43ea57190219"}, + {file = "moderngl-5.12.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:861aae4a38da0f5d82dc2d5ece0f0a6d799809c362343cd1a447ab840a68370f"}, + {file = "moderngl-5.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:726a025ab9822c295369a9ddb1bfaf4930f9645b7a958b74dfcd6a969d7052cf"}, + {file = "moderngl-5.12.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:29a181bae8bde003016fee671b93c2faa3e1460033033e2a832ec9187aa73efb"}, + {file = "moderngl-5.12.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:8b35c17d5497f19c524068f9337cbe5e0e0e5662150b12fa95618665130bbf16"}, + {file = "moderngl-5.12.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:74e5b7df5614f3291d197139a888c967aa29c348e13ebd28ce2a55bf03baed3d"}, + {file = "moderngl-5.12.0-cp38-cp38-win32.whl", hash = "sha256:8dc1bacc24840e5bc562e79be65dc506d6c5a7d40ecac01a062f86d013c890af"}, + {file = "moderngl-5.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:cbd822cf3707fe955cfd940ec68b900519e2c43a5ef8085de5b0c983b4142c8b"}, + {file = "moderngl-5.12.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:49a6e27abafacef104c7ca336f6790f91c69617a1d752ead4a017b706d632b55"}, + {file = "moderngl-5.12.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7146c6fec3b2d7e8d11fa2504046b186d396520c0c2f7ef3aed40d8456dbebfc"}, + {file = "moderngl-5.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28b9eb3574ffc6e303173ca0a419b63d8b12cd67f924289c02d127c4d17cdca5"}, + {file = "moderngl-5.12.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6948237626f9f0d9f931faa3b123d53613d5723679bc70b8db2590924795203f"}, + {file = "moderngl-5.12.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3c6b4342b7508d75744f1091868cf184cae0be85d37be858fba32eb20d799695"}, + {file = "moderngl-5.12.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:13fec30855d346c4e69eff437e56f2bdd9953d22e80b7c5a319bccac7024e463"}, + {file = "moderngl-5.12.0-cp39-cp39-win32.whl", hash = "sha256:878f249505785cde8cc39d6016e62e74b46acbf3bb6d5a86341c86a7da7e7531"}, + {file = "moderngl-5.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:e801cd0d35b4e3e99fc6a6f15eb193ce907bfa78127afa5825f1fad24c700c0e"}, + {file = "moderngl-5.12.0.tar.gz", hash = "sha256:52936a98ccb2f2e1d6e3cb18528b2919f6831e7e3f924e788b5873badce5129b"}, ] [package.dependencies] -glcontext = ">=2.5.0,<3" +glcontext = ">=3.0.0" + +[package.extras] +headless = ["glcontext (>=3.0.0)"] [[package]] name = "moderngl-window" -version = "2.4.6" +version = "3.0.3" description = "A cross platform helper library for ModernGL making window creation and resource loading simple" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "moderngl-window-2.4.6.tar.gz", hash = "sha256:db9b4c27f35faa6f243b6d8cde6ada6da6e79541d62b8e536c0b20da29720c32"}, - {file = "moderngl_window-2.4.6-py3-none-any.whl", hash = "sha256:cfa81c2b222536270a077e2901f5f7a18e317f7332026ae443662555ebf7a66d"}, + {file = "moderngl_window-3.0.3-py3-none-any.whl", hash = "sha256:897d7b3b489824b352218561514979e78c4069172a73e42386f7f22db51029da"}, + {file = "moderngl_window-3.0.3.tar.gz", hash = "sha256:b6108c2396cc54d444c11d7fc77a4db0c2c9a4d74c438ab75ea0ea61949b3143"}, ] [package.dependencies] moderngl = "<6" -numpy = ">=1.16,<2" +numpy = "*" Pillow = ">=10.0.1" pyglet = ">=2.0.0" -pyrr = ">=0.10.3,<1" +pyglm = ">=2.7.0,<3" [package.extras] -dev = ["build", "coverage", "flake8", "mypy", "pytest", "pywavefront", "scipy", "trimesh"] -docs = ["Sphinx (>=7.2.6,<7.3.0)", "doc8", "sphinx-rtd-theme (>=1.3.0,<1.4.0)"] +av = ["av"] +dev = ["build", "coverage", "mypy", "pytest", "pywavefront", "ruff", "scipy", "trimesh"] +docs = ["Sphinx (>=8.1.3,<8.2.0)", "doc8", "sphinx-rtd-dark-mode (==1.3.0)", "sphinx-rtd-theme (>=3.0.1,<3.1.0)"] glfw = ["glfw"] +imgui = ["imgui-bundle"] pdf = ["ReportLab (>=1.2)"] pygame = ["pygame (>=2.0.1)"] pygame-ce = ["pygame-ce (>=2.0.1)"] @@ -2472,29 +2378,7 @@ pysdl2 = ["PySDL2"] pyside2 = ["PySide2 (<6)"] pywavefront = ["pywavefront (>=1.2.0,<2)"] tk = ["pyopengltk (>=0.0.3)"] -trimesh = ["trimesh (>=3.2.6,<4)"] - -[[package]] -name = "multipledispatch" -version = "1.0.0" -description = "Multiple dispatch" -optional = false -python-versions = "*" -files = [ - {file = "multipledispatch-1.0.0-py3-none-any.whl", hash = "sha256:0c53cd8b077546da4e48869f49b13164bebafd0c2a5afceb6bb6a316e7fb46e4"}, - {file = "multipledispatch-1.0.0.tar.gz", hash = "sha256:5c839915465c68206c3e9c473357908216c28383b425361e5d144594bf85a7e0"}, -] - -[[package]] -name = "mypy-extensions" -version = "1.0.0" -description = "Type system extensions for programs checked with the mypy type checker." -optional = false -python-versions = ">=3.5" -files = [ - {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, - {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, -] +trimesh = ["trimesh (>=3.2.6)"] [[package]] name = "myst-parser" @@ -2524,13 +2408,13 @@ testing-docutils = ["pygments", "pytest (>=7,<8)", "pytest-param-files (>=0.3.4, [[package]] name = "nbclient" -version = "0.10.0" +version = "0.10.1" description = "A client library for executing notebooks. Formerly nbconvert's ExecutePreprocessor." optional = true python-versions = ">=3.8.0" files = [ - {file = "nbclient-0.10.0-py3-none-any.whl", hash = "sha256:f13e3529332a1f1f81d82a53210322476a168bb7090a0289c795fe9cc11c9d3f"}, - {file = "nbclient-0.10.0.tar.gz", hash = "sha256:4b3f1b7dba531e498449c4db4f53da339c91d449dc11e9af3a43b4eb5c5abb09"}, + {file = "nbclient-0.10.1-py3-none-any.whl", hash = "sha256:949019b9240d66897e442888cfb618f69ef23dc71c01cb5fced8499c2cfc084d"}, + {file = "nbclient-0.10.1.tar.gz", hash = "sha256:3e93e348ab27e712acd46fccd809139e356eb9a31aab641d1a7991a6eb4e6f68"}, ] [package.dependencies] @@ -2541,7 +2425,7 @@ traitlets = ">=5.4" [package.extras] dev = ["pre-commit"] -docs = ["autodoc-traits", "mock", "moto", "myst-parser", "nbclient[test]", "sphinx (>=1.7)", "sphinx-book-theme", "sphinxcontrib-spelling"] +docs = ["autodoc-traits", "flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "mock", "moto", "myst-parser", "nbconvert (>=7.0.0)", "pytest (>=7.0,<8)", "pytest-asyncio", "pytest-cov (>=4.0)", "sphinx (>=1.7)", "sphinx-book-theme", "sphinxcontrib-spelling", "testpath", "xmltodict"] test = ["flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "nbconvert (>=7.0.0)", "pytest (>=7.0,<8)", "pytest-asyncio", "pytest-cov (>=4.0)", "testpath", "xmltodict"] [[package]] @@ -2634,40 +2518,37 @@ test = ["pytest (>=7.2)", "pytest-cov (>=4.0)"] [[package]] name = "nodeenv" -version = "1.8.0" +version = "1.9.1" description = "Node.js virtual environment builder" optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ - {file = "nodeenv-1.8.0-py2.py3-none-any.whl", hash = "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec"}, - {file = "nodeenv-1.8.0.tar.gz", hash = "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2"}, + {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, + {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, ] -[package.dependencies] -setuptools = "*" - [[package]] name = "notebook" -version = "7.2.0" +version = "7.0.7" description = "Jupyter Notebook - A web-based notebook environment for interactive computing" optional = true python-versions = ">=3.8" files = [ - {file = "notebook-7.2.0-py3-none-any.whl", hash = "sha256:b4752d7407d6c8872fc505df0f00d3cae46e8efb033b822adacbaa3f1f3ce8f5"}, - {file = "notebook-7.2.0.tar.gz", hash = "sha256:34a2ba4b08ad5d19ec930db7484fb79746a1784be9e1a5f8218f9af8656a141f"}, + {file = "notebook-7.0.7-py3-none-any.whl", hash = "sha256:289b606d7e173f75a18beb1406ef411b43f97f7a9c55ba03efa3622905a62346"}, + {file = "notebook-7.0.7.tar.gz", hash = "sha256:3bcff00c17b3ac142ef5f436d50637d936b274cfa0b41f6ac0175363de9b4e09"}, ] [package.dependencies] jupyter-server = ">=2.4.0,<3" -jupyterlab = ">=4.2.0,<4.3" -jupyterlab-server = ">=2.27.1,<3" +jupyterlab = ">=4.0.2,<5" +jupyterlab-server = ">=2.22.1,<3" notebook-shim = ">=0.2,<0.3" tornado = ">=6.2.0" [package.extras] dev = ["hatch", "pre-commit"] docs = ["myst-parser", "nbsphinx", "pydata-sphinx-theme", "sphinx (>=1.3.6)", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] -test = ["importlib-resources (>=5.0)", "ipykernel", "jupyter-server[test] (>=2.4.0,<3)", "jupyterlab-server[test] (>=2.27.1,<3)", "nbval", "pytest (>=7.0)", "pytest-console-scripts", "pytest-timeout", "pytest-tornasync", "requests"] +test = ["importlib-resources (>=5.0)", "ipykernel", "jupyter-server[test] (>=2.4.0,<3)", "jupyterlab-server[test] (>=2.22.1,<3)", "nbval", "pytest (>=7.0)", "pytest-console-scripts", "pytest-timeout", "pytest-tornasync", "requests"] [[package]] name = "notebook-shim" @@ -2688,47 +2569,120 @@ test = ["pytest", "pytest-console-scripts", "pytest-jupyter", "pytest-tornasync" [[package]] name = "numpy" -version = "1.26.4" +version = "2.0.2" description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.9" files = [ - {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, - {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, - {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"}, - {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"}, - {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"}, - {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"}, - {file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"}, - {file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"}, - {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"}, - {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"}, - {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"}, - {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"}, - {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"}, - {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"}, - {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"}, - {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"}, - {file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"}, - {file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"}, - {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"}, - {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"}, - {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"}, - {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"}, - {file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"}, - {file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"}, - {file = "numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c"}, - {file = "numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be"}, - {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764"}, - {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3"}, - {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd"}, - {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c"}, - {file = "numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6"}, - {file = "numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea"}, - {file = "numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30"}, - {file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c"}, - {file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0"}, - {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, + {file = "numpy-2.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:51129a29dbe56f9ca83438b706e2e69a39892b5eda6cedcb6b0c9fdc9b0d3ece"}, + {file = "numpy-2.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f15975dfec0cf2239224d80e32c3170b1d168335eaedee69da84fbe9f1f9cd04"}, + {file = "numpy-2.0.2-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:8c5713284ce4e282544c68d1c3b2c7161d38c256d2eefc93c1d683cf47683e66"}, + {file = "numpy-2.0.2-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:becfae3ddd30736fe1889a37f1f580e245ba79a5855bff5f2a29cb3ccc22dd7b"}, + {file = "numpy-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2da5960c3cf0df7eafefd806d4e612c5e19358de82cb3c343631188991566ccd"}, + {file = "numpy-2.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:496f71341824ed9f3d2fd36cf3ac57ae2e0165c143b55c3a035ee219413f3318"}, + {file = "numpy-2.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a61ec659f68ae254e4d237816e33171497e978140353c0c2038d46e63282d0c8"}, + {file = "numpy-2.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d731a1c6116ba289c1e9ee714b08a8ff882944d4ad631fd411106a30f083c326"}, + {file = "numpy-2.0.2-cp310-cp310-win32.whl", hash = "sha256:984d96121c9f9616cd33fbd0618b7f08e0cfc9600a7ee1d6fd9b239186d19d97"}, + {file = "numpy-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:c7b0be4ef08607dd04da4092faee0b86607f111d5ae68036f16cc787e250a131"}, + {file = "numpy-2.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:49ca4decb342d66018b01932139c0961a8f9ddc7589611158cb3c27cbcf76448"}, + {file = "numpy-2.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:11a76c372d1d37437857280aa142086476136a8c0f373b2e648ab2c8f18fb195"}, + {file = "numpy-2.0.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:807ec44583fd708a21d4a11d94aedf2f4f3c3719035c76a2bbe1fe8e217bdc57"}, + {file = "numpy-2.0.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:8cafab480740e22f8d833acefed5cc87ce276f4ece12fdaa2e8903db2f82897a"}, + {file = "numpy-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a15f476a45e6e5a3a79d8a14e62161d27ad897381fecfa4a09ed5322f2085669"}, + {file = "numpy-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13e689d772146140a252c3a28501da66dfecd77490b498b168b501835041f951"}, + {file = "numpy-2.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9ea91dfb7c3d1c56a0e55657c0afb38cf1eeae4544c208dc465c3c9f3a7c09f9"}, + {file = "numpy-2.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c1c9307701fec8f3f7a1e6711f9089c06e6284b3afbbcd259f7791282d660a15"}, + {file = "numpy-2.0.2-cp311-cp311-win32.whl", hash = "sha256:a392a68bd329eafac5817e5aefeb39038c48b671afd242710b451e76090e81f4"}, + {file = "numpy-2.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:286cd40ce2b7d652a6f22efdfc6d1edf879440e53e76a75955bc0c826c7e64dc"}, + {file = "numpy-2.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:df55d490dea7934f330006d0f81e8551ba6010a5bf035a249ef61a94f21c500b"}, + {file = "numpy-2.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8df823f570d9adf0978347d1f926b2a867d5608f434a7cff7f7908c6570dcf5e"}, + {file = "numpy-2.0.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:9a92ae5c14811e390f3767053ff54eaee3bf84576d99a2456391401323f4ec2c"}, + {file = "numpy-2.0.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:a842d573724391493a97a62ebbb8e731f8a5dcc5d285dfc99141ca15a3302d0c"}, + {file = "numpy-2.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05e238064fc0610c840d1cf6a13bf63d7e391717d247f1bf0318172e759e692"}, + {file = "numpy-2.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0123ffdaa88fa4ab64835dcbde75dcdf89c453c922f18dced6e27c90d1d0ec5a"}, + {file = "numpy-2.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:96a55f64139912d61de9137f11bf39a55ec8faec288c75a54f93dfd39f7eb40c"}, + {file = "numpy-2.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec9852fb39354b5a45a80bdab5ac02dd02b15f44b3804e9f00c556bf24b4bded"}, + {file = "numpy-2.0.2-cp312-cp312-win32.whl", hash = "sha256:671bec6496f83202ed2d3c8fdc486a8fc86942f2e69ff0e986140339a63bcbe5"}, + {file = "numpy-2.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:cfd41e13fdc257aa5778496b8caa5e856dc4896d4ccf01841daee1d96465467a"}, + {file = "numpy-2.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9059e10581ce4093f735ed23f3b9d283b9d517ff46009ddd485f1747eb22653c"}, + {file = "numpy-2.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:423e89b23490805d2a5a96fe40ec507407b8ee786d66f7328be214f9679df6dd"}, + {file = "numpy-2.0.2-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:2b2955fa6f11907cf7a70dab0d0755159bca87755e831e47932367fc8f2f2d0b"}, + {file = "numpy-2.0.2-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:97032a27bd9d8988b9a97a8c4d2c9f2c15a81f61e2f21404d7e8ef00cb5be729"}, + {file = "numpy-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e795a8be3ddbac43274f18588329c72939870a16cae810c2b73461c40718ab1"}, + {file = "numpy-2.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26b258c385842546006213344c50655ff1555a9338e2e5e02a0756dc3e803dd"}, + {file = "numpy-2.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5fec9451a7789926bcf7c2b8d187292c9f93ea30284802a0ab3f5be8ab36865d"}, + {file = "numpy-2.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9189427407d88ff25ecf8f12469d4d39d35bee1db5d39fc5c168c6f088a6956d"}, + {file = "numpy-2.0.2-cp39-cp39-win32.whl", hash = "sha256:905d16e0c60200656500c95b6b8dca5d109e23cb24abc701d41c02d74c6b3afa"}, + {file = "numpy-2.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:a3f4ab0caa7f053f6797fcd4e1e25caee367db3112ef2b6ef82d749530768c73"}, + {file = "numpy-2.0.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7f0a0c6f12e07fa94133c8a67404322845220c06a9e80e85999afe727f7438b8"}, + {file = "numpy-2.0.2-pp39-pypy39_pp73-macosx_14_0_x86_64.whl", hash = "sha256:312950fdd060354350ed123c0e25a71327d3711584beaef30cdaa93320c392d4"}, + {file = "numpy-2.0.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26df23238872200f63518dd2aa984cfca675d82469535dc7162dc2ee52d9dd5c"}, + {file = "numpy-2.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a46288ec55ebbd58947d31d72be2c63cbf839f0a63b49cb755022310792a3385"}, + {file = "numpy-2.0.2.tar.gz", hash = "sha256:883c987dee1880e2a864ab0dc9892292582510604156762362d9326444636e78"}, +] + +[[package]] +name = "numpy" +version = "2.1.3" +description = "Fundamental package for array computing in Python" +optional = false +python-versions = ">=3.10" +files = [ + {file = "numpy-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c894b4305373b9c5576d7a12b473702afdf48ce5369c074ba304cc5ad8730dff"}, + {file = "numpy-2.1.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b47fbb433d3260adcd51eb54f92a2ffbc90a4595f8970ee00e064c644ac788f5"}, + {file = "numpy-2.1.3-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:825656d0743699c529c5943554d223c021ff0494ff1442152ce887ef4f7561a1"}, + {file = "numpy-2.1.3-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:6a4825252fcc430a182ac4dee5a505053d262c807f8a924603d411f6718b88fd"}, + {file = "numpy-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e711e02f49e176a01d0349d82cb5f05ba4db7d5e7e0defd026328e5cfb3226d3"}, + {file = "numpy-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78574ac2d1a4a02421f25da9559850d59457bac82f2b8d7a44fe83a64f770098"}, + {file = "numpy-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c7662f0e3673fe4e832fe07b65c50342ea27d989f92c80355658c7f888fcc83c"}, + {file = "numpy-2.1.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:fa2d1337dc61c8dc417fbccf20f6d1e139896a30721b7f1e832b2bb6ef4eb6c4"}, + {file = "numpy-2.1.3-cp310-cp310-win32.whl", hash = "sha256:72dcc4a35a8515d83e76b58fdf8113a5c969ccd505c8a946759b24e3182d1f23"}, + {file = "numpy-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:ecc76a9ba2911d8d37ac01de72834d8849e55473457558e12995f4cd53e778e0"}, + {file = "numpy-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4d1167c53b93f1f5d8a139a742b3c6f4d429b54e74e6b57d0eff40045187b15d"}, + {file = "numpy-2.1.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c80e4a09b3d95b4e1cac08643f1152fa71a0a821a2d4277334c88d54b2219a41"}, + {file = "numpy-2.1.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:576a1c1d25e9e02ed7fa5477f30a127fe56debd53b8d2c89d5578f9857d03ca9"}, + {file = "numpy-2.1.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:973faafebaae4c0aaa1a1ca1ce02434554d67e628b8d805e61f874b84e136b09"}, + {file = "numpy-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:762479be47a4863e261a840e8e01608d124ee1361e48b96916f38b119cfda04a"}, + {file = "numpy-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc6f24b3d1ecc1eebfbf5d6051faa49af40b03be1aaa781ebdadcbc090b4539b"}, + {file = "numpy-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:17ee83a1f4fef3c94d16dc1802b998668b5419362c8a4f4e8a491de1b41cc3ee"}, + {file = "numpy-2.1.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:15cb89f39fa6d0bdfb600ea24b250e5f1a3df23f901f51c8debaa6a5d122b2f0"}, + {file = "numpy-2.1.3-cp311-cp311-win32.whl", hash = "sha256:d9beb777a78c331580705326d2367488d5bc473b49a9bc3036c154832520aca9"}, + {file = "numpy-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:d89dd2b6da69c4fff5e39c28a382199ddedc3a5be5390115608345dec660b9e2"}, + {file = "numpy-2.1.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f55ba01150f52b1027829b50d70ef1dafd9821ea82905b63936668403c3b471e"}, + {file = "numpy-2.1.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:13138eadd4f4da03074851a698ffa7e405f41a0845a6b1ad135b81596e4e9958"}, + {file = "numpy-2.1.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:a6b46587b14b888e95e4a24d7b13ae91fa22386c199ee7b418f449032b2fa3b8"}, + {file = "numpy-2.1.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:0fa14563cc46422e99daef53d725d0c326e99e468a9320a240affffe87852564"}, + {file = "numpy-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8637dcd2caa676e475503d1f8fdb327bc495554e10838019651b76d17b98e512"}, + {file = "numpy-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2312b2aa89e1f43ecea6da6ea9a810d06aae08321609d8dc0d0eda6d946a541b"}, + {file = "numpy-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a38c19106902bb19351b83802531fea19dee18e5b37b36454f27f11ff956f7fc"}, + {file = "numpy-2.1.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:02135ade8b8a84011cbb67dc44e07c58f28575cf9ecf8ab304e51c05528c19f0"}, + {file = "numpy-2.1.3-cp312-cp312-win32.whl", hash = "sha256:e6988e90fcf617da2b5c78902fe8e668361b43b4fe26dbf2d7b0f8034d4cafb9"}, + {file = "numpy-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:0d30c543f02e84e92c4b1f415b7c6b5326cbe45ee7882b6b77db7195fb971e3a"}, + {file = "numpy-2.1.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96fe52fcdb9345b7cd82ecd34547fca4321f7656d500eca497eb7ea5a926692f"}, + {file = "numpy-2.1.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f653490b33e9c3a4c1c01d41bc2aef08f9475af51146e4a7710c450cf9761598"}, + {file = "numpy-2.1.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:dc258a761a16daa791081d026f0ed4399b582712e6fc887a95af09df10c5ca57"}, + {file = "numpy-2.1.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:016d0f6f5e77b0f0d45d77387ffa4bb89816b57c835580c3ce8e099ef830befe"}, + {file = "numpy-2.1.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c181ba05ce8299c7aa3125c27b9c2167bca4a4445b7ce73d5febc411ca692e43"}, + {file = "numpy-2.1.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5641516794ca9e5f8a4d17bb45446998c6554704d888f86df9b200e66bdcce56"}, + {file = "numpy-2.1.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ea4dedd6e394a9c180b33c2c872b92f7ce0f8e7ad93e9585312b0c5a04777a4a"}, + {file = "numpy-2.1.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0df3635b9c8ef48bd3be5f862cf71b0a4716fa0e702155c45067c6b711ddcef"}, + {file = "numpy-2.1.3-cp313-cp313-win32.whl", hash = "sha256:50ca6aba6e163363f132b5c101ba078b8cbd3fa92c7865fd7d4d62d9779ac29f"}, + {file = "numpy-2.1.3-cp313-cp313-win_amd64.whl", hash = "sha256:747641635d3d44bcb380d950679462fae44f54b131be347d5ec2bce47d3df9ed"}, + {file = "numpy-2.1.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:996bb9399059c5b82f76b53ff8bb686069c05acc94656bb259b1d63d04a9506f"}, + {file = "numpy-2.1.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:45966d859916ad02b779706bb43b954281db43e185015df6eb3323120188f9e4"}, + {file = "numpy-2.1.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:baed7e8d7481bfe0874b566850cb0b85243e982388b7b23348c6db2ee2b2ae8e"}, + {file = "numpy-2.1.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:a9f7f672a3388133335589cfca93ed468509cb7b93ba3105fce780d04a6576a0"}, + {file = "numpy-2.1.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7aac50327da5d208db2eec22eb11e491e3fe13d22653dce51b0f4109101b408"}, + {file = "numpy-2.1.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4394bc0dbd074b7f9b52024832d16e019decebf86caf909d94f6b3f77a8ee3b6"}, + {file = "numpy-2.1.3-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:50d18c4358a0a8a53f12a8ba9d772ab2d460321e6a93d6064fc22443d189853f"}, + {file = "numpy-2.1.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:14e253bd43fc6b37af4921b10f6add6925878a42a0c5fe83daee390bca80bc17"}, + {file = "numpy-2.1.3-cp313-cp313t-win32.whl", hash = "sha256:08788d27a5fd867a663f6fc753fd7c3ad7e92747efc73c53bca2f19f8bc06f48"}, + {file = "numpy-2.1.3-cp313-cp313t-win_amd64.whl", hash = "sha256:2564fbdf2b99b3f815f2107c1bbc93e2de8ee655a69c261363a1172a79a257d4"}, + {file = "numpy-2.1.3-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4f2015dfe437dfebbfce7c85c7b53d81ba49e71ba7eadbf1df40c915af75979f"}, + {file = "numpy-2.1.3-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:3522b0dfe983a575e6a9ab3a4a4dfe156c3e428468ff08ce582b9bb6bd1d71d4"}, + {file = "numpy-2.1.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c006b607a865b07cd981ccb218a04fc86b600411d83d6fc261357f1c0966755d"}, + {file = "numpy-2.1.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e14e26956e6f1696070788252dcdff11b4aca4c3e8bd166e0df1bb8f315a67cb"}, + {file = "numpy-2.1.3.tar.gz", hash = "sha256:aa08e04e08aaf974d4458def539dece0d28146d866a39da5639596f4921fd761"}, ] [[package]] @@ -2744,13 +2698,13 @@ files = [ [[package]] name = "packaging" -version = "24.0" +version = "24.2" description = "Core utilities for Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, - {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, + {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, + {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, ] [[package]] @@ -2779,17 +2733,6 @@ files = [ qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] testing = ["docopt", "pytest"] -[[package]] -name = "pathspec" -version = "0.12.1" -description = "Utility library for gitignore style pattern matching of file paths." -optional = false -python-versions = ">=3.8" -files = [ - {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, - {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, -] - [[package]] name = "pexpect" version = "4.9.0" @@ -2806,84 +2749,90 @@ ptyprocess = ">=0.5" [[package]] name = "pillow" -version = "10.3.0" +version = "11.0.0" description = "Python Imaging Library (Fork)" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "pillow-10.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:90b9e29824800e90c84e4022dd5cc16eb2d9605ee13f05d47641eb183cd73d45"}, - {file = "pillow-10.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a2c405445c79c3f5a124573a051062300936b0281fee57637e706453e452746c"}, - {file = "pillow-10.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78618cdbccaa74d3f88d0ad6cb8ac3007f1a6fa5c6f19af64b55ca170bfa1edf"}, - {file = "pillow-10.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:261ddb7ca91fcf71757979534fb4c128448b5b4c55cb6152d280312062f69599"}, - {file = "pillow-10.3.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:ce49c67f4ea0609933d01c0731b34b8695a7a748d6c8d186f95e7d085d2fe475"}, - {file = "pillow-10.3.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b14f16f94cbc61215115b9b1236f9c18403c15dd3c52cf629072afa9d54c1cbf"}, - {file = "pillow-10.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d33891be6df59d93df4d846640f0e46f1a807339f09e79a8040bc887bdcd7ed3"}, - {file = "pillow-10.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b50811d664d392f02f7761621303eba9d1b056fb1868c8cdf4231279645c25f5"}, - {file = "pillow-10.3.0-cp310-cp310-win32.whl", hash = "sha256:ca2870d5d10d8726a27396d3ca4cf7976cec0f3cb706debe88e3a5bd4610f7d2"}, - {file = "pillow-10.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:f0d0591a0aeaefdaf9a5e545e7485f89910c977087e7de2b6c388aec32011e9f"}, - {file = "pillow-10.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:ccce24b7ad89adb5a1e34a6ba96ac2530046763912806ad4c247356a8f33a67b"}, - {file = "pillow-10.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:5f77cf66e96ae734717d341c145c5949c63180842a545c47a0ce7ae52ca83795"}, - {file = "pillow-10.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e4b878386c4bf293578b48fc570b84ecfe477d3b77ba39a6e87150af77f40c57"}, - {file = "pillow-10.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdcbb4068117dfd9ce0138d068ac512843c52295ed996ae6dd1faf537b6dbc27"}, - {file = "pillow-10.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9797a6c8fe16f25749b371c02e2ade0efb51155e767a971c61734b1bf6293994"}, - {file = "pillow-10.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:9e91179a242bbc99be65e139e30690e081fe6cb91a8e77faf4c409653de39451"}, - {file = "pillow-10.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:1b87bd9d81d179bd8ab871603bd80d8645729939f90b71e62914e816a76fc6bd"}, - {file = "pillow-10.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:81d09caa7b27ef4e61cb7d8fbf1714f5aec1c6b6c5270ee53504981e6e9121ad"}, - {file = "pillow-10.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:048ad577748b9fa4a99a0548c64f2cb8d672d5bf2e643a739ac8faff1164238c"}, - {file = "pillow-10.3.0-cp311-cp311-win32.whl", hash = "sha256:7161ec49ef0800947dc5570f86568a7bb36fa97dd09e9827dc02b718c5643f09"}, - {file = "pillow-10.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:8eb0908e954d093b02a543dc963984d6e99ad2b5e36503d8a0aaf040505f747d"}, - {file = "pillow-10.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:4e6f7d1c414191c1199f8996d3f2282b9ebea0945693fb67392c75a3a320941f"}, - {file = "pillow-10.3.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:e46f38133e5a060d46bd630faa4d9fa0202377495df1f068a8299fd78c84de84"}, - {file = "pillow-10.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:50b8eae8f7334ec826d6eeffaeeb00e36b5e24aa0b9df322c247539714c6df19"}, - {file = "pillow-10.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d3bea1c75f8c53ee4d505c3e67d8c158ad4df0d83170605b50b64025917f338"}, - {file = "pillow-10.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19aeb96d43902f0a783946a0a87dbdad5c84c936025b8419da0a0cd7724356b1"}, - {file = "pillow-10.3.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:74d28c17412d9caa1066f7a31df8403ec23d5268ba46cd0ad2c50fb82ae40462"}, - {file = "pillow-10.3.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:ff61bfd9253c3915e6d41c651d5f962da23eda633cf02262990094a18a55371a"}, - {file = "pillow-10.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d886f5d353333b4771d21267c7ecc75b710f1a73d72d03ca06df49b09015a9ef"}, - {file = "pillow-10.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b5ec25d8b17217d635f8935dbc1b9aa5907962fae29dff220f2659487891cd3"}, - {file = "pillow-10.3.0-cp312-cp312-win32.whl", hash = "sha256:51243f1ed5161b9945011a7360e997729776f6e5d7005ba0c6879267d4c5139d"}, - {file = "pillow-10.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:412444afb8c4c7a6cc11a47dade32982439925537e483be7c0ae0cf96c4f6a0b"}, - {file = "pillow-10.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:798232c92e7665fe82ac085f9d8e8ca98826f8e27859d9a96b41d519ecd2e49a"}, - {file = "pillow-10.3.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:4eaa22f0d22b1a7e93ff0a596d57fdede2e550aecffb5a1ef1106aaece48e96b"}, - {file = "pillow-10.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cd5e14fbf22a87321b24c88669aad3a51ec052eb145315b3da3b7e3cc105b9a2"}, - {file = "pillow-10.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1530e8f3a4b965eb6a7785cf17a426c779333eb62c9a7d1bbcf3ffd5bf77a4aa"}, - {file = "pillow-10.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d512aafa1d32efa014fa041d38868fda85028e3f930a96f85d49c7d8ddc0383"}, - {file = "pillow-10.3.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:339894035d0ede518b16073bdc2feef4c991ee991a29774b33e515f1d308e08d"}, - {file = "pillow-10.3.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:aa7e402ce11f0885305bfb6afb3434b3cd8f53b563ac065452d9d5654c7b86fd"}, - {file = "pillow-10.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0ea2a783a2bdf2a561808fe4a7a12e9aa3799b701ba305de596bc48b8bdfce9d"}, - {file = "pillow-10.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c78e1b00a87ce43bb37642c0812315b411e856a905d58d597750eb79802aaaa3"}, - {file = "pillow-10.3.0-cp38-cp38-win32.whl", hash = "sha256:72d622d262e463dfb7595202d229f5f3ab4b852289a1cd09650362db23b9eb0b"}, - {file = "pillow-10.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:2034f6759a722da3a3dbd91a81148cf884e91d1b747992ca288ab88c1de15999"}, - {file = "pillow-10.3.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:2ed854e716a89b1afcedea551cd85f2eb2a807613752ab997b9974aaa0d56936"}, - {file = "pillow-10.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dc1a390a82755a8c26c9964d457d4c9cbec5405896cba94cf51f36ea0d855002"}, - {file = "pillow-10.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4203efca580f0dd6f882ca211f923168548f7ba334c189e9eab1178ab840bf60"}, - {file = "pillow-10.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3102045a10945173d38336f6e71a8dc71bcaeed55c3123ad4af82c52807b9375"}, - {file = "pillow-10.3.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:6fb1b30043271ec92dc65f6d9f0b7a830c210b8a96423074b15c7bc999975f57"}, - {file = "pillow-10.3.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:1dfc94946bc60ea375cc39cff0b8da6c7e5f8fcdc1d946beb8da5c216156ddd8"}, - {file = "pillow-10.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b09b86b27a064c9624d0a6c54da01c1beaf5b6cadfa609cf63789b1d08a797b9"}, - {file = "pillow-10.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d3b2348a78bc939b4fed6552abfd2e7988e0f81443ef3911a4b8498ca084f6eb"}, - {file = "pillow-10.3.0-cp39-cp39-win32.whl", hash = "sha256:45ebc7b45406febf07fef35d856f0293a92e7417ae7933207e90bf9090b70572"}, - {file = "pillow-10.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:0ba26351b137ca4e0db0342d5d00d2e355eb29372c05afd544ebf47c0956ffeb"}, - {file = "pillow-10.3.0-cp39-cp39-win_arm64.whl", hash = "sha256:50fd3f6b26e3441ae07b7c979309638b72abc1a25da31a81a7fbd9495713ef4f"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:6b02471b72526ab8a18c39cb7967b72d194ec53c1fd0a70b050565a0f366d355"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8ab74c06ffdab957d7670c2a5a6e1a70181cd10b727cd788c4dd9005b6a8acd9"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:048eeade4c33fdf7e08da40ef402e748df113fd0b4584e32c4af74fe78baaeb2"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e2ec1e921fd07c7cda7962bad283acc2f2a9ccc1b971ee4b216b75fad6f0463"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:4c8e73e99da7db1b4cad7f8d682cf6abad7844da39834c288fbfa394a47bbced"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:16563993329b79513f59142a6b02055e10514c1a8e86dca8b48a893e33cf91e3"}, - {file = "pillow-10.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:dd78700f5788ae180b5ee8902c6aea5a5726bac7c364b202b4b3e3ba2d293170"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:aff76a55a8aa8364d25400a210a65ff59d0168e0b4285ba6bf2bd83cf675ba32"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:b7bc2176354defba3edc2b9a777744462da2f8e921fbaf61e52acb95bafa9828"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:793b4e24db2e8742ca6423d3fde8396db336698c55cd34b660663ee9e45ed37f"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d93480005693d247f8346bc8ee28c72a2191bdf1f6b5db469c096c0c867ac015"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c83341b89884e2b2e55886e8fbbf37c3fa5efd6c8907124aeb72f285ae5696e5"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1a1d1915db1a4fdb2754b9de292642a39a7fb28f1736699527bb649484fb966a"}, - {file = "pillow-10.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a0eaa93d054751ee9964afa21c06247779b90440ca41d184aeb5d410f20ff591"}, - {file = "pillow-10.3.0.tar.gz", hash = "sha256:9d2455fbf44c914840c793e89aa82d0e1763a14253a000743719ae5946814b2d"}, + {file = "pillow-11.0.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:6619654954dc4936fcff82db8eb6401d3159ec6be81e33c6000dfd76ae189947"}, + {file = "pillow-11.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b3c5ac4bed7519088103d9450a1107f76308ecf91d6dabc8a33a2fcfb18d0fba"}, + {file = "pillow-11.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a65149d8ada1055029fcb665452b2814fe7d7082fcb0c5bed6db851cb69b2086"}, + {file = "pillow-11.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88a58d8ac0cc0e7f3a014509f0455248a76629ca9b604eca7dc5927cc593c5e9"}, + {file = "pillow-11.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:c26845094b1af3c91852745ae78e3ea47abf3dbcd1cf962f16b9a5fbe3ee8488"}, + {file = "pillow-11.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:1a61b54f87ab5786b8479f81c4b11f4d61702830354520837f8cc791ebba0f5f"}, + {file = "pillow-11.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:674629ff60030d144b7bca2b8330225a9b11c482ed408813924619c6f302fdbb"}, + {file = "pillow-11.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:598b4e238f13276e0008299bd2482003f48158e2b11826862b1eb2ad7c768b97"}, + {file = "pillow-11.0.0-cp310-cp310-win32.whl", hash = "sha256:9a0f748eaa434a41fccf8e1ee7a3eed68af1b690e75328fd7a60af123c193b50"}, + {file = "pillow-11.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:a5629742881bcbc1f42e840af185fd4d83a5edeb96475a575f4da50d6ede337c"}, + {file = "pillow-11.0.0-cp310-cp310-win_arm64.whl", hash = "sha256:ee217c198f2e41f184f3869f3e485557296d505b5195c513b2bfe0062dc537f1"}, + {file = "pillow-11.0.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1c1d72714f429a521d8d2d018badc42414c3077eb187a59579f28e4270b4b0fc"}, + {file = "pillow-11.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:499c3a1b0d6fc8213519e193796eb1a86a1be4b1877d678b30f83fd979811d1a"}, + {file = "pillow-11.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8b2351c85d855293a299038e1f89db92a2f35e8d2f783489c6f0b2b5f3fe8a3"}, + {file = "pillow-11.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f4dba50cfa56f910241eb7f883c20f1e7b1d8f7d91c750cd0b318bad443f4d5"}, + {file = "pillow-11.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:5ddbfd761ee00c12ee1be86c9c0683ecf5bb14c9772ddbd782085779a63dd55b"}, + {file = "pillow-11.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:45c566eb10b8967d71bf1ab8e4a525e5a93519e29ea071459ce517f6b903d7fa"}, + {file = "pillow-11.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b4fd7bd29610a83a8c9b564d457cf5bd92b4e11e79a4ee4716a63c959699b306"}, + {file = "pillow-11.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:cb929ca942d0ec4fac404cbf520ee6cac37bf35be479b970c4ffadf2b6a1cad9"}, + {file = "pillow-11.0.0-cp311-cp311-win32.whl", hash = "sha256:006bcdd307cc47ba43e924099a038cbf9591062e6c50e570819743f5607404f5"}, + {file = "pillow-11.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:52a2d8323a465f84faaba5236567d212c3668f2ab53e1c74c15583cf507a0291"}, + {file = "pillow-11.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:16095692a253047fe3ec028e951fa4221a1f3ed3d80c397e83541a3037ff67c9"}, + {file = "pillow-11.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d2c0a187a92a1cb5ef2c8ed5412dd8d4334272617f532d4ad4de31e0495bd923"}, + {file = "pillow-11.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:084a07ef0821cfe4858fe86652fffac8e187b6ae677e9906e192aafcc1b69903"}, + {file = "pillow-11.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8069c5179902dcdce0be9bfc8235347fdbac249d23bd90514b7a47a72d9fecf4"}, + {file = "pillow-11.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f02541ef64077f22bf4924f225c0fd1248c168f86e4b7abdedd87d6ebaceab0f"}, + {file = "pillow-11.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:fcb4621042ac4b7865c179bb972ed0da0218a076dc1820ffc48b1d74c1e37fe9"}, + {file = "pillow-11.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:00177a63030d612148e659b55ba99527803288cea7c75fb05766ab7981a8c1b7"}, + {file = "pillow-11.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8853a3bf12afddfdf15f57c4b02d7ded92c7a75a5d7331d19f4f9572a89c17e6"}, + {file = "pillow-11.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3107c66e43bda25359d5ef446f59c497de2b5ed4c7fdba0894f8d6cf3822dafc"}, + {file = "pillow-11.0.0-cp312-cp312-win32.whl", hash = "sha256:86510e3f5eca0ab87429dd77fafc04693195eec7fd6a137c389c3eeb4cfb77c6"}, + {file = "pillow-11.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:8ec4a89295cd6cd4d1058a5e6aec6bf51e0eaaf9714774e1bfac7cfc9051db47"}, + {file = "pillow-11.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:27a7860107500d813fcd203b4ea19b04babe79448268403172782754870dac25"}, + {file = "pillow-11.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bcd1fb5bb7b07f64c15618c89efcc2cfa3e95f0e3bcdbaf4642509de1942a699"}, + {file = "pillow-11.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0e038b0745997c7dcaae350d35859c9715c71e92ffb7e0f4a8e8a16732150f38"}, + {file = "pillow-11.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ae08bd8ffc41aebf578c2af2f9d8749d91f448b3bfd41d7d9ff573d74f2a6b2"}, + {file = "pillow-11.0.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d69bfd8ec3219ae71bcde1f942b728903cad25fafe3100ba2258b973bd2bc1b2"}, + {file = "pillow-11.0.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:61b887f9ddba63ddf62fd02a3ba7add935d053b6dd7d58998c630e6dbade8527"}, + {file = "pillow-11.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:c6a660307ca9d4867caa8d9ca2c2658ab685de83792d1876274991adec7b93fa"}, + {file = "pillow-11.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:73e3a0200cdda995c7e43dd47436c1548f87a30bb27fb871f352a22ab8dcf45f"}, + {file = "pillow-11.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fba162b8872d30fea8c52b258a542c5dfd7b235fb5cb352240c8d63b414013eb"}, + {file = "pillow-11.0.0-cp313-cp313-win32.whl", hash = "sha256:f1b82c27e89fffc6da125d5eb0ca6e68017faf5efc078128cfaa42cf5cb38798"}, + {file = "pillow-11.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:8ba470552b48e5835f1d23ecb936bb7f71d206f9dfeee64245f30c3270b994de"}, + {file = "pillow-11.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:846e193e103b41e984ac921b335df59195356ce3f71dcfd155aa79c603873b84"}, + {file = "pillow-11.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4ad70c4214f67d7466bea6a08061eba35c01b1b89eaa098040a35272a8efb22b"}, + {file = "pillow-11.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:6ec0d5af64f2e3d64a165f490d96368bb5dea8b8f9ad04487f9ab60dc4bb6003"}, + {file = "pillow-11.0.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c809a70e43c7977c4a42aefd62f0131823ebf7dd73556fa5d5950f5b354087e2"}, + {file = "pillow-11.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:4b60c9520f7207aaf2e1d94de026682fc227806c6e1f55bba7606d1c94dd623a"}, + {file = "pillow-11.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1e2688958a840c822279fda0086fec1fdab2f95bf2b717b66871c4ad9859d7e8"}, + {file = "pillow-11.0.0-cp313-cp313t-win32.whl", hash = "sha256:607bbe123c74e272e381a8d1957083a9463401f7bd01287f50521ecb05a313f8"}, + {file = "pillow-11.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5c39ed17edea3bc69c743a8dd3e9853b7509625c2462532e62baa0732163a904"}, + {file = "pillow-11.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:75acbbeb05b86bc53cbe7b7e6fe00fbcf82ad7c684b3ad82e3d711da9ba287d3"}, + {file = "pillow-11.0.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:2e46773dc9f35a1dd28bd6981332fd7f27bec001a918a72a79b4133cf5291dba"}, + {file = "pillow-11.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2679d2258b7f1192b378e2893a8a0a0ca472234d4c2c0e6bdd3380e8dfa21b6a"}, + {file = "pillow-11.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eda2616eb2313cbb3eebbe51f19362eb434b18e3bb599466a1ffa76a033fb916"}, + {file = "pillow-11.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20ec184af98a121fb2da42642dea8a29ec80fc3efbaefb86d8fdd2606619045d"}, + {file = "pillow-11.0.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:8594f42df584e5b4bb9281799698403f7af489fba84c34d53d1c4bfb71b7c4e7"}, + {file = "pillow-11.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:c12b5ae868897c7338519c03049a806af85b9b8c237b7d675b8c5e089e4a618e"}, + {file = "pillow-11.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:70fbbdacd1d271b77b7721fe3cdd2d537bbbd75d29e6300c672ec6bb38d9672f"}, + {file = "pillow-11.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5178952973e588b3f1360868847334e9e3bf49d19e169bbbdfaf8398002419ae"}, + {file = "pillow-11.0.0-cp39-cp39-win32.whl", hash = "sha256:8c676b587da5673d3c75bd67dd2a8cdfeb282ca38a30f37950511766b26858c4"}, + {file = "pillow-11.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:94f3e1780abb45062287b4614a5bc0874519c86a777d4a7ad34978e86428b8dd"}, + {file = "pillow-11.0.0-cp39-cp39-win_arm64.whl", hash = "sha256:290f2cc809f9da7d6d622550bbf4c1e57518212da51b6a30fe8e0a270a5b78bd"}, + {file = "pillow-11.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1187739620f2b365de756ce086fdb3604573337cc28a0d3ac4a01ab6b2d2a6d2"}, + {file = "pillow-11.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:fbbcb7b57dc9c794843e3d1258c0fbf0f48656d46ffe9e09b63bbd6e8cd5d0a2"}, + {file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d203af30149ae339ad1b4f710d9844ed8796e97fda23ffbc4cc472968a47d0b"}, + {file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21a0d3b115009ebb8ac3d2ebec5c2982cc693da935f4ab7bb5c8ebe2f47d36f2"}, + {file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:73853108f56df97baf2bb8b522f3578221e56f646ba345a372c78326710d3830"}, + {file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e58876c91f97b0952eb766123bfef372792ab3f4e3e1f1a2267834c2ab131734"}, + {file = "pillow-11.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:224aaa38177597bb179f3ec87eeefcce8e4f85e608025e9cfac60de237ba6316"}, + {file = "pillow-11.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5bd2d3bdb846d757055910f0a59792d33b555800813c3b39ada1829c372ccb06"}, + {file = "pillow-11.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:375b8dd15a1f5d2feafff536d47e22f69625c1aa92f12b339ec0b2ca40263273"}, + {file = "pillow-11.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:daffdf51ee5db69a82dd127eabecce20729e21f7a3680cf7cbb23f0829189790"}, + {file = "pillow-11.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7326a1787e3c7b0429659e0a944725e1b03eeaa10edd945a86dead1913383944"}, + {file = "pillow-11.0.0.tar.gz", hash = "sha256:72bacbaf24ac003fea9bff9837d1eedb6088758d41e100c1552930151f677739"}, ] [package.extras] -docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"] +docs = ["furo", "olefile", "sphinx (>=8.1)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] fpx = ["olefile"] mic = ["olefile"] tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] @@ -2892,19 +2841,19 @@ xmp = ["defusedxml"] [[package]] name = "platformdirs" -version = "4.2.2" +version = "4.3.6" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" files = [ - {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, - {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, + {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, + {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, ] [package.extras] -docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] -type = ["mypy (>=1.8)"] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.11.2)"] [[package]] name = "pluggy" @@ -2923,13 +2872,13 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pre-commit" -version = "3.7.1" +version = "3.8.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false python-versions = ">=3.9" files = [ - {file = "pre_commit-3.7.1-py2.py3-none-any.whl", hash = "sha256:fae36fd1d7ad7d6a5a1c0b0d5adb2ed1a3bda5a21bf6c3e5372073d7a11cd4c5"}, - {file = "pre_commit-3.7.1.tar.gz", hash = "sha256:8ca3ad567bc78a4972a3f1a477e94a79d4597e8140a6e0b651c5e33899c3654a"}, + {file = "pre_commit-3.8.0-py2.py3-none-any.whl", hash = "sha256:9a90a53bf82fdd8778d58085faf8d83df56e40dfe18f45b19446e26bf1b3a63f"}, + {file = "pre_commit-3.8.0.tar.gz", hash = "sha256:8bb6494d4a20423842e198980c9ecf9f96607a07ea29549e180eef9ae80fe7af"}, ] [package.dependencies] @@ -2941,13 +2890,13 @@ virtualenv = ">=20.10.0" [[package]] name = "prometheus-client" -version = "0.20.0" +version = "0.21.0" description = "Python client for the Prometheus monitoring system." optional = true python-versions = ">=3.8" files = [ - {file = "prometheus_client-0.20.0-py3-none-any.whl", hash = "sha256:cde524a85bce83ca359cc837f28b8c0db5cac7aa653a588fd7e84ba061c329e7"}, - {file = "prometheus_client-0.20.0.tar.gz", hash = "sha256:287629d00b147a32dcb2be0b9df905da599b2d82f80377083ec8463309a4bb89"}, + {file = "prometheus_client-0.21.0-py3-none-any.whl", hash = "sha256:4fa6b4dd0ac16d58bb587c04b1caae65b8c5043e85f778f42f5f632f6af2e166"}, + {file = "prometheus_client-0.21.0.tar.gz", hash = "sha256:96c83c606b71ff2b0a433c98889d275f51ffec6c5e267de37c7a2b5c9aa9233e"}, ] [package.extras] @@ -2955,13 +2904,13 @@ twisted = ["twisted"] [[package]] name = "prompt-toolkit" -version = "3.0.43" +version = "3.0.48" description = "Library for building powerful interactive command lines in Python" optional = true python-versions = ">=3.7.0" files = [ - {file = "prompt_toolkit-3.0.43-py3-none-any.whl", hash = "sha256:a11a29cb3bf0a28a387fe5122cdb649816a957cd9261dcedf8c9f1fef33eacf6"}, - {file = "prompt_toolkit-3.0.43.tar.gz", hash = "sha256:3527b7af26106cbc65a040bcc84839a3566ec1b051bb0bfe953631e704b0ff7d"}, + {file = "prompt_toolkit-3.0.48-py3-none-any.whl", hash = "sha256:f49a827f90062e411f1ce1f854f2aedb3c23353244f8108b89283587397ac10e"}, + {file = "prompt_toolkit-3.0.48.tar.gz", hash = "sha256:d6623ab0477a80df74e646bdbc93621143f5caf104206aa29294d53de1a03d90"}, ] [package.dependencies] @@ -3033,13 +2982,13 @@ files = [ [[package]] name = "pure-eval" -version = "0.2.2" +version = "0.2.3" description = "Safely evaluate AST nodes without side effects" optional = true python-versions = "*" files = [ - {file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"}, - {file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"}, + {file = "pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0"}, + {file = "pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42"}, ] [package.extras] @@ -3058,37 +3007,22 @@ files = [ [[package]] name = "pycairo" -version = "1.26.0" +version = "1.27.0" description = "Python interface for cairo" optional = false -python-versions = ">=3.8" -files = [ - {file = "pycairo-1.26.0-cp310-cp310-win32.whl", hash = "sha256:696ba8024d2827e66e088a6e05a3b0aea30d289476bcb2ca47c9670d40900a50"}, - {file = "pycairo-1.26.0-cp310-cp310-win_amd64.whl", hash = "sha256:b6690a00fb225c19f42d76660e676aba7ae7cb18f3632cb02bce7f0d9b9c3800"}, - {file = "pycairo-1.26.0-cp310-cp310-win_arm64.whl", hash = "sha256:1d54e28170a5e790269d9db4c195cca5152ff018ba7e330d0ed05d86ccc2ea7d"}, - {file = "pycairo-1.26.0-cp311-cp311-win32.whl", hash = "sha256:5986b8da3e7de7ab931d7ad527938df38f75d3a3bdea2b515c786c5ca2c5093c"}, - {file = "pycairo-1.26.0-cp311-cp311-win_amd64.whl", hash = "sha256:d374d9ec6d2f791bf57105d87a9028db1ef2b687848f64a524e447033eae7229"}, - {file = "pycairo-1.26.0-cp311-cp311-win_arm64.whl", hash = "sha256:20a31af89d92ffd5fc60c08e65ff649f16e18621a14a40dbdb049fc74942d7a9"}, - {file = "pycairo-1.26.0-cp312-cp312-win32.whl", hash = "sha256:d63929ab5a2f890a333f2f2f51de9f1c9fe20d1bddc982c2ca577b737448d72f"}, - {file = "pycairo-1.26.0-cp312-cp312-win_amd64.whl", hash = "sha256:8616408ae93de4824a3777ec532ea75643e4bf74e49d601062c0b1788180c962"}, - {file = "pycairo-1.26.0-cp312-cp312-win_arm64.whl", hash = "sha256:a611e4d82ad8470138bb46d465d47e8db826d9d80b6a520ccd83ee007f2073e4"}, - {file = "pycairo-1.26.0-cp38-cp38-win32.whl", hash = "sha256:675578bc6d62d15ff8669f264783efc9c8c73e3a6f564b294a70fb45a2f78667"}, - {file = "pycairo-1.26.0-cp38-cp38-win_amd64.whl", hash = "sha256:aac447b423b33b64119ecdd1ffebf9163b07f5401c5da50c707197efdd1c918a"}, - {file = "pycairo-1.26.0-cp39-cp39-win32.whl", hash = "sha256:9fa51168010e2dfb45499df071fca2d921893f724646f3454951000a7ad0cabb"}, - {file = "pycairo-1.26.0-cp39-cp39-win_amd64.whl", hash = "sha256:3e4e18ea03122e60abe3eb611e2849859cc950083ff85d8369328eadf3df63f5"}, - {file = "pycairo-1.26.0-cp39-cp39-win_arm64.whl", hash = "sha256:a8f3b567ba2ad55624a809823ccf75aff8d768c20216cb5888365f6fc695c1d2"}, - {file = "pycairo-1.26.0.tar.gz", hash = "sha256:2dddd0a874fbddb21e14acd9b955881ee1dc6e63b9c549a192d613a907f9cbeb"}, -] - -[[package]] -name = "pycodestyle" -version = "2.11.1" -description = "Python style guide checker" -optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "pycodestyle-2.11.1-py2.py3-none-any.whl", hash = "sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67"}, - {file = "pycodestyle-2.11.1.tar.gz", hash = "sha256:41ba0e7afc9752dfb53ced5489e89f8186be00e599e712660695b7a75ff2663f"}, + {file = "pycairo-1.27.0-cp310-cp310-win32.whl", hash = "sha256:e20f431244634cf244ab6b4c3a2e540e65746eed1324573cf291981c3e65fc05"}, + {file = "pycairo-1.27.0-cp310-cp310-win_amd64.whl", hash = "sha256:03bf570e3919901572987bc69237b648fe0de242439980be3e606b396e3318c9"}, + {file = "pycairo-1.27.0-cp311-cp311-win32.whl", hash = "sha256:9a9b79f92a434dae65c34c830bb9abdbd92654195e73d52663cbe45af1ad14b2"}, + {file = "pycairo-1.27.0-cp311-cp311-win_amd64.whl", hash = "sha256:d40a6d80b15dacb3672dc454df4bc4ab3988c6b3f36353b24a255dc59a1c8aea"}, + {file = "pycairo-1.27.0-cp312-cp312-win32.whl", hash = "sha256:e2239b9bb6c05edae5f3be97128e85147a155465e644f4d98ea0ceac7afc04ee"}, + {file = "pycairo-1.27.0-cp312-cp312-win_amd64.whl", hash = "sha256:27cb4d3a80e3b9990af552818515a8e466e0317063a6e61585533f1a86f1b7d5"}, + {file = "pycairo-1.27.0-cp313-cp313-win32.whl", hash = "sha256:01505c138a313df2469f812405963532fc2511fb9bca9bdc8e0ab94c55d1ced8"}, + {file = "pycairo-1.27.0-cp313-cp313-win_amd64.whl", hash = "sha256:b0349d744c068b6644ae23da6ada111c8a8a7e323b56cbce3707cba5bdb474cc"}, + {file = "pycairo-1.27.0-cp39-cp39-win32.whl", hash = "sha256:f9ca8430751f1fdcd3f072377560c9e15608b9a42d61375469db853566993c9b"}, + {file = "pycairo-1.27.0-cp39-cp39-win_amd64.whl", hash = "sha256:1b1321652a6e27c4de3069709b1cae22aed2707fd8c5e889c04a95669228af2a"}, + {file = "pycairo-1.27.0.tar.gz", hash = "sha256:5cb21e7a00a2afcafea7f14390235be33497a2cce53a98a19389492a60628430"}, ] [[package]] @@ -3102,23 +3036,6 @@ files = [ {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, ] -[[package]] -name = "pydocstyle" -version = "6.3.0" -description = "Python docstring style checker" -optional = false -python-versions = ">=3.6" -files = [ - {file = "pydocstyle-6.3.0-py3-none-any.whl", hash = "sha256:118762d452a49d6b05e194ef344a55822987a462831ade91ec5c06fd2169d019"}, - {file = "pydocstyle-6.3.0.tar.gz", hash = "sha256:7ce43f0c0ac87b07494eb9c0b462c0b73e6ff276807f204d6b53edc72b7e44e1"}, -] - -[package.dependencies] -snowballstemmer = ">=2.2.0" - -[package.extras] -toml = ["tomli (>=1.2.3)"] - [[package]] name = "pydub" version = "0.25.1" @@ -3130,26 +3047,15 @@ files = [ {file = "pydub-0.25.1.tar.gz", hash = "sha256:980a33ce9949cab2a569606b65674d748ecbca4f0796887fd6f46173a7b0d30f"}, ] -[[package]] -name = "pyflakes" -version = "3.1.0" -description = "passive checker of Python programs" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pyflakes-3.1.0-py2.py3-none-any.whl", hash = "sha256:4132f6d49cb4dae6819e5379898f2b8cce3c5f23994194c24b77d5da2e36f774"}, - {file = "pyflakes-3.1.0.tar.gz", hash = "sha256:a0aae034c444db0071aa077972ba4768d40c830d9539fd45bf4cd3f8f6992efc"}, -] - [[package]] name = "pygithub" -version = "2.3.0" +version = "2.5.0" description = "Use the full Github API v3" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "PyGithub-2.3.0-py3-none-any.whl", hash = "sha256:65b499728be3ce7b0cd2cd760da3b32f0f4d7bc55e5e0677617f90f6564e793e"}, - {file = "PyGithub-2.3.0.tar.gz", hash = "sha256:0148d7347a1cdeed99af905077010aef81a4dad988b0ba51d4108bf66b443f7e"}, + {file = "PyGithub-2.5.0-py3-none-any.whl", hash = "sha256:b0b635999a658ab8e08720bdd3318893ff20e2275f6446fcf35bf3f44f2c0fd2"}, + {file = "pygithub-2.5.0.tar.gz", hash = "sha256:e1613ac508a9be710920d26eb18b1905ebd9926aa49398e88151c1b526aad3cf"}, ] [package.dependencies] @@ -3162,13 +3068,103 @@ urllib3 = ">=1.26.0" [[package]] name = "pyglet" -version = "2.0.15" +version = "2.0.18" description = "pyglet is a cross-platform games and multimedia package." optional = false python-versions = ">=3.8" files = [ - {file = "pyglet-2.0.15-py3-none-any.whl", hash = "sha256:9e4cc16efc308106fd3a9ff8f04e7a6f4f6a807c6ac8a331375efbbac8be85af"}, - {file = "pyglet-2.0.15.tar.gz", hash = "sha256:42085567cece0c7f1c14e36eef799938cbf528cfbb0150c484b984f3ff1aa771"}, + {file = "pyglet-2.0.18-py3-none-any.whl", hash = "sha256:e592952ae0297e456c587b6486ed8c3e5f9d0c3519d517bb92dde5fdf4c26b41"}, + {file = "pyglet-2.0.18.tar.gz", hash = "sha256:7cf9238d70082a2da282759679f8a011cc979753a32224a8ead8ed80e48f99dc"}, +] + +[[package]] +name = "pyglm" +version = "2.7.3" +description = "OpenGL Mathematics library for Python" +optional = false +python-versions = "*" +files = [ + {file = "PyGLM-2.7.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:36ce22f992af9da9a780f6232d184c9e2269be7e5e13f2fd35bb781536c31b9c"}, + {file = "PyGLM-2.7.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c52d06037ea1b0b24274e8a4ade49c9d82902e317e10e3233db7e67ddd2ded1d"}, + {file = "PyGLM-2.7.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f642ba2f52a8256c4d555486e9eab33d9417145cc2b68be237f4f10cbde08ade"}, + {file = "PyGLM-2.7.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3e5d38c5c39961e7cc704e4ea0c6cc4eb86e9879420fa13a51158a95e1ebfcec"}, + {file = "PyGLM-2.7.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da1d6526e718940994721fce85caeb7d3ab01e395d5652a0beb89b38add554eb"}, + {file = "PyGLM-2.7.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd51aa7207f4c2ce4d16c221bf6d50f3c1043aea44dd28ee3a94eddba43ccaa7"}, + {file = "PyGLM-2.7.3-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7ab0e13efbf076c8eb35f2f8d52a549fe3251a650e21e6e00f4adddd3e71c6e5"}, + {file = "PyGLM-2.7.3-cp310-cp310-manylinux_2_27_s390x.manylinux_2_28_s390x.whl", hash = "sha256:72a2fa3b37ad52d36ff4dfd6bc5476ed4ee8cd167543c283b583ea8618b283a7"}, + {file = "PyGLM-2.7.3-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:011d4d67240362b7e22af2ce57b216be8e3caa19dfd546e31d41b9a38612989f"}, + {file = "PyGLM-2.7.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:629ee77eaffc340a4bac722cd2621b076d8eb83809b74a27e13be7624d78df2b"}, + {file = "PyGLM-2.7.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:119fc3be9db079c98e48978677b917616d3b9e058b791ec258c5b57eea4d11bb"}, + {file = "PyGLM-2.7.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:75dc188457f99cdd4e621d3b932b0e844688135c5b0aefb42c46efcfce7b7270"}, + {file = "PyGLM-2.7.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:26a0abd806408eebcada608d3eaebfec73f7b2500ea645ff2fd7d9db470ba565"}, + {file = "PyGLM-2.7.3-cp310-cp310-win32.whl", hash = "sha256:37e2501434465c945f0d87626d6c2157bd2aef3e3bf65c37ab953d914428c488"}, + {file = "PyGLM-2.7.3-cp310-cp310-win_amd64.whl", hash = "sha256:27731736bd37cada8a7e975030d5bcfbd0f448162a607a2c53d088512a106f82"}, + {file = "PyGLM-2.7.3-cp310-cp310-win_arm64.whl", hash = "sha256:bc60ad3da261d2866826dcd9e7ee55bb0dc5e1160d8226b2b7f1e431ae7c6200"}, + {file = "PyGLM-2.7.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2ad68211a45b02f8d5d47f067153aa1084c6ab4026b8f84eb6e8b5165a7394ad"}, + {file = "PyGLM-2.7.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93b65bab6525e3098ff99c933cccc635716acf45a8c4bdf27ad432f183a33923"}, + {file = "PyGLM-2.7.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2422a8119a85500546fc3b95d0a035bb768b0002376070e4ef91015b8bf4e01"}, + {file = "PyGLM-2.7.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e9504dac2ca742b0b5199ad3ab0ffcf56759c8c1a9ca0f9252258784163ef3b"}, + {file = "PyGLM-2.7.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c75eb893c0f2c08b75f8b0aa5f2fd382cca65e9bd907e858e10fd2341110e2de"}, + {file = "PyGLM-2.7.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4df26b2e793b90a12e8cd9ddd81e715889e7760b202f6307d221144022bd3a68"}, + {file = "PyGLM-2.7.3-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c803fa9624be0498d37ee035c496e0b5ce3f720cbb6c6a33b14a5c318f01bbc5"}, + {file = "PyGLM-2.7.3-cp311-cp311-manylinux_2_27_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7bef6e2db2242613ce594d8dbe88eefd74da94fb141f8943abbdbcea2d905249"}, + {file = "PyGLM-2.7.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a7d925dbadaf642a2aa9674081ce2df6193c45519f38bc09a6f9f9861a202e60"}, + {file = "PyGLM-2.7.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff169abe8923c7f9eaca21b744fca58ce29e611cd1b09025d7e65aaa8f4149a5"}, + {file = "PyGLM-2.7.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:02338dfec947cd661e9969d316ba6e7500afcb86f0a0722dd4f5709a8557e570"}, + {file = "PyGLM-2.7.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:f4d902a22f3643da2d375140c9ebe69c9a6ef33aca518f64671540ae7fb37149"}, + {file = "PyGLM-2.7.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ea99eb075c47bb1f0c7e405b0d7dda966d5c880246e93191a73aed22d3aa04e8"}, + {file = "PyGLM-2.7.3-cp311-cp311-win32.whl", hash = "sha256:823ed2564064c863d03753e40fdd840703726b072a53f61c0a0441643e1ec56c"}, + {file = "PyGLM-2.7.3-cp311-cp311-win_amd64.whl", hash = "sha256:e6472feddcce4138caf19dd25a948530460823bdaa7c8d87caa3bc8a1bb1089a"}, + {file = "PyGLM-2.7.3-cp311-cp311-win_arm64.whl", hash = "sha256:313a05afc0d151e56d5536db7da695e7bba5943a3f96b71ef213f4bc59715c93"}, + {file = "PyGLM-2.7.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5bfebc0caaa0a0096957d984416081a503b1cbd2ba79a0cd0add64e741144247"}, + {file = "PyGLM-2.7.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:265827ca2eecc7f50d1a37c412b6ed8118ec909f4a5198b2c0a7a914bc33c4a0"}, + {file = "PyGLM-2.7.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:243890559980131351281007e308e2db0dc52f5dedf1ce0f21383d32cbd3f367"}, + {file = "PyGLM-2.7.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78bb3f32fc92bf0f86527e8143ea861365fdecc05725932eef424346a1948b5b"}, + {file = "PyGLM-2.7.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9b193cf4d16b2f43d3458aeaaa29d6cad4f5f2518a3562f3c9b6e361d2d2623"}, + {file = "PyGLM-2.7.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15a26ac12fb7728b71a45ca9535e6c96cff5a9a1e5beae306ece37073513d519"}, + {file = "PyGLM-2.7.3-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bec15034f7c21b2c3c1b70d878f0590aad6a445a0e1290172cc90dccc7a71afb"}, + {file = "PyGLM-2.7.3-cp312-cp312-manylinux_2_27_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a8253002a1732622bbd8c605baf7ac03b9e1629cfe1136261e651b82204e31d7"}, + {file = "PyGLM-2.7.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5846787ae297623fe2a09e2a94814f1ca71a80ab929edc5bae93fcbefab7b559"}, + {file = "PyGLM-2.7.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:598404cdfc3fe5bbd6429a1c7879bc6516057827c9e6c2879b22167948854ec6"}, + {file = "PyGLM-2.7.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:a71de9de8bf2c585777fdfdde877082722582651a65cb6ab1e6be48299cbdd56"}, + {file = "PyGLM-2.7.3-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:a49f073a52ca26bf7672aa0685a75f0cb41201e84094ef8aa08c7d9432436bf5"}, + {file = "PyGLM-2.7.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e37cf83588ff9bc0e8019612c667c4b45a2b1cb195e3890a4609056fa2eda8b4"}, + {file = "PyGLM-2.7.3-cp312-cp312-win32.whl", hash = "sha256:8b2cf3857dfe598e8f7210aba3990b6b3bc73cb7ee43d422ef8920b1e28aba52"}, + {file = "PyGLM-2.7.3-cp312-cp312-win_amd64.whl", hash = "sha256:4018fbdf125b95d6295e2e3e9f6b1306a204df751d70736f78144cdde07cd721"}, + {file = "PyGLM-2.7.3-cp312-cp312-win_arm64.whl", hash = "sha256:5465b95bc92d0807a5289559bede5e18f084a6940a8d607f4fbe2457ba21989e"}, + {file = "PyGLM-2.7.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d38d3e15098458f7c13db98c3bed936aa6313f7d20eb83968ee2b4c36a7722d6"}, + {file = "PyGLM-2.7.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8fe12b0b048e9c5d35647f05ee7fa6c0aebedbc1cb6d4b4f75df5d7b9c16ab3"}, + {file = "PyGLM-2.7.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1928999a93ce156665f72b3c799c66a539f114025f4bcae894d46f09ff0ec39c"}, + {file = "PyGLM-2.7.3-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b846eec69f21faf17310562bf7aa3163b2e6dad391c2ddc22e76d3dded8b2e5"}, + {file = "PyGLM-2.7.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5af9ca9802d588910d8f72706690dcd276a82256a828a17f1a4bf898f84da82b"}, + {file = "PyGLM-2.7.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9d1d471cffee49dc2256f1c9f43600224e10a88a128dfd398b2af2e2104277c"}, + {file = "PyGLM-2.7.3-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a415d83a20021a2544276cc122fbea4540493f7a30f9e08da7d185d04e9ca71d"}, + {file = "PyGLM-2.7.3-cp313-cp313-manylinux_2_27_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fe0451bc8973260fa9e029773a57d4095c5e08a9f88a979f9699dfe196a956d7"}, + {file = "PyGLM-2.7.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f8143b81200d9c9d26442a7ba1614d64aeb319363057bec12d9330591c4f8cf5"}, + {file = "PyGLM-2.7.3-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:5c3425a3118924e0d148b9ee6dcf6f001fc55326e9f2bbed8360c5d71575e28e"}, + {file = "PyGLM-2.7.3-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:5dfb81078d4f9bc5c86be7939f1ab6265192ed16d18ab06fd062c6fcbe649195"}, + {file = "PyGLM-2.7.3-cp313-cp313-musllinux_1_1_s390x.whl", hash = "sha256:a27c0e0594592f44a3eeebc628974f27095751398184050e333d07884c0f0176"}, + {file = "PyGLM-2.7.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:8e9f88e62962685f1b0ac4aed8d77aabdf5fa95c6bc4894ea15ac9dc79842ad3"}, + {file = "PyGLM-2.7.3-cp313-cp313-win32.whl", hash = "sha256:c9048d98d622e8a95601482bd892a76c8da152bcfcef5d16d279c5bb507a09a7"}, + {file = "PyGLM-2.7.3-cp313-cp313-win_amd64.whl", hash = "sha256:68167968ee91ab176bf9a6e6afaadf4c0c65417c29fecc9f32c6da698ad028db"}, + {file = "PyGLM-2.7.3-cp313-cp313-win_arm64.whl", hash = "sha256:24622c249eb315588c042df3b960d3bd90ab6e01caf52009b546b526575d5e91"}, + {file = "PyGLM-2.7.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:23fdbe27e16b03206d8635dbb842fae6a470a7342af7c2395509c20607fe0251"}, + {file = "PyGLM-2.7.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6467e217ebb6fc9356ae77c2e6c807d9e4470b5db59006dd553eee5888815538"}, + {file = "PyGLM-2.7.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fcc4d575e20118c938bc451bbf7d69e50440e298e1be4359d2a1a4c8568866fa"}, + {file = "PyGLM-2.7.3-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11250311e3b0813f924147333c28658aa00c93a4ecc173ccbe95c145e4ade14c"}, + {file = "PyGLM-2.7.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:45e66c96d0b11587b4e21ed72bb0dd2a27bb4d12f75f26dc9e08f6d019c6b5ba"}, + {file = "PyGLM-2.7.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0906751e15c003428c2099a8230f9b7173ef1e0c89abd92d278e28600f0a0277"}, + {file = "PyGLM-2.7.3-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7c663673842b0aa0747aa1b26b584dfdffc3eb3a7611563eb546be44bbb9c98c"}, + {file = "PyGLM-2.7.3-cp39-cp39-manylinux_2_27_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9f37b1f19114cbe64fb11ab8c559fe6cc7af143b8f1e77bb812dd74212cb4e6b"}, + {file = "PyGLM-2.7.3-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b2a4a21ec5c79e0f5e8fa460520f9e1ac453f6d0804ca6acd679067aec3b06fc"}, + {file = "PyGLM-2.7.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3408cda39d1181ccf37a3171298df4acd1930b7335b20835ae8ad405ae902100"}, + {file = "PyGLM-2.7.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:8f6c24c2072f6898b6a2f64ffec16a08243451bee9e969344659f2323efcd4af"}, + {file = "PyGLM-2.7.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:472d92fbbeac5647a91adfb5d1b71a8368ced8b6cd92654822290a34de87a2ef"}, + {file = "PyGLM-2.7.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:29dd15a559df75acdab74b941ace809f81f20d655d6d616c09b85d2ffc66b5cd"}, + {file = "PyGLM-2.7.3-cp39-cp39-win32.whl", hash = "sha256:868b455946ca659d7d2344afffdcf3f4b6b57270b43b7428848661976dba8803"}, + {file = "PyGLM-2.7.3-cp39-cp39-win_amd64.whl", hash = "sha256:1689cbc0aec27107b933b9afbece524469257da6ef2ab78891cb77902e47259b"}, + {file = "PyGLM-2.7.3-cp39-cp39-win_arm64.whl", hash = "sha256:6a60f3a3f89af1428cded8e56f19c012dd331c3bd860923d542ba4837418a5d0"}, + {file = "pyglm-2.7.3.tar.gz", hash = "sha256:4ccb6c027622b948aebc501cd8c3c23690293115dc98108f8ed3b7fd533b398f"}, ] [[package]] @@ -3187,13 +3183,13 @@ windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pyjwt" -version = "2.8.0" +version = "2.10.1" description = "JSON Web Token implementation in Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "PyJWT-2.8.0-py3-none-any.whl", hash = "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320"}, - {file = "PyJWT-2.8.0.tar.gz", hash = "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de"}, + {file = "PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb"}, + {file = "pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953"}, ] [package.dependencies] @@ -3201,8 +3197,8 @@ cryptography = {version = ">=3.4.0", optional = true, markers = "extra == \"cryp [package.extras] crypto = ["cryptography (>=3.4.0)"] -dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] -docs = ["sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] +dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx", "sphinx-rtd-theme", "zope.interface"] +docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"] tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] [[package]] @@ -3233,77 +3229,66 @@ tests = ["hypothesis (>=3.27.0)", "pytest (>=3.2.1,!=3.3.0)"] [[package]] name = "pyobjc-core" -version = "10.2" +version = "10.3.2" description = "Python<->ObjC Interoperability Module" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-core-10.2.tar.gz", hash = "sha256:0153206e15d0e0d7abd53ee8a7fbaf5606602a032e177a028fc8589516a8771c"}, - {file = "pyobjc_core-10.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b8eab50ce7f17017a0f1d68c3b7e88bb1bb033415fdff62b8e0a9ee4ab72f242"}, - {file = "pyobjc_core-10.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f2115971463073426ab926416e17e5c16de5b90d1a1f2a2d8724637eb1c21308"}, - {file = "pyobjc_core-10.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:a70546246177c23acb323c9324330e37638f1a0a3d13664abcba3bb75e43012c"}, - {file = "pyobjc_core-10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a9b5a215080d13bd7526031d21d5eb27a410780878d863f486053a0eba7ca9a5"}, - {file = "pyobjc_core-10.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:eb1ab700a44bcc4ceb125091dfaae0b998b767b49990df5fdc83eb58158d8e3f"}, - {file = "pyobjc_core-10.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c9a7163aff9c47d654f835f80361c1b112886ec754800d34e75d1e02ff52c3d7"}, + {file = "pyobjc_core-10.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:acb40672d682851a5c7fd84e5041c4d069b62076168d72591abb5fcc871bb039"}, + {file = "pyobjc_core-10.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:cea5e77659619ad93c782ca07644b6efe7d7ec6f59e46128843a0a87c1af511a"}, + {file = "pyobjc_core-10.3.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:16644a92fb9661de841ba6115e5354db06a1d193a5e239046e840013c7b3874d"}, + {file = "pyobjc_core-10.3.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:76b8b911d94501dac89821df349b1860bb770dce102a1a293f524b5b09dd9462"}, + {file = "pyobjc_core-10.3.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:8c6288fdb210b64115760a4504efbc4daffdc390d309e9318eb0e3e3b78d2828"}, + {file = "pyobjc_core-10.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:87901e9f7032f33eb4fa884e407bf2744d5a0791b379bfca783982a02be3f7fb"}, + {file = "pyobjc_core-10.3.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:636971ab48a4198ca129e149fe58ccf85a7b4a9b93d27f5ae920d88eb2655431"}, + {file = "pyobjc_core-10.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:48e9ac3af42b2340dae709a8b894f5ef7e5132d8546adcd1797cffcc449dabdc"}, + {file = "pyobjc_core-10.3.2.tar.gz", hash = "sha256:dbf1475d864ce594288ce03e94e3a98dc7f0e4639971eb1e312bdf6661c21e0e"}, ] [[package]] name = "pyobjc-framework-cocoa" -version = "10.2" +version = "10.3.2" description = "Wrappers for the Cocoa frameworks on macOS" optional = false python-versions = ">=3.8" files = [ - {file = "pyobjc-framework-Cocoa-10.2.tar.gz", hash = "sha256:6383141379636b13855dca1b39c032752862b829f93a49d7ddb35046abfdc035"}, - {file = "pyobjc_framework_Cocoa-10.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f9227b4f271fda2250f5a88cbc686ff30ae02c0f923bb7854bb47972397496b2"}, - {file = "pyobjc_framework_Cocoa-10.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6a6042b7703bdc33b7491959c715c1e810a3f8c7a560c94b36e00ef321480797"}, - {file = "pyobjc_framework_Cocoa-10.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:18886d5013cd7dc7ecd6e0df5134c767569b5247fc10a5e293c72ee3937b217b"}, - {file = "pyobjc_framework_Cocoa-10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1ecf01400ee698d2e0ff4c907bcf9608d9d710e97203fbb97b37d208507a9362"}, - {file = "pyobjc_framework_Cocoa-10.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:0def036a7b24e3ae37a244c77bec96b7c9c8384bf6bb4d33369f0a0c8807a70d"}, - {file = "pyobjc_framework_Cocoa-10.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5f47ecc393bc1019c4b47e8653207188df784ac006ad54d8c2eb528906ff7013"}, + {file = "pyobjc_framework_Cocoa-10.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:61f44c2adab28fdf3aa3d593c9497a2d9ceb9583ed9814adb48828c385d83ff4"}, + {file = "pyobjc_framework_Cocoa-10.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7caaf8b260e81b27b7b787332846f644b9423bfc1536f6ec24edbde59ab77a87"}, + {file = "pyobjc_framework_Cocoa-10.3.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:c49e99fc4b9e613fb308651b99d52a8a9ae9916c8ef27aa2f5d585b6678a59bf"}, + {file = "pyobjc_framework_Cocoa-10.3.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f1161b5713f9b9934c12649d73a6749617172e240f9431eff9e22175262fdfda"}, + {file = "pyobjc_framework_Cocoa-10.3.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:08e48b9ee4eb393447b2b781d16663b954bd10a26927df74f92e924c05568d89"}, + {file = "pyobjc_framework_Cocoa-10.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7faa448d2038ae0e0287a326d390002e744bb6470e45995e2dbd16c892e4495a"}, + {file = "pyobjc_framework_Cocoa-10.3.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:fcd53fee2be9708576617994b107aedc2c40824b648cd51e780e8399c0a447b6"}, + {file = "pyobjc_framework_Cocoa-10.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:838fcf0d10674bde9ff64a3f20c0e188f2dc5e804476d80509b81c4ac1dabc59"}, + {file = "pyobjc_framework_cocoa-10.3.2.tar.gz", hash = "sha256:673968e5435845bef969bfe374f31a1a6dc660c98608d2b84d5cae6eafa5c39d"}, ] [package.dependencies] -pyobjc-core = ">=10.2" +pyobjc-core = ">=10.3.2" [[package]] name = "pyparsing" -version = "3.1.2" +version = "3.2.0" description = "pyparsing module - Classes and methods to define and execute parsing grammars" optional = false -python-versions = ">=3.6.8" +python-versions = ">=3.9" files = [ - {file = "pyparsing-3.1.2-py3-none-any.whl", hash = "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742"}, - {file = "pyparsing-3.1.2.tar.gz", hash = "sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad"}, + {file = "pyparsing-3.2.0-py3-none-any.whl", hash = "sha256:93d9577b88da0bbea8cc8334ee8b918ed014968fd2ec383e868fb8afb1ccef84"}, + {file = "pyparsing-3.2.0.tar.gz", hash = "sha256:cbf74e27246d595d9a74b186b810f6fbb86726dbf3b9532efb343f6d7294fe9c"}, ] [package.extras] diagrams = ["jinja2", "railroad-diagrams"] -[[package]] -name = "pyrr" -version = "0.10.3" -description = "3D mathematical functions using NumPy" -optional = false -python-versions = "*" -files = [ - {file = "pyrr-0.10.3-py3-none-any.whl", hash = "sha256:d8af23fb9bb29262405845e1c98f7339fbba5e49323b98528bd01160a75c65ac"}, - {file = "pyrr-0.10.3.tar.gz", hash = "sha256:3c0f7b20326e71f706a610d58f2190fff73af01eef60c19cb188b186f0ec7e1d"}, -] - -[package.dependencies] -multipledispatch = "*" -numpy = "*" - [[package]] name = "pytest" -version = "7.4.4" +version = "8.3.4" description = "pytest: simple powerful testing with Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, - {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, + {file = "pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6"}, + {file = "pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"}, ] [package.dependencies] @@ -3311,11 +3296,11 @@ colorama = {version = "*", markers = "sys_platform == \"win32\""} exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" -pluggy = ">=0.12,<2.0" -tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} +pluggy = ">=1.5,<2" +tomli = {version = ">=1", markers = "python_version < \"3.11\""} [package.extras] -testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] [[package]] name = "pytest-cov" @@ -3398,197 +3383,224 @@ files = [ [[package]] name = "pywin32" -version = "306" +version = "308" description = "Python for Window Extensions" optional = true python-versions = "*" files = [ - {file = "pywin32-306-cp310-cp310-win32.whl", hash = "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d"}, - {file = "pywin32-306-cp310-cp310-win_amd64.whl", hash = "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8"}, - {file = "pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407"}, - {file = "pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e"}, - {file = "pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a"}, - {file = "pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b"}, - {file = "pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e"}, - {file = "pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040"}, - {file = "pywin32-306-cp37-cp37m-win32.whl", hash = "sha256:1c73ea9a0d2283d889001998059f5eaaba3b6238f767c9cf2833b13e6a685f65"}, - {file = "pywin32-306-cp37-cp37m-win_amd64.whl", hash = "sha256:72c5f621542d7bdd4fdb716227be0dd3f8565c11b280be6315b06ace35487d36"}, - {file = "pywin32-306-cp38-cp38-win32.whl", hash = "sha256:e4c092e2589b5cf0d365849e73e02c391c1349958c5ac3e9d5ccb9a28e017b3a"}, - {file = "pywin32-306-cp38-cp38-win_amd64.whl", hash = "sha256:e8ac1ae3601bee6ca9f7cb4b5363bf1c0badb935ef243c4733ff9a393b1690c0"}, - {file = "pywin32-306-cp39-cp39-win32.whl", hash = "sha256:e25fd5b485b55ac9c057f67d94bc203f3f6595078d1fb3b458c9c28b7153a802"}, - {file = "pywin32-306-cp39-cp39-win_amd64.whl", hash = "sha256:39b61c15272833b5c329a2989999dcae836b1eed650252ab1b7bfbe1d59f30f4"}, + {file = "pywin32-308-cp310-cp310-win32.whl", hash = "sha256:796ff4426437896550d2981b9c2ac0ffd75238ad9ea2d3bfa67a1abd546d262e"}, + {file = "pywin32-308-cp310-cp310-win_amd64.whl", hash = "sha256:4fc888c59b3c0bef905ce7eb7e2106a07712015ea1c8234b703a088d46110e8e"}, + {file = "pywin32-308-cp310-cp310-win_arm64.whl", hash = "sha256:a5ab5381813b40f264fa3495b98af850098f814a25a63589a8e9eb12560f450c"}, + {file = "pywin32-308-cp311-cp311-win32.whl", hash = "sha256:5d8c8015b24a7d6855b1550d8e660d8daa09983c80e5daf89a273e5c6fb5095a"}, + {file = "pywin32-308-cp311-cp311-win_amd64.whl", hash = "sha256:575621b90f0dc2695fec346b2d6302faebd4f0f45c05ea29404cefe35d89442b"}, + {file = "pywin32-308-cp311-cp311-win_arm64.whl", hash = "sha256:100a5442b7332070983c4cd03f2e906a5648a5104b8a7f50175f7906efd16bb6"}, + {file = "pywin32-308-cp312-cp312-win32.whl", hash = "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897"}, + {file = "pywin32-308-cp312-cp312-win_amd64.whl", hash = "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47"}, + {file = "pywin32-308-cp312-cp312-win_arm64.whl", hash = "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091"}, + {file = "pywin32-308-cp313-cp313-win32.whl", hash = "sha256:1c44539a37a5b7b21d02ab34e6a4d314e0788f1690d65b48e9b0b89f31abbbed"}, + {file = "pywin32-308-cp313-cp313-win_amd64.whl", hash = "sha256:fd380990e792eaf6827fcb7e187b2b4b1cede0585e3d0c9e84201ec27b9905e4"}, + {file = "pywin32-308-cp313-cp313-win_arm64.whl", hash = "sha256:ef313c46d4c18dfb82a2431e3051ac8f112ccee1a34f29c263c583c568db63cd"}, + {file = "pywin32-308-cp37-cp37m-win32.whl", hash = "sha256:1f696ab352a2ddd63bd07430080dd598e6369152ea13a25ebcdd2f503a38f1ff"}, + {file = "pywin32-308-cp37-cp37m-win_amd64.whl", hash = "sha256:13dcb914ed4347019fbec6697a01a0aec61019c1046c2b905410d197856326a6"}, + {file = "pywin32-308-cp38-cp38-win32.whl", hash = "sha256:5794e764ebcabf4ff08c555b31bd348c9025929371763b2183172ff4708152f0"}, + {file = "pywin32-308-cp38-cp38-win_amd64.whl", hash = "sha256:3b92622e29d651c6b783e368ba7d6722b1634b8e70bd376fd7610fe1992e19de"}, + {file = "pywin32-308-cp39-cp39-win32.whl", hash = "sha256:7873ca4dc60ab3287919881a7d4f88baee4a6e639aa6962de25a98ba6b193341"}, + {file = "pywin32-308-cp39-cp39-win_amd64.whl", hash = "sha256:71b3322d949b4cc20776436a9c9ba0eeedcbc9c650daa536df63f0ff111bb920"}, ] [[package]] name = "pywinpty" -version = "2.0.13" +version = "2.0.14" description = "Pseudo terminal support for Windows from Python." optional = true python-versions = ">=3.8" files = [ - {file = "pywinpty-2.0.13-cp310-none-win_amd64.whl", hash = "sha256:697bff211fb5a6508fee2dc6ff174ce03f34a9a233df9d8b5fe9c8ce4d5eaf56"}, - {file = "pywinpty-2.0.13-cp311-none-win_amd64.whl", hash = "sha256:b96fb14698db1284db84ca38c79f15b4cfdc3172065b5137383910567591fa99"}, - {file = "pywinpty-2.0.13-cp312-none-win_amd64.whl", hash = "sha256:2fd876b82ca750bb1333236ce98488c1be96b08f4f7647cfdf4129dfad83c2d4"}, - {file = "pywinpty-2.0.13-cp38-none-win_amd64.whl", hash = "sha256:61d420c2116c0212808d31625611b51caf621fe67f8a6377e2e8b617ea1c1f7d"}, - {file = "pywinpty-2.0.13-cp39-none-win_amd64.whl", hash = "sha256:71cb613a9ee24174730ac7ae439fd179ca34ccb8c5349e8d7b72ab5dea2c6f4b"}, - {file = "pywinpty-2.0.13.tar.gz", hash = "sha256:c34e32351a3313ddd0d7da23d27f835c860d32fe4ac814d372a3ea9594f41dde"}, + {file = "pywinpty-2.0.14-cp310-none-win_amd64.whl", hash = "sha256:0b149c2918c7974f575ba79f5a4aad58bd859a52fa9eb1296cc22aa412aa411f"}, + {file = "pywinpty-2.0.14-cp311-none-win_amd64.whl", hash = "sha256:cf2a43ac7065b3e0dc8510f8c1f13a75fb8fde805efa3b8cff7599a1ef497bc7"}, + {file = "pywinpty-2.0.14-cp312-none-win_amd64.whl", hash = "sha256:55dad362ef3e9408ade68fd173e4f9032b3ce08f68cfe7eacb2c263ea1179737"}, + {file = "pywinpty-2.0.14-cp313-none-win_amd64.whl", hash = "sha256:074fb988a56ec79ca90ed03a896d40707131897cefb8f76f926e3834227f2819"}, + {file = "pywinpty-2.0.14-cp39-none-win_amd64.whl", hash = "sha256:5725fd56f73c0531ec218663bd8c8ff5acc43c78962fab28564871b5fce053fd"}, + {file = "pywinpty-2.0.14.tar.gz", hash = "sha256:18bd9529e4a5daf2d9719aa17788ba6013e594ae94c5a0c27e83df3278b0660e"}, ] [[package]] name = "pyyaml" -version = "6.0.1" +version = "6.0.2" description = "YAML parser and emitter for Python" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, - {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, - {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, - {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, - {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, - {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, - {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, - {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, - {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, - {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, - {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, - {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, - {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, - {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, - {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, - {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, - {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, - {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, - {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, - {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, - {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, - {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, - {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, - {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, - {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, - {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, - {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, - {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, - {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, + {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, + {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, + {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, + {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, + {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, + {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, + {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, + {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, + {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, + {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, + {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, + {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, + {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, + {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, + {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, ] [[package]] name = "pyzmq" -version = "26.0.3" +version = "26.2.0" description = "Python bindings for 0MQ" optional = true python-versions = ">=3.7" files = [ - {file = "pyzmq-26.0.3-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:44dd6fc3034f1eaa72ece33588867df9e006a7303725a12d64c3dff92330f625"}, - {file = "pyzmq-26.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:acb704195a71ac5ea5ecf2811c9ee19ecdc62b91878528302dd0be1b9451cc90"}, - {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dbb9c997932473a27afa93954bb77a9f9b786b4ccf718d903f35da3232317de"}, - {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6bcb34f869d431799c3ee7d516554797f7760cb2198ecaa89c3f176f72d062be"}, - {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ece17ec5f20d7d9b442e5174ae9f020365d01ba7c112205a4d59cf19dc38ee"}, - {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:ba6e5e6588e49139a0979d03a7deb9c734bde647b9a8808f26acf9c547cab1bf"}, - {file = "pyzmq-26.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3bf8b000a4e2967e6dfdd8656cd0757d18c7e5ce3d16339e550bd462f4857e59"}, - {file = "pyzmq-26.0.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:2136f64fbb86451dbbf70223635a468272dd20075f988a102bf8a3f194a411dc"}, - {file = "pyzmq-26.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e8918973fbd34e7814f59143c5f600ecd38b8038161239fd1a3d33d5817a38b8"}, - {file = "pyzmq-26.0.3-cp310-cp310-win32.whl", hash = "sha256:0aaf982e68a7ac284377d051c742610220fd06d330dcd4c4dbb4cdd77c22a537"}, - {file = "pyzmq-26.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:f1a9b7d00fdf60b4039f4455afd031fe85ee8305b019334b72dcf73c567edc47"}, - {file = "pyzmq-26.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:80b12f25d805a919d53efc0a5ad7c0c0326f13b4eae981a5d7b7cc343318ebb7"}, - {file = "pyzmq-26.0.3-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:a72a84570f84c374b4c287183debc776dc319d3e8ce6b6a0041ce2e400de3f32"}, - {file = "pyzmq-26.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7ca684ee649b55fd8f378127ac8462fb6c85f251c2fb027eb3c887e8ee347bcd"}, - {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e222562dc0f38571c8b1ffdae9d7adb866363134299264a1958d077800b193b7"}, - {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f17cde1db0754c35a91ac00b22b25c11da6eec5746431d6e5092f0cd31a3fea9"}, - {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b7c0c0b3244bb2275abe255d4a30c050d541c6cb18b870975553f1fb6f37527"}, - {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:ac97a21de3712afe6a6c071abfad40a6224fd14fa6ff0ff8d0c6e6cd4e2f807a"}, - {file = "pyzmq-26.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:88b88282e55fa39dd556d7fc04160bcf39dea015f78e0cecec8ff4f06c1fc2b5"}, - {file = "pyzmq-26.0.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:72b67f966b57dbd18dcc7efbc1c7fc9f5f983e572db1877081f075004614fcdd"}, - {file = "pyzmq-26.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f4b6cecbbf3b7380f3b61de3a7b93cb721125dc125c854c14ddc91225ba52f83"}, - {file = "pyzmq-26.0.3-cp311-cp311-win32.whl", hash = "sha256:eed56b6a39216d31ff8cd2f1d048b5bf1700e4b32a01b14379c3b6dde9ce3aa3"}, - {file = "pyzmq-26.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:3191d312c73e3cfd0f0afdf51df8405aafeb0bad71e7ed8f68b24b63c4f36500"}, - {file = "pyzmq-26.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:b6907da3017ef55139cf0e417c5123a84c7332520e73a6902ff1f79046cd3b94"}, - {file = "pyzmq-26.0.3-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:068ca17214038ae986d68f4a7021f97e187ed278ab6dccb79f837d765a54d753"}, - {file = "pyzmq-26.0.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7821d44fe07335bea256b9f1f41474a642ca55fa671dfd9f00af8d68a920c2d4"}, - {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eeb438a26d87c123bb318e5f2b3d86a36060b01f22fbdffd8cf247d52f7c9a2b"}, - {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:69ea9d6d9baa25a4dc9cef5e2b77b8537827b122214f210dd925132e34ae9b12"}, - {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7daa3e1369355766dea11f1d8ef829905c3b9da886ea3152788dc25ee6079e02"}, - {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:6ca7a9a06b52d0e38ccf6bca1aeff7be178917893f3883f37b75589d42c4ac20"}, - {file = "pyzmq-26.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1b7d0e124948daa4d9686d421ef5087c0516bc6179fdcf8828b8444f8e461a77"}, - {file = "pyzmq-26.0.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e746524418b70f38550f2190eeee834db8850088c834d4c8406fbb9bc1ae10b2"}, - {file = "pyzmq-26.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:6b3146f9ae6af82c47a5282ac8803523d381b3b21caeae0327ed2f7ecb718798"}, - {file = "pyzmq-26.0.3-cp312-cp312-win32.whl", hash = "sha256:2b291d1230845871c00c8462c50565a9cd6026fe1228e77ca934470bb7d70ea0"}, - {file = "pyzmq-26.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:926838a535c2c1ea21c903f909a9a54e675c2126728c21381a94ddf37c3cbddf"}, - {file = "pyzmq-26.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:5bf6c237f8c681dfb91b17f8435b2735951f0d1fad10cc5dfd96db110243370b"}, - {file = "pyzmq-26.0.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0c0991f5a96a8e620f7691e61178cd8f457b49e17b7d9cfa2067e2a0a89fc1d5"}, - {file = "pyzmq-26.0.3-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:dbf012d8fcb9f2cf0643b65df3b355fdd74fc0035d70bb5c845e9e30a3a4654b"}, - {file = "pyzmq-26.0.3-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:01fbfbeb8249a68d257f601deb50c70c929dc2dfe683b754659569e502fbd3aa"}, - {file = "pyzmq-26.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c8eb19abe87029c18f226d42b8a2c9efdd139d08f8bf6e085dd9075446db450"}, - {file = "pyzmq-26.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:5344b896e79800af86ad643408ca9aa303a017f6ebff8cee5a3163c1e9aec987"}, - {file = "pyzmq-26.0.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:204e0f176fd1d067671157d049466869b3ae1fc51e354708b0dc41cf94e23a3a"}, - {file = "pyzmq-26.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a42db008d58530efa3b881eeee4991146de0b790e095f7ae43ba5cc612decbc5"}, - {file = "pyzmq-26.0.3-cp37-cp37m-win32.whl", hash = "sha256:8d7a498671ca87e32b54cb47c82a92b40130a26c5197d392720a1bce1b3c77cf"}, - {file = "pyzmq-26.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:3b4032a96410bdc760061b14ed6a33613ffb7f702181ba999df5d16fb96ba16a"}, - {file = "pyzmq-26.0.3-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:2cc4e280098c1b192c42a849de8de2c8e0f3a84086a76ec5b07bfee29bda7d18"}, - {file = "pyzmq-26.0.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5bde86a2ed3ce587fa2b207424ce15b9a83a9fa14422dcc1c5356a13aed3df9d"}, - {file = "pyzmq-26.0.3-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:34106f68e20e6ff253c9f596ea50397dbd8699828d55e8fa18bd4323d8d966e6"}, - {file = "pyzmq-26.0.3-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ebbbd0e728af5db9b04e56389e2299a57ea8b9dd15c9759153ee2455b32be6ad"}, - {file = "pyzmq-26.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6b1d1c631e5940cac5a0b22c5379c86e8df6a4ec277c7a856b714021ab6cfad"}, - {file = "pyzmq-26.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e891ce81edd463b3b4c3b885c5603c00141151dd9c6936d98a680c8c72fe5c67"}, - {file = "pyzmq-26.0.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9b273ecfbc590a1b98f014ae41e5cf723932f3b53ba9367cfb676f838038b32c"}, - {file = "pyzmq-26.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b32bff85fb02a75ea0b68f21e2412255b5731f3f389ed9aecc13a6752f58ac97"}, - {file = "pyzmq-26.0.3-cp38-cp38-win32.whl", hash = "sha256:f6c21c00478a7bea93caaaef9e7629145d4153b15a8653e8bb4609d4bc70dbfc"}, - {file = "pyzmq-26.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:3401613148d93ef0fd9aabdbddb212de3db7a4475367f49f590c837355343972"}, - {file = "pyzmq-26.0.3-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:2ed8357f4c6e0daa4f3baf31832df8a33334e0fe5b020a61bc8b345a3db7a606"}, - {file = "pyzmq-26.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c1c8f2a2ca45292084c75bb6d3a25545cff0ed931ed228d3a1810ae3758f975f"}, - {file = "pyzmq-26.0.3-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:b63731993cdddcc8e087c64e9cf003f909262b359110070183d7f3025d1c56b5"}, - {file = "pyzmq-26.0.3-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b3cd31f859b662ac5d7f4226ec7d8bd60384fa037fc02aee6ff0b53ba29a3ba8"}, - {file = "pyzmq-26.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:115f8359402fa527cf47708d6f8a0f8234f0e9ca0cab7c18c9c189c194dbf620"}, - {file = "pyzmq-26.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:715bdf952b9533ba13dfcf1f431a8f49e63cecc31d91d007bc1deb914f47d0e4"}, - {file = "pyzmq-26.0.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e1258c639e00bf5e8a522fec6c3eaa3e30cf1c23a2f21a586be7e04d50c9acab"}, - {file = "pyzmq-26.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:15c59e780be8f30a60816a9adab900c12a58d79c1ac742b4a8df044ab2a6d920"}, - {file = "pyzmq-26.0.3-cp39-cp39-win32.whl", hash = "sha256:d0cdde3c78d8ab5b46595054e5def32a755fc028685add5ddc7403e9f6de9879"}, - {file = "pyzmq-26.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:ce828058d482ef860746bf532822842e0ff484e27f540ef5c813d516dd8896d2"}, - {file = "pyzmq-26.0.3-cp39-cp39-win_arm64.whl", hash = "sha256:788f15721c64109cf720791714dc14afd0f449d63f3a5487724f024345067381"}, - {file = "pyzmq-26.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2c18645ef6294d99b256806e34653e86236eb266278c8ec8112622b61db255de"}, - {file = "pyzmq-26.0.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7e6bc96ebe49604df3ec2c6389cc3876cabe475e6bfc84ced1bf4e630662cb35"}, - {file = "pyzmq-26.0.3-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:971e8990c5cc4ddcff26e149398fc7b0f6a042306e82500f5e8db3b10ce69f84"}, - {file = "pyzmq-26.0.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8416c23161abd94cc7da80c734ad7c9f5dbebdadfdaa77dad78244457448223"}, - {file = "pyzmq-26.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:082a2988364b60bb5de809373098361cf1dbb239623e39e46cb18bc035ed9c0c"}, - {file = "pyzmq-26.0.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d57dfbf9737763b3a60d26e6800e02e04284926329aee8fb01049635e957fe81"}, - {file = "pyzmq-26.0.3-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:77a85dca4c2430ac04dc2a2185c2deb3858a34fe7f403d0a946fa56970cf60a1"}, - {file = "pyzmq-26.0.3-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4c82a6d952a1d555bf4be42b6532927d2a5686dd3c3e280e5f63225ab47ac1f5"}, - {file = "pyzmq-26.0.3-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4496b1282c70c442809fc1b151977c3d967bfb33e4e17cedbf226d97de18f709"}, - {file = "pyzmq-26.0.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:e4946d6bdb7ba972dfda282f9127e5756d4f299028b1566d1245fa0d438847e6"}, - {file = "pyzmq-26.0.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:03c0ae165e700364b266876d712acb1ac02693acd920afa67da2ebb91a0b3c09"}, - {file = "pyzmq-26.0.3-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:3e3070e680f79887d60feeda051a58d0ac36622e1759f305a41059eff62c6da7"}, - {file = "pyzmq-26.0.3-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6ca08b840fe95d1c2bd9ab92dac5685f949fc6f9ae820ec16193e5ddf603c3b2"}, - {file = "pyzmq-26.0.3-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e76654e9dbfb835b3518f9938e565c7806976c07b37c33526b574cc1a1050480"}, - {file = "pyzmq-26.0.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:871587bdadd1075b112e697173e946a07d722459d20716ceb3d1bd6c64bd08ce"}, - {file = "pyzmq-26.0.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d0a2d1bd63a4ad79483049b26514e70fa618ce6115220da9efdff63688808b17"}, - {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0270b49b6847f0d106d64b5086e9ad5dc8a902413b5dbbb15d12b60f9c1747a4"}, - {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:703c60b9910488d3d0954ca585c34f541e506a091a41930e663a098d3b794c67"}, - {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:74423631b6be371edfbf7eabb02ab995c2563fee60a80a30829176842e71722a"}, - {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4adfbb5451196842a88fda3612e2c0414134874bffb1c2ce83ab4242ec9e027d"}, - {file = "pyzmq-26.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3516119f4f9b8671083a70b6afaa0a070f5683e431ab3dc26e9215620d7ca1ad"}, - {file = "pyzmq-26.0.3.tar.gz", hash = "sha256:dba7d9f2e047dfa2bca3b01f4f84aa5246725203d6284e3790f2ca15fba6b40a"}, + {file = "pyzmq-26.2.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:ddf33d97d2f52d89f6e6e7ae66ee35a4d9ca6f36eda89c24591b0c40205a3629"}, + {file = "pyzmq-26.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dacd995031a01d16eec825bf30802fceb2c3791ef24bcce48fa98ce40918c27b"}, + {file = "pyzmq-26.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89289a5ee32ef6c439086184529ae060c741334b8970a6855ec0b6ad3ff28764"}, + {file = "pyzmq-26.2.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5506f06d7dc6ecf1efacb4a013b1f05071bb24b76350832c96449f4a2d95091c"}, + {file = "pyzmq-26.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ea039387c10202ce304af74def5021e9adc6297067f3441d348d2b633e8166a"}, + {file = "pyzmq-26.2.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a2224fa4a4c2ee872886ed00a571f5e967c85e078e8e8c2530a2fb01b3309b88"}, + {file = "pyzmq-26.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:28ad5233e9c3b52d76196c696e362508959741e1a005fb8fa03b51aea156088f"}, + {file = "pyzmq-26.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:1c17211bc037c7d88e85ed8b7d8f7e52db6dc8eca5590d162717c654550f7282"}, + {file = "pyzmq-26.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b8f86dd868d41bea9a5f873ee13bf5551c94cf6bc51baebc6f85075971fe6eea"}, + {file = "pyzmq-26.2.0-cp310-cp310-win32.whl", hash = "sha256:46a446c212e58456b23af260f3d9fb785054f3e3653dbf7279d8f2b5546b21c2"}, + {file = "pyzmq-26.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:49d34ab71db5a9c292a7644ce74190b1dd5a3475612eefb1f8be1d6961441971"}, + {file = "pyzmq-26.2.0-cp310-cp310-win_arm64.whl", hash = "sha256:bfa832bfa540e5b5c27dcf5de5d82ebc431b82c453a43d141afb1e5d2de025fa"}, + {file = "pyzmq-26.2.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:8f7e66c7113c684c2b3f1c83cdd3376103ee0ce4c49ff80a648643e57fb22218"}, + {file = "pyzmq-26.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3a495b30fc91db2db25120df5847d9833af237546fd59170701acd816ccc01c4"}, + {file = "pyzmq-26.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77eb0968da535cba0470a5165468b2cac7772cfb569977cff92e240f57e31bef"}, + {file = "pyzmq-26.2.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ace4f71f1900a548f48407fc9be59c6ba9d9aaf658c2eea6cf2779e72f9f317"}, + {file = "pyzmq-26.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:92a78853d7280bffb93df0a4a6a2498cba10ee793cc8076ef797ef2f74d107cf"}, + {file = "pyzmq-26.2.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:689c5d781014956a4a6de61d74ba97b23547e431e9e7d64f27d4922ba96e9d6e"}, + {file = "pyzmq-26.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0aca98bc423eb7d153214b2df397c6421ba6373d3397b26c057af3c904452e37"}, + {file = "pyzmq-26.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1f3496d76b89d9429a656293744ceca4d2ac2a10ae59b84c1da9b5165f429ad3"}, + {file = "pyzmq-26.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5c2b3bfd4b9689919db068ac6c9911f3fcb231c39f7dd30e3138be94896d18e6"}, + {file = "pyzmq-26.2.0-cp311-cp311-win32.whl", hash = "sha256:eac5174677da084abf378739dbf4ad245661635f1600edd1221f150b165343f4"}, + {file = "pyzmq-26.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:5a509df7d0a83a4b178d0f937ef14286659225ef4e8812e05580776c70e155d5"}, + {file = "pyzmq-26.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:c0e6091b157d48cbe37bd67233318dbb53e1e6327d6fc3bb284afd585d141003"}, + {file = "pyzmq-26.2.0-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:ded0fc7d90fe93ae0b18059930086c51e640cdd3baebdc783a695c77f123dcd9"}, + {file = "pyzmq-26.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:17bf5a931c7f6618023cdacc7081f3f266aecb68ca692adac015c383a134ca52"}, + {file = "pyzmq-26.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55cf66647e49d4621a7e20c8d13511ef1fe1efbbccf670811864452487007e08"}, + {file = "pyzmq-26.2.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4661c88db4a9e0f958c8abc2b97472e23061f0bc737f6f6179d7a27024e1faa5"}, + {file = "pyzmq-26.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea7f69de383cb47522c9c208aec6dd17697db7875a4674c4af3f8cfdac0bdeae"}, + {file = "pyzmq-26.2.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:7f98f6dfa8b8ccaf39163ce872bddacca38f6a67289116c8937a02e30bbe9711"}, + {file = "pyzmq-26.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e3e0210287329272539eea617830a6a28161fbbd8a3271bf4150ae3e58c5d0e6"}, + {file = "pyzmq-26.2.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6b274e0762c33c7471f1a7471d1a2085b1a35eba5cdc48d2ae319f28b6fc4de3"}, + {file = "pyzmq-26.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:29c6a4635eef69d68a00321e12a7d2559fe2dfccfa8efae3ffb8e91cd0b36a8b"}, + {file = "pyzmq-26.2.0-cp312-cp312-win32.whl", hash = "sha256:989d842dc06dc59feea09e58c74ca3e1678c812a4a8a2a419046d711031f69c7"}, + {file = "pyzmq-26.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:2a50625acdc7801bc6f74698c5c583a491c61d73c6b7ea4dee3901bb99adb27a"}, + {file = "pyzmq-26.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:4d29ab8592b6ad12ebbf92ac2ed2bedcfd1cec192d8e559e2e099f648570e19b"}, + {file = "pyzmq-26.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9dd8cd1aeb00775f527ec60022004d030ddc51d783d056e3e23e74e623e33726"}, + {file = "pyzmq-26.2.0-cp313-cp313-macosx_10_15_universal2.whl", hash = "sha256:28c812d9757fe8acecc910c9ac9dafd2ce968c00f9e619db09e9f8f54c3a68a3"}, + {file = "pyzmq-26.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d80b1dd99c1942f74ed608ddb38b181b87476c6a966a88a950c7dee118fdf50"}, + {file = "pyzmq-26.2.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8c997098cc65e3208eca09303630e84d42718620e83b733d0fd69543a9cab9cb"}, + {file = "pyzmq-26.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ad1bc8d1b7a18497dda9600b12dc193c577beb391beae5cd2349184db40f187"}, + {file = "pyzmq-26.2.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:bea2acdd8ea4275e1278350ced63da0b166421928276c7c8e3f9729d7402a57b"}, + {file = "pyzmq-26.2.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:23f4aad749d13698f3f7b64aad34f5fc02d6f20f05999eebc96b89b01262fb18"}, + {file = "pyzmq-26.2.0-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:a4f96f0d88accc3dbe4a9025f785ba830f968e21e3e2c6321ccdfc9aef755115"}, + {file = "pyzmq-26.2.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ced65e5a985398827cc9276b93ef6dfabe0273c23de8c7931339d7e141c2818e"}, + {file = "pyzmq-26.2.0-cp313-cp313-win32.whl", hash = "sha256:31507f7b47cc1ead1f6e86927f8ebb196a0bab043f6345ce070f412a59bf87b5"}, + {file = "pyzmq-26.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:70fc7fcf0410d16ebdda9b26cbd8bf8d803d220a7f3522e060a69a9c87bf7bad"}, + {file = "pyzmq-26.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:c3789bd5768ab5618ebf09cef6ec2b35fed88709b104351748a63045f0ff9797"}, + {file = "pyzmq-26.2.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:034da5fc55d9f8da09015d368f519478a52675e558c989bfcb5cf6d4e16a7d2a"}, + {file = "pyzmq-26.2.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:c92d73464b886931308ccc45b2744e5968cbaade0b1d6aeb40d8ab537765f5bc"}, + {file = "pyzmq-26.2.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:794a4562dcb374f7dbbfb3f51d28fb40123b5a2abadee7b4091f93054909add5"}, + {file = "pyzmq-26.2.0-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aee22939bb6075e7afededabad1a56a905da0b3c4e3e0c45e75810ebe3a52672"}, + {file = "pyzmq-26.2.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ae90ff9dad33a1cfe947d2c40cb9cb5e600d759ac4f0fd22616ce6540f72797"}, + {file = "pyzmq-26.2.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:43a47408ac52647dfabbc66a25b05b6a61700b5165807e3fbd40063fcaf46386"}, + {file = "pyzmq-26.2.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:25bf2374a2a8433633c65ccb9553350d5e17e60c8eb4de4d92cc6bd60f01d306"}, + {file = "pyzmq-26.2.0-cp313-cp313t-musllinux_1_1_i686.whl", hash = "sha256:007137c9ac9ad5ea21e6ad97d3489af654381324d5d3ba614c323f60dab8fae6"}, + {file = "pyzmq-26.2.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:470d4a4f6d48fb34e92d768b4e8a5cc3780db0d69107abf1cd7ff734b9766eb0"}, + {file = "pyzmq-26.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3b55a4229ce5da9497dd0452b914556ae58e96a4381bb6f59f1305dfd7e53fc8"}, + {file = "pyzmq-26.2.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9cb3a6460cdea8fe8194a76de8895707e61ded10ad0be97188cc8463ffa7e3a8"}, + {file = "pyzmq-26.2.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8ab5cad923cc95c87bffee098a27856c859bd5d0af31bd346035aa816b081fe1"}, + {file = "pyzmq-26.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9ed69074a610fad1c2fda66180e7b2edd4d31c53f2d1872bc2d1211563904cd9"}, + {file = "pyzmq-26.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:cccba051221b916a4f5e538997c45d7d136a5646442b1231b916d0164067ea27"}, + {file = "pyzmq-26.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:0eaa83fc4c1e271c24eaf8fb083cbccef8fde77ec8cd45f3c35a9a123e6da097"}, + {file = "pyzmq-26.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:9edda2df81daa129b25a39b86cb57dfdfe16f7ec15b42b19bfac503360d27a93"}, + {file = "pyzmq-26.2.0-cp37-cp37m-win32.whl", hash = "sha256:ea0eb6af8a17fa272f7b98d7bebfab7836a0d62738e16ba380f440fceca2d951"}, + {file = "pyzmq-26.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:4ff9dc6bc1664bb9eec25cd17506ef6672d506115095411e237d571e92a58231"}, + {file = "pyzmq-26.2.0-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:2eb7735ee73ca1b0d71e0e67c3739c689067f055c764f73aac4cc8ecf958ee3f"}, + {file = "pyzmq-26.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1a534f43bc738181aa7cbbaf48e3eca62c76453a40a746ab95d4b27b1111a7d2"}, + {file = "pyzmq-26.2.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:aedd5dd8692635813368e558a05266b995d3d020b23e49581ddd5bbe197a8ab6"}, + {file = "pyzmq-26.2.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8be4700cd8bb02cc454f630dcdf7cfa99de96788b80c51b60fe2fe1dac480289"}, + {file = "pyzmq-26.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fcc03fa4997c447dce58264e93b5aa2d57714fbe0f06c07b7785ae131512732"}, + {file = "pyzmq-26.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:402b190912935d3db15b03e8f7485812db350d271b284ded2b80d2e5704be780"}, + {file = "pyzmq-26.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8685fa9c25ff00f550c1fec650430c4b71e4e48e8d852f7ddcf2e48308038640"}, + {file = "pyzmq-26.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:76589c020680778f06b7e0b193f4b6dd66d470234a16e1df90329f5e14a171cd"}, + {file = "pyzmq-26.2.0-cp38-cp38-win32.whl", hash = "sha256:8423c1877d72c041f2c263b1ec6e34360448decfb323fa8b94e85883043ef988"}, + {file = "pyzmq-26.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:76589f2cd6b77b5bdea4fca5992dc1c23389d68b18ccc26a53680ba2dc80ff2f"}, + {file = "pyzmq-26.2.0-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:b1d464cb8d72bfc1a3adc53305a63a8e0cac6bc8c5a07e8ca190ab8d3faa43c2"}, + {file = "pyzmq-26.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4da04c48873a6abdd71811c5e163bd656ee1b957971db7f35140a2d573f6949c"}, + {file = "pyzmq-26.2.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:d049df610ac811dcffdc147153b414147428567fbbc8be43bb8885f04db39d98"}, + {file = "pyzmq-26.2.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:05590cdbc6b902101d0e65d6a4780af14dc22914cc6ab995d99b85af45362cc9"}, + {file = "pyzmq-26.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c811cfcd6a9bf680236c40c6f617187515269ab2912f3d7e8c0174898e2519db"}, + {file = "pyzmq-26.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6835dd60355593de10350394242b5757fbbd88b25287314316f266e24c61d073"}, + {file = "pyzmq-26.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc6bee759a6bddea5db78d7dcd609397449cb2d2d6587f48f3ca613b19410cfc"}, + {file = "pyzmq-26.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c530e1eecd036ecc83c3407f77bb86feb79916d4a33d11394b8234f3bd35b940"}, + {file = "pyzmq-26.2.0-cp39-cp39-win32.whl", hash = "sha256:367b4f689786fca726ef7a6c5ba606958b145b9340a5e4808132cc65759abd44"}, + {file = "pyzmq-26.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:e6fa2e3e683f34aea77de8112f6483803c96a44fd726d7358b9888ae5bb394ec"}, + {file = "pyzmq-26.2.0-cp39-cp39-win_arm64.whl", hash = "sha256:7445be39143a8aa4faec43b076e06944b8f9d0701b669df4af200531b21e40bb"}, + {file = "pyzmq-26.2.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:706e794564bec25819d21a41c31d4df2d48e1cc4b061e8d345d7fb4dd3e94072"}, + {file = "pyzmq-26.2.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b435f2753621cd36e7c1762156815e21c985c72b19135dac43a7f4f31d28dd1"}, + {file = "pyzmq-26.2.0-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:160c7e0a5eb178011e72892f99f918c04a131f36056d10d9c1afb223fc952c2d"}, + {file = "pyzmq-26.2.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c4a71d5d6e7b28a47a394c0471b7e77a0661e2d651e7ae91e0cab0a587859ca"}, + {file = "pyzmq-26.2.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:90412f2db8c02a3864cbfc67db0e3dcdbda336acf1c469526d3e869394fe001c"}, + {file = "pyzmq-26.2.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2ea4ad4e6a12e454de05f2949d4beddb52460f3de7c8b9d5c46fbb7d7222e02c"}, + {file = "pyzmq-26.2.0-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:fc4f7a173a5609631bb0c42c23d12c49df3966f89f496a51d3eb0ec81f4519d6"}, + {file = "pyzmq-26.2.0-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:878206a45202247781472a2d99df12a176fef806ca175799e1c6ad263510d57c"}, + {file = "pyzmq-26.2.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:17c412bad2eb9468e876f556eb4ee910e62d721d2c7a53c7fa31e643d35352e6"}, + {file = "pyzmq-26.2.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:0d987a3ae5a71c6226b203cfd298720e0086c7fe7c74f35fa8edddfbd6597eed"}, + {file = "pyzmq-26.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:39887ac397ff35b7b775db7201095fc6310a35fdbae85bac4523f7eb3b840e20"}, + {file = "pyzmq-26.2.0-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:fdb5b3e311d4d4b0eb8b3e8b4d1b0a512713ad7e6a68791d0923d1aec433d919"}, + {file = "pyzmq-26.2.0-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:226af7dcb51fdb0109f0016449b357e182ea0ceb6b47dfb5999d569e5db161d5"}, + {file = "pyzmq-26.2.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bed0e799e6120b9c32756203fb9dfe8ca2fb8467fed830c34c877e25638c3fc"}, + {file = "pyzmq-26.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:29c7947c594e105cb9e6c466bace8532dc1ca02d498684128b339799f5248277"}, + {file = "pyzmq-26.2.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:cdeabcff45d1c219636ee2e54d852262e5c2e085d6cb476d938aee8d921356b3"}, + {file = "pyzmq-26.2.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35cffef589bcdc587d06f9149f8d5e9e8859920a071df5a2671de2213bef592a"}, + {file = "pyzmq-26.2.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18c8dc3b7468d8b4bdf60ce9d7141897da103c7a4690157b32b60acb45e333e6"}, + {file = "pyzmq-26.2.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7133d0a1677aec369d67dd78520d3fa96dd7f3dcec99d66c1762870e5ea1a50a"}, + {file = "pyzmq-26.2.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6a96179a24b14fa6428cbfc08641c779a53f8fcec43644030328f44034c7f1f4"}, + {file = "pyzmq-26.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:4f78c88905461a9203eac9faac157a2a0dbba84a0fd09fd29315db27be40af9f"}, + {file = "pyzmq-26.2.0.tar.gz", hash = "sha256:070672c258581c8e4f640b5159297580a9974b026043bd4ab0470be9ed324f1f"}, ] [package.dependencies] @@ -3611,13 +3623,13 @@ rpds-py = ">=0.7.0" [[package]] name = "requests" -version = "2.32.1" +version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" files = [ - {file = "requests-2.32.1-py3-none-any.whl", hash = "sha256:21ac9465cdf8c1650fe1ecde8a71669a93d4e6f147550483a2967d08396a56a5"}, - {file = "requests-2.32.1.tar.gz", hash = "sha256:eb97e87e64c79e64e5b8ac75cee9dd1f97f49e289b083ee6be96268930725685"}, + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, ] [package.dependencies] @@ -3630,19 +3642,6 @@ urllib3 = ">=1.21.1,<3" socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] -[[package]] -name = "restructuredtext-lint" -version = "1.4.0" -description = "reStructuredText linter" -optional = false -python-versions = "*" -files = [ - {file = "restructuredtext_lint-1.4.0.tar.gz", hash = "sha256:1b235c0c922341ab6c530390892eb9e92f90b9b75046063e047cacfb0f050c45"}, -] - -[package.dependencies] -docutils = ">=0.11,<1.0" - [[package]] name = "rfc3339-validator" version = "0.1.4" @@ -3670,188 +3669,192 @@ files = [ [[package]] name = "rich" -version = "13.7.1" +version = "13.9.4" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" optional = false -python-versions = ">=3.7.0" +python-versions = ">=3.8.0" files = [ - {file = "rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222"}, - {file = "rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"}, + {file = "rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90"}, + {file = "rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098"}, ] [package.dependencies] markdown-it-py = ">=2.2.0" pygments = ">=2.13.0,<3.0.0" +typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.11\""} [package.extras] jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "rpds-py" -version = "0.18.1" +version = "0.22.0" description = "Python bindings to Rust's persistent data structures (rpds)" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "rpds_py-0.18.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:d31dea506d718693b6b2cffc0648a8929bdc51c70a311b2770f09611caa10d53"}, - {file = "rpds_py-0.18.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:732672fbc449bab754e0b15356c077cc31566df874964d4801ab14f71951ea80"}, - {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a98a1f0552b5f227a3d6422dbd61bc6f30db170939bd87ed14f3c339aa6c7c9"}, - {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7f1944ce16401aad1e3f7d312247b3d5de7981f634dc9dfe90da72b87d37887d"}, - {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38e14fb4e370885c4ecd734f093a2225ee52dc384b86fa55fe3f74638b2cfb09"}, - {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08d74b184f9ab6289b87b19fe6a6d1a97fbfea84b8a3e745e87a5de3029bf944"}, - {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d70129cef4a8d979caa37e7fe957202e7eee8ea02c5e16455bc9808a59c6b2f0"}, - {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ce0bb20e3a11bd04461324a6a798af34d503f8d6f1aa3d2aa8901ceaf039176d"}, - {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:81c5196a790032e0fc2464c0b4ab95f8610f96f1f2fa3d4deacce6a79852da60"}, - {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f3027be483868c99b4985fda802a57a67fdf30c5d9a50338d9db646d590198da"}, - {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d44607f98caa2961bab4fa3c4309724b185b464cdc3ba6f3d7340bac3ec97cc1"}, - {file = "rpds_py-0.18.1-cp310-none-win32.whl", hash = "sha256:c273e795e7a0f1fddd46e1e3cb8be15634c29ae8ff31c196debb620e1edb9333"}, - {file = "rpds_py-0.18.1-cp310-none-win_amd64.whl", hash = "sha256:8352f48d511de5f973e4f2f9412736d7dea76c69faa6d36bcf885b50c758ab9a"}, - {file = "rpds_py-0.18.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6b5ff7e1d63a8281654b5e2896d7f08799378e594f09cf3674e832ecaf396ce8"}, - {file = "rpds_py-0.18.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8927638a4d4137a289e41d0fd631551e89fa346d6dbcfc31ad627557d03ceb6d"}, - {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:154bf5c93d79558b44e5b50cc354aa0459e518e83677791e6adb0b039b7aa6a7"}, - {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07f2139741e5deb2c5154a7b9629bc5aa48c766b643c1a6750d16f865a82c5fc"}, - {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c7672e9fba7425f79019db9945b16e308ed8bc89348c23d955c8c0540da0a07"}, - {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:489bdfe1abd0406eba6b3bb4fdc87c7fa40f1031de073d0cfb744634cc8fa261"}, - {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c20f05e8e3d4fc76875fc9cb8cf24b90a63f5a1b4c5b9273f0e8225e169b100"}, - {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:967342e045564cef76dfcf1edb700b1e20838d83b1aa02ab313e6a497cf923b8"}, - {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2cc7c1a47f3a63282ab0f422d90ddac4aa3034e39fc66a559ab93041e6505da7"}, - {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f7afbfee1157e0f9376c00bb232e80a60e59ed716e3211a80cb8506550671e6e"}, - {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9e6934d70dc50f9f8ea47081ceafdec09245fd9f6032669c3b45705dea096b88"}, - {file = "rpds_py-0.18.1-cp311-none-win32.whl", hash = "sha256:c69882964516dc143083d3795cb508e806b09fc3800fd0d4cddc1df6c36e76bb"}, - {file = "rpds_py-0.18.1-cp311-none-win_amd64.whl", hash = "sha256:70a838f7754483bcdc830444952fd89645569e7452e3226de4a613a4c1793fb2"}, - {file = "rpds_py-0.18.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3dd3cd86e1db5aadd334e011eba4e29d37a104b403e8ca24dcd6703c68ca55b3"}, - {file = "rpds_py-0.18.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:05f3d615099bd9b13ecf2fc9cf2d839ad3f20239c678f461c753e93755d629ee"}, - {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35b2b771b13eee8729a5049c976197ff58a27a3829c018a04341bcf1ae409b2b"}, - {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ee17cd26b97d537af8f33635ef38be873073d516fd425e80559f4585a7b90c43"}, - {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b646bf655b135ccf4522ed43d6902af37d3f5dbcf0da66c769a2b3938b9d8184"}, - {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:19ba472b9606c36716062c023afa2484d1e4220548751bda14f725a7de17b4f6"}, - {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e30ac5e329098903262dc5bdd7e2086e0256aa762cc8b744f9e7bf2a427d3f8"}, - {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d58ad6317d188c43750cb76e9deacf6051d0f884d87dc6518e0280438648a9ac"}, - {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e1735502458621921cee039c47318cb90b51d532c2766593be6207eec53e5c4c"}, - {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f5bab211605d91db0e2995a17b5c6ee5edec1270e46223e513eaa20da20076ac"}, - {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2fc24a329a717f9e2448f8cd1f960f9dac4e45b6224d60734edeb67499bab03a"}, - {file = "rpds_py-0.18.1-cp312-none-win32.whl", hash = "sha256:1805d5901779662d599d0e2e4159d8a82c0b05faa86ef9222bf974572286b2b6"}, - {file = "rpds_py-0.18.1-cp312-none-win_amd64.whl", hash = "sha256:720edcb916df872d80f80a1cc5ea9058300b97721efda8651efcd938a9c70a72"}, - {file = "rpds_py-0.18.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:c827576e2fa017a081346dce87d532a5310241648eb3700af9a571a6e9fc7e74"}, - {file = "rpds_py-0.18.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:aa3679e751408d75a0b4d8d26d6647b6d9326f5e35c00a7ccd82b78ef64f65f8"}, - {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0abeee75434e2ee2d142d650d1e54ac1f8b01e6e6abdde8ffd6eeac6e9c38e20"}, - {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed402d6153c5d519a0faf1bb69898e97fb31613b49da27a84a13935ea9164dfc"}, - {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:338dee44b0cef8b70fd2ef54b4e09bb1b97fc6c3a58fea5db6cc083fd9fc2724"}, - {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7750569d9526199c5b97e5a9f8d96a13300950d910cf04a861d96f4273d5b104"}, - {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:607345bd5912aacc0c5a63d45a1f73fef29e697884f7e861094e443187c02be5"}, - {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:207c82978115baa1fd8d706d720b4a4d2b0913df1c78c85ba73fe6c5804505f0"}, - {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:6d1e42d2735d437e7e80bab4d78eb2e459af48c0a46e686ea35f690b93db792d"}, - {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:5463c47c08630007dc0fe99fb480ea4f34a89712410592380425a9b4e1611d8e"}, - {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:06d218939e1bf2ca50e6b0ec700ffe755e5216a8230ab3e87c059ebb4ea06afc"}, - {file = "rpds_py-0.18.1-cp38-none-win32.whl", hash = "sha256:312fe69b4fe1ffbe76520a7676b1e5ac06ddf7826d764cc10265c3b53f96dbe9"}, - {file = "rpds_py-0.18.1-cp38-none-win_amd64.whl", hash = "sha256:9437ca26784120a279f3137ee080b0e717012c42921eb07861b412340f85bae2"}, - {file = "rpds_py-0.18.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:19e515b78c3fc1039dd7da0a33c28c3154458f947f4dc198d3c72db2b6b5dc93"}, - {file = "rpds_py-0.18.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a7b28c5b066bca9a4eb4e2f2663012debe680f097979d880657f00e1c30875a0"}, - {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:673fdbbf668dd958eff750e500495ef3f611e2ecc209464f661bc82e9838991e"}, - {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d960de62227635d2e61068f42a6cb6aae91a7fe00fca0e3aeed17667c8a34611"}, - {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:352a88dc7892f1da66b6027af06a2e7e5d53fe05924cc2cfc56495b586a10b72"}, - {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e0ee01ad8260184db21468a6e1c37afa0529acc12c3a697ee498d3c2c4dcaf3"}, - {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4c39ad2f512b4041343ea3c7894339e4ca7839ac38ca83d68a832fc8b3748ab"}, - {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aaa71ee43a703c321906813bb252f69524f02aa05bf4eec85f0c41d5d62d0f4c"}, - {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6cd8098517c64a85e790657e7b1e509b9fe07487fd358e19431cb120f7d96338"}, - {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:4adec039b8e2928983f885c53b7cc4cda8965b62b6596501a0308d2703f8af1b"}, - {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:32b7daaa3e9389db3695964ce8e566e3413b0c43e3394c05e4b243a4cd7bef26"}, - {file = "rpds_py-0.18.1-cp39-none-win32.whl", hash = "sha256:2625f03b105328729f9450c8badda34d5243231eef6535f80064d57035738360"}, - {file = "rpds_py-0.18.1-cp39-none-win_amd64.whl", hash = "sha256:bf18932d0003c8c4d51a39f244231986ab23ee057d235a12b2684ea26a353590"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cbfbea39ba64f5e53ae2915de36f130588bba71245b418060ec3330ebf85678e"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:a3d456ff2a6a4d2adcdf3c1c960a36f4fd2fec6e3b4902a42a384d17cf4e7a65"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7700936ef9d006b7ef605dc53aa364da2de5a3aa65516a1f3ce73bf82ecfc7ae"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:51584acc5916212e1bf45edd17f3a6b05fe0cbb40482d25e619f824dccb679de"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:942695a206a58d2575033ff1e42b12b2aece98d6003c6bc739fbf33d1773b12f"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b906b5f58892813e5ba5c6056d6a5ad08f358ba49f046d910ad992196ea61397"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6f8e3fecca256fefc91bb6765a693d96692459d7d4c644660a9fff32e517843"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7732770412bab81c5a9f6d20aeb60ae943a9b36dcd990d876a773526468e7163"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:bd1105b50ede37461c1d51b9698c4f4be6e13e69a908ab7751e3807985fc0346"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:618916f5535784960f3ecf8111581f4ad31d347c3de66d02e728de460a46303c"}, - {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:17c6d2155e2423f7e79e3bb18151c686d40db42d8645e7977442170c360194d4"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:6c4c4c3f878df21faf5fac86eda32671c27889e13570645a9eea0a1abdd50922"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:fab6ce90574645a0d6c58890e9bcaac8d94dff54fb51c69e5522a7358b80ab64"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:531796fb842b53f2695e94dc338929e9f9dbf473b64710c28af5a160b2a8927d"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:740884bc62a5e2bbb31e584f5d23b32320fd75d79f916f15a788d527a5e83644"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:998125738de0158f088aef3cb264a34251908dd2e5d9966774fdab7402edfab7"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e2be6e9dd4111d5b31ba3b74d17da54a8319d8168890fbaea4b9e5c3de630ae5"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0cee71bc618cd93716f3c1bf56653740d2d13ddbd47673efa8bf41435a60daa"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2c3caec4ec5cd1d18e5dd6ae5194d24ed12785212a90b37f5f7f06b8bedd7139"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:27bba383e8c5231cd559affe169ca0b96ec78d39909ffd817f28b166d7ddd4d8"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:a888e8bdb45916234b99da2d859566f1e8a1d2275a801bb8e4a9644e3c7e7909"}, - {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:6031b25fb1b06327b43d841f33842b383beba399884f8228a6bb3df3088485ff"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48c2faaa8adfacefcbfdb5f2e2e7bdad081e5ace8d182e5f4ade971f128e6bb3"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:d85164315bd68c0806768dc6bb0429c6f95c354f87485ee3593c4f6b14def2bd"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6afd80f6c79893cfc0574956f78a0add8c76e3696f2d6a15bca2c66c415cf2d4"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa242ac1ff583e4ec7771141606aafc92b361cd90a05c30d93e343a0c2d82a89"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d21be4770ff4e08698e1e8e0bce06edb6ea0626e7c8f560bc08222880aca6a6f"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c45a639e93a0c5d4b788b2613bd637468edd62f8f95ebc6fcc303d58ab3f0a8"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:910e71711d1055b2768181efa0a17537b2622afeb0424116619817007f8a2b10"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b9bb1f182a97880f6078283b3505a707057c42bf55d8fca604f70dedfdc0772a"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:1d54f74f40b1f7aaa595a02ff42ef38ca654b1469bef7d52867da474243cc633"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:8d2e182c9ee01135e11e9676e9a62dfad791a7a467738f06726872374a83db49"}, - {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:636a15acc588f70fda1661234761f9ed9ad79ebed3f2125d44be0862708b666e"}, - {file = "rpds_py-0.18.1.tar.gz", hash = "sha256:dc48b479d540770c811fbd1eb9ba2bb66951863e448efec2e2c102625328e92f"}, + {file = "rpds_py-0.22.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:a4366f264fa60d3c109f0b27af0cd9eb8d46746bd70bd3d9d425f035b6c7e286"}, + {file = "rpds_py-0.22.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e34a3e665d38d0749072e6565400c8ce9abae976e338919a0dfbfb0e1ba43068"}, + {file = "rpds_py-0.22.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38cacf1f378571450576f2c8ce87da6f3fddc59d744de5c12b37acc23285b1e1"}, + {file = "rpds_py-0.22.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8cbb040fec8eddd5a6a75e737fd73c9ce37e51f94bacdd0b178d0174a4758395"}, + {file = "rpds_py-0.22.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d80fd710b3307a3c63809048b72c536689b9b0b31a2518339c3f1a4d29c73d7a"}, + {file = "rpds_py-0.22.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b5d17d8f5b885ce50e0cda85f99c0719e365e98b587338535fa566a48375afb"}, + {file = "rpds_py-0.22.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f7a048ec1ebc991331d709be4884dc318c9eaafa66dcde8be0933ac0e702149"}, + {file = "rpds_py-0.22.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:306da3dfa174b489a3fc63b0872e2226a5ddf94c59875a770d72aff945d5ed96"}, + {file = "rpds_py-0.22.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c7b4450093c0c909299770226fb0285be47b0a57545bae25b5c4e51566b0e587"}, + {file = "rpds_py-0.22.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0903ffdb5b9007e503203b6285e4ff0faf96d875c19f1d103b475acf7d9f7311"}, + {file = "rpds_py-0.22.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d1522025cda9e57329aade769f56e5793b2a5da7759a21914ee10e67e17e601e"}, + {file = "rpds_py-0.22.0-cp310-cp310-win32.whl", hash = "sha256:49e084d47a66027ac72844f9f52f13d347a9a1f05d4f84381b420e47f836a7fd"}, + {file = "rpds_py-0.22.0-cp310-cp310-win_amd64.whl", hash = "sha256:d9ceca96df54cb1675a0b7f52f1c6d5d1df62c5b40741ba211780f1b05a282a2"}, + {file = "rpds_py-0.22.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:771c9a3851beaa617d8c8115d65f834a2b52490f42ee2b88b13f1fc5529e9e0c"}, + {file = "rpds_py-0.22.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:341a07a4b55126bfae68c9bf24220a73d456111e5eb3dcbdab9fd16de2341224"}, + {file = "rpds_py-0.22.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7649c8b8e4bd1ccc5fcbd51a855d57a617deeba19c66e3d04b1abecc61036b2"}, + {file = "rpds_py-0.22.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f513758e7cda8bc262e80299a8e3395d7ef7f4ae705be62632f229bc6c33208"}, + {file = "rpds_py-0.22.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba1fc34d0b2f6fd53377a4c954116251eba6d076bf64f903311f4a7d27d10acd"}, + {file = "rpds_py-0.22.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:632d2fdddd9fbe3ac8896a119fd18a71fc95ca9c4cbe5223096c142d8c4a2b1d"}, + {file = "rpds_py-0.22.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:326e42f2b49462e05f8527a1311ce98f9f97c484b3e443ec0ea4638bed3aebcf"}, + {file = "rpds_py-0.22.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e9bbdba9e75b1a9ee1dd1335034dad998ef1acc08492226c6fd50aa773bdfa7d"}, + {file = "rpds_py-0.22.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:41f65a97bf2c4b161c9f8f89bc37058346bec9b36e373c8ad00a16c957bff625"}, + {file = "rpds_py-0.22.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0686f2c16eafdc2c6b4ce6e86e5b3092e87db09ae64be2787616444eb35b9756"}, + {file = "rpds_py-0.22.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4e7c9aa2353eb0b0d845323857197daa036c2ff8624df990b0d886d22a8f665e"}, + {file = "rpds_py-0.22.0-cp311-cp311-win32.whl", hash = "sha256:2d2fc3ab021be3e0b5aec6d4164f2689d231b8bfc5185cc454314746aa4aee72"}, + {file = "rpds_py-0.22.0-cp311-cp311-win_amd64.whl", hash = "sha256:87453d491369cd8018016d2714a13e8461975161703c18ee31eecf087a8ae5d4"}, + {file = "rpds_py-0.22.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:e9d4293b21c69ee4f9e1a99ac4f772951d345611c614a0cfae2ec6b565279bc9"}, + {file = "rpds_py-0.22.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:67e013a17a3db4d98cc228fd5aeb36a51b0f5cf7330b9102a552060f1fe4e560"}, + {file = "rpds_py-0.22.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b639a19e1791b646d27f15d17530a51722cc728d43b2dff3aeb904f92d91bac"}, + {file = "rpds_py-0.22.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1357c3092702078b7782b6ebd5ba9b22c1a291c34fbf9d8f1a48237466ac7758"}, + {file = "rpds_py-0.22.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:842855bbb113a19c393c6de5aa6ed9a26c6b13c2fead5e49114d39f0d08b94d8"}, + {file = "rpds_py-0.22.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ae7927cd2b869ca4dc645169d8af5494a29c99afd0ea0f24dd00c811ab1d8b8"}, + {file = "rpds_py-0.22.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91bfef5daa2a5a4fe62f8d317fc91a626073639f951f851bd2cb252d01bc6c5"}, + {file = "rpds_py-0.22.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4fc4824e38c1e91a73bc820e7caacaf19d0acd557465aceef0420ca59489b390"}, + {file = "rpds_py-0.22.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:92d28a608127b357da47c99e0d0e0655ca2060286540fe9f2a25a2e8ac666e05"}, + {file = "rpds_py-0.22.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c637188b930175c256f13adbfc427b83ec7e64476d1ec9d6608f312bb84e06c3"}, + {file = "rpds_py-0.22.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:93bbd66f46dddc41e8c656130c97c0fb515e0fa44e1eebb2592769dbbd41b2f5"}, + {file = "rpds_py-0.22.0-cp312-cp312-win32.whl", hash = "sha256:54d8f94dec5765a9edc19610fecf0fdf9cab36cbb9def1213188215f735a6f98"}, + {file = "rpds_py-0.22.0-cp312-cp312-win_amd64.whl", hash = "sha256:931bf3d0705b2834fed29354f35170fa022fe22a95542b61b7c66aca5f8a224f"}, + {file = "rpds_py-0.22.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:2a57300cc8b034c5707085249efd09f19116bb80278d0ec925d7f3710165c510"}, + {file = "rpds_py-0.22.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c398a5a8e258dfdc5ea2aa4e5aa2ca3207f654a8eb268693dd1a76939074a588"}, + {file = "rpds_py-0.22.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a6cc4eb1e86364331928acafb2bb41d8ab735ca3caf2d6019b9f6dac3f4f65d"}, + {file = "rpds_py-0.22.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:574c5c94213bc9990805bfd7e4ba3826d3c098516cbc19f0d0ef0433ad93fa06"}, + {file = "rpds_py-0.22.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c0321bc03a1c513eca1837e3bba948b975bcf3a172aebc197ab3573207f137a"}, + {file = "rpds_py-0.22.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d276280649305c1da6cdd84585d48ae1f0efa67434d8b10d2df95228e59a05bb"}, + {file = "rpds_py-0.22.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c17b43fe9c6da16885e3fe28922bcd1a029e61631fb771c7d501019b40bcc904"}, + {file = "rpds_py-0.22.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:48c95997af9314f4034fe5ba2d837399e786586e220835a578d28fe8161e6ae5"}, + {file = "rpds_py-0.22.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e9aa4af6b879bb75a3c7766fbf49d77f4097dd12b548ecbbd8b3f85caa833281"}, + {file = "rpds_py-0.22.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8426f97117b914b9bfb2a7bd46edc148e8defda728a55a5df3a564abe70cd7a4"}, + {file = "rpds_py-0.22.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:034964ea0ea09645bdde13038b38abb14be0aa747f20fcfab6181207dd9e0483"}, + {file = "rpds_py-0.22.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:3dc7c64b56b82428894f056e9ff6e8ee917ff74fc26b65211a33602c2372e928"}, + {file = "rpds_py-0.22.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:1212cb231f2002934cd8d71a0d718fdd9d9a2dd671e0feef8501038df3508026"}, + {file = "rpds_py-0.22.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f21e1278c9456cd601832375c778ca44614d3433996488221a56572c223f04a"}, + {file = "rpds_py-0.22.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:875fe8dffb43c20f68379ee098b035a7038d7903c795d46715f66575a7050b19"}, + {file = "rpds_py-0.22.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e23dcdd4b2ff9c6b3317ea7921b210d39592f8ca1cdea58ada25b202c65c0a69"}, + {file = "rpds_py-0.22.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0fb8efc9e579acf1e556fd86277fecec320c21ca9b5d39db96433ad8c45bc4a"}, + {file = "rpds_py-0.22.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe23687924b25a2dee52fab15976fd6577ed8518072bcda9ff2e2b88ab1f168b"}, + {file = "rpds_py-0.22.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d5469b347445d1c31105f33e7bfc9a8ba213d48e42641a610dda65bf9e3c83f5"}, + {file = "rpds_py-0.22.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a810a57ce5e8ecf8eac6ec4dab534ff80c34e5a2c31db60e992009cd20f58e0f"}, + {file = "rpds_py-0.22.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:d9bb9242b38a664f307b3b897f093896f7ed51ef4fe25a0502e5a368de9151ea"}, + {file = "rpds_py-0.22.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:b4660943030406aaa40ec9f51960dd88049903d9536bc3c8ebb5cc4e1f119bbe"}, + {file = "rpds_py-0.22.0-cp313-cp313t-win32.whl", hash = "sha256:208ce1d8e3af138d1d9b21d7206356b7f29b96675e0113aea652cf024e4ddfdc"}, + {file = "rpds_py-0.22.0-cp313-cp313t-win_amd64.whl", hash = "sha256:e6da2e0500742e0f157f005924a0589f2e2dcbfdd6cd0cc0abce367433e989be"}, + {file = "rpds_py-0.22.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:f980a0640599a74f27fd9d50c84c293f1cb7afc2046c5c6d3efaf8ec7cdbc326"}, + {file = "rpds_py-0.22.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ca505fd3767a09a139737f3278bc8a485cb64043062da89bcba27e2f2ea78d33"}, + {file = "rpds_py-0.22.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba235e00e0878ba1080b0f2a761f143b2a2d1c354f3d8e507fbf2f3de401bf18"}, + {file = "rpds_py-0.22.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:81e7a27365b02fe70a77f1365376879917235b3fec551d19b4c91b51d0bc1d07"}, + {file = "rpds_py-0.22.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:32a0e24cab2daae0503b06666d516e90a080c1a95aff0406b9f03c6489177c4b"}, + {file = "rpds_py-0.22.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a73ed43d64209e853bba567a543170267a5cd64f359540b0ca2d597e329ba172"}, + {file = "rpds_py-0.22.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0abcce5e874474d3eab5ad53be03dae2abe651d248bdeaabe83708e82969e78"}, + {file = "rpds_py-0.22.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f4e9946c8c7def17e4fcb5eddb14c4eb6ebc7f6f309075e6c8d23b133c104607"}, + {file = "rpds_py-0.22.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:758098b38c344d9a7f279baf0689261777e601f620078ef5afdc9bd3339965c3"}, + {file = "rpds_py-0.22.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:9ad4640a409bc2b7d22b7921e7660f0db96c5c8c69fbb2e8f3261d4f71d33983"}, + {file = "rpds_py-0.22.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8c48fc7458fe3a74dcdf56ba3534ff41bd421f69436df09ff3497fdaac18b431"}, + {file = "rpds_py-0.22.0-cp39-cp39-win32.whl", hash = "sha256:fde778947304e55fc732bc8ea5c6063e74244ac1808471cb498983a210aaf62c"}, + {file = "rpds_py-0.22.0-cp39-cp39-win_amd64.whl", hash = "sha256:5fdf91a7c07f40e47b193f2acae0ed9da35d09325d7c3c3279f722b7cbf3d264"}, + {file = "rpds_py-0.22.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c8fd7a16f7a047e06c747cfcf2acef3ac316132df1c6077445b29ee6f3f3a70b"}, + {file = "rpds_py-0.22.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:6b6e4bcfc32f831bfe3d6d8a5acedfbfd5e252a03c83fa24813b277a3a8a13ca"}, + {file = "rpds_py-0.22.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eadd2417e83a77ce3ae4a0efd08cb0ebdfd317b6406d11020354a53ad458ec84"}, + {file = "rpds_py-0.22.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f9dc2113e0cf0dd637751ca736186fca63664939ceb9f9f67e93ade88c69c0c9"}, + {file = "rpds_py-0.22.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc2c00acdf68f1f69a476b770af311a7dc3955b7de228b04a40bcc51ac4d743b"}, + {file = "rpds_py-0.22.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dfdabdf8519c93908b2bf0f87c3f86f9e88bab279fb4acfd0907519ca5a1739f"}, + {file = "rpds_py-0.22.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8338db3c76833d02dc21c3e2c42534091341d26e4f7ba32c6032bb558a02e07b"}, + {file = "rpds_py-0.22.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8ad4dfda52e64af3202ceb2143a62deba97894b71c64a4405ee80f6b3ea77285"}, + {file = "rpds_py-0.22.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:3b94b074dcce39976db22ea75c7aea8b22d95e6d3b62f76e20e1179a278521d8"}, + {file = "rpds_py-0.22.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:d4f2af3107fe4dc40c0d1a2409863f5249c6796398a1d83c1d99a0b3fa6cfb8d"}, + {file = "rpds_py-0.22.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:bb11809b0de643a292a82f728c494a2bbef0e30a7c42d37464abbd6bef7ca7b1"}, + {file = "rpds_py-0.22.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c1c21030ed494deb10226f90e2dbd84a012d59810c409832714a3dd576527be2"}, + {file = "rpds_py-0.22.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:64a0c965a1e299c9b280006bdb15c276c427c45360aed676305dc36bcaa4d13c"}, + {file = "rpds_py-0.22.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:2498ff422823be087b48bc82710deb87ac34f6b7c8034ee39920647647de1e60"}, + {file = "rpds_py-0.22.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59e63da174ff287db05ef7c21d75974a5bac727ed60452aeb3a14278477842a8"}, + {file = "rpds_py-0.22.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e1c04fb380bc8efaae2fdf17ed6cd5d223da78a8b0b18a610f53d4c5d6e31dfd"}, + {file = "rpds_py-0.22.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e04919ffa9a728c446b27b6b625fa1d00ece221bdb9d633e978a7e0353a12c0e"}, + {file = "rpds_py-0.22.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:24c28df05bd284879d0fac850ba697077d2a33b7ebcaea6318d6b6cdfdc86ddc"}, + {file = "rpds_py-0.22.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d33622dc63c295788eed09dbb1d11bed178909d3267b02d873116ee6be368244"}, + {file = "rpds_py-0.22.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7539dbb8f705e13629ba6f23388976aad809e387f32a6e5c0712e4e8d9bfcce7"}, + {file = "rpds_py-0.22.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:b8906f537978da3f7f0bd1ba37b69f6a877bb43312023b086582707d2835bf2f"}, + {file = "rpds_py-0.22.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:62ab12fe03ffc49978d29de9c31bbb216610157f7e5ca8e172fed6642aead3be"}, + {file = "rpds_py-0.22.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:762206ba3bf1d6c8c9e0055871d3c0d5b074b7c3120193e6c067e7866f106ab1"}, + {file = "rpds_py-0.22.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ed0102146574e5e9f079b2e1a06e6b5b12a691f9c74a65b93b7f3d4feda566c6"}, + {file = "rpds_py-0.22.0.tar.gz", hash = "sha256:32de71c393f126d8203e9815557c7ff4d72ed1ad3aa3f52f6c7938413176750a"}, ] [[package]] name = "ruff" -version = "0.4.4" +version = "0.8.1" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.4.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:29d44ef5bb6a08e235c8249294fa8d431adc1426bfda99ed493119e6f9ea1bf6"}, - {file = "ruff-0.4.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c4efe62b5bbb24178c950732ddd40712b878a9b96b1d02b0ff0b08a090cbd891"}, - {file = "ruff-0.4.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c8e2f1e8fc12d07ab521a9005d68a969e167b589cbcaee354cb61e9d9de9c15"}, - {file = "ruff-0.4.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:60ed88b636a463214905c002fa3eaab19795679ed55529f91e488db3fe8976ab"}, - {file = "ruff-0.4.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b90fc5e170fc71c712cc4d9ab0e24ea505c6a9e4ebf346787a67e691dfb72e85"}, - {file = "ruff-0.4.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:8e7e6ebc10ef16dcdc77fd5557ee60647512b400e4a60bdc4849468f076f6eef"}, - {file = "ruff-0.4.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b9ddb2c494fb79fc208cd15ffe08f32b7682519e067413dbaf5f4b01a6087bcd"}, - {file = "ruff-0.4.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c51c928a14f9f0a871082603e25a1588059b7e08a920f2f9fa7157b5bf08cfe9"}, - {file = "ruff-0.4.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5eb0a4bfd6400b7d07c09a7725e1a98c3b838be557fee229ac0f84d9aa49c36"}, - {file = "ruff-0.4.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:b1867ee9bf3acc21778dcb293db504692eda5f7a11a6e6cc40890182a9f9e595"}, - {file = "ruff-0.4.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:1aecced1269481ef2894cc495647392a34b0bf3e28ff53ed95a385b13aa45768"}, - {file = "ruff-0.4.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:9da73eb616b3241a307b837f32756dc20a0b07e2bcb694fec73699c93d04a69e"}, - {file = "ruff-0.4.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:958b4ea5589706a81065e2a776237de2ecc3e763342e5cc8e02a4a4d8a5e6f95"}, - {file = "ruff-0.4.4-py3-none-win32.whl", hash = "sha256:cb53473849f011bca6e754f2cdf47cafc9c4f4ff4570003a0dad0b9b6890e876"}, - {file = "ruff-0.4.4-py3-none-win_amd64.whl", hash = "sha256:424e5b72597482543b684c11def82669cc6b395aa8cc69acc1858b5ef3e5daae"}, - {file = "ruff-0.4.4-py3-none-win_arm64.whl", hash = "sha256:39df0537b47d3b597293edbb95baf54ff5b49589eb7ff41926d8243caa995ea6"}, - {file = "ruff-0.4.4.tar.gz", hash = "sha256:f87ea42d5cdebdc6a69761a9d0bc83ae9b3b30d0ad78952005ba6568d6c022af"}, + {file = "ruff-0.8.1-py3-none-linux_armv6l.whl", hash = "sha256:fae0805bd514066f20309f6742f6ee7904a773eb9e6c17c45d6b1600ca65c9b5"}, + {file = "ruff-0.8.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b8a4f7385c2285c30f34b200ca5511fcc865f17578383db154e098150ce0a087"}, + {file = "ruff-0.8.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:cd054486da0c53e41e0086e1730eb77d1f698154f910e0cd9e0d64274979a209"}, + {file = "ruff-0.8.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2029b8c22da147c50ae577e621a5bfbc5d1fed75d86af53643d7a7aee1d23871"}, + {file = "ruff-0.8.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2666520828dee7dfc7e47ee4ea0d928f40de72056d929a7c5292d95071d881d1"}, + {file = "ruff-0.8.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:333c57013ef8c97a53892aa56042831c372e0bb1785ab7026187b7abd0135ad5"}, + {file = "ruff-0.8.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:288326162804f34088ac007139488dcb43de590a5ccfec3166396530b58fb89d"}, + {file = "ruff-0.8.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b12c39b9448632284561cbf4191aa1b005882acbc81900ffa9f9f471c8ff7e26"}, + {file = "ruff-0.8.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:364e6674450cbac8e998f7b30639040c99d81dfb5bbc6dfad69bc7a8f916b3d1"}, + {file = "ruff-0.8.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b22346f845fec132aa39cd29acb94451d030c10874408dbf776af3aaeb53284c"}, + {file = "ruff-0.8.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:b2f2f7a7e7648a2bfe6ead4e0a16745db956da0e3a231ad443d2a66a105c04fa"}, + {file = "ruff-0.8.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:adf314fc458374c25c5c4a4a9270c3e8a6a807b1bec018cfa2813d6546215540"}, + {file = "ruff-0.8.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a885d68342a231b5ba4d30b8c6e1b1ee3a65cf37e3d29b3c74069cdf1ee1e3c9"}, + {file = "ruff-0.8.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:d2c16e3508c8cc73e96aa5127d0df8913d2290098f776416a4b157657bee44c5"}, + {file = "ruff-0.8.1-py3-none-win32.whl", hash = "sha256:93335cd7c0eaedb44882d75a7acb7df4b77cd7cd0d2255c93b28791716e81790"}, + {file = "ruff-0.8.1-py3-none-win_amd64.whl", hash = "sha256:2954cdbe8dfd8ab359d4a30cd971b589d335a44d444b6ca2cb3d1da21b75e4b6"}, + {file = "ruff-0.8.1-py3-none-win_arm64.whl", hash = "sha256:55873cc1a473e5ac129d15eccb3c008c096b94809d693fc7053f588b67822737"}, + {file = "ruff-0.8.1.tar.gz", hash = "sha256:3583db9a6450364ed5ca3f3b4225958b24f78178908d5c4bc0f46251ccca898f"}, ] [[package]] name = "scipy" -version = "1.13.0" +version = "1.13.1" description = "Fundamental algorithms for scientific computing in Python" optional = false python-versions = ">=3.9" files = [ - {file = "scipy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ba419578ab343a4e0a77c0ef82f088238a93eef141b2b8017e46149776dfad4d"}, - {file = "scipy-1.13.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:22789b56a999265431c417d462e5b7f2b487e831ca7bef5edeb56efe4c93f86e"}, - {file = "scipy-1.13.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05f1432ba070e90d42d7fd836462c50bf98bd08bed0aa616c359eed8a04e3922"}, - {file = "scipy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8434f6f3fa49f631fae84afee424e2483289dfc30a47755b4b4e6b07b2633a4"}, - {file = "scipy-1.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:dcbb9ea49b0167de4167c40eeee6e167caeef11effb0670b554d10b1e693a8b9"}, - {file = "scipy-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:1d2f7bb14c178f8b13ebae93f67e42b0a6b0fc50eba1cd8021c9b6e08e8fb1cd"}, - {file = "scipy-1.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0fbcf8abaf5aa2dc8d6400566c1a727aed338b5fe880cde64907596a89d576fa"}, - {file = "scipy-1.13.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:5e4a756355522eb60fcd61f8372ac2549073c8788f6114449b37e9e8104f15a5"}, - {file = "scipy-1.13.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5acd8e1dbd8dbe38d0004b1497019b2dbbc3d70691e65d69615f8a7292865d7"}, - {file = "scipy-1.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ff7dad5d24a8045d836671e082a490848e8639cabb3dbdacb29f943a678683d"}, - {file = "scipy-1.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4dca18c3ffee287ddd3bc8f1dabaf45f5305c5afc9f8ab9cbfab855e70b2df5c"}, - {file = "scipy-1.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:a2f471de4d01200718b2b8927f7d76b5d9bde18047ea0fa8bd15c5ba3f26a1d6"}, - {file = "scipy-1.13.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d0de696f589681c2802f9090fff730c218f7c51ff49bf252b6a97ec4a5d19e8b"}, - {file = "scipy-1.13.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:b2a3ff461ec4756b7e8e42e1c681077349a038f0686132d623fa404c0bee2551"}, - {file = "scipy-1.13.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bf9fe63e7a4bf01d3645b13ff2aa6dea023d38993f42aaac81a18b1bda7a82a"}, - {file = "scipy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e7626dfd91cdea5714f343ce1176b6c4745155d234f1033584154f60ef1ff42"}, - {file = "scipy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:109d391d720fcebf2fbe008621952b08e52907cf4c8c7efc7376822151820820"}, - {file = "scipy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:8930ae3ea371d6b91c203b1032b9600d69c568e537b7988a3073dfe4d4774f21"}, - {file = "scipy-1.13.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5407708195cb38d70fd2d6bb04b1b9dd5c92297d86e9f9daae1576bd9e06f602"}, - {file = "scipy-1.13.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:ac38c4c92951ac0f729c4c48c9e13eb3675d9986cc0c83943784d7390d540c78"}, - {file = "scipy-1.13.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09c74543c4fbeb67af6ce457f6a6a28e5d3739a87f62412e4a16e46f164f0ae5"}, - {file = "scipy-1.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28e286bf9ac422d6beb559bc61312c348ca9b0f0dae0d7c5afde7f722d6ea13d"}, - {file = "scipy-1.13.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:33fde20efc380bd23a78a4d26d59fc8704e9b5fd9b08841693eb46716ba13d86"}, - {file = "scipy-1.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:45c08bec71d3546d606989ba6e7daa6f0992918171e2a6f7fbedfa7361c2de1e"}, - {file = "scipy-1.13.0.tar.gz", hash = "sha256:58569af537ea29d3f78e5abd18398459f195546bb3be23d16677fb26616cc11e"}, + {file = "scipy-1.13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:20335853b85e9a49ff7572ab453794298bcf0354d8068c5f6775a0eabf350aca"}, + {file = "scipy-1.13.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:d605e9c23906d1994f55ace80e0125c587f96c020037ea6aa98d01b4bd2e222f"}, + {file = "scipy-1.13.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfa31f1def5c819b19ecc3a8b52d28ffdcc7ed52bb20c9a7589669dd3c250989"}, + {file = "scipy-1.13.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26264b282b9da0952a024ae34710c2aff7d27480ee91a2e82b7b7073c24722f"}, + {file = "scipy-1.13.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:eccfa1906eacc02de42d70ef4aecea45415f5be17e72b61bafcfd329bdc52e94"}, + {file = "scipy-1.13.1-cp310-cp310-win_amd64.whl", hash = "sha256:2831f0dc9c5ea9edd6e51e6e769b655f08ec6db6e2e10f86ef39bd32eb11da54"}, + {file = "scipy-1.13.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:27e52b09c0d3a1d5b63e1105f24177e544a222b43611aaf5bc44d4a0979e32f9"}, + {file = "scipy-1.13.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:54f430b00f0133e2224c3ba42b805bfd0086fe488835effa33fa291561932326"}, + {file = "scipy-1.13.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e89369d27f9e7b0884ae559a3a956e77c02114cc60a6058b4e5011572eea9299"}, + {file = "scipy-1.13.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a78b4b3345f1b6f68a763c6e25c0c9a23a9fd0f39f5f3d200efe8feda560a5fa"}, + {file = "scipy-1.13.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:45484bee6d65633752c490404513b9ef02475b4284c4cfab0ef946def50b3f59"}, + {file = "scipy-1.13.1-cp311-cp311-win_amd64.whl", hash = "sha256:5713f62f781eebd8d597eb3f88b8bf9274e79eeabf63afb4a737abc6c84ad37b"}, + {file = "scipy-1.13.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5d72782f39716b2b3509cd7c33cdc08c96f2f4d2b06d51e52fb45a19ca0c86a1"}, + {file = "scipy-1.13.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:017367484ce5498445aade74b1d5ab377acdc65e27095155e448c88497755a5d"}, + {file = "scipy-1.13.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:949ae67db5fa78a86e8fa644b9a6b07252f449dcf74247108c50e1d20d2b4627"}, + {file = "scipy-1.13.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de3ade0e53bc1f21358aa74ff4830235d716211d7d077e340c7349bc3542e884"}, + {file = "scipy-1.13.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2ac65fb503dad64218c228e2dc2d0a0193f7904747db43014645ae139c8fad16"}, + {file = "scipy-1.13.1-cp312-cp312-win_amd64.whl", hash = "sha256:cdd7dacfb95fea358916410ec61bbc20440f7860333aee6d882bb8046264e949"}, + {file = "scipy-1.13.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:436bbb42a94a8aeef855d755ce5a465479c721e9d684de76bf61a62e7c2b81d5"}, + {file = "scipy-1.13.1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:8335549ebbca860c52bf3d02f80784e91a004b71b059e3eea9678ba994796a24"}, + {file = "scipy-1.13.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d533654b7d221a6a97304ab63c41c96473ff04459e404b83275b60aa8f4b7004"}, + {file = "scipy-1.13.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:637e98dcf185ba7f8e663e122ebf908c4702420477ae52a04f9908707456ba4d"}, + {file = "scipy-1.13.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a014c2b3697bde71724244f63de2476925596c24285c7a637364761f8710891c"}, + {file = "scipy-1.13.1-cp39-cp39-win_amd64.whl", hash = "sha256:392e4ec766654852c25ebad4f64e4e584cf19820b980bc04960bca0b0cd6eaa2"}, + {file = "scipy-1.13.1.tar.gz", hash = "sha256:095a87a0312b08dfd6a6155cbbd310a8c51800fc931b8c0b84003014b874ed3c"}, ] [package.dependencies] @@ -3862,15 +3865,64 @@ dev = ["cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy", "pycodestyle", "pyde doc = ["jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.12.0)", "jupytext", "matplotlib (>=3.5)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0)", "sphinx-design (>=0.4.0)"] test = ["array-api-strict", "asv", "gmpy2", "hypothesis (>=6.30)", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] +[[package]] +name = "scipy" +version = "1.14.1" +description = "Fundamental algorithms for scientific computing in Python" +optional = false +python-versions = ">=3.10" +files = [ + {file = "scipy-1.14.1-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:b28d2ca4add7ac16ae8bb6632a3c86e4b9e4d52d3e34267f6e1b0c1f8d87e389"}, + {file = "scipy-1.14.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:d0d2821003174de06b69e58cef2316a6622b60ee613121199cb2852a873f8cf3"}, + {file = "scipy-1.14.1-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:8bddf15838ba768bb5f5083c1ea012d64c9a444e16192762bd858f1e126196d0"}, + {file = "scipy-1.14.1-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:97c5dddd5932bd2a1a31c927ba5e1463a53b87ca96b5c9bdf5dfd6096e27efc3"}, + {file = "scipy-1.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ff0a7e01e422c15739ecd64432743cf7aae2b03f3084288f399affcefe5222d"}, + {file = "scipy-1.14.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e32dced201274bf96899e6491d9ba3e9a5f6b336708656466ad0522d8528f69"}, + {file = "scipy-1.14.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8426251ad1e4ad903a4514712d2fa8fdd5382c978010d1c6f5f37ef286a713ad"}, + {file = "scipy-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:a49f6ed96f83966f576b33a44257d869756df6cf1ef4934f59dd58b25e0327e5"}, + {file = "scipy-1.14.1-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:2da0469a4ef0ecd3693761acbdc20f2fdeafb69e6819cc081308cc978153c675"}, + {file = "scipy-1.14.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:c0ee987efa6737242745f347835da2cc5bb9f1b42996a4d97d5c7ff7928cb6f2"}, + {file = "scipy-1.14.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3a1b111fac6baec1c1d92f27e76511c9e7218f1695d61b59e05e0fe04dc59617"}, + {file = "scipy-1.14.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:8475230e55549ab3f207bff11ebfc91c805dc3463ef62eda3ccf593254524ce8"}, + {file = "scipy-1.14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:278266012eb69f4a720827bdd2dc54b2271c97d84255b2faaa8f161a158c3b37"}, + {file = "scipy-1.14.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fef8c87f8abfb884dac04e97824b61299880c43f4ce675dd2cbeadd3c9b466d2"}, + {file = "scipy-1.14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b05d43735bb2f07d689f56f7b474788a13ed8adc484a85aa65c0fd931cf9ccd2"}, + {file = "scipy-1.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:716e389b694c4bb564b4fc0c51bc84d381735e0d39d3f26ec1af2556ec6aad94"}, + {file = "scipy-1.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:631f07b3734d34aced009aaf6fedfd0eb3498a97e581c3b1e5f14a04164a456d"}, + {file = "scipy-1.14.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:af29a935803cc707ab2ed7791c44288a682f9c8107bc00f0eccc4f92c08d6e07"}, + {file = "scipy-1.14.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:2843f2d527d9eebec9a43e6b406fb7266f3af25a751aa91d62ff416f54170bc5"}, + {file = "scipy-1.14.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:eb58ca0abd96911932f688528977858681a59d61a7ce908ffd355957f7025cfc"}, + {file = "scipy-1.14.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:30ac8812c1d2aab7131a79ba62933a2a76f582d5dbbc695192453dae67ad6310"}, + {file = "scipy-1.14.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f9ea80f2e65bdaa0b7627fb00cbeb2daf163caa015e59b7516395fe3bd1e066"}, + {file = "scipy-1.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:edaf02b82cd7639db00dbff629995ef185c8df4c3ffa71a5562a595765a06ce1"}, + {file = "scipy-1.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:2ff38e22128e6c03ff73b6bb0f85f897d2362f8c052e3b8ad00532198fbdae3f"}, + {file = "scipy-1.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1729560c906963fc8389f6aac023739ff3983e727b1a4d87696b7bf108316a79"}, + {file = "scipy-1.14.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:4079b90df244709e675cdc8b93bfd8a395d59af40b72e339c2287c91860deb8e"}, + {file = "scipy-1.14.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:e0cf28db0f24a38b2a0ca33a85a54852586e43cf6fd876365c86e0657cfe7d73"}, + {file = "scipy-1.14.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:0c2f95de3b04e26f5f3ad5bb05e74ba7f68b837133a4492414b3afd79dfe540e"}, + {file = "scipy-1.14.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b99722ea48b7ea25e8e015e8341ae74624f72e5f21fc2abd45f3a93266de4c5d"}, + {file = "scipy-1.14.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5149e3fd2d686e42144a093b206aef01932a0059c2a33ddfa67f5f035bdfe13e"}, + {file = "scipy-1.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e4f5a7c49323533f9103d4dacf4e4f07078f360743dec7f7596949149efeec06"}, + {file = "scipy-1.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:baff393942b550823bfce952bb62270ee17504d02a1801d7fd0719534dfb9c84"}, + {file = "scipy-1.14.1.tar.gz", hash = "sha256:5a275584e726026a5699459aa72f828a610821006228e841b94275c4a7c08417"}, +] + +[package.dependencies] +numpy = ">=1.23.5,<2.3" + +[package.extras] +dev = ["cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy (==1.10.0)", "pycodestyle", "pydevtool", "rich-click", "ruff (>=0.0.292)", "types-psutil", "typing_extensions"] +doc = ["jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.13.1)", "jupytext", "matplotlib (>=3.5)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0,<=7.3.7)", "sphinx-design (>=0.4.0)"] +test = ["Cython", "array-api-strict (>=2.0)", "asv", "gmpy2", "hypothesis (>=6.30)", "meson", "mpmath", "ninja", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] + [[package]] name = "screeninfo" -version = "0.8.1" +version = "0.7" description = "Fetch location and size of physical screens." optional = false -python-versions = ">=3.6.2,<4.0.0" +python-versions = "*" files = [ - {file = "screeninfo-0.8.1-py3-none-any.whl", hash = "sha256:e97d6b173856edcfa3bd282f81deb528188aff14b11ec3e195584e7641be733c"}, - {file = "screeninfo-0.8.1.tar.gz", hash = "sha256:9983076bcc7e34402a1a9e4d7dabf3729411fd2abb3f3b4be7eba73519cd2ed1"}, + {file = "screeninfo-0.7.tar.gz", hash = "sha256:12a97c3527e3544ac5dbd7c1204283e2653d655cbd15844c990a83b1b13ef500"}, ] [package.dependencies] @@ -3895,18 +3947,23 @@ win32 = ["pywin32"] [[package]] name = "setuptools" -version = "70.0.0" +version = "75.6.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" -optional = false -python-versions = ">=3.8" +optional = true +python-versions = ">=3.9" files = [ - {file = "setuptools-70.0.0-py3-none-any.whl", hash = "sha256:54faa7f2e8d2d11bcd2c07bed282eef1046b5c080d1c32add737d7b5817b1ad4"}, - {file = "setuptools-70.0.0.tar.gz", hash = "sha256:f211a66637b8fa059bb28183da127d4e86396c991a942b028c6650d4319c3fd0"}, + {file = "setuptools-75.6.0-py3-none-any.whl", hash = "sha256:ce74b49e8f7110f9bf04883b730f4765b774ef3ef28f722cce7c273d253aaf7d"}, + {file = "setuptools-75.6.0.tar.gz", hash = "sha256:8199222558df7c86216af4f84c30e9b34a61d8ba19366cc914424cdbd28252f6"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mypy (==1.9)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.1)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.7.0)"] +core = ["importlib_metadata (>=6)", "jaraco.collections", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] +type = ["importlib_metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (>=1.12,<1.14)", "pytest-mypy"] [[package]] name = "six" @@ -3921,50 +3978,57 @@ files = [ [[package]] name = "skia-pathops" -version = "0.8.0.post1" +version = "0.8.0.post2" description = "Python access to operations on paths using the Skia library" optional = false python-versions = ">=3.8" files = [ - {file = "skia-pathops-0.8.0.post1.zip", hash = "sha256:a056249de2f61fa55116b9ee55513c6a36b878aee00c91450e404d1606485cbb"}, - {file = "skia_pathops-0.8.0.post1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:952a03a19e687caa341ce6966eac03b167de8faea48574d3cf4bb758c2cefcfb"}, - {file = "skia_pathops-0.8.0.post1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:003efdbbc4400fffba00e0f9523b6b762269d7e257a6ad45cefbe4844fe04e4a"}, - {file = "skia_pathops-0.8.0.post1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77e8b60380a94bc277a50177f70392646e0cce83c5c8fa8ab5817d813eef0224"}, - {file = "skia_pathops-0.8.0.post1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d7b3361338f80bea1529698c2c66df1bdffc89339b90257d9a8e8e1cbda7f2c"}, - {file = "skia_pathops-0.8.0.post1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8ccd03685b08e2ba7e65005911f0eac224eec3eabff18f9aeb8d757188dc5cbb"}, - {file = "skia_pathops-0.8.0.post1-cp310-cp310-win32.whl", hash = "sha256:e273b565544b801219bbea6b32c5b1f3f9c2ce4f43870700a859174aa1f6564b"}, - {file = "skia_pathops-0.8.0.post1-cp310-cp310-win_amd64.whl", hash = "sha256:35b3f990e9f0fc861e962b9bca959ab0de68c095959e0dccc21d7e5076141c12"}, - {file = "skia_pathops-0.8.0.post1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:934fafd7e8552b40cf7c6a02b8d3b40ead6dff2f2c0426a26e4b9a031b880a65"}, - {file = "skia_pathops-0.8.0.post1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:db4e3a9af2bbd76d2522909cf6d32c84a0a5c6e1f8d3eff18305a960b3645293"}, - {file = "skia_pathops-0.8.0.post1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8973b7dccc96a9273b529f1ccea70f6d05e5b4ff90d0fe7e424a4fcff2134bd6"}, - {file = "skia_pathops-0.8.0.post1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27861201a5eabcd50b1d4c94be9cd28749d9236cbbab797e5ca6a293b6c15178"}, - {file = "skia_pathops-0.8.0.post1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30cb3286ff91325f1ae452f9d1bc58b92e4a5c5beeca3bd17b269c6376a0dbfa"}, - {file = "skia_pathops-0.8.0.post1-cp311-cp311-win32.whl", hash = "sha256:960a387300550a4fed0a66d5c29d26a02d9df965caf9e5ccd1eeef4e225b06c6"}, - {file = "skia_pathops-0.8.0.post1-cp311-cp311-win_amd64.whl", hash = "sha256:8235e313199be4b250ed32799d3de5a4be7ed60ecd62f19d426518814e6853a7"}, - {file = "skia_pathops-0.8.0.post1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:3dc8febcb792c2542f05e12a3cee409ae421cdf865878c19d7b525291fa93348"}, - {file = "skia_pathops-0.8.0.post1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:25fd0e8a18bc021f5b0b9cab37d607ea5c61f503b9e860d223906954b0c53c43"}, - {file = "skia_pathops-0.8.0.post1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9005f5dc5b162cac0d782e9adb5ecb304ab7ae5c873d2ed2a9895e89bf660ee2"}, - {file = "skia_pathops-0.8.0.post1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7b6873b65b682f8cf94a3baf8fccf98219f689e09a08967075bda36da128d57"}, - {file = "skia_pathops-0.8.0.post1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3a4f111f55811ab9f8cb4ee057823db95355c8a424a2c2272ccda56ec0c48ba4"}, - {file = "skia_pathops-0.8.0.post1-cp312-cp312-win32.whl", hash = "sha256:69ff7abe4ba02b0c7159ae04d8173b4186336f3809d512e660f5569f39e08572"}, - {file = "skia_pathops-0.8.0.post1-cp312-cp312-win_amd64.whl", hash = "sha256:bc8792c342795c8d90a71d7df641513372954562b3a851b21c501400dba60dcc"}, - {file = "skia_pathops-0.8.0.post1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a5e7dd0b372c72a2c4b15505c31c1cfa0476ae2b46c8d52932a3278653e0afc4"}, - {file = "skia_pathops-0.8.0.post1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:08d73f6a6568e1ac486c927035166d9c3bcb6c60bcc10c081d626c05397d2c21"}, - {file = "skia_pathops-0.8.0.post1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ecece9b39ca2d4ed03bc49364f291f8e94bcd832cbd1e23d5539570d6f22daf"}, - {file = "skia_pathops-0.8.0.post1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2af80580d722032e650ffa535173e58c16ac7a222eb8886786c9b6f6b7e1df63"}, - {file = "skia_pathops-0.8.0.post1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:27746a5d18c908f54778654be5a09c2af52b5655977b04650089c962c1700c25"}, - {file = "skia_pathops-0.8.0.post1-cp38-cp38-win32.whl", hash = "sha256:dab68a6ca259e87a3787ebdb18ebb198711419894cd591d01d3599e036847823"}, - {file = "skia_pathops-0.8.0.post1-cp38-cp38-win_amd64.whl", hash = "sha256:4c97ae7c611b39641de0aaf7340441615327480eb90dea3ca03dc3ca6aa82b44"}, - {file = "skia_pathops-0.8.0.post1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:307a94ba2f72601273c187f7fa934b1747dbfeb348dca175c7b40873823711a1"}, - {file = "skia_pathops-0.8.0.post1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5d7acb97291c2107046027fb0671870b7ca0428f55fc550a13cf262d621b8f17"}, - {file = "skia_pathops-0.8.0.post1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:434037b8b5ab1824b79d09d2e19a80ad8d2561018d5fb1d167b320e0bb1be7ac"}, - {file = "skia_pathops-0.8.0.post1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a3f62afaef14e4a1f02aef3c8d194a04d7735a0e2c700bb4ce39b6c42e8c1ea"}, - {file = "skia_pathops-0.8.0.post1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:143da8261ea047d0752f406448216cf490e4642a9798e7adfadd0bed855c464a"}, - {file = "skia_pathops-0.8.0.post1-cp39-cp39-win32.whl", hash = "sha256:83091a316bc5d24ee02ba9f4ca5b690478d1b43a50285bd8afcf623a3f58e87e"}, - {file = "skia_pathops-0.8.0.post1-cp39-cp39-win_amd64.whl", hash = "sha256:01939106a9aa8e756dd4bf376f16fd9ce616cda16aed1ab34d13e67a498db0aa"}, - {file = "skia_pathops-0.8.0.post1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c5b66e5644a4f791e3b1fb1e78559130c042f15f744bc1867c18f9268aafab3"}, - {file = "skia_pathops-0.8.0.post1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d48fd852f3ac7e30f6221ff93e0cfb8593ea897027fd6b36987479eb406fb22"}, - {file = "skia_pathops-0.8.0.post1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed911ba99e2113574b6314d424696e6e302d427c65136ff8df14359bacb794c7"}, + {file = "skia_pathops-0.8.0.post2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7cd3722709dd186bfe1934f40c1d135252017c516c9cfc11b8c35139aaa4a167"}, + {file = "skia_pathops-0.8.0.post2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:150c9b935c3fc9ca8c259ca8c08f5677863d6c70326f3bea48811caeaef49127"}, + {file = "skia_pathops-0.8.0.post2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1b4e59e9cb89c1feb8b95052e746b6501430d5f117a39014d0a1168373fcf54"}, + {file = "skia_pathops-0.8.0.post2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67dabd89b8ab7c9efddde540c0f16c762039c7f3cf6d4cc89ab94a359fe312fd"}, + {file = "skia_pathops-0.8.0.post2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7b6bb38173a023f3232a76aa1c700a2f034b6edd1cc44693c76cf7926d941fe3"}, + {file = "skia_pathops-0.8.0.post2-cp310-cp310-win32.whl", hash = "sha256:e5e04a1818380e6ae9186a7ef41c2edcc14b2521b6c6fcfdde53b28be7a71068"}, + {file = "skia_pathops-0.8.0.post2-cp310-cp310-win_amd64.whl", hash = "sha256:767e1893fed727096bca20e2725c12f46a95c350b6b3cefc9ab67e55442908e4"}, + {file = "skia_pathops-0.8.0.post2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ada3230a64ccf458e5b47b05b92ad6404ae641b54784d140a02d159b01db8db1"}, + {file = "skia_pathops-0.8.0.post2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8a577e6146a4edfb4dc29d973a9f42fa979aee4d498471933bac5a11fc5686d6"}, + {file = "skia_pathops-0.8.0.post2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec5d532eaa341aef9b09bf7c06783803abadc8822056e44830be08285ad3c870"}, + {file = "skia_pathops-0.8.0.post2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ce6bbdfec398ba6da48323947a8c72796a36903b8f96f6c87f9623172755c14"}, + {file = "skia_pathops-0.8.0.post2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f1e46df0bc41420e0271900b9c7d01104c7a5b1c33ec2d7d1759db82bc9efeab"}, + {file = "skia_pathops-0.8.0.post2-cp311-cp311-win32.whl", hash = "sha256:4435eca08149bdd1e177e172f26d65f50c8c6814e2477abc5a4e2fab44b6972e"}, + {file = "skia_pathops-0.8.0.post2-cp311-cp311-win_amd64.whl", hash = "sha256:c7c9a17a67dcf270c3595d806a8c5996acdd09e7c966f8ed971d40f8511bbd5c"}, + {file = "skia_pathops-0.8.0.post2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:aa11950fda8d390fe074cb0a83ac0d8a95f72087b0a38add30b9f22c3591554e"}, + {file = "skia_pathops-0.8.0.post2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:496def3492582161ce95a43b2c539af8b219c60fba223b25e8eef1ac8f9ee3d7"}, + {file = "skia_pathops-0.8.0.post2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4f3da50b749141caf6f17f032d2e3aae5faec96e39ed9c94e6b55e6e3a3a1c7"}, + {file = "skia_pathops-0.8.0.post2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89f82f2273208f72403da8dc7457d64fbd3f7d8f1f7f54cb8483eeda00747933"}, + {file = "skia_pathops-0.8.0.post2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:153055698053539b439720643a045ec3a50c35ea66bca7d89977e66a0d68282a"}, + {file = "skia_pathops-0.8.0.post2-cp312-cp312-win32.whl", hash = "sha256:575061162264edd3c707e375c0fca85e7f72f5fada2e42c26853a6551c47e076"}, + {file = "skia_pathops-0.8.0.post2-cp312-cp312-win_amd64.whl", hash = "sha256:6f2f60feceb7213a80ab7824f0c7e41de3c26a29a3a1ab8a1f60ec750292b444"}, + {file = "skia_pathops-0.8.0.post2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:4059d5c54dc4d2686e3b54c347fa1aad48ef6a0bc12ca75a27a260b291a98238"}, + {file = "skia_pathops-0.8.0.post2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c0db10dfb00a1093a72e56827c172e3ca4922762f4c321d6ccc0703bc201b966"}, + {file = "skia_pathops-0.8.0.post2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ddb5b52fae729ea456e777e715d17f25940e53bbd0ca0fad8b1e6268c7f493be"}, + {file = "skia_pathops-0.8.0.post2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7db6b12d5cd85d0dec27f8f4ff41f8e2befa76a40170cda9715f98d2002d0da1"}, + {file = "skia_pathops-0.8.0.post2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ae0a7937f6160247515a272f36598e35abb700ae4f1b5adec2e8119fcd535dcb"}, + {file = "skia_pathops-0.8.0.post2-cp313-cp313-win32.whl", hash = "sha256:20e759441ce209e0fe026900057ac846e6912e7112b81229c330a6ad1e550efb"}, + {file = "skia_pathops-0.8.0.post2-cp313-cp313-win_amd64.whl", hash = "sha256:1753fd7b4151c9ae3e5f198227ab39598a60be90c7ccc5c796a6ca5ef26d24d6"}, + {file = "skia_pathops-0.8.0.post2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5537a0dc3abe640c41338daba5ad76c5d49ec983f63810c09f7fec807c362906"}, + {file = "skia_pathops-0.8.0.post2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5a0ed94833af70def1865ab538dc9be6fa47f250ff3e0f2c25cccde068fd86ae"}, + {file = "skia_pathops-0.8.0.post2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ebcce8a446a8c4bd7d6da434057cd2acb3a17d0a017c8a177a476de022629e0"}, + {file = "skia_pathops-0.8.0.post2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:371499d6a94f37d76ecaa96686dcabf44b85590f92336dd53991ef56f162711e"}, + {file = "skia_pathops-0.8.0.post2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c2b27b17a90dedff3385ef2d8a7d6e881117856ef84d497745ed996f01d91910"}, + {file = "skia_pathops-0.8.0.post2-cp38-cp38-win32.whl", hash = "sha256:d36b4d08122d83a808610c6096972a2620b9adefa4c7e0c00d8f6ec396df4d9f"}, + {file = "skia_pathops-0.8.0.post2-cp38-cp38-win_amd64.whl", hash = "sha256:0541e79be26b92c799da793b59eb1a3653b38d1301a61c28e2fa6109a5ade180"}, + {file = "skia_pathops-0.8.0.post2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef2e8892083bf91de0914615f25c5d0b2392c25fad5a06df3ff39e56b933130"}, + {file = "skia_pathops-0.8.0.post2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d3306e4adc525ecc8e8847e52086df1fb990444de2af79b0ec1ccc2c59f2919c"}, + {file = "skia_pathops-0.8.0.post2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7ce8b2b9f3417b20a83fb9194b40ea32dc4aeb50ba7d59ff23ef889406cd35b"}, + {file = "skia_pathops-0.8.0.post2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96bf52955047e00cafb2899725d0585b19a6ce07fe8f566d7d736262843f8b34"}, + {file = "skia_pathops-0.8.0.post2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c576a0d077eeb319e8f95d6043bccfbc3c1b320ec809a79b56f3c66e35a563a8"}, + {file = "skia_pathops-0.8.0.post2-cp39-cp39-win32.whl", hash = "sha256:343a2c83c07d5764f28233d8bda7cf07b444586d748e5560b45e295465cf05c1"}, + {file = "skia_pathops-0.8.0.post2-cp39-cp39-win_amd64.whl", hash = "sha256:4c486a4d800e3685974a0cc8f5fd0486a01edfd355a5c2327e796b6e48f269c7"}, + {file = "skia_pathops-0.8.0.post2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee98a3affee6bb13998828f5565cbb9fd7c52120b71310098bd2764cbd4fa6ad"}, + {file = "skia_pathops-0.8.0.post2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b948b340859771ccee6a878783220fcbf072961af83dd05580b24cfac9611ed7"}, + {file = "skia_pathops-0.8.0.post2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8983fba1b163a65438c51a3fb34c95e27652aad92d900d348bcc81babff3434"}, + {file = "skia_pathops-0.8.0.post2.zip", hash = "sha256:9e252cdeb6c4d162e82986d31dbd89c675d1677cb8019c2e13e6295d4a557269"}, ] [package.extras] @@ -4005,38 +4069,38 @@ files = [ [[package]] name = "soupsieve" -version = "2.5" +version = "2.6" description = "A modern CSS selector implementation for Beautiful Soup." optional = false python-versions = ">=3.8" files = [ - {file = "soupsieve-2.5-py3-none-any.whl", hash = "sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7"}, - {file = "soupsieve-2.5.tar.gz", hash = "sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690"}, + {file = "soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9"}, + {file = "soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb"}, ] [[package]] name = "sphinx" -version = "7.3.7" +version = "7.4.7" description = "Python documentation generator" optional = false python-versions = ">=3.9" files = [ - {file = "sphinx-7.3.7-py3-none-any.whl", hash = "sha256:413f75440be4cacf328f580b4274ada4565fb2187d696a84970c23f77b64d8c3"}, - {file = "sphinx-7.3.7.tar.gz", hash = "sha256:a4a7db75ed37531c05002d56ed6948d4c42f473a36f46e1382b0bd76ca9627bc"}, + {file = "sphinx-7.4.7-py3-none-any.whl", hash = "sha256:c2419e2135d11f1951cd994d6eb18a1835bd8fdd8429f9ca375dc1f3281bd239"}, + {file = "sphinx-7.4.7.tar.gz", hash = "sha256:242f92a7ea7e6c5b406fdc2615413890ba9f699114a9c09192d7dfead2ee9cfe"}, ] [package.dependencies] alabaster = ">=0.7.14,<0.8.0" -babel = ">=2.9" -colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} -docutils = ">=0.18.1,<0.22" +babel = ">=2.13" +colorama = {version = ">=0.4.6", markers = "sys_platform == \"win32\""} +docutils = ">=0.20,<0.22" imagesize = ">=1.3" -importlib-metadata = {version = ">=4.8", markers = "python_version < \"3.10\""} -Jinja2 = ">=3.0" -packaging = ">=21.0" -Pygments = ">=2.14" -requests = ">=2.25.0" -snowballstemmer = ">=2.0" +importlib-metadata = {version = ">=6.0", markers = "python_version < \"3.10\""} +Jinja2 = ">=3.1" +packaging = ">=23.0" +Pygments = ">=2.17" +requests = ">=2.30.0" +snowballstemmer = ">=2.2" sphinxcontrib-applehelp = "*" sphinxcontrib-devhelp = "*" sphinxcontrib-htmlhelp = ">=2.0.0" @@ -4047,8 +4111,8 @@ tomli = {version = ">=2", markers = "python_version < \"3.11\""} [package.extras] docs = ["sphinxcontrib-websupport"] -lint = ["flake8 (>=3.5.0)", "importlib_metadata", "mypy (==1.9.0)", "pytest (>=6.0)", "ruff (==0.3.7)", "sphinx-lint", "tomli", "types-docutils", "types-requests"] -test = ["cython (>=3.0)", "defusedxml (>=0.7.1)", "pytest (>=6.0)", "setuptools (>=67.0)"] +lint = ["flake8 (>=6.0)", "importlib-metadata (>=6.0)", "mypy (==1.10.1)", "pytest (>=6.0)", "ruff (==0.5.2)", "sphinx-lint (>=0.9)", "tomli (>=2)", "types-docutils (==0.21.0.20240711)", "types-requests (>=2.30.0)"] +test = ["cython (>=3.0)", "defusedxml (>=0.7.1)", "pytest (>=8.0)", "setuptools (>=70.0)", "typing_extensions (>=4.9)"] [[package]] name = "sphinx-basic-ng" @@ -4085,51 +4149,90 @@ sphinx = ">=1.8" code-style = ["pre-commit (==2.12.1)"] rtd = ["ipython", "myst-nb", "sphinx", "sphinx-book-theme", "sphinx-examples"] +[[package]] +name = "sphinx-design" +version = "0.6.1" +description = "A sphinx extension for designing beautiful, view size responsive web components." +optional = false +python-versions = ">=3.9" +files = [ + {file = "sphinx_design-0.6.1-py3-none-any.whl", hash = "sha256:b11f37db1a802a183d61b159d9a202314d4d2fe29c163437001324fe2f19549c"}, + {file = "sphinx_design-0.6.1.tar.gz", hash = "sha256:b44eea3719386d04d765c1a8257caca2b3e6f8421d7b3a5e742c0fd45f84e632"}, +] + +[package.dependencies] +sphinx = ">=6,<9" + +[package.extras] +code-style = ["pre-commit (>=3,<4)"] +rtd = ["myst-parser (>=2,<4)"] +testing = ["defusedxml", "myst-parser (>=2,<4)", "pytest (>=8.3,<9.0)", "pytest-cov", "pytest-regressions"] +testing-no-myst = ["defusedxml", "pytest (>=8.3,<9.0)", "pytest-cov", "pytest-regressions"] +theme-furo = ["furo (>=2024.7.18,<2024.8.0)"] +theme-im = ["sphinx-immaterial (>=0.12.2,<0.13.0)"] +theme-pydata = ["pydata-sphinx-theme (>=0.15.2,<0.16.0)"] +theme-rtd = ["sphinx-rtd-theme (>=2.0,<3.0)"] +theme-sbt = ["sphinx-book-theme (>=1.1,<2.0)"] + +[[package]] +name = "sphinx-reredirects" +version = "0.1.5" +description = "Handles redirects for moved pages in Sphinx documentation projects" +optional = false +python-versions = ">=3.5" +files = [ + {file = "sphinx_reredirects-0.1.5-py3-none-any.whl", hash = "sha256:444ae1438fba4418242ca76d6a6de3eaee82aaf0d8f2b0cac71a15d32ce6eba2"}, + {file = "sphinx_reredirects-0.1.5.tar.gz", hash = "sha256:cfa753b441020a22708ce8eb17d4fd553a28fc87a609330092917ada2a6da0d8"}, +] + +[package.dependencies] +sphinx = ">=7.1" + [[package]] name = "sphinxcontrib-applehelp" -version = "1.0.8" +version = "2.0.0" description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_applehelp-1.0.8-py3-none-any.whl", hash = "sha256:cb61eb0ec1b61f349e5cc36b2028e9e7ca765be05e49641c97241274753067b4"}, - {file = "sphinxcontrib_applehelp-1.0.8.tar.gz", hash = "sha256:c40a4f96f3776c4393d933412053962fac2b84f4c99a7982ba42e09576a70619"}, + {file = "sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5"}, + {file = "sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1"}, ] [package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] name = "sphinxcontrib-devhelp" -version = "1.0.6" +version = "2.0.0" description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp documents" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_devhelp-1.0.6-py3-none-any.whl", hash = "sha256:6485d09629944511c893fa11355bda18b742b83a2b181f9a009f7e500595c90f"}, - {file = "sphinxcontrib_devhelp-1.0.6.tar.gz", hash = "sha256:9893fd3f90506bc4b97bdb977ceb8fbd823989f4316b28c3841ec128544372d3"}, + {file = "sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2"}, + {file = "sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad"}, ] [package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] name = "sphinxcontrib-htmlhelp" -version = "2.0.5" +version = "2.1.0" description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_htmlhelp-2.0.5-py3-none-any.whl", hash = "sha256:393f04f112b4d2f53d93448d4bce35842f62b307ccdc549ec1585e950bc35e04"}, - {file = "sphinxcontrib_htmlhelp-2.0.5.tar.gz", hash = "sha256:0dc87637d5de53dd5eec3a6a01753b1ccf99494bd756aafecd74b4fa9e729015"}, + {file = "sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8"}, + {file = "sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9"}, ] [package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] standalone = ["Sphinx (>=5)"] test = ["html5lib", "pytest"] @@ -4163,33 +4266,33 @@ Sphinx = ">=1.7.0" [[package]] name = "sphinxcontrib-qthelp" -version = "1.0.7" +version = "2.0.0" description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp documents" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_qthelp-1.0.7-py3-none-any.whl", hash = "sha256:e2ae3b5c492d58fcbd73281fbd27e34b8393ec34a073c792642cd8e529288182"}, - {file = "sphinxcontrib_qthelp-1.0.7.tar.gz", hash = "sha256:053dedc38823a80a7209a80860b16b722e9e0209e32fea98c90e4e6624588ed6"}, + {file = "sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb"}, + {file = "sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab"}, ] [package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] standalone = ["Sphinx (>=5)"] -test = ["pytest"] +test = ["defusedxml (>=0.7.1)", "pytest"] [[package]] name = "sphinxcontrib-serializinghtml" -version = "1.1.10" +version = "2.0.0" description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_serializinghtml-1.1.10-py3-none-any.whl", hash = "sha256:326369b8df80a7d2d8d7f99aa5ac577f51ea51556ed974e7716cfd4fca3f6cb7"}, - {file = "sphinxcontrib_serializinghtml-1.1.10.tar.gz", hash = "sha256:93f3f5dc458b91b192fe10c397e324f262cf163d79f3282c158e8436a2c4511f"}, + {file = "sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331"}, + {file = "sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d"}, ] [package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] standalone = ["Sphinx (>=5)"] test = ["pytest"] @@ -4270,13 +4373,13 @@ typing = ["mypy (>=1.6,<2.0)", "traitlets (>=5.11.1)"] [[package]] name = "tinycss2" -version = "1.3.0" +version = "1.4.0" description = "A tiny CSS parser" optional = true python-versions = ">=3.8" files = [ - {file = "tinycss2-1.3.0-py3-none-any.whl", hash = "sha256:54a8dbdffb334d536851be0226030e9505965bb2f30f21a4a82c55fb2a80fae7"}, - {file = "tinycss2-1.3.0.tar.gz", hash = "sha256:152f9acabd296a8375fbca5b84c961ff95971fcfc32e79550c8df8e29118c54d"}, + {file = "tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289"}, + {file = "tinycss2-1.4.0.tar.gz", hash = "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7"}, ] [package.dependencies] @@ -4288,51 +4391,82 @@ test = ["pytest", "ruff"] [[package]] name = "tomli" -version = "2.0.1" +version = "2.2.1" description = "A lil' TOML parser" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, + {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, + {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, + {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, + {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, + {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, + {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, + {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, + {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, ] [[package]] name = "tornado" -version = "6.4.1" +version = "6.4.2" description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." optional = true python-versions = ">=3.8" files = [ - {file = "tornado-6.4.1-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:163b0aafc8e23d8cdc3c9dfb24c5368af84a81e3364745ccb4427669bf84aec8"}, - {file = "tornado-6.4.1-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6d5ce3437e18a2b66fbadb183c1d3364fb03f2be71299e7d10dbeeb69f4b2a14"}, - {file = "tornado-6.4.1-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2e20b9113cd7293f164dc46fffb13535266e713cdb87bd2d15ddb336e96cfc4"}, - {file = "tornado-6.4.1-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ae50a504a740365267b2a8d1a90c9fbc86b780a39170feca9bcc1787ff80842"}, - {file = "tornado-6.4.1-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:613bf4ddf5c7a95509218b149b555621497a6cc0d46ac341b30bd9ec19eac7f3"}, - {file = "tornado-6.4.1-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:25486eb223babe3eed4b8aecbac33b37e3dd6d776bc730ca14e1bf93888b979f"}, - {file = "tornado-6.4.1-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:454db8a7ecfcf2ff6042dde58404164d969b6f5d58b926da15e6b23817950fc4"}, - {file = "tornado-6.4.1-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a02a08cc7a9314b006f653ce40483b9b3c12cda222d6a46d4ac63bb6c9057698"}, - {file = "tornado-6.4.1-cp38-abi3-win32.whl", hash = "sha256:d9a566c40b89757c9aa8e6f032bcdb8ca8795d7c1a9762910c722b1635c9de4d"}, - {file = "tornado-6.4.1-cp38-abi3-win_amd64.whl", hash = "sha256:b24b8982ed444378d7f21d563f4180a2de31ced9d8d84443907a0a64da2072e7"}, - {file = "tornado-6.4.1.tar.gz", hash = "sha256:92d3ab53183d8c50f8204a51e6f91d18a15d5ef261e84d452800d4ff6fc504e9"}, + {file = "tornado-6.4.2-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e828cce1123e9e44ae2a50a9de3055497ab1d0aeb440c5ac23064d9e44880da1"}, + {file = "tornado-6.4.2-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:072ce12ada169c5b00b7d92a99ba089447ccc993ea2143c9ede887e0937aa803"}, + {file = "tornado-6.4.2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a017d239bd1bb0919f72af256a970624241f070496635784d9bf0db640d3fec"}, + {file = "tornado-6.4.2-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c36e62ce8f63409301537222faffcef7dfc5284f27eec227389f2ad11b09d946"}, + {file = "tornado-6.4.2-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bca9eb02196e789c9cb5c3c7c0f04fb447dc2adffd95265b2c7223a8a615ccbf"}, + {file = "tornado-6.4.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:304463bd0772442ff4d0f5149c6f1c2135a1fae045adf070821c6cdc76980634"}, + {file = "tornado-6.4.2-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:c82c46813ba483a385ab2a99caeaedf92585a1f90defb5693351fa7e4ea0bf73"}, + {file = "tornado-6.4.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:932d195ca9015956fa502c6b56af9eb06106140d844a335590c1ec7f5277d10c"}, + {file = "tornado-6.4.2-cp38-abi3-win32.whl", hash = "sha256:2876cef82e6c5978fde1e0d5b1f919d756968d5b4282418f3146b79b58556482"}, + {file = "tornado-6.4.2-cp38-abi3-win_amd64.whl", hash = "sha256:908b71bf3ff37d81073356a5fadcc660eb10c1476ee6e2725588626ce7e5ca38"}, + {file = "tornado-6.4.2.tar.gz", hash = "sha256:92bad5b4746e9879fd7bf1eb21dce4e3fc5128d71601f80005afa39237ad620b"}, ] [[package]] name = "tqdm" -version = "4.66.4" +version = "4.67.1" description = "Fast, Extensible Progress Meter" optional = false python-versions = ">=3.7" files = [ - {file = "tqdm-4.66.4-py3-none-any.whl", hash = "sha256:b75ca56b413b030bc3f00af51fd2c1a1a5eac6a0c1cca83cbb37a5c52abce644"}, - {file = "tqdm-4.66.4.tar.gz", hash = "sha256:e4d936c9de8727928f3be6079590e97d9abfe8d39a590be678eb5919ffc186bb"}, + {file = "tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2"}, + {file = "tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2"}, ] [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} [package.extras] -dev = ["pytest (>=6)", "pytest-cov", "pytest-timeout", "pytest-xdist"] +dev = ["nbval", "pytest (>=6)", "pytest-asyncio (>=0.24)", "pytest-cov", "pytest-timeout"] +discord = ["requests"] notebook = ["ipywidgets (>=6)"] slack = ["slack-sdk"] telegram = ["requests"] @@ -4365,24 +4499,24 @@ files = [ [[package]] name = "types-docutils" -version = "0.21.0.20240423" +version = "0.21.0.20241128" description = "Typing stubs for docutils" optional = false python-versions = ">=3.8" files = [ - {file = "types-docutils-0.21.0.20240423.tar.gz", hash = "sha256:7716ec6c68b5179b7ba1738cace2f1326e64df9f44b7ab08d9904d32c23fc15f"}, - {file = "types_docutils-0.21.0.20240423-py3-none-any.whl", hash = "sha256:7f6e84ba8fcd2454c5b8bb8d77384d091a901929cc2b31079316e10eb346580a"}, + {file = "types_docutils-0.21.0.20241128-py3-none-any.whl", hash = "sha256:e0409204009639e9b0bf4521eeabe58b5e574ce9c0db08421c2ac26c32be0039"}, + {file = "types_docutils-0.21.0.20241128.tar.gz", hash = "sha256:4dd059805b83ac6ec5a223699195c4e9eeb0446a4f7f2aeff1759a4a7cc17473"}, ] [[package]] name = "types-pillow" -version = "10.2.0.20240520" +version = "10.2.0.20240822" description = "Typing stubs for Pillow" optional = false python-versions = ">=3.8" files = [ - {file = "types-Pillow-10.2.0.20240520.tar.gz", hash = "sha256:130b979195465fa1e1676d8e81c9c7c30319e8e95b12fae945e8f0d525213107"}, - {file = "types_Pillow-10.2.0.20240520-py3-none-any.whl", hash = "sha256:33c36494b380e2a269bb742181bea5d9b00820367822dbd3760f07210a1da23d"}, + {file = "types-Pillow-10.2.0.20240822.tar.gz", hash = "sha256:559fb52a2ef991c326e4a0d20accb3bb63a7ba8d40eb493e0ecb0310ba52f0d3"}, + {file = "types_Pillow-10.2.0.20240822-py3-none-any.whl", hash = "sha256:d9dab025aba07aeb12fd50a6799d4eac52a9603488eca09d7662543983f16c5d"}, ] [[package]] @@ -4402,35 +4536,35 @@ types-setuptools = "*" [[package]] name = "types-python-dateutil" -version = "2.9.0.20240316" +version = "2.9.0.20241003" description = "Typing stubs for python-dateutil" optional = true python-versions = ">=3.8" files = [ - {file = "types-python-dateutil-2.9.0.20240316.tar.gz", hash = "sha256:5d2f2e240b86905e40944dd787db6da9263f0deabef1076ddaed797351ec0202"}, - {file = "types_python_dateutil-2.9.0.20240316-py3-none-any.whl", hash = "sha256:6b8cb66d960771ce5ff974e9dd45e38facb81718cc1e208b10b1baccbfdbee3b"}, + {file = "types-python-dateutil-2.9.0.20241003.tar.gz", hash = "sha256:58cb85449b2a56d6684e41aeefb4c4280631246a0da1a719bdbe6f3fb0317446"}, + {file = "types_python_dateutil-2.9.0.20241003-py3-none-any.whl", hash = "sha256:250e1d8e80e7bbc3a6c99b907762711d1a1cdd00e978ad39cb5940f6f0a87f3d"}, ] [[package]] name = "types-setuptools" -version = "69.5.0.20240519" +version = "75.6.0.20241126" description = "Typing stubs for setuptools" optional = false python-versions = ">=3.8" files = [ - {file = "types-setuptools-69.5.0.20240519.tar.gz", hash = "sha256:275fb72048b0203d3fbef268298ea78a0913cd114a74872d93f8638ccc5b7c63"}, - {file = "types_setuptools-69.5.0.20240519-py3-none-any.whl", hash = "sha256:52b264eff8913b5d85848d83bd98efea935fc6129d681d370eb957783880b720"}, + {file = "types_setuptools-75.6.0.20241126-py3-none-any.whl", hash = "sha256:aaae310a0e27033c1da8457d4d26ac673b0c8a0de7272d6d4708e263f2ea3b9b"}, + {file = "types_setuptools-75.6.0.20241126.tar.gz", hash = "sha256:7bf25ad4be39740e469f9268b6beddda6e088891fa5a27e985c6ce68bf62ace0"}, ] [[package]] name = "typing-extensions" -version = "4.11.0" +version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.11.0-py3-none-any.whl", hash = "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a"}, - {file = "typing_extensions-4.11.0.tar.gz", hash = "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0"}, + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] [[package]] @@ -4449,13 +4583,13 @@ dev = ["flake8", "flake8-annotations", "flake8-bandit", "flake8-bugbear", "flake [[package]] name = "urllib3" -version = "2.2.2" +version = "2.2.3" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.8" files = [ - {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, - {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, + {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, + {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, ] [package.extras] @@ -4466,13 +4600,13 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "virtualenv" -version = "20.26.2" +version = "20.28.0" description = "Virtual Python Environment builder" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "virtualenv-20.26.2-py3-none-any.whl", hash = "sha256:a624db5e94f01ad993d476b9ee5346fdf7b9de43ccaee0e0197012dc838a0e9b"}, - {file = "virtualenv-20.26.2.tar.gz", hash = "sha256:82bf0f4eebbb78d36ddaee0283d43fe5736b53880b8a8cdcd37390a07ac3741c"}, + {file = "virtualenv-20.28.0-py3-none-any.whl", hash = "sha256:23eae1b4516ecd610481eda647f3a7c09aea295055337331bb4e6892ecce47b0"}, + {file = "virtualenv-20.28.0.tar.gz", hash = "sha256:2c9c3262bb8e7b87ea801d715fae4495e6032450c71d2309be9550e7364049aa"}, ] [package.dependencies] @@ -4486,40 +4620,41 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess [[package]] name = "watchdog" -version = "4.0.0" +version = "6.0.0" description = "Filesystem events monitoring" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "watchdog-4.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:39cb34b1f1afbf23e9562501673e7146777efe95da24fab5707b88f7fb11649b"}, - {file = "watchdog-4.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c522392acc5e962bcac3b22b9592493ffd06d1fc5d755954e6be9f4990de932b"}, - {file = "watchdog-4.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6c47bdd680009b11c9ac382163e05ca43baf4127954c5f6d0250e7d772d2b80c"}, - {file = "watchdog-4.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8350d4055505412a426b6ad8c521bc7d367d1637a762c70fdd93a3a0d595990b"}, - {file = "watchdog-4.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c17d98799f32e3f55f181f19dd2021d762eb38fdd381b4a748b9f5a36738e935"}, - {file = "watchdog-4.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4986db5e8880b0e6b7cd52ba36255d4793bf5cdc95bd6264806c233173b1ec0b"}, - {file = "watchdog-4.0.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:11e12fafb13372e18ca1bbf12d50f593e7280646687463dd47730fd4f4d5d257"}, - {file = "watchdog-4.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5369136a6474678e02426bd984466343924d1df8e2fd94a9b443cb7e3aa20d19"}, - {file = "watchdog-4.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76ad8484379695f3fe46228962017a7e1337e9acadafed67eb20aabb175df98b"}, - {file = "watchdog-4.0.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:45cc09cc4c3b43fb10b59ef4d07318d9a3ecdbff03abd2e36e77b6dd9f9a5c85"}, - {file = "watchdog-4.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:eed82cdf79cd7f0232e2fdc1ad05b06a5e102a43e331f7d041e5f0e0a34a51c4"}, - {file = "watchdog-4.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ba30a896166f0fee83183cec913298151b73164160d965af2e93a20bbd2ab605"}, - {file = "watchdog-4.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d18d7f18a47de6863cd480734613502904611730f8def45fc52a5d97503e5101"}, - {file = "watchdog-4.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2895bf0518361a9728773083908801a376743bcc37dfa252b801af8fd281b1ca"}, - {file = "watchdog-4.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:87e9df830022488e235dd601478c15ad73a0389628588ba0b028cb74eb72fed8"}, - {file = "watchdog-4.0.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6e949a8a94186bced05b6508faa61b7adacc911115664ccb1923b9ad1f1ccf7b"}, - {file = "watchdog-4.0.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6a4db54edea37d1058b08947c789a2354ee02972ed5d1e0dca9b0b820f4c7f92"}, - {file = "watchdog-4.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d31481ccf4694a8416b681544c23bd271f5a123162ab603c7d7d2dd7dd901a07"}, - {file = "watchdog-4.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8fec441f5adcf81dd240a5fe78e3d83767999771630b5ddfc5867827a34fa3d3"}, - {file = "watchdog-4.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:6a9c71a0b02985b4b0b6d14b875a6c86ddea2fdbebd0c9a720a806a8bbffc69f"}, - {file = "watchdog-4.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:557ba04c816d23ce98a06e70af6abaa0485f6d94994ec78a42b05d1c03dcbd50"}, - {file = "watchdog-4.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:d0f9bd1fd919134d459d8abf954f63886745f4660ef66480b9d753a7c9d40927"}, - {file = "watchdog-4.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:f9b2fdca47dc855516b2d66eef3c39f2672cbf7e7a42e7e67ad2cbfcd6ba107d"}, - {file = "watchdog-4.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:73c7a935e62033bd5e8f0da33a4dcb763da2361921a69a5a95aaf6c93aa03a87"}, - {file = "watchdog-4.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:6a80d5cae8c265842c7419c560b9961561556c4361b297b4c431903f8c33b269"}, - {file = "watchdog-4.0.0-py3-none-win32.whl", hash = "sha256:8f9a542c979df62098ae9c58b19e03ad3df1c9d8c6895d96c0d51da17b243b1c"}, - {file = "watchdog-4.0.0-py3-none-win_amd64.whl", hash = "sha256:f970663fa4f7e80401a7b0cbeec00fa801bf0287d93d48368fc3e6fa32716245"}, - {file = "watchdog-4.0.0-py3-none-win_ia64.whl", hash = "sha256:9a03e16e55465177d416699331b0f3564138f1807ecc5f2de9d55d8f188d08c7"}, - {file = "watchdog-4.0.0.tar.gz", hash = "sha256:e3e7065cbdabe6183ab82199d7a4f6b3ba0a438c5a512a68559846ccb76a78ec"}, + {file = "watchdog-6.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1cdb490583ebd691c012b3d6dae011000fe42edb7a82ece80965b42abd61f26"}, + {file = "watchdog-6.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc64ab3bdb6a04d69d4023b29422170b74681784ffb9463ed4870cf2f3e66112"}, + {file = "watchdog-6.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c897ac1b55c5a1461e16dae288d22bb2e412ba9807df8397a635d88f671d36c3"}, + {file = "watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c"}, + {file = "watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2"}, + {file = "watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c"}, + {file = "watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948"}, + {file = "watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860"}, + {file = "watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0"}, + {file = "watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c"}, + {file = "watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134"}, + {file = "watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b"}, + {file = "watchdog-6.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e6f0e77c9417e7cd62af82529b10563db3423625c5fce018430b249bf977f9e8"}, + {file = "watchdog-6.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:90c8e78f3b94014f7aaae121e6b909674df5b46ec24d6bebc45c44c56729af2a"}, + {file = "watchdog-6.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e7631a77ffb1f7d2eefa4445ebbee491c720a5661ddf6df3498ebecae5ed375c"}, + {file = "watchdog-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881"}, + {file = "watchdog-6.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11"}, + {file = "watchdog-6.0.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7a0e56874cfbc4b9b05c60c8a1926fedf56324bb08cfbc188969777940aef3aa"}, + {file = "watchdog-6.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e6439e374fc012255b4ec786ae3c4bc838cd7309a540e5fe0952d03687d8804e"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2"}, + {file = "watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a"}, + {file = "watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680"}, + {file = "watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f"}, + {file = "watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282"}, ] [package.extras] @@ -4538,19 +4673,15 @@ files = [ [[package]] name = "webcolors" -version = "1.13" +version = "24.11.1" description = "A library for working with the color formats defined by HTML and CSS." optional = true -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "webcolors-1.13-py3-none-any.whl", hash = "sha256:29bc7e8752c0a1bd4a1f03c14d6e6a72e93d82193738fa860cbff59d0fcc11bf"}, - {file = "webcolors-1.13.tar.gz", hash = "sha256:c225b674c83fa923be93d235330ce0300373d02885cef23238813b0d5668304a"}, + {file = "webcolors-24.11.1-py3-none-any.whl", hash = "sha256:515291393b4cdf0eb19c155749a096f779f7d909f7cceea072791cb9095b92e9"}, + {file = "webcolors-24.11.1.tar.gz", hash = "sha256:ecb3d768f32202af770477b8b65f318fa4f566c22948673a977b00d589dd80f6"}, ] -[package.extras] -docs = ["furo", "sphinx", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-notfound-page", "sphinxext-opengraph"] -tests = ["pytest", "pytest-cov"] - [[package]] name = "webencodings" version = "0.5.1" @@ -4580,97 +4711,96 @@ test = ["websockets"] [[package]] name = "wrapt" -version = "1.16.0" +version = "1.17.0" description = "Module for decorators, wrappers and monkey patching." optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "wrapt-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4"}, - {file = "wrapt-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020"}, - {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440"}, - {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487"}, - {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf"}, - {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72"}, - {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0"}, - {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136"}, - {file = "wrapt-1.16.0-cp310-cp310-win32.whl", hash = "sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d"}, - {file = "wrapt-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2"}, - {file = "wrapt-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09"}, - {file = "wrapt-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d"}, - {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389"}, - {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060"}, - {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1"}, - {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3"}, - {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956"}, - {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d"}, - {file = "wrapt-1.16.0-cp311-cp311-win32.whl", hash = "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362"}, - {file = "wrapt-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89"}, - {file = "wrapt-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b"}, - {file = "wrapt-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36"}, - {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73"}, - {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809"}, - {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b"}, - {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81"}, - {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9"}, - {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c"}, - {file = "wrapt-1.16.0-cp312-cp312-win32.whl", hash = "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc"}, - {file = "wrapt-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8"}, - {file = "wrapt-1.16.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8"}, - {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39"}, - {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c"}, - {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40"}, - {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc"}, - {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e"}, - {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465"}, - {file = "wrapt-1.16.0-cp36-cp36m-win32.whl", hash = "sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e"}, - {file = "wrapt-1.16.0-cp36-cp36m-win_amd64.whl", hash = "sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966"}, - {file = "wrapt-1.16.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593"}, - {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292"}, - {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5"}, - {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf"}, - {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228"}, - {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f"}, - {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c"}, - {file = "wrapt-1.16.0-cp37-cp37m-win32.whl", hash = "sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c"}, - {file = "wrapt-1.16.0-cp37-cp37m-win_amd64.whl", hash = "sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00"}, - {file = "wrapt-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0"}, - {file = "wrapt-1.16.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202"}, - {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0"}, - {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e"}, - {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f"}, - {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267"}, - {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca"}, - {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6"}, - {file = "wrapt-1.16.0-cp38-cp38-win32.whl", hash = "sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b"}, - {file = "wrapt-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41"}, - {file = "wrapt-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2"}, - {file = "wrapt-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb"}, - {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8"}, - {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c"}, - {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a"}, - {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664"}, - {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f"}, - {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537"}, - {file = "wrapt-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3"}, - {file = "wrapt-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35"}, - {file = "wrapt-1.16.0-py3-none-any.whl", hash = "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1"}, - {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"}, + {file = "wrapt-1.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2a0c23b8319848426f305f9cb0c98a6e32ee68a36264f45948ccf8e7d2b941f8"}, + {file = "wrapt-1.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1ca5f060e205f72bec57faae5bd817a1560fcfc4af03f414b08fa29106b7e2d"}, + {file = "wrapt-1.17.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e185ec6060e301a7e5f8461c86fb3640a7beb1a0f0208ffde7a65ec4074931df"}, + {file = "wrapt-1.17.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb90765dd91aed05b53cd7a87bd7f5c188fcd95960914bae0d32c5e7f899719d"}, + {file = "wrapt-1.17.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:879591c2b5ab0a7184258274c42a126b74a2c3d5a329df16d69f9cee07bba6ea"}, + {file = "wrapt-1.17.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fce6fee67c318fdfb7f285c29a82d84782ae2579c0e1b385b7f36c6e8074fffb"}, + {file = "wrapt-1.17.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0698d3a86f68abc894d537887b9bbf84d29bcfbc759e23f4644be27acf6da301"}, + {file = "wrapt-1.17.0-cp310-cp310-win32.whl", hash = "sha256:69d093792dc34a9c4c8a70e4973a3361c7a7578e9cd86961b2bbf38ca71e4e22"}, + {file = "wrapt-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:f28b29dc158ca5d6ac396c8e0a2ef45c4e97bb7e65522bfc04c989e6fe814575"}, + {file = "wrapt-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:74bf625b1b4caaa7bad51d9003f8b07a468a704e0644a700e936c357c17dd45a"}, + {file = "wrapt-1.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f2a28eb35cf99d5f5bd12f5dd44a0f41d206db226535b37b0c60e9da162c3ed"}, + {file = "wrapt-1.17.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:81b1289e99cf4bad07c23393ab447e5e96db0ab50974a280f7954b071d41b489"}, + {file = "wrapt-1.17.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f2939cd4a2a52ca32bc0b359015718472d7f6de870760342e7ba295be9ebaf9"}, + {file = "wrapt-1.17.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6a9653131bda68a1f029c52157fd81e11f07d485df55410401f745007bd6d339"}, + {file = "wrapt-1.17.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4e4b4385363de9052dac1a67bfb535c376f3d19c238b5f36bddc95efae15e12d"}, + {file = "wrapt-1.17.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bdf62d25234290db1837875d4dceb2151e4ea7f9fff2ed41c0fde23ed542eb5b"}, + {file = "wrapt-1.17.0-cp311-cp311-win32.whl", hash = "sha256:5d8fd17635b262448ab8f99230fe4dac991af1dabdbb92f7a70a6afac8a7e346"}, + {file = "wrapt-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:92a3d214d5e53cb1db8b015f30d544bc9d3f7179a05feb8f16df713cecc2620a"}, + {file = "wrapt-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:89fc28495896097622c3fc238915c79365dd0ede02f9a82ce436b13bd0ab7569"}, + {file = "wrapt-1.17.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:875d240fdbdbe9e11f9831901fb8719da0bd4e6131f83aa9f69b96d18fae7504"}, + {file = "wrapt-1.17.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5ed16d95fd142e9c72b6c10b06514ad30e846a0d0917ab406186541fe68b451"}, + {file = "wrapt-1.17.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18b956061b8db634120b58f668592a772e87e2e78bc1f6a906cfcaa0cc7991c1"}, + {file = "wrapt-1.17.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:daba396199399ccabafbfc509037ac635a6bc18510ad1add8fd16d4739cdd106"}, + {file = "wrapt-1.17.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4d63f4d446e10ad19ed01188d6c1e1bb134cde8c18b0aa2acfd973d41fcc5ada"}, + {file = "wrapt-1.17.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8a5e7cc39a45fc430af1aefc4d77ee6bad72c5bcdb1322cfde852c15192b8bd4"}, + {file = "wrapt-1.17.0-cp312-cp312-win32.whl", hash = "sha256:0a0a1a1ec28b641f2a3a2c35cbe86c00051c04fffcfcc577ffcdd707df3f8635"}, + {file = "wrapt-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:3c34f6896a01b84bab196f7119770fd8466c8ae3dfa73c59c0bb281e7b588ce7"}, + {file = "wrapt-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:714c12485aa52efbc0fc0ade1e9ab3a70343db82627f90f2ecbc898fdf0bb181"}, + {file = "wrapt-1.17.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da427d311782324a376cacb47c1a4adc43f99fd9d996ffc1b3e8529c4074d393"}, + {file = "wrapt-1.17.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba1739fb38441a27a676f4de4123d3e858e494fac05868b7a281c0a383c098f4"}, + {file = "wrapt-1.17.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e711fc1acc7468463bc084d1b68561e40d1eaa135d8c509a65dd534403d83d7b"}, + {file = "wrapt-1.17.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:140ea00c87fafc42739bd74a94a5a9003f8e72c27c47cd4f61d8e05e6dec8721"}, + {file = "wrapt-1.17.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:73a96fd11d2b2e77d623a7f26e004cc31f131a365add1ce1ce9a19e55a1eef90"}, + {file = "wrapt-1.17.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0b48554952f0f387984da81ccfa73b62e52817a4386d070c75e4db7d43a28c4a"}, + {file = "wrapt-1.17.0-cp313-cp313-win32.whl", hash = "sha256:498fec8da10e3e62edd1e7368f4b24aa362ac0ad931e678332d1b209aec93045"}, + {file = "wrapt-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:fd136bb85f4568fffca995bd3c8d52080b1e5b225dbf1c2b17b66b4c5fa02838"}, + {file = "wrapt-1.17.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:17fcf043d0b4724858f25b8826c36e08f9fb2e475410bece0ec44a22d533da9b"}, + {file = "wrapt-1.17.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4a557d97f12813dc5e18dad9fa765ae44ddd56a672bb5de4825527c847d6379"}, + {file = "wrapt-1.17.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0229b247b0fc7dee0d36176cbb79dbaf2a9eb7ecc50ec3121f40ef443155fb1d"}, + {file = "wrapt-1.17.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8425cfce27b8b20c9b89d77fb50e368d8306a90bf2b6eef2cdf5cd5083adf83f"}, + {file = "wrapt-1.17.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9c900108df470060174108012de06d45f514aa4ec21a191e7ab42988ff42a86c"}, + {file = "wrapt-1.17.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:4e547b447073fc0dbfcbff15154c1be8823d10dab4ad401bdb1575e3fdedff1b"}, + {file = "wrapt-1.17.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:914f66f3b6fc7b915d46c1cc424bc2441841083de01b90f9e81109c9759e43ab"}, + {file = "wrapt-1.17.0-cp313-cp313t-win32.whl", hash = "sha256:a4192b45dff127c7d69b3bdfb4d3e47b64179a0b9900b6351859f3001397dabf"}, + {file = "wrapt-1.17.0-cp313-cp313t-win_amd64.whl", hash = "sha256:4f643df3d4419ea3f856c5c3f40fec1d65ea2e89ec812c83f7767c8730f9827a"}, + {file = "wrapt-1.17.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:69c40d4655e078ede067a7095544bcec5a963566e17503e75a3a3e0fe2803b13"}, + {file = "wrapt-1.17.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f495b6754358979379f84534f8dd7a43ff8cff2558dcdea4a148a6e713a758f"}, + {file = "wrapt-1.17.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:baa7ef4e0886a6f482e00d1d5bcd37c201b383f1d314643dfb0367169f94f04c"}, + {file = "wrapt-1.17.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8fc931382e56627ec4acb01e09ce66e5c03c384ca52606111cee50d931a342d"}, + {file = "wrapt-1.17.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:8f8909cdb9f1b237786c09a810e24ee5e15ef17019f7cecb207ce205b9b5fcce"}, + {file = "wrapt-1.17.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ad47b095f0bdc5585bced35bd088cbfe4177236c7df9984b3cc46b391cc60627"}, + {file = "wrapt-1.17.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:948a9bd0fb2c5120457b07e59c8d7210cbc8703243225dbd78f4dfc13c8d2d1f"}, + {file = "wrapt-1.17.0-cp38-cp38-win32.whl", hash = "sha256:5ae271862b2142f4bc687bdbfcc942e2473a89999a54231aa1c2c676e28f29ea"}, + {file = "wrapt-1.17.0-cp38-cp38-win_amd64.whl", hash = "sha256:f335579a1b485c834849e9075191c9898e0731af45705c2ebf70e0cd5d58beed"}, + {file = "wrapt-1.17.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d751300b94e35b6016d4b1e7d0e7bbc3b5e1751e2405ef908316c2a9024008a1"}, + {file = "wrapt-1.17.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7264cbb4a18dc4acfd73b63e4bcfec9c9802614572025bdd44d0721983fc1d9c"}, + {file = "wrapt-1.17.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33539c6f5b96cf0b1105a0ff4cf5db9332e773bb521cc804a90e58dc49b10578"}, + {file = "wrapt-1.17.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c30970bdee1cad6a8da2044febd824ef6dc4cc0b19e39af3085c763fdec7de33"}, + {file = "wrapt-1.17.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:bc7f729a72b16ee21795a943f85c6244971724819819a41ddbaeb691b2dd85ad"}, + {file = "wrapt-1.17.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:6ff02a91c4fc9b6a94e1c9c20f62ea06a7e375f42fe57587f004d1078ac86ca9"}, + {file = "wrapt-1.17.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2dfb7cff84e72e7bf975b06b4989477873dcf160b2fd89959c629535df53d4e0"}, + {file = "wrapt-1.17.0-cp39-cp39-win32.whl", hash = "sha256:2399408ac33ffd5b200480ee858baa58d77dd30e0dd0cab6a8a9547135f30a88"}, + {file = "wrapt-1.17.0-cp39-cp39-win_amd64.whl", hash = "sha256:4f763a29ee6a20c529496a20a7bcb16a73de27f5da6a843249c7047daf135977"}, + {file = "wrapt-1.17.0-py3-none-any.whl", hash = "sha256:d2c63b93548eda58abf5188e505ffed0229bf675f7c3090f8e36ad55b8cbc371"}, + {file = "wrapt-1.17.0.tar.gz", hash = "sha256:16187aa2317c731170a88ef35e8937ae0f533c402872c1ee5e6d079fcf320801"}, ] [[package]] name = "zipp" -version = "3.18.2" +version = "3.21.0" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "zipp-3.18.2-py3-none-any.whl", hash = "sha256:dce197b859eb796242b0622af1b8beb0a722d52aa2f57133ead08edd5bf5374e"}, - {file = "zipp-3.18.2.tar.gz", hash = "sha256:6278d9ddbcfb1f1089a88fde84481528b07b0e10474e09dcfe53dad4069fa059"}, + {file = "zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"}, + {file = "zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] +type = ["pytest-mypy"] [extras] gui = ["dearpygui"] @@ -4678,5 +4808,5 @@ jupyterlab = ["jupyterlab", "notebook"] [metadata] lock-version = "2.0" -python-versions = ">=3.9,<3.13" -content-hash = "482eafcb61a2e3c6f64af915960bb4ae1298620c2be1bd5201fa47907e2eec94" +python-versions = ">=3.9" +content-hash = "06dc9ff9e7fe83005f978bd3e555c37073b542161a645ee1c83990d8f1445119" diff --git a/pyproject.toml b/pyproject.toml index c38f80daef..ffe54554a3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,11 +14,11 @@ classifiers= [ "Topic :: Scientific/Engineering", "Topic :: Multimedia :: Video", "Topic :: Multimedia :: Graphics", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Natural Language :: English", ] exclude = ["scripts/","logo/","readme-assets/"] @@ -27,8 +27,8 @@ packages = [ ] [tool.poetry.dependencies] -python = ">=3.9,<3.13" -av = ">=9.0.0" +python = ">=3.9" +av = ">=9.0.0,<14.0.0" # v14.0.0 contains breaking changes, remove after dropping python 3.9 click = ">=8.0" cloup = ">=2.0.0" dearpygui = { version = ">=1.0.0", optional = true } @@ -42,13 +42,25 @@ moderngl = ">=5.0.0,<6.0.0" moderngl-window = ">=2.0.0" networkx = ">=2.6" notebook = { version = ">=6.0.0", optional = true } -numpy = ">=1.26" +numpy = [ + # numpy 2.1 is the first version with prebuilt wheels for 3.13, + # while numpy 2.0 is the last version supporting 3.9 + # TODO: remove when python 3.10 is the minimum supported version + {version = ">=2.1", python = ">=3.10"}, + {version = ">=2.0", python = "<3.10"}, +] Pillow = ">=9.1" pycairo = ">=1.13,<2.0.0" pydub = ">=0.20.0" +audioop-lts = { version = ">=0.2.0", python = ">=3.13" } # for pydub Pygments = ">=2.0.0" rich = ">=12.0.0" -scipy = ">=1.6.0" +scipy = [ + # scipy 1.14.0 is the first version with prebuilt wheels for 3.13 + # TODO: remove when python 3.10 is the minimum supported version + {version = ">=1.13.0", python = "<3.13"}, + {version = ">=1.14.0", python = ">=3.13"}, +] screeninfo = ">=0.7" skia-pathops = ">=0.7.0" srt = ">=3.0.0" @@ -62,15 +74,6 @@ jupyterlab = ["jupyterlab", "notebook"] gui = ["dearpygui"] [tool.poetry.group.dev.dependencies] -black = ">=23.11,<25.0" -flake8 = "^6.1.0" -flake8-bugbear = "^23.11.28" -flake8-builtins = "^2.2.0" -flake8-comprehensions = "^3.7.0" -flake8-docstrings = "^1.7.0" -flake8-pytest-style = "^1.7.2" -flake8-simplify = "^0.14.1" -flake8-rst-docstrings = "^0.3.0" furo = "^2023.09.10" gitpython = "^3" isort = "^5.12.0" @@ -79,7 +82,7 @@ myst-parser = "^2.0.0" pre-commit = "^3.5.0" psutil = {version = "^5.8.0", python = "<3.10"} psutil-wheels = {version = "5.8.0", python = ">=3.10"} -pytest = "^7.4.3" +pytest = "^8.3" pygithub = "^2.1.1" pytest-cov = "^4.1.0" pytest-xdist = "^2.2" # Using latest gives flaky tests @@ -91,6 +94,8 @@ sphinxext-opengraph = "^0.9.1" types-decorator = "^0.1.7" types-Pillow = "^10.1.0.2" types-Pygments = "^2.17.0.0" +sphinx-design = "^0.6.1" +sphinx-reredirects = "^0.1.5" [tool.poetry.urls] "Bug Tracker" = "https://github.com/ManimCommunity/manim/issues" @@ -136,17 +141,41 @@ fix = true [tool.ruff.lint] select = [ + "A", + "B", + "C4", + "D", "E", "F", "I", + "PGH", + "PT", + "SIM", "UP", ] ignore = [ + # mutable argument defaults (too many changes) + "B006", + # No function calls in defaults + # ignored because np.array() and straight_path() + "B008", + # docstring ignores - mostly stylistic + "D1", + "D203", + "D205", + "D212", + "D4", # due to the import * used in manim "F403", "F405", + # fixtures not returning anything should have leading underscore + "PT004", + # Exception too broad (this would require lots of changes + re.escape) for little benefit + "PT011", # as recommended by https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules + "D206", + "D300", "E111", "E114", "E117", @@ -158,6 +187,10 @@ dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" [tool.ruff.lint.per-file-ignores] "tests/*" = [ + # flake8-builtins + "A", + # unused expression + "B018", # unused variable "F841", # from __future__ import annotations @@ -176,9 +209,12 @@ dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" [tool.ruff.lint.isort] required-imports = ["from __future__ import annotations"] +[tool.ruff.lint.flake8-pytest-style] +fixture-parentheses = false +mark-parentheses = false + +[tool.ruff.lint.pydocstyle] +convention = "numpy" + [tool.ruff.format] docstring-code-format = true - -[tool.codespell] -write-changes = true -ignore-words-list = ["medias", "nam"] diff --git a/scripts/dev_changelog.py b/scripts/dev_changelog.py index 35e77dd798..af1fb6fc38 100755 --- a/scripts/dev_changelog.py +++ b/scripts/dev_changelog.py @@ -110,7 +110,7 @@ def process_pullrequests(lst, cur, github_repo, pr_nums): authors.add(pr.user) reviewers = reviewers.union(rev.user for rev in pr.get_reviews()) pr_labels = [label.name for label in pr.labels] - for label in PR_LABELS.keys(): + for label in PR_LABELS: if label in pr_labels: pr_by_labels[label].append(pr) break # ensure that PR is only added in one category @@ -217,7 +217,6 @@ def main(token, prior, tag, additional, outfile): ADDITIONAL includes additional PR(s) that have not been recognized automatically. """ - lst_release, cur_release = prior, tag github = Github(token) @@ -291,7 +290,7 @@ def main(token, prior, tag, additional, outfile): ) pr_by_labels = contributions["PRs"] - for label in PR_LABELS.keys(): + for label in PR_LABELS: pr_of_label = pr_by_labels[label] if pr_of_label: diff --git a/scripts/make_and_open_docs.py b/scripts/make_and_open_docs.py index 11b9360edc..c6179384ba 100644 --- a/scripts/make_and_open_docs.py +++ b/scripts/make_and_open_docs.py @@ -1,12 +1,12 @@ from __future__ import annotations -import os +import subprocess import sys import webbrowser from pathlib import Path -path_makefile = Path(__file__).parents[1] / "docs" -os.system(f"cd {path_makefile} && make html") +path_makefile = Path(__file__).resolve().parents[1] / "docs" +subprocess.run(["make", "html"], cwd=path_makefile) website = (path_makefile / "build" / "html" / "index.html").absolute().as_uri() try: # Allows you to pass a custom browser if you want. diff --git a/tests/conftest.py b/tests/conftest.py index 5b9edb656a..4de34bbbc1 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,11 +1,32 @@ from __future__ import annotations +import logging import sys from pathlib import Path +import cairo +import moderngl import pytest -from manim import config, tempconfig +import manim + + +def pytest_report_header(config): + try: + ctx = moderngl.create_standalone_context() + info = ctx.info + ctx.release() + except Exception as e: + raise Exception("Error while creating moderngl context") from e + + return ( + f"\nCairo Version: {cairo.cairo_version()}", + "\nOpenGL information", + "------------------", + f"vendor: {info['GL_VENDOR'].strip()}", + f"renderer: {info['GL_RENDERER'].strip()}", + f"version: {info['GL_VERSION'].strip()}\n", + ) def pytest_addoption(parser): @@ -45,6 +66,41 @@ def pytest_collection_modifyitems(config, items): item.add_marker(slow_skip) +@pytest.fixture(autouse=True) +def temp_media_dir(tmpdir, monkeypatch, request): + if isinstance(request.node, pytest.DoctestItem): + monkeypatch.chdir(tmpdir) + yield tmpdir + else: + with manim.tempconfig({"media_dir": str(tmpdir)}): + assert manim.config.media_dir == str(tmpdir) + yield tmpdir + + +@pytest.fixture +def manim_caplog(caplog): + logger = logging.getLogger("manim") + logger.propagate = True + caplog.set_level(logging.INFO, logger="manim") + yield caplog + logger.propagate = False + + +@pytest.fixture +def config(): + saved = manim.config.copy() + manim.config.renderer = "cairo" + # we need to return the actual config so that tests + # using tempconfig pass + yield manim.config + manim.config.update(saved) + + +@pytest.fixture +def dry_run(config): + config.dry_run = True + + @pytest.fixture(scope="session") def python_version(): # use the same python executable as it is running currently @@ -62,10 +118,10 @@ def reset_cfg_file(): @pytest.fixture -def using_opengl_renderer(): +def using_opengl_renderer(config): """Standard fixture for running with opengl that makes tests use a standard_config.cfg with a temp dir.""" - with tempconfig({"renderer": "opengl"}): - yield + config.renderer = "opengl" + yield # as a special case needed to manually revert back to cairo # due to side effects of setting the renderer config.renderer = "cairo" diff --git a/tests/helpers/graphical_units.py b/tests/helpers/graphical_units.py index 75fb00343a..1395559e52 100644 --- a/tests/helpers/graphical_units.py +++ b/tests/helpers/graphical_units.py @@ -2,16 +2,18 @@ from __future__ import annotations +import logging import tempfile from pathlib import Path import numpy as np -from manim import config, logger from manim.scene.scene import Scene +logger = logging.getLogger("manim") -def set_test_scene(scene_object: type[Scene], module_name: str): + +def set_test_scene(scene_object: type[Scene], module_name: str, config): """Function used to set up the test data for a new feature. This will basically set up a pre-rendered frame for a scene. This is meant to be used only when setting up tests. Please refer to the wiki. @@ -46,7 +48,7 @@ def set_test_scene(scene_object: type[Scene], module_name: str): assert not np.all( data == np.array([0, 0, 0, 255]), - ), f"Control data generated for {str(scene)} only contains empty pixels." + ), f"Control data generated for {scene!s} only contains empty pixels." assert data.shape == (480, 854, 4) tests_directory = Path(__file__).absolute().parent.parent path_control_data = Path(tests_directory) / "control_data" / "graphical_units_data" diff --git a/tests/module/animation/test_animate.py b/tests/module/animation/test_animate.py index 4f39d85481..91d3b19dfd 100644 --- a/tests/module/animation/test_animate.py +++ b/tests/module/animation/test_animate.py @@ -23,10 +23,8 @@ def test_chained_animate(): scale_factor = 2 direction = np.array((1, 1, 0)) anim = s.animate.scale(scale_factor).shift(direction).build() - assert ( - anim.mobject.target.width == scale_factor * s.width - and (anim.mobject.target.get_center() == direction).all() - ) + assert anim.mobject.target.width == scale_factor * s.width + assert (anim.mobject.target.get_center() == direction).all() def test_overridden_animate(): @@ -103,10 +101,8 @@ def test_chained_animate_with_args(): run_time = 2 anim = s.animate(run_time=run_time).scale(scale_factor).shift(direction).build() - assert ( - anim.mobject.target.width == scale_factor * s.width - and (anim.mobject.target.get_center() == direction).all() - ) + assert anim.mobject.target.width == scale_factor * s.width + assert (anim.mobject.target.get_center() == direction).all() assert anim.run_time == run_time diff --git a/tests/module/animation/test_animation.py b/tests/module/animation/test_animation.py index 67579c4fbf..5991aab074 100644 --- a/tests/module/animation/test_animation.py +++ b/tests/module/animation/test_animation.py @@ -2,33 +2,56 @@ import pytest -from manim import FadeIn, Scene, config +from manim import FadeIn, Scene -@pytest.mark.parametrize( - "run_time", - [0, -1], -) -def test_animation_forbidden_run_time(run_time): +def test_animation_zero_total_run_time(): test_scene = Scene() - with pytest.raises(ValueError, match="Please set the run_time to be positive"): - test_scene.play(FadeIn(None, run_time=run_time)) + with pytest.raises( + ValueError, match="The total run_time must be a positive number." + ): + test_scene.play(FadeIn(None, run_time=0)) -def test_animation_run_time_shorter_than_frame_rate(caplog): +def test_single_animation_zero_run_time_with_more_animations(): + test_scene = Scene() + test_scene.play(FadeIn(None, run_time=0), FadeIn(None, run_time=1)) + + +def test_animation_negative_run_time(): + with pytest.raises(ValueError, match="The run_time of FadeIn cannot be negative."): + FadeIn(None, run_time=-1) + + +def test_animation_run_time_shorter_than_frame_rate(manim_caplog, config): test_scene = Scene() test_scene.play(FadeIn(None, run_time=1 / (config.frame_rate + 1))) - assert ( - "Original run time of FadeIn(Mobject) is shorter than current frame rate" - in caplog.text - ) + assert "too short for the current frame rate" in manim_caplog.text + + +@pytest.mark.parametrize("duration", [0, -1]) +def test_wait_invalid_duration(duration): + test_scene = Scene() + with pytest.raises(ValueError, match="The duration must be a positive number."): + test_scene.wait(duration) @pytest.mark.parametrize("frozen_frame", [False, True]) -def test_wait_run_time_shorter_than_frame_rate(caplog, frozen_frame): +def test_wait_duration_shorter_than_frame_rate(manim_caplog, frozen_frame): test_scene = Scene() test_scene.wait(1e-9, frozen_frame=frozen_frame) - assert ( - "Original run time of Wait(Mobject) is shorter than current frame rate" - in caplog.text - ) + assert "too short for the current frame rate" in manim_caplog.text + + +@pytest.mark.parametrize("duration", [0, -1]) +def test_pause_invalid_duration(duration): + test_scene = Scene() + with pytest.raises(ValueError, match="The duration must be a positive number."): + test_scene.pause(duration) + + +@pytest.mark.parametrize("max_time", [0, -1]) +def test_wait_until_invalid_max_time(max_time): + test_scene = Scene() + with pytest.raises(ValueError, match="The max_time must be a positive number."): + test_scene.wait_until(lambda: True, max_time) diff --git a/tests/module/animation/test_composition.py b/tests/module/animation/test_composition.py index 89eb22658b..53d5767aae 100644 --- a/tests/module/animation/test_composition.py +++ b/tests/module/animation/test_composition.py @@ -132,7 +132,7 @@ def test_animationgroup_with_wait(): @pytest.mark.parametrize( - "animation_remover, animation_group_remover", + ("animation_remover", "animation_group_remover"), [(False, True), (True, False)], ) def test_animationgroup_is_passing_remover_to_animations( diff --git a/tests/module/animation/test_creation.py b/tests/module/animation/test_creation.py index 3208ad1b41..d2a0b08666 100644 --- a/tests/module/animation/test_creation.py +++ b/tests/module/animation/test_creation.py @@ -3,7 +3,7 @@ import numpy as np import pytest -from manim import AddTextLetterByLetter, Text, config +from manim import AddTextLetterByLetter, Text def test_non_empty_text_creation(): @@ -25,7 +25,7 @@ def test_whitespace_text_creation(): AddTextLetterByLetter(Text(" ")) -def test_run_time_for_non_empty_text(): +def test_run_time_for_non_empty_text(config): """Ensure the run_time is calculated correctly for non-empty text.""" s = Text("Hello") run_time_per_char = 0.1 diff --git a/tests/module/mobject/geometry/test_unit_geometry.py b/tests/module/mobject/geometry/test_unit_geometry.py index 45f4da279f..4f5403a14e 100644 --- a/tests/module/mobject/geometry/test_unit_geometry.py +++ b/tests/module/mobject/geometry/test_unit_geometry.py @@ -4,7 +4,7 @@ import numpy as np -from manim import BackgroundRectangle, Circle, Sector +from manim import BackgroundRectangle, Circle, Sector, Square, SurroundingRectangle logger = logging.getLogger(__name__) @@ -15,14 +15,41 @@ def test_get_arc_center(): ) -def test_BackgroundRectangle(caplog): - caplog.set_level(logging.INFO) - c = Circle() - bg = BackgroundRectangle(c) +def test_SurroundingRectangle(): + circle = Circle() + square = Square() + sr = SurroundingRectangle(circle, square) + sr.set_style(fill_opacity=0.42) + assert sr.get_fill_opacity() == 0.42 + + +def test_BackgroundRectangle(manim_caplog): + circle = Circle() + square = Square() + bg = BackgroundRectangle(circle, square) bg.set_style(fill_opacity=0.42) assert bg.get_fill_opacity() == 0.42 bg.set_style(fill_opacity=1, hello="world") assert ( "Argument {'hello': 'world'} is ignored in BackgroundRectangle.set_style." - in caplog.text + in manim_caplog.text ) + + +def test_Square_side_length_reflets_correct_width_and_height(): + sq = Square(side_length=1).scale(3) + assert sq.side_length == 3 + assert sq.height == 3 + assert sq.width == 3 + + +def test_changing_Square_side_length_updates_the_square_appropriately(): + sq = Square(side_length=1) + sq.side_length = 3 + assert sq.height == 3 + assert sq.width == 3 + + +def test_Square_side_length_consistent_after_scale_and_rotation(): + sq = Square(side_length=1).scale(3).rotate(np.pi / 4) + assert np.isclose(sq.side_length, 3) diff --git a/tests/module/mobject/graphing/test_coordinate_system.py b/tests/module/mobject/graphing/test_coordinate_system.py index 727bb0ba68..470d9d0074 100644 --- a/tests/module/mobject/graphing/test_coordinate_system.py +++ b/tests/module/mobject/graphing/test_coordinate_system.py @@ -56,7 +56,7 @@ def test_dimension(): def test_abstract_base_class(): """Check that CoordinateSystem has some abstract methods.""" - with pytest.raises(Exception): + with pytest.raises(NotImplementedError): CS().get_axes() diff --git a/tests/module/mobject/graphing/test_number_line.py b/tests/module/mobject/graphing/test_number_line.py index 56cd7267ed..1f0f7c343c 100644 --- a/tests/module/mobject/graphing/test_number_line.py +++ b/tests/module/mobject/graphing/test_number_line.py @@ -8,7 +8,8 @@ def test_unit_vector(): """Check if the magnitude of unit vector along - the NumberLine is equal to its unit_size.""" + the NumberLine is equal to its unit_size. + """ axis1 = NumberLine(unit_size=0.4) axis2 = NumberLine(x_range=[-2, 5], length=12) for axis in (axis1, axis2): @@ -17,7 +18,8 @@ def test_unit_vector(): def test_decimal_determined_by_step(): """Checks that step size is considered when determining the number of decimal - places.""" + places. + """ axis = NumberLine(x_range=[-2, 2, 0.5]) expected_decimal_places = 1 actual_decimal_places = axis.decimal_number_config["num_decimal_places"] diff --git a/tests/module/mobject/mobject/test_copy.py b/tests/module/mobject/mobject/test_copy.py index ce9f472f7e..39c6afd94c 100644 --- a/tests/module/mobject/mobject/test_copy.py +++ b/tests/module/mobject/mobject/test_copy.py @@ -2,7 +2,7 @@ from pathlib import Path -from manim import BraceLabel, Mobject, config +from manim import BraceLabel, Mobject def test_mobject_copy(): @@ -18,7 +18,7 @@ def test_mobject_copy(): assert orig.submobjects[i] is not copy.submobjects[i] -def test_bracelabel_copy(tmp_path): +def test_bracelabel_copy(tmp_path, config): """Test that a copy is a deepcopy.""" # For this test to work, we need to tweak some folders temporarily original_text_dir = config["text_dir"] diff --git a/tests/module/mobject/mobject/test_opengl_metaclass.py b/tests/module/mobject/mobject/test_opengl_metaclass.py index bc172bfa38..930a5616da 100644 --- a/tests/module/mobject/mobject/test_opengl_metaclass.py +++ b/tests/module/mobject/mobject/test_opengl_metaclass.py @@ -1,20 +1,20 @@ from __future__ import annotations -from manim import Mobject, config, tempconfig +from manim import Mobject from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL from manim.mobject.opengl.opengl_mobject import OpenGLMobject -def test_metaclass_registry(): +def test_metaclass_registry(config): class SomeTestMobject(Mobject, metaclass=ConvertToOpenGL): pass assert SomeTestMobject in ConvertToOpenGL._converted_classes - with tempconfig({"renderer": "opengl"}): - assert OpenGLMobject in SomeTestMobject.__bases__ - assert Mobject not in SomeTestMobject.__bases__ + config.renderer = "opengl" + assert OpenGLMobject in SomeTestMobject.__bases__ + assert Mobject not in SomeTestMobject.__bases__ - config.renderer = "cairo" - assert Mobject in SomeTestMobject.__bases__ - assert OpenGLMobject not in SomeTestMobject.__bases__ + config.renderer = "cairo" + assert Mobject in SomeTestMobject.__bases__ + assert OpenGLMobject not in SomeTestMobject.__bases__ diff --git a/tests/module/mobject/mobject/test_set_attr.py b/tests/module/mobject/mobject/test_set_attr.py index f9cdd40fe6..9edfb93bc4 100644 --- a/tests/module/mobject/mobject/test_set_attr.py +++ b/tests/module/mobject/mobject/test_set_attr.py @@ -2,13 +2,11 @@ import numpy as np -from manim import RendererType, config from manim.constants import RIGHT from manim.mobject.geometry.polygram import Square -def test_Data(): - config.renderer = RendererType.OPENGL +def test_Data(using_opengl_renderer): a = Square().move_to(RIGHT) data_bb = a.data["bounding_box"] np.testing.assert_array_equal( @@ -39,6 +37,3 @@ def test_Data(): ) np.testing.assert_array_equal(a.bounding_box, data_bb) - config.renderer = ( - RendererType.CAIRO - ) # needs to be here or else the following cairo tests fail diff --git a/tests/module/mobject/test_boolean_ops.py b/tests/module/mobject/test_boolean_ops.py index 844a9f2b51..b3560e87fa 100644 --- a/tests/module/mobject/test_boolean_ops.py +++ b/tests/module/mobject/test_boolean_ops.py @@ -8,7 +8,7 @@ @pytest.mark.parametrize( - "test_input,expected", + ("test_input", "expected"), [ ( [(1.0, 2.0), (3.0, 4.0)], diff --git a/tests/module/mobject/text/test_numbers.py b/tests/module/mobject/text/test_numbers.py index 9482dd728f..7e46e83dea 100644 --- a/tests/module/mobject/text/test_numbers.py +++ b/tests/module/mobject/text/test_numbers.py @@ -5,7 +5,8 @@ def test_font_size(): """Test that DecimalNumber returns the correct font_size value - after being scaled.""" + after being scaled. + """ num = DecimalNumber(0).scale(0.3) assert round(num.font_size, 5) == 14.4 @@ -39,7 +40,8 @@ def test_set_value_size(): def test_color_when_number_of_digits_changes(): """Test that all digits of an Integer are colored correctly when - the number of digits changes.""" + the number of digits changes. + """ mob = Integer(color=RED) mob.set_value(42) assert all( diff --git a/tests/module/mobject/text/test_texmobject.py b/tests/module/mobject/text/test_texmobject.py index c8d4f51f84..ca8e635ea6 100644 --- a/tests/module/mobject/text/test_texmobject.py +++ b/tests/module/mobject/text/test_texmobject.py @@ -5,21 +5,21 @@ import numpy as np import pytest -from manim import MathTex, SingleStringMathTex, Tex, TexTemplate, config, tempconfig +from manim import MathTex, SingleStringMathTex, Tex, TexTemplate, tempconfig -def test_MathTex(): +def test_MathTex(config): MathTex("a^2 + b^2 = c^2") assert Path(config.media_dir, "Tex", "e4be163a00cf424f.svg").exists() -def test_SingleStringMathTex(): +def test_SingleStringMathTex(config): SingleStringMathTex("test") assert Path(config.media_dir, "Tex", "8ce17c7f5013209f.svg").exists() @pytest.mark.parametrize( # : PT006 - "text_input,length_sub", + ("text_input", "length_sub"), [("{{ a }} + {{ b }} = {{ c }}", 5), (r"\frac{1}{a+b\sqrt{2}}", 1)], ) def test_double_braces_testing(text_input, length_sub): @@ -27,7 +27,7 @@ def test_double_braces_testing(text_input, length_sub): assert len(t1.submobjects) == length_sub -def test_tex(): +def test_tex(config): Tex("The horse does not eat cucumber salad.") assert Path(config.media_dir, "Tex", "c3945e23e546c95a.svg").exists() @@ -45,7 +45,7 @@ def test_tex_temp_directory(tmpdir, monkeypatch): assert Path("media", "Tex", "c3945e23e546c95a.svg").exists() -def test_percent_char_rendering(): +def test_percent_char_rendering(config): Tex(r"\%") assert Path(config.media_dir, "Tex", "4a583af4d19a3adf.tex").exists() @@ -123,7 +123,8 @@ def test_tex_size(): def test_font_size(): """Test that tex_mobject classes return - the correct font_size value after being scaled.""" + the correct font_size value after being scaled. + """ string = MathTex(0).scale(0.3) assert round(string.font_size, 5) == 14.4 @@ -194,7 +195,7 @@ def test_error_in_nested_context(capsys): \end{align} """ - with pytest.raises(ValueError) as err: + with pytest.raises(ValueError): Tex(invalid_tex) stdout = str(capsys.readouterr().out) @@ -202,25 +203,25 @@ def test_error_in_nested_context(capsys): assert r"\begin{frame}" not in stdout -def test_tempconfig_resetting_tex_template(): +def test_tempconfig_resetting_tex_template(config): my_template = TexTemplate() my_template.preamble = "Custom preamble!" - tex_template_config_value = config.tex_template with tempconfig({"tex_template": my_template}): assert config.tex_template.preamble == "Custom preamble!" assert config.tex_template.preamble != "Custom preamble!" -def test_tex_garbage_collection(tmpdir, monkeypatch): +def test_tex_garbage_collection(tmpdir, monkeypatch, config): monkeypatch.chdir(tmpdir) Path(tmpdir, "media").mkdir() + config.media_dir = "media" - with tempconfig({"media_dir": "media"}): - tex_without_log = Tex("Hello World!") # d771330b76d29ffb.tex - assert Path("media", "Tex", "d771330b76d29ffb.tex").exists() - assert not Path("media", "Tex", "d771330b76d29ffb.log").exists() + tex_without_log = Tex("Hello World!") # d771330b76d29ffb.tex + assert Path("media", "Tex", "d771330b76d29ffb.tex").exists() + assert not Path("media", "Tex", "d771330b76d29ffb.log").exists() + + config.no_latex_cleanup = True - with tempconfig({"media_dir": "media", "no_latex_cleanup": True}): - tex_with_log = Tex("Hello World, again!") # da27670a37b08799.tex - assert Path("media", "Tex", "da27670a37b08799.log").exists() + tex_with_log = Tex("Hello World, again!") # da27670a37b08799.tex + assert Path("media", "Tex", "da27670a37b08799.log").exists() diff --git a/tests/module/mobject/text/test_text_mobject.py b/tests/module/mobject/text/test_text_mobject.py index a6b8b3b453..2e656b90ae 100644 --- a/tests/module/mobject/text/test_text_mobject.py +++ b/tests/module/mobject/text/test_text_mobject.py @@ -8,7 +8,8 @@ def test_font_size(): """Test that Text and MarkupText return the - correct font_size value after being scaled.""" + correct font_size value after being scaled. + """ text_string = Text("0").scale(0.3) markuptext_string = MarkupText("0").scale(0.3) diff --git a/tests/module/mobject/types/vectorized_mobject/test_stroke.py b/tests/module/mobject/types/vectorized_mobject/test_stroke.py index 1110db14b8..25c09cd294 100644 --- a/tests/module/mobject/types/vectorized_mobject/test_stroke.py +++ b/tests/module/mobject/types/vectorized_mobject/test_stroke.py @@ -39,3 +39,25 @@ def test_streamline_attributes_for_single_color(): ) assert vector_field[0].stroke_width == 1.0 assert vector_field[0].stroke_opacity == 0.2 + + +def test_stroke_scale(): + a = VMobject() + b = VMobject() + a.set_stroke(width=50) + b.set_stroke(width=50) + a.scale(0.5) + b.scale(0.5, scale_stroke=True) + assert a.get_stroke_width() == 50 + assert b.get_stroke_width() == 25 + + +def test_background_stroke_scale(): + a = VMobject() + b = VMobject() + a.set_stroke(width=50, background=True) + b.set_stroke(width=50, background=True) + a.scale(0.5) + b.scale(0.5, scale_stroke=True) + assert a.get_stroke_width(background=True) == 50 + assert b.get_stroke_width(background=True) == 25 diff --git a/tests/module/mobject/types/vectorized_mobject/test_vectorized_mobject.py b/tests/module/mobject/types/vectorized_mobject/test_vectorized_mobject.py index 7e92a68ac8..4d604f2dfb 100644 --- a/tests/module/mobject/types/vectorized_mobject/test_vectorized_mobject.py +++ b/tests/module/mobject/types/vectorized_mobject/test_vectorized_mobject.py @@ -132,14 +132,14 @@ def test_vgroup_init(): VGroup(3.0) assert str(init_with_float_info.value) == ( "Only values of type VMobject can be added as submobjects of VGroup, " - "but the value 3.0 (at index 0) is of type float." + "but the value 3.0 (at index 0 of parameter 0) is of type float." ) with pytest.raises(TypeError) as init_with_mob_info: VGroup(Mobject()) assert str(init_with_mob_info.value) == ( "Only values of type VMobject can be added as submobjects of VGroup, " - "but the value Mobject (at index 0) is of type Mobject. You can try " + "but the value Mobject (at index 0 of parameter 0) is of type Mobject. You can try " "adding this value into a Group instead." ) @@ -147,11 +147,57 @@ def test_vgroup_init(): VGroup(VMobject(), Mobject()) assert str(init_with_vmob_and_mob_info.value) == ( "Only values of type VMobject can be added as submobjects of VGroup, " - "but the value Mobject (at index 1) is of type Mobject. You can try " + "but the value Mobject (at index 0 of parameter 1) is of type Mobject. You can try " "adding this value into a Group instead." ) +def test_vgroup_init_with_iterable(): + """Test VGroup instantiation with an iterable type.""" + + def type_generator(type_to_generate, n): + return (type_to_generate() for _ in range(n)) + + def mixed_type_generator(major_type, minor_type, minor_type_positions, n): + return ( + minor_type() if i in minor_type_positions else major_type() + for i in range(n) + ) + + obj = VGroup(VMobject()) + assert len(obj.submobjects) == 1 + + obj = VGroup(type_generator(VMobject, 38)) + assert len(obj.submobjects) == 38 + + obj = VGroup(VMobject(), [VMobject(), VMobject()], type_generator(VMobject, 38)) + assert len(obj.submobjects) == 41 + + # A VGroup cannot be initialised with an iterable containing a Mobject + with pytest.raises(TypeError) as init_with_mob_iterable: + VGroup(type_generator(Mobject, 5)) + assert str(init_with_mob_iterable.value) == ( + "Only values of type VMobject can be added as submobjects of VGroup, " + "but the value Mobject (at index 0 of parameter 0) is of type Mobject." + ) + + # A VGroup cannot be initialised with an iterable containing a Mobject in any position + with pytest.raises(TypeError) as init_with_mobs_and_vmobs_iterable: + VGroup(mixed_type_generator(VMobject, Mobject, [3, 5], 7)) + assert str(init_with_mobs_and_vmobs_iterable.value) == ( + "Only values of type VMobject can be added as submobjects of VGroup, " + "but the value Mobject (at index 3 of parameter 0) is of type Mobject." + ) + + # A VGroup cannot be initialised with an iterable containing non VMobject's in any position + with pytest.raises(TypeError) as init_with_float_and_vmobs_iterable: + VGroup(mixed_type_generator(VMobject, float, [6, 7], 9)) + assert str(init_with_float_and_vmobs_iterable.value) == ( + "Only values of type VMobject can be added as submobjects of VGroup, " + "but the value 0.0 (at index 6 of parameter 0) is of type float." + ) + + def test_vgroup_add(): """Test the VGroup add method.""" obj = VGroup() @@ -165,7 +211,7 @@ def test_vgroup_add(): obj.add(3) assert str(add_int_info.value) == ( "Only values of type VMobject can be added as submobjects of VGroup, " - "but the value 3 (at index 0) is of type int." + "but the value 3 (at index 0 of parameter 0) is of type int." ) assert len(obj.submobjects) == 1 @@ -175,7 +221,7 @@ def test_vgroup_add(): obj.add(Mobject()) assert str(add_mob_info.value) == ( "Only values of type VMobject can be added as submobjects of VGroup, " - "but the value Mobject (at index 0) is of type Mobject. You can try " + "but the value Mobject (at index 0 of parameter 0) is of type Mobject. You can try " "adding this value into a Group instead." ) assert len(obj.submobjects) == 1 @@ -185,7 +231,7 @@ def test_vgroup_add(): obj.add(VMobject(), Mobject()) assert str(add_vmob_and_mob_info.value) == ( "Only values of type VMobject can be added as submobjects of VGroup, " - "but the value Mobject (at index 1) is of type Mobject. You can try " + "but the value Mobject (at index 0 of parameter 1) is of type Mobject. You can try " "adding this value into a Group instead." ) assert len(obj.submobjects) == 1 diff --git a/tests/module/scene/test_auto_zoom.py b/tests/module/scene/test_auto_zoom.py index 76c17231fe..4c95ed83ca 100644 --- a/tests/module/scene/test_auto_zoom.py +++ b/tests/module/scene/test_auto_zoom.py @@ -16,6 +16,7 @@ def test_zoom(): assert scene.camera.frame_width == abs( s1.get_left()[0] - s2.get_right()[0], - ) and scene.camera.frame.get_center()[0] == ( + ) + assert scene.camera.frame.get_center()[0] == ( abs(s1.get_center()[0] + s2.get_center()[0]) / 2 ) diff --git a/tests/module/scene/test_scene.py b/tests/module/scene/test_scene.py index 0790b7ece6..70ea9eaf2a 100644 --- a/tests/module/scene/test_scene.py +++ b/tests/module/scene/test_scene.py @@ -4,104 +4,100 @@ import pytest -from manim import Circle, FadeIn, Group, Mobject, Scene, Square, tempconfig +from manim import Circle, FadeIn, Group, Mobject, Scene, Square from manim.animation.animation import Wait -def test_scene_add_remove(): - with tempconfig({"dry_run": True}): - scene = Scene() - assert len(scene.mobjects) == 0 - scene.add(Mobject()) - assert len(scene.mobjects) == 1 - scene.add(*(Mobject() for _ in range(10))) - assert len(scene.mobjects) == 11 - - # Check that adding a mobject twice does not actually add it twice - repeated = Mobject() - scene.add(repeated) - assert len(scene.mobjects) == 12 - scene.add(repeated) - assert len(scene.mobjects) == 12 - - # Check that Scene.add() returns the Scene (for chained calls) - assert scene.add(Mobject()) is scene - to_remove = Mobject() - scene = Scene() - scene.add(to_remove) - scene.add(*(Mobject() for _ in range(10))) - assert len(scene.mobjects) == 11 - scene.remove(to_remove) - assert len(scene.mobjects) == 10 - scene.remove(to_remove) - assert len(scene.mobjects) == 10 - - # Check that Scene.remove() returns the instance (for chained calls) - assert scene.add(Mobject()) is scene - - -def test_scene_time(): - with tempconfig({"dry_run": True}): - scene = Scene() - assert scene.renderer.time == 0 - scene.wait(2) - assert scene.renderer.time == 2 - scene.play(FadeIn(Circle()), run_time=0.5) - assert pytest.approx(scene.renderer.time) == 2.5 - scene.renderer._original_skipping_status = True - scene.play(FadeIn(Square()), run_time=5) # this animation gets skipped. - assert pytest.approx(scene.renderer.time) == 7.5 - - -def test_subcaption(): - with tempconfig({"dry_run": True}): - scene = Scene() - scene.add_subcaption("Testing add_subcaption", duration=1, offset=0) - scene.wait() - scene.play( - Wait(), - run_time=2, - subcaption="Testing Scene.play subcaption interface", - subcaption_duration=1.5, - subcaption_offset=0.5, - ) - subcaptions = scene.renderer.file_writer.subcaptions - assert len(subcaptions) == 2 - assert subcaptions[0].start == datetime.timedelta(seconds=0) - assert subcaptions[0].end == datetime.timedelta(seconds=1) - assert subcaptions[0].content == "Testing add_subcaption" - assert subcaptions[1].start == datetime.timedelta(seconds=1.5) - assert subcaptions[1].end == datetime.timedelta(seconds=3) - assert subcaptions[1].content == "Testing Scene.play subcaption interface" - - -def test_replace(): +def test_scene_add_remove(dry_run): + scene = Scene() + assert len(scene.mobjects) == 0 + scene.add(Mobject()) + assert len(scene.mobjects) == 1 + scene.add(*(Mobject() for _ in range(10))) + assert len(scene.mobjects) == 11 + + # Check that adding a mobject twice does not actually add it twice + repeated = Mobject() + scene.add(repeated) + assert len(scene.mobjects) == 12 + scene.add(repeated) + assert len(scene.mobjects) == 12 + + # Check that Scene.add() returns the Scene (for chained calls) + assert scene.add(Mobject()) is scene + to_remove = Mobject() + scene = Scene() + scene.add(to_remove) + scene.add(*(Mobject() for _ in range(10))) + assert len(scene.mobjects) == 11 + scene.remove(to_remove) + assert len(scene.mobjects) == 10 + scene.remove(to_remove) + assert len(scene.mobjects) == 10 + + # Check that Scene.remove() returns the instance (for chained calls) + assert scene.add(Mobject()) is scene + + +def test_scene_time(dry_run): + scene = Scene() + assert scene.time == 0 + scene.wait(2) + assert scene.time == 2 + scene.play(FadeIn(Circle()), run_time=0.5) + assert pytest.approx(scene.time) == 2.5 + scene.renderer._original_skipping_status = True + scene.play(FadeIn(Square()), run_time=5) # this animation gets skipped. + assert pytest.approx(scene.time) == 7.5 + + +def test_subcaption(dry_run): + scene = Scene() + scene.add_subcaption("Testing add_subcaption", duration=1, offset=0) + scene.wait() + scene.play( + Wait(), + run_time=2, + subcaption="Testing Scene.play subcaption interface", + subcaption_duration=1.5, + subcaption_offset=0.5, + ) + subcaptions = scene.renderer.file_writer.subcaptions + assert len(subcaptions) == 2 + assert subcaptions[0].start == datetime.timedelta(seconds=0) + assert subcaptions[0].end == datetime.timedelta(seconds=1) + assert subcaptions[0].content == "Testing add_subcaption" + assert subcaptions[1].start == datetime.timedelta(seconds=1.5) + assert subcaptions[1].end == datetime.timedelta(seconds=3) + assert subcaptions[1].content == "Testing Scene.play subcaption interface" + + +def test_replace(dry_run): def assert_names(mobjs, names): assert len(mobjs) == len(names) for i in range(0, len(mobjs)): assert mobjs[i].name == names[i] - with tempconfig({"dry_run": True}): - scene = Scene() + scene = Scene() - first = Mobject(name="first") - second = Mobject(name="second") - third = Mobject(name="third") - fourth = Mobject(name="fourth") + first = Mobject(name="first") + second = Mobject(name="second") + third = Mobject(name="third") + fourth = Mobject(name="fourth") - scene.add(first) - scene.add(Group(second, third, name="group")) - scene.add(fourth) - assert_names(scene.mobjects, ["first", "group", "fourth"]) - assert_names(scene.mobjects[1], ["second", "third"]) + scene.add(first) + scene.add(Group(second, third, name="group")) + scene.add(fourth) + assert_names(scene.mobjects, ["first", "group", "fourth"]) + assert_names(scene.mobjects[1], ["second", "third"]) - alpha = Mobject(name="alpha") - beta = Mobject(name="beta") + alpha = Mobject(name="alpha") + beta = Mobject(name="beta") - scene.replace(first, alpha) - assert_names(scene.mobjects, ["alpha", "group", "fourth"]) - assert_names(scene.mobjects[1], ["second", "third"]) + scene.replace(first, alpha) + assert_names(scene.mobjects, ["alpha", "group", "fourth"]) + assert_names(scene.mobjects[1], ["second", "third"]) - scene.replace(second, beta) - assert_names(scene.mobjects, ["alpha", "group", "fourth"]) - assert_names(scene.mobjects[1], ["beta", "third"]) + scene.replace(second, beta) + assert_names(scene.mobjects, ["alpha", "group", "fourth"]) + assert_names(scene.mobjects[1], ["beta", "third"]) diff --git a/tests/module/scene/test_sound.py b/tests/module/scene/test_sound.py index cfd67ed2df..cfa9a4da42 100644 --- a/tests/module/scene/test_sound.py +++ b/tests/module/scene/test_sound.py @@ -10,14 +10,12 @@ def test_add_sound(tmpdir): # create sound file sound_loc = Path(tmpdir, "noise.wav") - f = wave.open(str(sound_loc), "w") - f.setparams((2, 2, 44100, 0, "NONE", "not compressed")) - for _ in range(22050): # half a second of sound - packed_value = struct.pack("h", 14242) - f.writeframes(packed_value) - f.writeframes(packed_value) - - f.close() + with wave.open(str(sound_loc), "w") as f: + f.setparams((2, 2, 44100, 0, "NONE", "not compressed")) + for _ in range(22050): # half a second of sound + packed_value = struct.pack("h", 14242) + f.writeframes(packed_value) + f.writeframes(packed_value) scene = Scene() scene.add_sound(sound_loc) diff --git a/tests/module/utils/test_bezier.py b/tests/module/utils/test_bezier.py index dca4be193e..e7e02a89ee 100644 --- a/tests/module/utils/test_bezier.py +++ b/tests/module/utils/test_bezier.py @@ -8,6 +8,7 @@ from manim.typing import ManimFloat from manim.utils.bezier import ( _get_subdivision_matrix, + get_quadratic_approximation_of_cubic, get_smooth_cubic_bezier_handle_points, partial_bezier_points, split_bezier, @@ -167,3 +168,50 @@ def test_get_smooth_cubic_bezier_handle_points() -> None: ] ), ) + + +def test_get_quadratic_approximation_of_cubic() -> None: + C = np.array( + [ + [-5, 2, 0], + [-4, 2, 0], + [-3, 2, 0], + [-2, 2, 0], + [-2, 2, 0], + [-7 / 3, 4 / 3, 0], + [-8 / 3, 2 / 3, 0], + [-3, 0, 0], + [-3, 0, 0], + [-1 / 3, -1, 0], + [7 / 3, -2, 0], + [5, -3, 0], + ] + ) + a0, h0, h1, a1 = C[::4], C[1::4], C[2::4], C[3::4] + + Q = get_quadratic_approximation_of_cubic(a0, h0, h1, a1) + assert np.allclose( + Q, + np.array( + [ + [-5, 2, 0], + [-17 / 4, 2, 0], + [-7 / 2, 2, 0], + [-7 / 2, 2, 0], + [-11 / 4, 2, 0], + [-2, 2, 0], + [-2, 2, 0], + [-9 / 4, 3 / 2, 0], + [-5 / 2, 1, 0], + [-5 / 2, 1, 0], + [-11 / 4, 1 / 2, 0], + [-3, 0, 0], + [-3, 0, 0], + [-1, -3 / 4, 0], + [1, -3 / 2, 0], + [1, -3 / 2, 0], + [3, -9 / 4, 0], + [5, -3, 0], + ] + ), + ) diff --git a/tests/module/utils/test_deprecation.py b/tests/module/utils/test_deprecation.py index e498b8b196..dcb766a464 100644 --- a/tests/module/utils/test_deprecation.py +++ b/tests/module/utils/test_deprecation.py @@ -1,23 +1,13 @@ from __future__ import annotations -import logging - -import pytest - from manim.utils.deprecation import deprecated, deprecated_params -def _get_caplog_record_msg(warn_caplog_manim): - logger_name, level, message = warn_caplog_manim.record_tuples[0] +def _get_caplog_record_msg(manim_caplog): + logger_name, level, message = manim_caplog.record_tuples[0] return message -@pytest.fixture() -def warn_caplog_manim(caplog): - caplog.set_level(logging.WARNING, logger="manim") - yield caplog - - @deprecated class Foo: def __init__(self): @@ -77,11 +67,11 @@ def __init__(self): doc_admonition = "\n\n.. attention:: Deprecated\n " -def test_deprecate_class_no_args(warn_caplog_manim): +def test_deprecate_class_no_args(manim_caplog): """Test the deprecation of a class (decorator with no arguments).""" f = Foo() - assert len(warn_caplog_manim.record_tuples) == 1 - msg = _get_caplog_record_msg(warn_caplog_manim) + assert len(manim_caplog.record_tuples) == 1 + msg = _get_caplog_record_msg(manim_caplog) assert ( msg == "The class Foo has been deprecated and may be removed in a later version." @@ -89,11 +79,11 @@ def test_deprecate_class_no_args(warn_caplog_manim): assert f.__doc__ == f"{doc_admonition}{msg}" -def test_deprecate_class_since(warn_caplog_manim): +def test_deprecate_class_since(manim_caplog): """Test the deprecation of a class (decorator with since argument).""" b = Bar() - assert len(warn_caplog_manim.record_tuples) == 1 - msg = _get_caplog_record_msg(warn_caplog_manim) + assert len(manim_caplog.record_tuples) == 1 + msg = _get_caplog_record_msg(manim_caplog) assert ( msg == "The class Bar has been deprecated since v0.6.0 and may be removed in a later version." @@ -101,11 +91,11 @@ def test_deprecate_class_since(warn_caplog_manim): assert b.__doc__ == f"The Bar class.{doc_admonition}{msg}" -def test_deprecate_class_until(warn_caplog_manim): +def test_deprecate_class_until(manim_caplog): """Test the deprecation of a class (decorator with until argument).""" bz = Baz() - assert len(warn_caplog_manim.record_tuples) == 1 - msg = _get_caplog_record_msg(warn_caplog_manim) + assert len(manim_caplog.record_tuples) == 1 + msg = _get_caplog_record_msg(manim_caplog) assert ( msg == "The class Baz has been deprecated and is expected to be removed after 06/01/2021." @@ -113,11 +103,11 @@ def test_deprecate_class_until(warn_caplog_manim): assert bz.__doc__ == f"The Baz class.{doc_admonition}{msg}" -def test_deprecate_class_since_and_until(warn_caplog_manim): +def test_deprecate_class_since_and_until(manim_caplog): """Test the deprecation of a class (decorator with since and until arguments).""" qx = Qux() - assert len(warn_caplog_manim.record_tuples) == 1 - msg = _get_caplog_record_msg(warn_caplog_manim) + assert len(manim_caplog.record_tuples) == 1 + msg = _get_caplog_record_msg(manim_caplog) assert ( msg == "The class Qux has been deprecated since 0.7.0 and is expected to be removed after 0.9.0-rc2." @@ -125,11 +115,11 @@ def test_deprecate_class_since_and_until(warn_caplog_manim): assert qx.__doc__ == f"{doc_admonition}{msg}" -def test_deprecate_class_msg(warn_caplog_manim): +def test_deprecate_class_msg(manim_caplog): """Test the deprecation of a class (decorator with msg argument).""" qu = Quux() - assert len(warn_caplog_manim.record_tuples) == 1 - msg = _get_caplog_record_msg(warn_caplog_manim) + assert len(manim_caplog.record_tuples) == 1 + msg = _get_caplog_record_msg(manim_caplog) assert ( msg == "The class Quux has been deprecated and may be removed in a later version. Use something else." @@ -137,11 +127,11 @@ def test_deprecate_class_msg(warn_caplog_manim): assert qu.__doc__ == f"{doc_admonition}{msg}" -def test_deprecate_class_replacement(warn_caplog_manim): +def test_deprecate_class_replacement(manim_caplog): """Test the deprecation of a class (decorator with replacement argument).""" qz = Quuz() - assert len(warn_caplog_manim.record_tuples) == 1 - msg = _get_caplog_record_msg(warn_caplog_manim) + assert len(manim_caplog.record_tuples) == 1 + msg = _get_caplog_record_msg(manim_caplog) assert ( msg == "The class Quuz has been deprecated and may be removed in a later version. Use ReplaceQuuz instead." @@ -150,11 +140,11 @@ def test_deprecate_class_replacement(warn_caplog_manim): assert qz.__doc__ == f"{doc_admonition}{doc_msg}" -def test_deprecate_class_all(warn_caplog_manim): +def test_deprecate_class_all(manim_caplog): """Test the deprecation of a class (decorator with all arguments).""" qza = QuuzAll() - assert len(warn_caplog_manim.record_tuples) == 1 - msg = _get_caplog_record_msg(warn_caplog_manim) + assert len(manim_caplog.record_tuples) == 1 + msg = _get_caplog_record_msg(manim_caplog) assert ( msg == "The class QuuzAll has been deprecated since 0.7.0 and is expected to be removed after 1.2.1. Use ReplaceQuuz instead. Don't use this please." @@ -175,7 +165,6 @@ def __init__(self): @deprecated(since="0.8.0", message="This method is useless.") def mid_func(self): """Middle function in Top.""" - pass @deprecated(until="1.4.0", replacement="Top.NewNested") @@ -190,7 +179,6 @@ def __init__(self): @deprecated(since="1.0.0", until="12/25/2025") def nested_func(self): """Nested function in Top.NewNested.""" - pass class Bottom: @@ -243,11 +231,11 @@ def quuz(self, **kwargs): return kwargs -def test_deprecate_func_no_args(warn_caplog_manim): +def test_deprecate_func_no_args(manim_caplog): """Test the deprecation of a method (decorator with no arguments).""" useless() - assert len(warn_caplog_manim.record_tuples) == 1 - msg = _get_caplog_record_msg(warn_caplog_manim) + assert len(manim_caplog.record_tuples) == 1 + msg = _get_caplog_record_msg(manim_caplog) assert ( msg == "The function useless has been deprecated and may be removed in a later version." @@ -255,12 +243,12 @@ def test_deprecate_func_no_args(warn_caplog_manim): assert useless.__doc__ == f"{doc_admonition}{msg}" -def test_deprecate_func_in_class_since_and_message(warn_caplog_manim): +def test_deprecate_func_in_class_since_and_message(manim_caplog): """Test the deprecation of a method within a class (decorator with since and message arguments).""" t = Top() t.mid_func() - assert len(warn_caplog_manim.record_tuples) == 1 - msg = _get_caplog_record_msg(warn_caplog_manim) + assert len(manim_caplog.record_tuples) == 1 + msg = _get_caplog_record_msg(manim_caplog) assert ( msg == "The method Top.mid_func has been deprecated since 0.8.0 and may be removed in a later version. This method is useless." @@ -268,11 +256,11 @@ def test_deprecate_func_in_class_since_and_message(warn_caplog_manim): assert t.mid_func.__doc__ == f"Middle function in Top.{doc_admonition}{msg}" -def test_deprecate_nested_class_until_and_replacement(warn_caplog_manim): +def test_deprecate_nested_class_until_and_replacement(manim_caplog): """Test the deprecation of a nested class (decorator with until and replacement arguments).""" n = Top().Nested() - assert len(warn_caplog_manim.record_tuples) == 1 - msg = _get_caplog_record_msg(warn_caplog_manim) + assert len(manim_caplog.record_tuples) == 1 + msg = _get_caplog_record_msg(manim_caplog) assert ( msg == "The class Top.Nested has been deprecated and is expected to be removed after 1.4.0. Use Top.NewNested instead." @@ -281,12 +269,12 @@ def test_deprecate_nested_class_until_and_replacement(warn_caplog_manim): assert n.__doc__ == f"{doc_admonition}{doc_msg}" -def test_deprecate_nested_class_func_since_and_until(warn_caplog_manim): +def test_deprecate_nested_class_func_since_and_until(manim_caplog): """Test the deprecation of a method within a nested class (decorator with since and until arguments).""" n = Top().NewNested() n.nested_func() - assert len(warn_caplog_manim.record_tuples) == 1 - msg = _get_caplog_record_msg(warn_caplog_manim) + assert len(manim_caplog.record_tuples) == 1 + msg = _get_caplog_record_msg(manim_caplog) assert ( msg == "The method Top.NewNested.nested_func has been deprecated since 1.0.0 and is expected to be removed after 12/25/2025." @@ -297,13 +285,13 @@ def test_deprecate_nested_class_func_since_and_until(warn_caplog_manim): ) -def test_deprecate_nested_func(warn_caplog_manim): +def test_deprecate_nested_func(manim_caplog): """Test the deprecation of a nested method (decorator with no arguments).""" b = Top().Bottom() answer = b.normal_func() answer(1) - assert len(warn_caplog_manim.record_tuples) == 1 - msg = _get_caplog_record_msg(warn_caplog_manim) + assert len(manim_caplog.record_tuples) == 1 + msg = _get_caplog_record_msg(manim_caplog) assert ( msg == "The method Top.Bottom.normal_func..nested_func has been deprecated and may be removed in a later version." @@ -311,36 +299,36 @@ def test_deprecate_nested_func(warn_caplog_manim): assert answer.__doc__ == f"{doc_admonition}{msg}" -def test_deprecate_func_params(warn_caplog_manim): +def test_deprecate_func_params(manim_caplog): """Test the deprecation of method parameters (decorator with params argument).""" t = Top() t.foo(a=2, b=3, z=4) - assert len(warn_caplog_manim.record_tuples) == 1 - msg = _get_caplog_record_msg(warn_caplog_manim) + assert len(manim_caplog.record_tuples) == 1 + msg = _get_caplog_record_msg(manim_caplog) assert ( msg == "The parameters a and b of method Top.foo have been deprecated and may be removed in a later version. Use something else." ) -def test_deprecate_func_single_param_since_and_until(warn_caplog_manim): +def test_deprecate_func_single_param_since_and_until(manim_caplog): """Test the deprecation of a single method parameter (decorator with since and until arguments).""" t = Top() t.bar(a=1, b=2) - assert len(warn_caplog_manim.record_tuples) == 1 - msg = _get_caplog_record_msg(warn_caplog_manim) + assert len(manim_caplog.record_tuples) == 1 + msg = _get_caplog_record_msg(manim_caplog) assert ( msg == "The parameter a of method Top.bar has been deprecated since v0.2 and is expected to be removed after v0.4." ) -def test_deprecate_func_param_redirect_tuple(warn_caplog_manim): +def test_deprecate_func_param_redirect_tuple(manim_caplog): """Test the deprecation of a method parameter and redirecting it to a new one using tuple.""" t = Top() obj = t.baz(x=1, old_param=2) - assert len(warn_caplog_manim.record_tuples) == 1 - msg = _get_caplog_record_msg(warn_caplog_manim) + assert len(manim_caplog.record_tuples) == 1 + msg = _get_caplog_record_msg(manim_caplog) assert ( msg == "The parameter old_param of method Top.baz has been deprecated and may be removed in a later version." @@ -348,12 +336,12 @@ def test_deprecate_func_param_redirect_tuple(warn_caplog_manim): assert obj == {"x": 1, "new_param": 2} -def test_deprecate_func_param_redirect_lambda(warn_caplog_manim): +def test_deprecate_func_param_redirect_lambda(manim_caplog): """Test the deprecation of a method parameter and redirecting it to a new one using lambda function.""" t = Top() obj = t.qux(runtime_in_ms=500) - assert len(warn_caplog_manim.record_tuples) == 1 - msg = _get_caplog_record_msg(warn_caplog_manim) + assert len(manim_caplog.record_tuples) == 1 + msg = _get_caplog_record_msg(manim_caplog) assert ( msg == "The parameter runtime_in_ms of method Top.qux has been deprecated and may be removed in a later version." @@ -361,12 +349,12 @@ def test_deprecate_func_param_redirect_lambda(warn_caplog_manim): assert obj == {"run_time": 0.5} -def test_deprecate_func_param_redirect_many_to_one(warn_caplog_manim): +def test_deprecate_func_param_redirect_many_to_one(manim_caplog): """Test the deprecation of multiple method parameters and redirecting them to one.""" t = Top() obj = t.quux(point2D_x=3, point2D_y=5) - assert len(warn_caplog_manim.record_tuples) == 1 - msg = _get_caplog_record_msg(warn_caplog_manim) + assert len(manim_caplog.record_tuples) == 1 + msg = _get_caplog_record_msg(manim_caplog) assert ( msg == "The parameters point2D_x and point2D_y of method Top.quux have been deprecated and may be removed in a later version." @@ -374,23 +362,23 @@ def test_deprecate_func_param_redirect_many_to_one(warn_caplog_manim): assert obj == {"point2D": (3, 5)} -def test_deprecate_func_param_redirect_one_to_many(warn_caplog_manim): +def test_deprecate_func_param_redirect_one_to_many(manim_caplog): """Test the deprecation of one method parameter and redirecting it to many.""" t = Top() obj1 = t.quuz(point2D=0) - assert len(warn_caplog_manim.record_tuples) == 1 - msg = _get_caplog_record_msg(warn_caplog_manim) + assert len(manim_caplog.record_tuples) == 1 + msg = _get_caplog_record_msg(manim_caplog) assert ( msg == "The parameter point2D of method Top.quuz has been deprecated and may be removed in a later version." ) assert obj1 == {"x": 0, "y": 0} - warn_caplog_manim.clear() + manim_caplog.clear() obj2 = t.quuz(point2D=(2, 3)) - assert len(warn_caplog_manim.record_tuples) == 1 - msg = _get_caplog_record_msg(warn_caplog_manim) + assert len(manim_caplog.record_tuples) == 1 + msg = _get_caplog_record_msg(manim_caplog) assert ( msg == "The parameter point2D of method Top.quuz has been deprecated and may be removed in a later version." diff --git a/tests/module/utils/test_manim_color.py b/tests/module/utils/test_manim_color.py index 1ae07c3b8b..97da13fecc 100644 --- a/tests/module/utils/test_manim_color.py +++ b/tests/module/utils/test_manim_color.py @@ -1,9 +1,20 @@ from __future__ import annotations +import colorsys + import numpy as np import numpy.testing as nt -from manim.utils.color import BLACK, WHITE, ManimColor, ManimColorDType +from manim.utils.color import ( + BLACK, + HSV, + RED, + WHITE, + YELLOW, + ManimColor, + ManimColorDType, +) +from manim.utils.color.XKCD import GREEN def test_init_with_int() -> None: @@ -20,3 +31,174 @@ def test_init_with_int() -> None: nt.assert_array_equal( color._internal_value, np.array([1.0, 1.0, 1.0, 1.0], dtype=ManimColorDType) ) + + +def test_init_with_hex() -> None: + color = ManimColor("0xFF0000") + nt.assert_array_equal(color._internal_value, np.array([1, 0, 0, 1])) + color = ManimColor("0xFF000000") + nt.assert_array_equal(color._internal_value, np.array([1, 0, 0, 0])) + + color = ManimColor("#FF0000") + nt.assert_array_equal(color._internal_value, np.array([1, 0, 0, 1])) + color = ManimColor("#FF000000") + nt.assert_array_equal(color._internal_value, np.array([1, 0, 0, 0])) + + +def test_init_with_string() -> None: + color = ManimColor("BLACK") + nt.assert_array_equal(color._internal_value, BLACK._internal_value) + + +def test_init_with_tuple_int() -> None: + color = ManimColor((50, 10, 50)) + nt.assert_array_equal( + color._internal_value, np.array([50 / 255, 10 / 255, 50 / 255, 1.0]) + ) + + color = ManimColor((50, 10, 50, 50)) + nt.assert_array_equal( + color._internal_value, np.array([50 / 255, 10 / 255, 50 / 255, 50 / 255]) + ) + + +def test_init_with_tuple_float() -> None: + color = ManimColor((0.5, 0.6, 0.7)) + nt.assert_array_equal(color._internal_value, np.array([0.5, 0.6, 0.7, 1.0])) + + color = ManimColor((0.5, 0.6, 0.7, 0.1)) + nt.assert_array_equal(color._internal_value, np.array([0.5, 0.6, 0.7, 0.1])) + + +def test_to_integer() -> None: + color = ManimColor((0x1, 0x2, 0x3, 0x4)) + nt.assert_equal(color.to_integer(), 0x010203) + + +def test_to_rgb() -> None: + color = ManimColor((0x1, 0x2, 0x3, 0x4)) + nt.assert_array_equal(color.to_rgb(), (0x1 / 255, 0x2 / 255, 0x3 / 255)) + nt.assert_array_equal(color.to_int_rgb(), (0x1, 0x2, 0x3)) + nt.assert_array_equal(color.to_rgba(), (0x1 / 255, 0x2 / 255, 0x3 / 255, 0x4 / 255)) + nt.assert_array_equal(color.to_int_rgba(), (0x1, 0x2, 0x3, 0x4)) + nt.assert_array_equal( + color.to_rgba_with_alpha(0.5), (0x1 / 255, 0x2 / 255, 0x3 / 255, 0.5) + ) + nt.assert_array_equal( + color.to_int_rgba_with_alpha(0.5), (0x1, 0x2, 0x3, int(0.5 * 255)) + ) + + +def test_to_hex() -> None: + color = ManimColor((0x1, 0x2, 0x3, 0x4)) + nt.assert_equal(color.to_hex(), "#010203") + nt.assert_equal(color.to_hex(True), "#01020304") + + +def test_to_hsv() -> None: + color = ManimColor((0x1, 0x2, 0x3, 0x4)) + nt.assert_array_equal( + color.to_hsv(), colorsys.rgb_to_hsv(0x1 / 255, 0x2 / 255, 0x3 / 255) + ) + + +def test_to_hsl() -> None: + color = ManimColor((0x1, 0x2, 0x3, 0x4)) + nt.assert_array_equal( + color.to_hsl(), colorsys.rgb_to_hls(0x1 / 255, 0x2 / 255, 0x3 / 255) + ) + + +def test_invert() -> None: + color = ManimColor((0x1, 0x2, 0x3, 0x4)) + rgba = color._internal_value + inverted = color.invert() + nt.assert_array_equal( + inverted._internal_value, (1 - rgba[0], 1 - rgba[1], 1 - rgba[2], rgba[3]) + ) + + +def test_invert_with_alpha() -> None: + color = ManimColor((0x1, 0x2, 0x3, 0x4)) + rgba = color._internal_value + inverted = color.invert(True) + nt.assert_array_equal( + inverted._internal_value, (1 - rgba[0], 1 - rgba[1], 1 - rgba[2], 1 - rgba[3]) + ) + + +def test_interpolate() -> None: + r1 = RED._internal_value + r2 = YELLOW._internal_value + nt.assert_array_equal( + RED.interpolate(YELLOW, 0.5)._internal_value, 0.5 * r1 + 0.5 * r2 + ) + + +def test_opacity() -> None: + nt.assert_equal(RED.opacity(0.5)._internal_value[3], 0.5) + + +def test_parse() -> None: + nt.assert_equal(ManimColor.parse([RED, YELLOW]), [RED, YELLOW]) + + +def test_mc_operators() -> None: + c1 = RED + c2 = GREEN + halfway1 = 0.5 * c1 + 0.5 * c2 + halfway2 = c1.interpolate(c2, 0.5) + nt.assert_equal(halfway1, halfway2) + nt.assert_array_equal((WHITE / 2.0)._internal_value, np.array([0.5, 0.5, 0.5, 0.5])) + + +def test_mc_from_functions() -> None: + color = ManimColor.from_hex("#ff00a0") + nt.assert_equal(color.to_hex(), "#FF00A0") + + color = ManimColor.from_rgb((1.0, 1.0, 0.0)) + nt.assert_equal(color.to_hex(), "#FFFF00") + + color = ManimColor.from_rgba((1.0, 1.0, 0.0, 1.0)) + nt.assert_equal(color.to_hex(True), "#FFFF00FF") + + color = ManimColor.from_hsv((1.0, 1.0, 1.0), alpha=0.0) + nt.assert_equal(color.to_hex(True), "#FF000000") + + +def test_hsv_init() -> None: + color = HSV((0.25, 1, 1)) + nt.assert_array_equal(color._internal_value, np.array([0.5, 1.0, 0.0, 1.0])) + + +def test_into_HSV() -> None: + nt.assert_equal(RED.into(HSV).into(ManimColor), RED) + + +def test_contrasting() -> None: + nt.assert_equal(BLACK.contrasting(), WHITE) + nt.assert_equal(WHITE.contrasting(), BLACK) + nt.assert_equal(RED.contrasting(0.1), BLACK) + nt.assert_equal(RED.contrasting(0.9), WHITE) + nt.assert_equal(BLACK.contrasting(dark=GREEN, light=RED), RED) + nt.assert_equal(WHITE.contrasting(dark=GREEN, light=RED), GREEN) + + +def test_lighter() -> None: + c = RED.opacity(0.42) + cl = c.lighter(0.2) + nt.assert_array_equal( + cl._internal_value[:3], + 0.8 * c._internal_value[:3] + 0.2 * WHITE._internal_value[:3], + ) + nt.assert_equal(cl[-1], c[-1]) + + +def test_darker() -> None: + c = RED.opacity(0.42) + cd = c.darker(0.2) + nt.assert_array_equal( + cd._internal_value[:3], + 0.8 * c._internal_value[:3] + 0.2 * BLACK._internal_value[:3], + ) + nt.assert_equal(cd[-1], c[-1]) diff --git a/tests/module/utils/test_units.py b/tests/module/utils/test_units.py index 6c2cba1ac1..5f2995e626 100644 --- a/tests/module/utils/test_units.py +++ b/tests/module/utils/test_units.py @@ -3,13 +3,13 @@ import numpy as np import pytest -from manim import PI, X_AXIS, Y_AXIS, Z_AXIS, config +from manim import PI, X_AXIS, Y_AXIS, Z_AXIS from manim.utils.unit import Degrees, Munits, Percent, Pixels -def test_units(): +def test_units(config): # make sure we are using the right frame geometry - assert config.pixel_width == 1920 + config.pixel_width = 1920 np.testing.assert_allclose(config.frame_height, 8.0) diff --git a/tests/opengl/control_data/coordinate_system_opengl/gradient_line_graph_x_axis_using_opengl_renderer[None].npz b/tests/opengl/control_data/coordinate_system_opengl/gradient_line_graph_x_axis_using_opengl_renderer[None].npz new file mode 100644 index 0000000000..6efda8b2e0 Binary files /dev/null and b/tests/opengl/control_data/coordinate_system_opengl/gradient_line_graph_x_axis_using_opengl_renderer[None].npz differ diff --git a/tests/opengl/control_data/coordinate_system_opengl/gradient_line_graph_y_axis_using_opengl_renderer[None].npz b/tests/opengl/control_data/coordinate_system_opengl/gradient_line_graph_y_axis_using_opengl_renderer[None].npz new file mode 100644 index 0000000000..3c7afcda7d Binary files /dev/null and b/tests/opengl/control_data/coordinate_system_opengl/gradient_line_graph_y_axis_using_opengl_renderer[None].npz differ diff --git a/tests/opengl/test_animate_opengl.py b/tests/opengl/test_animate_opengl.py index 1243fcb212..b5cf21afa6 100644 --- a/tests/opengl/test_animate_opengl.py +++ b/tests/opengl/test_animate_opengl.py @@ -23,10 +23,8 @@ def test_chained_animate(using_opengl_renderer): scale_factor = 2 direction = np.array((1, 1, 0)) anim = s.animate.scale(scale_factor).shift(direction).build() - assert ( - anim.mobject.target.width == scale_factor * s.width - and (anim.mobject.target.get_center() == direction).all() - ) + assert anim.mobject.target.width == scale_factor * s.width + assert (anim.mobject.target.get_center() == direction).all() def test_overridden_animate(using_opengl_renderer): @@ -103,10 +101,8 @@ def test_chained_animate_with_args(using_opengl_renderer): run_time = 2 anim = s.animate(run_time=run_time).scale(scale_factor).shift(direction).build() - assert ( - anim.mobject.target.width == scale_factor * s.width - and (anim.mobject.target.get_center() == direction).all() - ) + assert anim.mobject.target.width == scale_factor * s.width + assert (anim.mobject.target.get_center() == direction).all() assert anim.run_time == run_time diff --git a/tests/opengl/test_config_opengl.py b/tests/opengl/test_config_opengl.py index 378ba33558..d0ca0e5a81 100644 --- a/tests/opengl/test_config_opengl.py +++ b/tests/opengl/test_config_opengl.py @@ -5,10 +5,10 @@ import numpy as np -from manim import WHITE, Scene, Square, config, tempconfig +from manim import WHITE, Scene, Square, tempconfig -def test_tempconfig(using_opengl_renderer): +def test_tempconfig(config, using_opengl_renderer): """Test the tempconfig context manager.""" original = config.copy() @@ -37,19 +37,20 @@ def construct(self): self.wait(1) -def test_background_color(using_opengl_renderer): +def test_background_color(config, using_opengl_renderer, dry_run): """Test the 'background_color' config option.""" - with tempconfig({"background_color": WHITE, "verbosity": "ERROR", "dry_run": True}): - scene = MyScene() - scene.render() - frame = scene.renderer.get_frame() - np.testing.assert_allclose(frame[0, 0], [255, 255, 255, 255]) + config.background_color = WHITE + config.verbose = "ERROR" + scene = MyScene() + scene.render() + frame = scene.renderer.get_frame() + np.testing.assert_allclose(frame[0, 0], [255, 255, 255, 255]) -def test_digest_file(using_opengl_renderer, tmp_path): + +def test_digest_file(config, using_opengl_renderer, tmp_path): """Test that a config file can be digested programmatically.""" - with tempconfig({}): - tmp_cfg = tempfile.NamedTemporaryFile("w", dir=tmp_path, delete=False) + with tempfile.NamedTemporaryFile("w", dir=tmp_path, delete=False) as tmp_cfg: tmp_cfg.write( """ [CLI] @@ -58,14 +59,13 @@ def test_digest_file(using_opengl_renderer, tmp_path): frame_height = 10 """, ) - tmp_cfg.close() - config.digest_file(tmp_cfg.name) + config.digest_file(tmp_cfg.name) - assert config.get_dir("media_dir") == Path("this_is_my_favorite_path") - assert config.get_dir("video_dir") == Path("this_is_my_favorite_path/videos") + assert config.get_dir("media_dir") == Path("this_is_my_favorite_path") + assert config.get_dir("video_dir") == Path("this_is_my_favorite_path/videos") -def test_frame_size(using_opengl_renderer, tmp_path): +def test_frame_size(config, using_opengl_renderer, tmp_path): """Test that the frame size can be set via config file.""" np.testing.assert_allclose( config.aspect_ratio, config.pixel_width / config.pixel_height @@ -73,15 +73,14 @@ def test_frame_size(using_opengl_renderer, tmp_path): np.testing.assert_allclose(config.frame_height, 8.0) with tempconfig({}): - tmp_cfg = tempfile.NamedTemporaryFile("w", dir=tmp_path, delete=False) - tmp_cfg.write( - """ - [CLI] - pixel_height = 10 - pixel_width = 10 - """, - ) - tmp_cfg.close() + with tempfile.NamedTemporaryFile("w", dir=tmp_path, delete=False) as tmp_cfg: + tmp_cfg.write( + """ + [CLI] + pixel_height = 10 + pixel_width = 10 + """, + ) config.digest_file(tmp_cfg.name) # aspect ratio is set using pixel measurements @@ -90,8 +89,9 @@ def test_frame_size(using_opengl_renderer, tmp_path): np.testing.assert_allclose(config.frame_height, 8.0) np.testing.assert_allclose(config.frame_width, 8.0) - with tempconfig({}): - tmp_cfg = tempfile.NamedTemporaryFile("w", dir=tmp_path, delete=False) + +def test_frame_size_if_frame_width(config, using_opengl_renderer, tmp_path): + with tempfile.NamedTemporaryFile("w", dir=tmp_path, delete=False) as tmp_cfg: tmp_cfg.write( """ [CLI] @@ -101,16 +101,16 @@ def test_frame_size(using_opengl_renderer, tmp_path): frame_width = 10 """, ) - tmp_cfg.close() - config.digest_file(tmp_cfg.name) + tmp_cfg.close() + config.digest_file(tmp_cfg.name) - np.testing.assert_allclose(config.aspect_ratio, 1.0) - # if both are specified in the cfg file, the aspect ratio is ignored - np.testing.assert_allclose(config.frame_height, 10.0) - np.testing.assert_allclose(config.frame_width, 10.0) + np.testing.assert_allclose(config.aspect_ratio, 1.0) + # if both are specified in the cfg file, the aspect ratio is ignored + np.testing.assert_allclose(config.frame_height, 10.0) + np.testing.assert_allclose(config.frame_width, 10.0) -def test_temporary_dry_run(using_opengl_renderer): +def test_temporary_dry_run(config, using_opengl_renderer): """Test that tempconfig correctly restores after setting dry_run.""" assert config["write_to_movie"] assert not config["save_last_frame"] @@ -123,21 +123,20 @@ def test_temporary_dry_run(using_opengl_renderer): assert not config["save_last_frame"] -def test_dry_run_with_png_format(using_opengl_renderer): +def test_dry_run_with_png_format(config, using_opengl_renderer, dry_run): """Test that there are no exceptions when running a png without output""" - with tempconfig( - {"dry_run": True, "write_to_movie": False, "disable_caching": True} - ): - assert config["dry_run"] is True - scene = MyScene() - scene.render() + config.disable_caching = True + assert config["dry_run"] is True + scene = MyScene() + scene.render() -def test_dry_run_with_png_format_skipped_animations(using_opengl_renderer): +def test_dry_run_with_png_format_skipped_animations( + config, using_opengl_renderer, dry_run +): """Test that there are no exceptions when running a png without output and skipped animations""" - with tempconfig( - {"dry_run": True, "write_to_movie": False, "disable_caching": True} - ): - assert config["dry_run"] is True - scene = MyScene(skip_animations=True) - scene.render() + config.write_to_movie = False + config.disable_caching = True + assert config["dry_run"] is True + scene = MyScene(skip_animations=True) + scene.render() diff --git a/tests/opengl/test_coordinate_system_opengl.py b/tests/opengl/test_coordinate_system_opengl.py index ed596d7e9d..c9f5cc81b6 100644 --- a/tests/opengl/test_coordinate_system_opengl.py +++ b/tests/opengl/test_coordinate_system_opengl.py @@ -20,6 +20,10 @@ tempconfig, ) from manim import CoordinateSystem as CS +from manim.utils.color import BLUE, GREEN, ORANGE, RED, YELLOW +from manim.utils.testing.frames_comparison import frames_comparison + +__module_test__ = "coordinate_system_opengl" def test_initial_config(using_opengl_renderer): @@ -55,7 +59,7 @@ def test_dimension(using_opengl_renderer): def test_abstract_base_class(using_opengl_renderer): """Check that CoordinateSystem has some abstract methods.""" - with pytest.raises(Exception): + with pytest.raises(NotImplementedError): CS().get_axes() @@ -138,3 +142,33 @@ def test_input_to_graph_point(using_opengl_renderer): # test the line_graph implementation position = np.around(ax.input_to_graph_point(x=PI, graph=line_graph), decimals=4) np.testing.assert_array_equal(position, (2.6928, 1.2876, 0)) + + +@frames_comparison +def test_gradient_line_graph_x_axis(scene, using_opengl_renderer): + """Test that using `colorscale` generates a line whose gradient matches the y-axis""" + axes = Axes(x_range=[-3, 3], y_range=[-3, 3]) + + curve = axes.plot( + lambda x: 0.1 * x**3, + x_range=(-3, 3, 0.001), + colorscale=[BLUE, GREEN, YELLOW, ORANGE, RED], + colorscale_axis=0, + ) + + scene.add(axes, curve) + + +@frames_comparison +def test_gradient_line_graph_y_axis(scene, using_opengl_renderer): + """Test that using `colorscale` generates a line whose gradient matches the y-axis""" + axes = Axes(x_range=[-3, 3], y_range=[-3, 3]) + + curve = axes.plot( + lambda x: 0.1 * x**3, + x_range=(-3, 3, 0.001), + colorscale=[BLUE, GREEN, YELLOW, ORANGE, RED], + colorscale_axis=1, + ) + + scene.add(axes, curve) diff --git a/tests/opengl/test_copy_opengl.py b/tests/opengl/test_copy_opengl.py index db2e06dba4..504b7f26a5 100644 --- a/tests/opengl/test_copy_opengl.py +++ b/tests/opengl/test_copy_opengl.py @@ -2,7 +2,7 @@ from pathlib import Path -from manim import BraceLabel, config +from manim import BraceLabel from manim.mobject.opengl.opengl_mobject import OpenGLMobject @@ -19,7 +19,7 @@ def test_opengl_mobject_copy(using_opengl_renderer): assert orig.submobjects[i] is not copy.submobjects[i] -def test_bracelabel_copy(using_opengl_renderer, tmp_path): +def test_bracelabel_copy(config, using_opengl_renderer, tmp_path): """Test that a copy is a deepcopy.""" # For this test to work, we need to tweak some folders temporarily original_text_dir = config["text_dir"] diff --git a/tests/opengl/test_ipython_magic_opengl.py b/tests/opengl/test_ipython_magic_opengl.py index ad1c61a6b5..2d4617af0f 100644 --- a/tests/opengl/test_ipython_magic_opengl.py +++ b/tests/opengl/test_ipython_magic_opengl.py @@ -2,36 +2,29 @@ import re -from manim import config, tempconfig from manim.utils.ipython_magic import _generate_file_name -def test_jupyter_file_naming(): +def test_jupyter_file_naming(config, using_opengl_renderer): """Check the format of file names for jupyter""" scene_name = "SimpleScene" expected_pattern = r"[0-9a-zA-Z_]+[@_-]\d\d\d\d-\d\d-\d\d[@_-]\d\d-\d\d-\d\d" - current_renderer = config.renderer - with tempconfig({"scene_names": [scene_name], "renderer": "opengl"}): - file_name = _generate_file_name() - match = re.match(expected_pattern, file_name) - assert scene_name in file_name, ( - "Expected file to contain " + scene_name + " but got " + file_name - ) - assert match, "file name does not match expected pattern " + expected_pattern - # needs manually set back to avoid issues across tests - config.renderer = current_renderer + config.scene_names = [scene_name] + file_name = _generate_file_name() + match = re.match(expected_pattern, file_name) + assert scene_name in file_name, ( + "Expected file to contain " + scene_name + " but got " + file_name + ) + assert match, "file name does not match expected pattern " + expected_pattern -def test_jupyter_file_output(tmp_path): +def test_jupyter_file_output(tmp_path, config, using_opengl_renderer): """Check the jupyter file naming is valid and can be created""" scene_name = "SimpleScene" - current_renderer = config.renderer - with tempconfig({"scene_names": [scene_name], "renderer": "opengl"}): - file_name = _generate_file_name() - actual_path = tmp_path.with_name(file_name) - with actual_path.open("w") as outfile: - outfile.write("") - assert actual_path.exists() - assert actual_path.is_file() - # needs manually set back to avoid issues across tests - config.renderer = current_renderer + config.scene_names = [scene_name] + file_name = _generate_file_name() + actual_path = tmp_path.with_name(file_name) + with actual_path.open("w") as outfile: + outfile.write("") + assert actual_path.exists() + assert actual_path.is_file() diff --git a/tests/opengl/test_number_line_opengl.py b/tests/opengl/test_number_line_opengl.py index 4092e4bfd1..5eb52eb914 100644 --- a/tests/opengl/test_number_line_opengl.py +++ b/tests/opengl/test_number_line_opengl.py @@ -8,7 +8,8 @@ def test_unit_vector(): """Check if the magnitude of unit vector along - the NumberLine is equal to its unit_size.""" + the NumberLine is equal to its unit_size. + """ axis1 = NumberLine(unit_size=0.4) axis2 = NumberLine(x_range=[-2, 5], length=12) for axis in (axis1, axis2): @@ -17,7 +18,8 @@ def test_unit_vector(): def test_decimal_determined_by_step(): """Checks that step size is considered when determining the number of decimal - places.""" + places. + """ axis = NumberLine(x_range=[-2, 2, 0.5]) expected_decimal_places = 1 actual_decimal_places = axis.decimal_number_config["num_decimal_places"] diff --git a/tests/opengl/test_numbers_opengl.py b/tests/opengl/test_numbers_opengl.py index 9bc2ddd13f..78cd4fac0d 100644 --- a/tests/opengl/test_numbers_opengl.py +++ b/tests/opengl/test_numbers_opengl.py @@ -5,7 +5,8 @@ def test_font_size(): """Test that DecimalNumber returns the correct font_size value - after being scaled.""" + after being scaled. + """ num = DecimalNumber(0).scale(0.3) assert round(num.font_size, 5) == 14.4 diff --git a/tests/opengl/test_opengl_vectorized_mobject.py b/tests/opengl/test_opengl_vectorized_mobject.py index 6f73ef0265..ae41f83b61 100644 --- a/tests/opengl/test_opengl_vectorized_mobject.py +++ b/tests/opengl/test_opengl_vectorized_mobject.py @@ -3,7 +3,7 @@ import numpy as np import pytest -from manim import Circle, Line, Square, VDict, VGroup +from manim import Circle, Line, Square, VDict, VGroup, VMobject from manim.mobject.opengl.opengl_mobject import OpenGLMobject from manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVMobject @@ -90,14 +90,14 @@ def test_vgroup_init(using_opengl_renderer): VGroup(3.0) assert str(init_with_float_info.value) == ( "Only values of type OpenGLVMobject can be added as submobjects of " - "VGroup, but the value 3.0 (at index 0) is of type float." + "VGroup, but the value 3.0 (at index 0 of parameter 0) is of type float." ) with pytest.raises(TypeError) as init_with_mob_info: VGroup(OpenGLMobject()) assert str(init_with_mob_info.value) == ( "Only values of type OpenGLVMobject can be added as submobjects of " - "VGroup, but the value OpenGLMobject (at index 0) is of type " + "VGroup, but the value OpenGLMobject (at index 0 of parameter 0) is of type " "OpenGLMobject. You can try adding this value into a Group instead." ) @@ -105,11 +105,69 @@ def test_vgroup_init(using_opengl_renderer): VGroup(OpenGLVMobject(), OpenGLMobject()) assert str(init_with_vmob_and_mob_info.value) == ( "Only values of type OpenGLVMobject can be added as submobjects of " - "VGroup, but the value OpenGLMobject (at index 1) is of type " + "VGroup, but the value OpenGLMobject (at index 0 of parameter 1) is of type " "OpenGLMobject. You can try adding this value into a Group instead." ) +def test_vgroup_init_with_iterable(using_opengl_renderer): + """Test VGroup instantiation with an iterable type.""" + + def type_generator(type_to_generate, n): + return (type_to_generate() for _ in range(n)) + + def mixed_type_generator(major_type, minor_type, minor_type_positions, n): + return ( + minor_type() if i in minor_type_positions else major_type() + for i in range(n) + ) + + obj = VGroup(OpenGLVMobject()) + assert len(obj.submobjects) == 1 + + obj = VGroup(type_generator(OpenGLVMobject, 38)) + assert len(obj.submobjects) == 38 + + obj = VGroup( + OpenGLVMobject(), + [OpenGLVMobject(), OpenGLVMobject()], + type_generator(OpenGLVMobject, 38), + ) + assert len(obj.submobjects) == 41 + + # A VGroup cannot be initialised with an iterable containing a OpenGLMobject + with pytest.raises(TypeError) as init_with_mob_iterable: + VGroup(type_generator(OpenGLMobject, 5)) + assert str(init_with_mob_iterable.value) == ( + "Only values of type OpenGLVMobject can be added as submobjects of VGroup, " + "but the value OpenGLMobject (at index 0 of parameter 0) is of type OpenGLMobject." + ) + + # A VGroup cannot be initialised with an iterable containing a OpenGLMobject in any position + with pytest.raises(TypeError) as init_with_mobs_and_vmobs_iterable: + VGroup(mixed_type_generator(OpenGLVMobject, OpenGLMobject, [3, 5], 7)) + assert str(init_with_mobs_and_vmobs_iterable.value) == ( + "Only values of type OpenGLVMobject can be added as submobjects of VGroup, " + "but the value OpenGLMobject (at index 3 of parameter 0) is of type OpenGLMobject." + ) + + # A VGroup cannot be initialised with an iterable containing non OpenGLVMobject's in any position + with pytest.raises(TypeError) as init_with_float_and_vmobs_iterable: + VGroup(mixed_type_generator(OpenGLVMobject, float, [6, 7], 9)) + assert str(init_with_float_and_vmobs_iterable.value) == ( + "Only values of type OpenGLVMobject can be added as submobjects of VGroup, " + "but the value 0.0 (at index 6 of parameter 0) is of type float." + ) + + # A VGroup cannot be initialised with an iterable containing both OpenGLVMobject's and VMobject's + with pytest.raises(TypeError) as init_with_mobs_and_vmobs_iterable: + VGroup(mixed_type_generator(OpenGLVMobject, VMobject, [3, 5], 7)) + assert str(init_with_mobs_and_vmobs_iterable.value) == ( + "Only values of type OpenGLVMobject can be added as submobjects of VGroup, " + "but the value VMobject (at index 3 of parameter 0) is of type VMobject." + ) + + def test_vgroup_add(using_opengl_renderer): """Test the VGroup add method.""" obj = VGroup() @@ -123,7 +181,7 @@ def test_vgroup_add(using_opengl_renderer): obj.add(3) assert str(add_int_info.value) == ( "Only values of type OpenGLVMobject can be added as submobjects of " - "VGroup, but the value 3 (at index 0) is of type int." + "VGroup, but the value 3 (at index 0 of parameter 0) is of type int." ) assert len(obj.submobjects) == 1 @@ -133,7 +191,7 @@ def test_vgroup_add(using_opengl_renderer): obj.add(OpenGLMobject()) assert str(add_mob_info.value) == ( "Only values of type OpenGLVMobject can be added as submobjects of " - "VGroup, but the value OpenGLMobject (at index 0) is of type " + "VGroup, but the value OpenGLMobject (at index 0 of parameter 0) is of type " "OpenGLMobject. You can try adding this value into a Group instead." ) assert len(obj.submobjects) == 1 @@ -143,7 +201,7 @@ def test_vgroup_add(using_opengl_renderer): obj.add(OpenGLVMobject(), OpenGLMobject()) assert str(add_vmob_and_mob_info.value) == ( "Only values of type OpenGLVMobject can be added as submobjects of " - "VGroup, but the value OpenGLMobject (at index 1) is of type " + "VGroup, but the value OpenGLMobject (at index 0 of parameter 1) is of type " "OpenGLMobject. You can try adding this value into a Group instead." ) assert len(obj.submobjects) == 1 diff --git a/tests/opengl/test_sound_opengl.py b/tests/opengl/test_sound_opengl.py index 40ec914de5..cc4ccceaec 100644 --- a/tests/opengl/test_sound_opengl.py +++ b/tests/opengl/test_sound_opengl.py @@ -13,14 +13,12 @@ def test_add_sound(using_opengl_renderer, tmpdir): # create sound file sound_loc = Path(tmpdir, "noise.wav") - f = wave.open(str(sound_loc), "w") - f.setparams((2, 2, 44100, 0, "NONE", "not compressed")) - for _ in range(22050): # half a second of sound - packed_value = struct.pack("h", 14242) - f.writeframes(packed_value) - f.writeframes(packed_value) - - f.close() + with wave.open(str(sound_loc), "w") as f: + f.setparams((2, 2, 44100, 0, "NONE", "not compressed")) + for _ in range(22050): # half a second of sound + packed_value = struct.pack("h", 14242) + f.writeframes(packed_value) + f.writeframes(packed_value) scene = Scene() scene.add_sound(sound_loc) diff --git a/tests/opengl/test_texmobject_opengl.py b/tests/opengl/test_texmobject_opengl.py index 4fe5a76f81..e9826f9d8f 100644 --- a/tests/opengl/test_texmobject_opengl.py +++ b/tests/opengl/test_texmobject_opengl.py @@ -4,21 +4,21 @@ import pytest -from manim import MathTex, SingleStringMathTex, Tex, config +from manim import MathTex, SingleStringMathTex, Tex -def test_MathTex(using_opengl_renderer): +def test_MathTex(config, using_opengl_renderer): MathTex("a^2 + b^2 = c^2") assert Path(config.media_dir, "Tex", "e4be163a00cf424f.svg").exists() -def test_SingleStringMathTex(using_opengl_renderer): +def test_SingleStringMathTex(config, using_opengl_renderer): SingleStringMathTex("test") assert Path(config.media_dir, "Tex", "8ce17c7f5013209f.svg").exists() @pytest.mark.parametrize( # : PT006 - "text_input,length_sub", + ("text_input", "length_sub"), [("{{ a }} + {{ b }} = {{ c }}", 5), (r"\frac{1}{a+b\sqrt{2}}", 1)], ) def test_double_braces_testing(using_opengl_renderer, text_input, length_sub): @@ -26,7 +26,7 @@ def test_double_braces_testing(using_opengl_renderer, text_input, length_sub): assert len(t1.submobjects) == length_sub -def test_tex(using_opengl_renderer): +def test_tex(config, using_opengl_renderer): Tex("The horse does not eat cucumber salad.") assert Path(config.media_dir, "Tex", "c3945e23e546c95a.svg").exists() @@ -87,7 +87,8 @@ def test_tex_size(using_opengl_renderer): def test_font_size(using_opengl_renderer): """Test that tex_mobject classes return - the correct font_size value after being scaled.""" + the correct font_size value after being scaled. + """ string = MathTex(0).scale(0.3) assert round(string.font_size, 5) == 14.4 diff --git a/tests/opengl/test_text_mobject_opengl.py b/tests/opengl/test_text_mobject_opengl.py index 9fa9415314..db6a6532f4 100644 --- a/tests/opengl/test_text_mobject_opengl.py +++ b/tests/opengl/test_text_mobject_opengl.py @@ -5,7 +5,8 @@ def test_font_size(using_opengl_renderer): """Test that Text and MarkupText return the - correct font_size value after being scaled.""" + correct font_size value after being scaled. + """ text_string = Text("0").scale(0.3) markuptext_string = MarkupText("0").scale(0.3) diff --git a/tests/test_config.py b/tests/test_config.py index 0c60d59b10..0703b31bf4 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -4,13 +4,14 @@ from pathlib import Path import numpy as np +import pytest -from manim import WHITE, Scene, Square, Tex, Text, config, tempconfig +from manim import WHITE, Scene, Square, Tex, Text, tempconfig from manim._config.utils import ManimConfig from tests.assert_utils import assert_dir_exists, assert_dir_filled, assert_file_exists -def test_tempconfig(): +def test_tempconfig(config): """Test the tempconfig context manager.""" original = config.copy() @@ -33,6 +34,20 @@ def test_tempconfig(): assert config[k] == v +@pytest.mark.parametrize( + ("format", "expected_file_extension"), + [ + ("mp4", ".mp4"), + ("webm", ".webm"), + ("mov", ".mov"), + ("gif", ".mp4"), + ], +) +def test_resolve_file_extensions(config, format, expected_file_extension): + config.format = format + assert config.movie_file_extension == expected_file_extension + + class MyScene(Scene): def construct(self): self.add(Square()) @@ -41,39 +56,51 @@ def construct(self): self.wait(1) -def test_transparent(): +def test_transparent(config): """Test the 'transparent' config option.""" - orig_verbosity = config["verbosity"] - config["verbosity"] = "ERROR" + config.verbosity = "ERROR" + config.dry_run = True - with tempconfig({"dry_run": True}): - scene = MyScene() - scene.render() - frame = scene.renderer.get_frame() + scene = MyScene() + scene.render() + frame = scene.renderer.get_frame() np.testing.assert_allclose(frame[0, 0], [0, 0, 0, 255]) - with tempconfig({"transparent": True, "dry_run": True}): - scene = MyScene() - scene.render() - frame = scene.renderer.get_frame() - np.testing.assert_allclose(frame[0, 0], [0, 0, 0, 0]) + config.transparent = True + + scene = MyScene() + scene.render() + frame = scene.renderer.get_frame() + np.testing.assert_allclose(frame[0, 0], [0, 0, 0, 0]) + - config["verbosity"] = orig_verbosity +def test_transparent_by_background_opacity(config, dry_run): + config.background_opacity = 0.5 + assert config.transparent is True + scene = MyScene() + scene.render() + frame = scene.renderer.get_frame() + np.testing.assert_allclose(frame[0, 0], [0, 0, 0, 127]) + assert config.movie_file_extension == ".mov" + assert config.transparent is True -def test_background_color(): + +def test_background_color(config): """Test the 'background_color' config option.""" - with tempconfig({"background_color": WHITE, "verbosity": "ERROR", "dry_run": True}): - scene = MyScene() - scene.render() - frame = scene.renderer.get_frame() - np.testing.assert_allclose(frame[0, 0], [255, 255, 255, 255]) + config.background_color = WHITE + config.verbosity = "ERROR" + config.dry_run = True + + scene = MyScene() + scene.render() + frame = scene.renderer.get_frame() + np.testing.assert_allclose(frame[0, 0], [255, 255, 255, 255]) -def test_digest_file(tmp_path): +def test_digest_file(tmp_path, config): """Test that a config file can be digested programmatically.""" - with tempconfig({}): - tmp_cfg = tempfile.NamedTemporaryFile("w", dir=tmp_path, delete=False) + with tempfile.NamedTemporaryFile("w", dir=tmp_path, delete=False) as tmp_cfg: tmp_cfg.write( """ [CLI] @@ -83,65 +110,52 @@ def test_digest_file(tmp_path): frame_height = 10 """, ) - tmp_cfg.close() - config.digest_file(tmp_cfg.name) + config.digest_file(tmp_cfg.name) - assert config.get_dir("media_dir") == Path("this_is_my_favorite_path") - assert config.get_dir("video_dir") == Path("this_is_my_favorite_path/videos") - assert config.get_dir("sections_dir", scene_name="test") == Path( - "this_is_my_favorite_path/test/prepare_for_unforeseen_consequences" - ) + assert config.get_dir("media_dir") == Path("this_is_my_favorite_path") + assert config.get_dir("video_dir") == Path("this_is_my_favorite_path/videos") + assert config.get_dir("sections_dir", scene_name="test") == Path( + "this_is_my_favorite_path/test/prepare_for_unforeseen_consequences" + ) -def test_custom_dirs(tmp_path): - with tempconfig( - { - "media_dir": tmp_path, - "save_sections": True, - "log_to_file": True, - "frame_rate": 15, - "pixel_height": 854, - "pixel_width": 480, - "sections_dir": "{media_dir}/test_sections", - "video_dir": "{media_dir}/test_video", - "partial_movie_dir": "{media_dir}/test_partial_movie_dir", - "images_dir": "{media_dir}/test_images", - "text_dir": "{media_dir}/test_text", - "tex_dir": "{media_dir}/test_tex", - "log_dir": "{media_dir}/test_log", - } - ): - scene = MyScene() - scene.render() - tmp_path = Path(tmp_path) - assert_dir_filled(tmp_path / "test_sections") - assert_file_exists(tmp_path / "test_sections/MyScene.json") - - assert_dir_filled(tmp_path / "test_video") - assert_file_exists(tmp_path / "test_video/MyScene.mp4") - - assert_dir_filled(tmp_path / "test_partial_movie_dir") - assert_file_exists( - tmp_path / "test_partial_movie_dir/partial_movie_file_list.txt" - ) +def test_custom_dirs(tmp_path, config): + config.media_dir = tmp_path + config.save_sections = True + config.log_to_file = True + config.frame_rate = 15 + config.pixel_height = 854 + config.pixel_width = 480 + config.sections_dir = "{media_dir}/test_sections" + config.video_dir = "{media_dir}/test_video" + config.partial_movie_dir = "{media_dir}/test_partial_movie_dir" + config.images_dir = "{media_dir}/test_images" + config.text_dir = "{media_dir}/test_text" + config.tex_dir = "{media_dir}/test_tex" + config.log_dir = "{media_dir}/test_log" - # TODO: another example with image output would be nice - assert_dir_exists(tmp_path / "test_images") + scene = MyScene() + scene.render() + tmp_path = Path(tmp_path) + assert_dir_filled(tmp_path / "test_sections") + assert_file_exists(tmp_path / "test_sections/MyScene.json") - assert_dir_filled(tmp_path / "test_text") - assert_dir_filled(tmp_path / "test_tex") - assert_dir_filled(tmp_path / "test_log") + assert_dir_filled(tmp_path / "test_video") + assert_file_exists(tmp_path / "test_video/MyScene.mp4") + assert_dir_filled(tmp_path / "test_partial_movie_dir") + assert_file_exists(tmp_path / "test_partial_movie_dir/partial_movie_file_list.txt") -def test_frame_size(tmp_path): - """Test that the frame size can be set via config file.""" - np.testing.assert_allclose( - config.aspect_ratio, config.pixel_width / config.pixel_height - ) - np.testing.assert_allclose(config.frame_height, 8.0) + # TODO: another example with image output would be nice + assert_dir_exists(tmp_path / "test_images") + + assert_dir_filled(tmp_path / "test_text") + assert_dir_filled(tmp_path / "test_tex") + assert_dir_filled(tmp_path / "test_log") - with tempconfig({}): - tmp_cfg = tempfile.NamedTemporaryFile("w", dir=tmp_path, delete=False) + +def test_pixel_dimensions(tmp_path, config): + with tempfile.NamedTemporaryFile("w", dir=tmp_path, delete=False) as tmp_cfg: tmp_cfg.write( """ [CLI] @@ -149,17 +163,23 @@ def test_frame_size(tmp_path): pixel_width = 10 """, ) - tmp_cfg.close() - config.digest_file(tmp_cfg.name) + config.digest_file(tmp_cfg.name) - # aspect ratio is set using pixel measurements - np.testing.assert_allclose(config.aspect_ratio, 1.0) - # if not specified in the cfg file, frame_width is set using the aspect ratio - np.testing.assert_allclose(config.frame_height, 8.0) - np.testing.assert_allclose(config.frame_width, 8.0) + # aspect ratio is set using pixel measurements + np.testing.assert_allclose(config.aspect_ratio, 1.0) + # if not specified in the cfg file, frame_width is set using the aspect ratio + np.testing.assert_allclose(config.frame_height, 8.0) + np.testing.assert_allclose(config.frame_width, 8.0) - with tempconfig({}): - tmp_cfg = tempfile.NamedTemporaryFile("w", dir=tmp_path, delete=False) + +def test_frame_size(tmp_path, config): + """Test that the frame size can be set via config file.""" + np.testing.assert_allclose( + config.aspect_ratio, config.pixel_width / config.pixel_height + ) + np.testing.assert_allclose(config.frame_height, 8.0) + + with tempfile.NamedTemporaryFile("w", dir=tmp_path, delete=False) as tmp_cfg: tmp_cfg.write( """ [CLI] @@ -169,16 +189,15 @@ def test_frame_size(tmp_path): frame_width = 10 """, ) - tmp_cfg.close() - config.digest_file(tmp_cfg.name) + config.digest_file(tmp_cfg.name) - np.testing.assert_allclose(config.aspect_ratio, 1.0) - # if both are specified in the cfg file, the aspect ratio is ignored - np.testing.assert_allclose(config.frame_height, 10.0) - np.testing.assert_allclose(config.frame_width, 10.0) + np.testing.assert_allclose(config.aspect_ratio, 1.0) + # if both are specified in the cfg file, the aspect ratio is ignored + np.testing.assert_allclose(config.frame_height, 10.0) + np.testing.assert_allclose(config.frame_width, 10.0) -def test_temporary_dry_run(): +def test_temporary_dry_run(config): """Test that tempconfig correctly restores after setting dry_run.""" assert config["write_to_movie"] assert not config["save_last_frame"] @@ -191,40 +210,58 @@ def test_temporary_dry_run(): assert not config["save_last_frame"] -def test_dry_run_with_png_format(): +def test_dry_run_with_png_format(config, dry_run): """Test that there are no exceptions when running a png without output""" - with tempconfig( - {"dry_run": True, "write_to_movie": False, "disable_caching": True} - ): - assert config["dry_run"] is True - scene = MyScene() - scene.render() + config.write_to_movie = False + config.disable_caching = True + assert config.dry_run is True + scene = MyScene() + scene.render() -def test_dry_run_with_png_format_skipped_animations(): +def test_dry_run_with_png_format_skipped_animations(config, dry_run): """Test that there are no exceptions when running a png without output and skipped animations""" - with tempconfig( - {"dry_run": True, "write_to_movie": False, "disable_caching": True} - ): - assert config["dry_run"] is True - scene = MyScene(skip_animations=True) - scene.render() + config.write_to_movie = False + config.disable_caching = True + assert config["dry_run"] is True + scene = MyScene(skip_animations=True) + scene.render() def test_tex_template_file(tmp_path): """Test that a custom tex template file can be set from a config file.""" tex_file = Path(tmp_path / "my_template.tex") tex_file.write_text("Hello World!") - tmp_cfg = tempfile.NamedTemporaryFile("w", dir=tmp_path, delete=False) - tmp_cfg.write( - f""" - [CLI] - tex_template_file = {tex_file} - """, - ) - tmp_cfg.close() + with tempfile.NamedTemporaryFile("w", dir=tmp_path, delete=False) as tmp_cfg: + tmp_cfg.write( + f""" + [CLI] + tex_template_file = {tex_file} + """, + ) custom_config = ManimConfig().digest_file(tmp_cfg.name) assert Path(custom_config.tex_template_file) == tex_file assert custom_config.tex_template.body == "Hello World!" + + +def test_from_to_animations_only_first_animation(config): + config: ManimConfig + config.from_animation_number = 0 + config.upto_animation_number = 0 + + class SceneWithTwoAnimations(Scene): + def construct(self): + self.after_first_animation = False + s = Square() + self.add(s) + self.play(s.animate.scale(2)) + self.renderer.update_skipping_status() + self.after_first_animation = True + self.play(s.animate.scale(2)) + + scene = SceneWithTwoAnimations() + scene.render() + + assert scene.after_first_animation is False diff --git a/tests/test_graphical_units/conftest.py b/tests/test_graphical_units/conftest.py index 9a00b02648..3314541023 100644 --- a/tests/test_graphical_units/conftest.py +++ b/tests/test_graphical_units/conftest.py @@ -10,4 +10,4 @@ def show_diff(request): @pytest.fixture(params=[True, False]) def use_vectorized(request): - yield request.param + return request.param diff --git a/tests/test_graphical_units/control_data/coordinate_system/gradient_line_graph_x_axis.npz b/tests/test_graphical_units/control_data/coordinate_system/gradient_line_graph_x_axis.npz new file mode 100644 index 0000000000..6efda8b2e0 Binary files /dev/null and b/tests/test_graphical_units/control_data/coordinate_system/gradient_line_graph_x_axis.npz differ diff --git a/tests/test_graphical_units/control_data/coordinate_system/gradient_line_graph_y_axis.npz b/tests/test_graphical_units/control_data/coordinate_system/gradient_line_graph_y_axis.npz new file mode 100644 index 0000000000..3c7afcda7d Binary files /dev/null and b/tests/test_graphical_units/control_data/coordinate_system/gradient_line_graph_y_axis.npz differ diff --git a/tests/test_graphical_units/control_data/geometry/ConvexHull.npz b/tests/test_graphical_units/control_data/geometry/ConvexHull.npz new file mode 100644 index 0000000000..6ccb415ee0 Binary files /dev/null and b/tests/test_graphical_units/control_data/geometry/ConvexHull.npz differ diff --git a/tests/test_graphical_units/control_data/geometry/LabeledPolygram.npz b/tests/test_graphical_units/control_data/geometry/LabeledPolygram.npz new file mode 100644 index 0000000000..2a14d5f2be Binary files /dev/null and b/tests/test_graphical_units/control_data/geometry/LabeledPolygram.npz differ diff --git a/tests/test_graphical_units/control_data/polyhedra/ConvexHull3D.npz b/tests/test_graphical_units/control_data/polyhedra/ConvexHull3D.npz new file mode 100644 index 0000000000..eaa726b0fb Binary files /dev/null and b/tests/test_graphical_units/control_data/polyhedra/ConvexHull3D.npz differ diff --git a/tests/test_graphical_units/control_data/threed/AddFixedInFrameMobjects.npz b/tests/test_graphical_units/control_data/threed/AddFixedInFrameMobjects.npz index 08ca1e595a..7387d9f235 100644 Binary files a/tests/test_graphical_units/control_data/threed/AddFixedInFrameMobjects.npz and b/tests/test_graphical_units/control_data/threed/AddFixedInFrameMobjects.npz differ diff --git a/tests/test_graphical_units/control_data/threed/AmbientCameraMove.npz b/tests/test_graphical_units/control_data/threed/AmbientCameraMove.npz index 4e6e101e7e..f91b970ef8 100644 Binary files a/tests/test_graphical_units/control_data/threed/AmbientCameraMove.npz and b/tests/test_graphical_units/control_data/threed/AmbientCameraMove.npz differ diff --git a/tests/test_graphical_units/control_data/threed/Arrow3D.npz b/tests/test_graphical_units/control_data/threed/Arrow3D.npz index a4fc4c5106..a4a6c9b873 100644 Binary files a/tests/test_graphical_units/control_data/threed/Arrow3D.npz and b/tests/test_graphical_units/control_data/threed/Arrow3D.npz differ diff --git a/tests/test_graphical_units/control_data/threed/Axes.npz b/tests/test_graphical_units/control_data/threed/Axes.npz index 206b28697b..287a866dd8 100644 Binary files a/tests/test_graphical_units/control_data/threed/Axes.npz and b/tests/test_graphical_units/control_data/threed/Axes.npz differ diff --git a/tests/test_graphical_units/control_data/threed/CameraMove.npz b/tests/test_graphical_units/control_data/threed/CameraMove.npz index 23ccfb73b6..a884913567 100644 Binary files a/tests/test_graphical_units/control_data/threed/CameraMove.npz and b/tests/test_graphical_units/control_data/threed/CameraMove.npz differ diff --git a/tests/test_graphical_units/control_data/threed/CameraMoveAxes.npz b/tests/test_graphical_units/control_data/threed/CameraMoveAxes.npz index 8628c6cb04..fc365464f7 100644 Binary files a/tests/test_graphical_units/control_data/threed/CameraMoveAxes.npz and b/tests/test_graphical_units/control_data/threed/CameraMoveAxes.npz differ diff --git a/tests/test_graphical_units/control_data/threed/Cone.npz b/tests/test_graphical_units/control_data/threed/Cone.npz index 66f315afcd..59a856f5ac 100644 Binary files a/tests/test_graphical_units/control_data/threed/Cone.npz and b/tests/test_graphical_units/control_data/threed/Cone.npz differ diff --git a/tests/test_graphical_units/control_data/threed/Cube.npz b/tests/test_graphical_units/control_data/threed/Cube.npz index 8a7d147db4..a955b37eef 100644 Binary files a/tests/test_graphical_units/control_data/threed/Cube.npz and b/tests/test_graphical_units/control_data/threed/Cube.npz differ diff --git a/tests/test_graphical_units/control_data/threed/Cylinder.npz b/tests/test_graphical_units/control_data/threed/Cylinder.npz index f253885453..bd42a1d91e 100644 Binary files a/tests/test_graphical_units/control_data/threed/Cylinder.npz and b/tests/test_graphical_units/control_data/threed/Cylinder.npz differ diff --git a/tests/test_graphical_units/control_data/threed/Dot3D.npz b/tests/test_graphical_units/control_data/threed/Dot3D.npz index 4593a97c0b..351dab60ee 100644 Binary files a/tests/test_graphical_units/control_data/threed/Dot3D.npz and b/tests/test_graphical_units/control_data/threed/Dot3D.npz differ diff --git a/tests/test_graphical_units/control_data/threed/Line3D.npz b/tests/test_graphical_units/control_data/threed/Line3D.npz index ccf2bb20af..174b9a06e4 100644 Binary files a/tests/test_graphical_units/control_data/threed/Line3D.npz and b/tests/test_graphical_units/control_data/threed/Line3D.npz differ diff --git a/tests/test_graphical_units/control_data/threed/MovingVertices.npz b/tests/test_graphical_units/control_data/threed/MovingVertices.npz index 04006a76ed..2da8e3a251 100644 Binary files a/tests/test_graphical_units/control_data/threed/MovingVertices.npz and b/tests/test_graphical_units/control_data/threed/MovingVertices.npz differ diff --git a/tests/test_graphical_units/control_data/threed/Sphere.npz b/tests/test_graphical_units/control_data/threed/Sphere.npz index 58cd442676..c007a0baa8 100644 Binary files a/tests/test_graphical_units/control_data/threed/Sphere.npz and b/tests/test_graphical_units/control_data/threed/Sphere.npz differ diff --git a/tests/test_graphical_units/control_data/threed/SurfaceColorscale.npz b/tests/test_graphical_units/control_data/threed/SurfaceColorscale.npz index 3a8539352e..e3b4a5e957 100644 Binary files a/tests/test_graphical_units/control_data/threed/SurfaceColorscale.npz and b/tests/test_graphical_units/control_data/threed/SurfaceColorscale.npz differ diff --git a/tests/test_graphical_units/control_data/threed/Torus.npz b/tests/test_graphical_units/control_data/threed/Torus.npz index e50dd86de4..f973dea171 100644 Binary files a/tests/test_graphical_units/control_data/threed/Torus.npz and b/tests/test_graphical_units/control_data/threed/Torus.npz differ diff --git a/tests/test_graphical_units/control_data/threed/Y_Direction.npz b/tests/test_graphical_units/control_data/threed/Y_Direction.npz index b4f0b39e54..7e3187910c 100644 Binary files a/tests/test_graphical_units/control_data/threed/Y_Direction.npz and b/tests/test_graphical_units/control_data/threed/Y_Direction.npz differ diff --git a/tests/test_graphical_units/test_animation.py b/tests/test_graphical_units/test_animation.py new file mode 100644 index 0000000000..3758e4985b --- /dev/null +++ b/tests/test_graphical_units/test_animation.py @@ -0,0 +1,16 @@ +from manim import * +from manim.animation.animation import DEFAULT_ANIMATION_RUN_TIME + +__module_test__ = "animation" + + +def test_animation_set_default(): + s = Square() + Rotate.set_default(run_time=100) + anim = Rotate(s) + assert anim.run_time == 100 + anim = Rotate(s, run_time=5) + assert anim.run_time == 5 + Rotate.set_default() + anim = Rotate(s) + assert anim.run_time == DEFAULT_ANIMATION_RUN_TIME diff --git a/tests/test_graphical_units/test_coordinate_systems.py b/tests/test_graphical_units/test_coordinate_systems.py index d7603f4d00..7d6dad67af 100644 --- a/tests/test_graphical_units/test_coordinate_systems.py +++ b/tests/test_graphical_units/test_coordinate_systems.py @@ -141,3 +141,33 @@ def test_number_plane_log(scene): ) scene.add(VGroup(plane1, plane2).arrange()) + + +@frames_comparison +def test_gradient_line_graph_x_axis(scene): + """Test that using `colorscale` generates a line whose gradient matches the y-axis""" + axes = Axes(x_range=[-3, 3], y_range=[-3, 3]) + + curve = axes.plot( + lambda x: 0.1 * x**3, + x_range=(-3, 3, 0.001), + colorscale=[BLUE, GREEN, YELLOW, ORANGE, RED], + colorscale_axis=0, + ) + + scene.add(axes, curve) + + +@frames_comparison +def test_gradient_line_graph_y_axis(scene): + """Test that using `colorscale` generates a line whose gradient matches the y-axis""" + axes = Axes(x_range=[-3, 3], y_range=[-3, 3]) + + curve = axes.plot( + lambda x: 0.1 * x**3, + x_range=(-3, 3, 0.001), + colorscale=[BLUE, GREEN, YELLOW, ORANGE, RED], + colorscale_axis=1, + ) + + scene.add(axes, curve) diff --git a/tests/test_graphical_units/test_geometry.py b/tests/test_graphical_units/test_geometry.py index 10ea6094e9..fef2ca0951 100644 --- a/tests/test_graphical_units/test_geometry.py +++ b/tests/test_graphical_units/test_geometry.py @@ -138,6 +138,20 @@ def test_RoundedRectangle(scene): scene.add(a) +@frames_comparison +def test_ConvexHull(scene): + a = ConvexHull( + *[ + [-2.7, -0.6, 0], + [0.2, -1.7, 0], + [1.9, 1.2, 0], + [-2.7, 0.9, 0], + [1.6, 2.2, 0], + ] + ) + scene.add(a) + + @frames_comparison def test_Arrange(scene): s1 = Square() @@ -254,9 +268,7 @@ def test_LabeledLine(scene): line = LabeledLine( label="0.5", label_position=0.8, - font_size=20, - label_color=WHITE, - label_frame=True, + label_config={"font_size": 20}, start=LEFT + DOWN, end=RIGHT + UP, ) @@ -266,6 +278,27 @@ def test_LabeledLine(scene): @frames_comparison def test_LabeledArrow(scene): l_arrow = LabeledArrow( - "0.5", start=LEFT * 3, end=RIGHT * 3 + UP * 2, label_position=0.5, font_size=15 + label="0.5", + label_position=0.5, + label_config={"font_size": 15}, + start=LEFT * 3, + end=RIGHT * 3 + UP * 2, ) scene.add(l_arrow) + + +@frames_comparison +def test_LabeledPolygram(scene): + polygram = LabeledPolygram( + [ + [-2.5, -2.5, 0], + [2.5, -2.5, 0], + [2.5, 2.5, 0], + [-2.5, 2.5, 0], + [-2.5, -2.5, 0], + ], + [[-1, -1, 0], [0.5, -1, 0], [0.5, 0.5, 0], [-1, 0.5, 0], [-1, -1, 0]], + [[1, 1, 0], [2, 1, 0], [2, 2, 0], [1, 2, 0], [1, 1, 0]], + label="C", + ) + scene.add(polygram) diff --git a/tests/test_graphical_units/test_polyhedra.py b/tests/test_graphical_units/test_polyhedra.py index bc13676fde..9679bed3a1 100644 --- a/tests/test_graphical_units/test_polyhedra.py +++ b/tests/test_graphical_units/test_polyhedra.py @@ -24,3 +24,17 @@ def test_Icosahedron(scene): @frames_comparison def test_Dodecahedron(scene): scene.add(Dodecahedron()) + + +@frames_comparison +def test_ConvexHull3D(scene): + a = ConvexHull3D( + *[ + [-2.7, -0.6, 3.5], + [0.2, -1.7, -2.8], + [1.9, 1.2, 0.7], + [-2.7, 0.9, 1.9], + [1.6, 2.2, -4.2], + ] + ) + scene.add(a) diff --git a/tests/test_graphical_units/test_tex_mobject.py b/tests/test_graphical_units/test_tex_mobject.py index b229e1cb0f..aabc8e01f9 100644 --- a/tests/test_graphical_units/test_tex_mobject.py +++ b/tests/test_graphical_units/test_tex_mobject.py @@ -7,8 +7,8 @@ @frames_comparison def test_color_inheritance(scene): """Test that Text and MarkupText correctly inherit colour from - their parent class.""" - + their parent class. + """ VMobject.set_default(color=RED) tex = Tex("test color inheritance") mathtex = MathTex("test color inheritance") @@ -24,3 +24,33 @@ def test_set_opacity_by_tex(scene): tex = MathTex("f(x) = y", substrings_to_isolate=["f(x)"]) tex.set_opacity_by_tex("f(x)", 0.2, 0.5) scene.add(tex) + + +def test_preserve_tex_color(): + """Test that Tex preserves original tex colors.""" + template = TexTemplate(preamble=r"\usepackage{xcolor}") + Tex.set_default(tex_template=template) + + txt = Tex(r"\textcolor{red}{Hello} World") + assert len(txt[0].submobjects) == 10 + assert all(char.fill_color.to_hex() == "#FF0000" for char in txt[0][:5]) # "Hello" + assert all( + char.fill_color.to_hex() == WHITE.to_hex() for char in txt[0][-5:] + ) # "World" + + txt = Tex(r"\textcolor{red}{Hello} World", color=BLUE) + assert len(txt[0].submobjects) == 10 + assert all(char.fill_color.to_hex() == "#FF0000" for char in txt[0][:5]) # "Hello" + assert all( + char.fill_color.to_hex() == BLUE.to_hex() for char in txt[0][-5:] + ) # "World" + + Tex.set_default(color=GREEN) + txt = Tex(r"\textcolor{red}{Hello} World") + assert len(txt[0].submobjects) == 10 + assert all(char.fill_color.to_hex() == "#FF0000" for char in txt[0][:5]) # "Hello" + assert all( + char.fill_color.to_hex() == GREEN.to_hex() for char in txt[0][-5:] + ) # "World" + + Tex.set_default() diff --git a/tests/test_graphical_units/test_text.py b/tests/test_graphical_units/test_text.py index ab5d4fbeb1..7c75f8b995 100644 --- a/tests/test_graphical_units/test_text.py +++ b/tests/test_graphical_units/test_text.py @@ -20,7 +20,8 @@ def test_Text2Color(): def test_text_color_inheritance(): """Test that Text and MarkupText correctly inherit colour from - their parent class.""" + their parent class. + """ VMobject.set_default(color=RED) # set both to a singular font so that the tests agree. text = Text("test_color_inheritance", font="Sans") diff --git a/tests/test_graphical_units/test_transform_matching_parts.py b/tests/test_graphical_units/test_transform_matching_parts.py index b5af1fb2a3..3694f51bee 100644 --- a/tests/test_graphical_units/test_transform_matching_parts.py +++ b/tests/test_graphical_units/test_transform_matching_parts.py @@ -12,7 +12,8 @@ def test_TransformMatchingLeavesOneObject(scene): circle = Circle().shift(RIGHT) scene.add(square) scene.play(TransformMatchingShapes(square, circle)) - assert len(scene.mobjects) == 1 and isinstance(scene.mobjects[0], Circle) + assert len(scene.mobjects) == 1 + assert isinstance(scene.mobjects[0], Circle) @frames_comparison(last_frame=False) diff --git a/tests/test_ipython_magic.py b/tests/test_ipython_magic.py index 91d1fba8c2..6452d58de5 100644 --- a/tests/test_ipython_magic.py +++ b/tests/test_ipython_magic.py @@ -2,30 +2,29 @@ import re -from manim import tempconfig from manim.utils.ipython_magic import _generate_file_name -def test_jupyter_file_naming(): +def test_jupyter_file_naming(config): """Check the format of file names for jupyter""" scene_name = "SimpleScene" expected_pattern = r"[0-9a-zA-Z_]+[@_-]\d\d\d\d-\d\d-\d\d[@_-]\d\d-\d\d-\d\d" - with tempconfig({"scene_names": [scene_name]}): - file_name = _generate_file_name() - match = re.match(expected_pattern, file_name) - assert scene_name in file_name, ( - "Expected file to contain " + scene_name + " but got " + file_name - ) - assert match, "file name does not match expected pattern " + expected_pattern + config.scene_names = [scene_name] + file_name = _generate_file_name() + match = re.match(expected_pattern, file_name) + assert scene_name in file_name, ( + "Expected file to contain " + scene_name + " but got " + file_name + ) + assert match, "file name does not match expected pattern " + expected_pattern -def test_jupyter_file_output(tmp_path): +def test_jupyter_file_output(tmp_path, config): """Check the jupyter file naming is valid and can be created""" scene_name = "SimpleScene" - with tempconfig({"scene_names": [scene_name]}): - file_name = _generate_file_name() - actual_path = tmp_path.with_name(file_name) - with actual_path.open("w") as outfile: - outfile.write("") - assert actual_path.exists() - assert actual_path.is_file() + config.scene_names = [scene_name] + file_name = _generate_file_name() + actual_path = tmp_path.with_name(file_name) + with actual_path.open("w") as outfile: + outfile.write("") + assert actual_path.exists() + assert actual_path.is_file() diff --git a/tests/test_linear_transformation_scene.py b/tests/test_linear_transformation_scene.py index c45e3f6997..d0592b8f44 100644 --- a/tests/test_linear_transformation_scene.py +++ b/tests/test_linear_transformation_scene.py @@ -20,5 +20,6 @@ def test_ghost_vectors_len_and_types(): assert len(ghosts[0]) == 2 # check types of ghost vectors - assert isinstance(ghosts, VGroup) and isinstance(ghosts[0], VGroup) + assert isinstance(ghosts, VGroup) + assert isinstance(ghosts[0], VGroup) assert all(isinstance(x, Vector) for x in ghosts[0]) diff --git a/tests/test_logging/test_logging.py b/tests/test_logging/test_logging.py index ca209482a7..397573a51e 100644 --- a/tests/test_logging/test_logging.py +++ b/tests/test_logging/test_logging.py @@ -46,7 +46,8 @@ def test_error_logging(tmp_path, python_version): out, err, exitcode = capture(command) if err is None: err = out - assert exitcode != 0 and "Traceback (most recent call last)" in err + assert exitcode != 0 + assert "Traceback (most recent call last)" in err @logs_comparison( @@ -69,4 +70,5 @@ def test_tex_error_logs(tmp_path, python_version): "BadTex", ] _, err, exitcode = capture(command) - assert exitcode != 0 and len(err) > 0 + assert exitcode != 0 + assert len(err) > 0 diff --git a/tests/test_plugins/test_plugins.py b/tests/test_plugins/test_plugins.py index e81dc47085..428dbd732c 100644 --- a/tests/test_plugins/test_plugins.py +++ b/tests/test_plugins/test_plugins.py @@ -59,7 +59,7 @@ def {function_name}(): @pytest.fixture def simple_scenes_path(): - yield Path(__file__).parent / "simple_scenes.py" + return Path(__file__).parent / "simple_scenes.py" def cfg_file_create(cfg_file_contents, path): @@ -73,7 +73,7 @@ def random_string(): all_letters = string.ascii_lowercase a = random.Random() final_letters = [a.choice(all_letters) for _ in range(8)] - yield "".join(final_letters) + return "".join(final_letters) def test_plugin_warning(tmp_path, python_version, simple_scenes_path): diff --git a/tests/test_scene_rendering/click.mp3 b/tests/test_scene_rendering/click.mp3 new file mode 100644 index 0000000000..8abc5221dd Binary files /dev/null and b/tests/test_scene_rendering/click.mp3 differ diff --git a/tests/test_scene_rendering/conftest.py b/tests/test_scene_rendering/conftest.py index d7ae208524..7263a3f37c 100644 --- a/tests/test_scene_rendering/conftest.py +++ b/tests/test_scene_rendering/conftest.py @@ -4,8 +4,6 @@ import pytest -from manim import config, tempconfig - @pytest.fixture def manim_cfg_file(): @@ -18,50 +16,39 @@ def simple_scenes_path(): @pytest.fixture -def using_temp_config(tmpdir): - """Standard fixture that makes tests use a standard_config.cfg with a temp dir.""" - with tempconfig( - config.digest_file(Path(__file__).parent.parent / "standard_config.cfg"), - ): - config.media_dir = tmpdir - yield +def standard_config(config): + return config.digest_file(Path(__file__).parent.parent / "standard_config.cfg") @pytest.fixture -def using_temp_opengl_config(tmpdir): +def using_temp_config(tmpdir, standard_config): """Standard fixture that makes tests use a standard_config.cfg with a temp dir.""" - with tempconfig( - config.digest_file(Path(__file__).parent.parent / "standard_config.cfg"), - ): - config.media_dir = tmpdir - config.renderer = "opengl" - yield + standard_config.media_dir = tmpdir @pytest.fixture -def disabling_caching(): - with tempconfig({"disable_caching": True}): - yield +def using_temp_opengl_config(tmpdir, standard_config, using_opengl_renderer): + """Standard fixture that makes tests use a standard_config.cfg with a temp dir.""" + standard_config.media_dir = tmpdir @pytest.fixture -def infallible_scenes_path(): - return Path(__file__).parent / "infallible_scenes.py" +def disabling_caching(config): + config.disable_caching = True @pytest.fixture -def use_opengl_renderer(enable_preview): - with tempconfig({"renderer": "opengl", "preview": enable_preview}): - yield +def infallible_scenes_path(): + return Path(__file__).parent / "infallible_scenes.py" @pytest.fixture -def force_window_config_write_to_movie(): - with tempconfig({"force_window": True, "write_to_movie": True}): - yield +def force_window_config_write_to_movie(config): + config.force_window = True + config.write_to_movie = True @pytest.fixture -def force_window_config_pngs(): - with tempconfig({"force_window": True, "format": "png"}): - yield +def force_window_config_pngs(config): + config.force_window = True + config.format = "png" diff --git a/tests/test_scene_rendering/opengl/test_opengl_renderer.py b/tests/test_scene_rendering/opengl/test_opengl_renderer.py index 95f7adde0b..f2236cb04d 100644 --- a/tests/test_scene_rendering/opengl/test_opengl_renderer.py +++ b/tests/test_scene_rendering/opengl/test_opengl_renderer.py @@ -3,6 +3,7 @@ import platform from unittest.mock import Mock +import numpy as np import pytest from manim.renderer.opengl_renderer import OpenGLRenderer @@ -10,18 +11,21 @@ from tests.test_scene_rendering.simple_scenes import * -def test_write_to_movie_disables_window(using_temp_opengl_config, disabling_caching): +def test_write_to_movie_disables_window( + config, using_temp_opengl_config, disabling_caching +): """write_to_movie should disable window by default""" scene = SquareToCircle() renderer = scene.renderer renderer.update_frame = Mock(wraps=renderer.update_frame) scene.render() assert renderer.window is None - assert_file_exists(config["output_file"]) + assert_file_exists(config.output_file) -@pytest.mark.skip(reason="Temporarily skip due to failing in Windows CI") # type: ignore +@pytest.mark.skip(reason="Temporarily skip due to failing in Windows CI") def test_force_window_opengl_render_with_movies( + config, using_temp_opengl_config, force_window_config_write_to_movie, disabling_caching, @@ -53,9 +57,10 @@ def test_force_window_opengl_render_with_format( renderer.window.close() -@pytest.mark.parametrize("enable_preview", [False]) -def test_get_frame_with_preview_disabled(use_opengl_renderer): +def test_get_frame_with_preview_disabled(config, using_opengl_renderer): """Get frame is able to fetch frame with the correct dimensions when preview is disabled""" + config.preview = False + scene = SquareToCircle() assert isinstance(scene.renderer, OpenGLRenderer) assert not config.preview @@ -70,9 +75,10 @@ def test_get_frame_with_preview_disabled(use_opengl_renderer): @pytest.mark.slow -@pytest.mark.parametrize("enable_preview", [True]) -def test_get_frame_with_preview_enabled(use_opengl_renderer): +def test_get_frame_with_preview_enabled(config, using_opengl_renderer): """Get frame is able to fetch frame with the correct dimensions when preview is enabled""" + config.preview = True + scene = SquareToCircle() assert isinstance(scene.renderer, OpenGLRenderer) assert config.preview is True @@ -86,8 +92,9 @@ def test_get_frame_with_preview_enabled(use_opengl_renderer): assert renderer.get_pixel_shape()[1] == frame.shape[0] -@pytest.mark.parametrize("enable_preview", [True]) -def test_pixel_coords_to_space_coords(use_opengl_renderer): +def test_pixel_coords_to_space_coords(config, using_opengl_renderer): + config.preview = True + scene = SquareToCircle() assert isinstance(scene.renderer, OpenGLRenderer) diff --git a/tests/test_scene_rendering/opengl/test_play_logic_opengl.py b/tests/test_scene_rendering/opengl/test_play_logic_opengl.py index cb640c5f80..64c4c39204 100644 --- a/tests/test_scene_rendering/opengl/test_play_logic_opengl.py +++ b/tests/test_scene_rendering/opengl/test_play_logic_opengl.py @@ -5,8 +5,11 @@ import pytest -from manim import * -from manim import config +from manim import ( + Scene, + ValueTracker, + np, +) from ..simple_scenes import ( SceneForFrozenFrameTests, @@ -23,7 +26,7 @@ reason="Mock object has a different implementation in python 3.7, which makes it broken with this logic.", ) @pytest.mark.parametrize("frame_rate", argvalues=[15, 30, 60]) -def test_t_values(using_temp_opengl_config, disabling_caching, frame_rate): +def test_t_values(config, using_temp_opengl_config, disabling_caching, frame_rate): """Test that the framerate corresponds to the number of t values generated""" config.frame_rate = frame_rate scene = SquareToCircle() @@ -36,10 +39,6 @@ def test_t_values(using_temp_opengl_config, disabling_caching, frame_rate): ) -@pytest.mark.skipif( - sys.version_info < (3, 8), - reason="Mock object has a different implementation in python 3.7, which makes it broken with this logic.", -) def test_t_values_with_skip_animations(using_temp_opengl_config, disabling_caching): """Test the behaviour of scene.skip_animations""" scene = SquareToCircle() @@ -95,7 +94,7 @@ def test_t_values_with_cached_data(using_temp_opengl_config): @pytest.mark.xfail(reason="Not currently handled correctly for opengl") -def test_t_values_save_last_frame(using_temp_opengl_config): +def test_t_values_save_last_frame(config, using_temp_opengl_config): """Test that there is only one t value handled when only saving the last frame""" config.save_last_frame = True scene = SquareToCircle() diff --git a/tests/test_scene_rendering/simple_scenes.py b/tests/test_scene_rendering/simple_scenes.py index 8f4dd9d434..7f626ffbe2 100644 --- a/tests/test_scene_rendering/simple_scenes.py +++ b/tests/test_scene_rendering/simple_scenes.py @@ -4,6 +4,21 @@ from manim import * +__all__ = [ + "SquareToCircle", + "SceneWithMultipleCalls", + "SceneWithMultipleWaitCalls", + "NoAnimations", + "SceneWithStaticWait", + "SceneWithSceneUpdater", + "SceneForFrozenFrameTests", + "SceneWithNonStaticWait", + "StaticScene", + "InteractiveStaticScene", + "SceneWithSections", + "ElaborateSceneWithSections", +] + class SquareToCircle(Scene): def construct(self): @@ -120,7 +135,7 @@ class PresentationSectionType(str, Enum): ) self.wait(2) - self.next_section(type=PresentationSectionType.SKIP) + self.next_section(section_type=PresentationSectionType.SKIP) self.wait() self.next_section( diff --git a/tests/test_scene_rendering/test_file_writer.py b/tests/test_scene_rendering/test_file_writer.py index 6ccc8b25d0..0065547709 100644 --- a/tests/test_scene_rendering/test_file_writer.py +++ b/tests/test_scene_rendering/test_file_writer.py @@ -1,4 +1,5 @@ import sys +from fractions import Fraction from pathlib import Path import av @@ -6,6 +7,7 @@ import pytest from manim import DR, Circle, Create, Scene, Star, tempconfig +from manim.scene.scene_file_writer import to_av_frame_rate from manim.utils.commands import capture, get_video_metadata @@ -32,7 +34,7 @@ def construct(self): "transparent", [False, True], ) -def test_gif_writing(tmp_path, transparent): +def test_gif_writing(config, tmp_path, transparent): output_filename = f"gif_{'transparent' if transparent else 'opaque'}" with tempconfig( { @@ -81,7 +83,7 @@ def test_gif_writing(tmp_path, transparent): @pytest.mark.slow @pytest.mark.parametrize( - "format, transparent, codec, pixel_format", + ("format", "transparent", "codec", "pixel_format"), [ ("mp4", False, "h264", "yuv420p"), ("mov", False, "h264", "yuv420p"), @@ -90,7 +92,7 @@ def test_gif_writing(tmp_path, transparent): ("webm", True, "vp9", "yuv420p"), ], ) -def test_codecs(tmp_path, format, transparent, codec, pixel_format): +def test_codecs(config, tmp_path, format, transparent, codec, pixel_format): output_filename = f"codec_{format}_{'transparent' if transparent else 'opaque'}" with tempconfig( { @@ -145,8 +147,19 @@ def test_codecs(tmp_path, format, transparent, codec, pixel_format): np.testing.assert_allclose(first_frame[-1, -1], target_rgba_center, atol=5) +def test_scene_with_non_raw_or_wav_audio(config, manim_caplog): + class SceneWithMP3(Scene): + def construct(self): + file_path = Path(__file__).parent / "click.mp3" + self.add_sound(file_path) + self.wait() + + SceneWithMP3().render() + assert "click.mp3 to .wav" in manim_caplog.text + + @pytest.mark.slow -def test_unicode_partial_movie(tmpdir, simple_scenes_path): +def test_unicode_partial_movie(config, tmpdir, simple_scenes_path): # Characters that failed for a user on Windows # due to its weird default encoding. unicode_str = "三角函数" @@ -164,3 +177,11 @@ def test_unicode_partial_movie(tmpdir, simple_scenes_path): _, err, exit_code = capture(command) assert exit_code == 0, err + + +def test_frame_rates(): + assert to_av_frame_rate(25) == Fraction(25, 1) + assert to_av_frame_rate(24.0) == Fraction(24, 1) + assert to_av_frame_rate(23.976) == Fraction(24 * 1000, 1001) + assert to_av_frame_rate(23.98) == Fraction(24 * 1000, 1001) + assert to_av_frame_rate(59.94) == Fraction(60 * 1000, 1001) diff --git a/tests/test_scene_rendering/test_play_logic.py b/tests/test_scene_rendering/test_play_logic.py index a0d97920bd..4aaae3c8ad 100644 --- a/tests/test_scene_rendering/test_play_logic.py +++ b/tests/test_scene_rendering/test_play_logic.py @@ -5,8 +5,14 @@ import pytest -from manim import * -from manim import config +from manim import ( + Dot, + Mobject, + Scene, + ValueTracker, + Wait, + np, +) from .simple_scenes import ( SceneForFrozenFrameTests, @@ -18,12 +24,8 @@ ) -@pytest.mark.skipif( - sys.version_info < (3, 8), - reason="Mock object has a different implementation in python 3.7, which makes it broken with this logic.", -) @pytest.mark.parametrize("frame_rate", argvalues=[15, 30, 60]) -def test_t_values(using_temp_config, disabling_caching, frame_rate): +def test_t_values(config, using_temp_config, disabling_caching, frame_rate): """Test that the framerate corresponds to the number of t values generated""" config.frame_rate = frame_rate scene = SquareToCircle() @@ -76,14 +78,14 @@ def test_non_static_wait_detection(using_temp_config, disabling_caching): def test_wait_with_stop_condition(using_temp_config, disabling_caching): class TestScene(Scene): def construct(self): - self.wait_until(lambda: self.renderer.time >= 1) - assert self.renderer.time >= 1 + self.wait_until(lambda: self.time >= 1) + assert self.time >= 1 d = Dot() d.add_updater(lambda mobj, dt: self.add(Mobject())) self.add(d) self.play(Wait(run_time=5, stop_condition=lambda: len(self.mobjects) > 5)) assert len(self.mobjects) > 5 - assert self.renderer.time < 2 + assert self.time < 2 scene = TestScene() scene.render() @@ -110,7 +112,7 @@ def test_t_values_with_cached_data(using_temp_config): assert scene.update_to_time.call_count == 10 -def test_t_values_save_last_frame(using_temp_config): +def test_t_values_save_last_frame(config, using_temp_config): """Test that there is only one t value handled when only saving the last frame""" config.save_last_frame = True scene = SquareToCircle() diff --git a/tests/utils/logging_tester.py b/tests/utils/logging_tester.py index d2501c8c2a..1fd8b4b165 100644 --- a/tests/utils/logging_tester.py +++ b/tests/utils/logging_tester.py @@ -66,7 +66,6 @@ def logs_comparison( Callable[[Any], Any] The test wrapped with which we are going to make the comparison. """ - control_data_file = Path(control_data_file) log_path_from_media_dir = Path(log_path_from_media_dir) diff --git a/tests/utils/video_tester.py b/tests/utils/video_tester.py index 2b74e65409..21b136b305 100644 --- a/tests/utils/video_tester.py +++ b/tests/utils/video_tester.py @@ -90,7 +90,6 @@ def video_comparison( -------- tests/helpers/video_utils.py : create control data """ - control_data_file = Path(control_data_file) scene_path_from_media_dir = Path(scene_path_from_media_dir)